Skip to content

Commit

Permalink
wip(docs)
Browse files Browse the repository at this point in the history
  • Loading branch information
emil14 committed Feb 8, 2024
1 parent 2eca8b6 commit 597173f
Show file tree
Hide file tree
Showing 13 changed files with 159 additions and 77 deletions.
31 changes: 30 additions & 1 deletion assets/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,33 @@ pre {
.docs-nav a:hover {
opacity: 1;
text-decoration: underline;
}
}

a.theme-toggle:hover {
text-decoration: none;
}

.docs-card {
display: block;
box-shadow: none;
border: 1px solid var(--color-lightGrey);
border-bottom: none;
border-radius: 0;
}

.docs-card:first-child {
border-radius: 5px 5px 0 0;
}

.docs-card:last-child {
border-bottom: 1px solid var(--color-lightGrey);
border-radius: 0 0 5px 5px;
}

a.docs-card:hover {
/* background-color: var(--color-primary); */
/* border-color: var(--bg-color); */
text-decoration: none;
/* color: var(--bg-color); */
}

2 changes: 1 addition & 1 deletion content/docs/about/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: About The Language
weight: 1
description: Nevalang is a general purpose flow-based programming language with static structural typing that compiles to machine code and Go and designed with visual programming in mind.
---

7 changes: 3 additions & 4 deletions content/docs/directives/index.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
---
title: Compiler directives
weight: 5
---

Compiler directives are special instructions for compiler.
description: "Compiler directives are special instructions for compiler.
They are not intended to be used on a daily basis by regular user but good nevalang programmer understands how they work because they are base for how many language features operate.
They are not intended to be used on a daily basis by regular user but good nevalang programmer understands how they work because they are base for how many language features operate"
---

## `#extern`

Expand Down
1 change: 1 addition & 0 deletions content/docs/faq/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: FAQ
weight: 6
description: Answer to questions about language design.
---

## What is this?
Expand Down
1 change: 1 addition & 0 deletions content/docs/quick-start/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: Quick Start
weight: 2
description: Install Nevalang and create your first project in one minute!
---

## Installing Nevalang
Expand Down
7 changes: 3 additions & 4 deletions content/docs/style-guide/index.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
---
title: Style guide
weight: 4
description: The Nevalang style guide outlined in this document sets the standards for organizing and formatting code, designing components, and choosing appropriate names. It's recommended that all programs follow this guide to ensure consistency across Nevalang code, making it easier to read and understand.
---

The Nevalang style guide outlined in this document sets the standards for organizing and formatting code, designing components, and choosing appropriate names. It's recommended that all programs follow this guide to ensure consistency across Nevalang code, making it easier to read and understand.

## Code Organization

- **File Size**: Aim for files to be up to 300 lines. Files longer than 300 lines should be split, indicating a need for better organization.
- **Lines Count**: Aim for files to be up to 300 lines. Files longer than 300 lines should be split, indicating a need for better organization.

## Formatting

Expand All @@ -16,7 +15,7 @@ The Nevalang style guide outlined in this document sets the standards for organi
- **Entity Blocks**: Group similar entities (like types or components) within `{}` blocks for clarity, but use discretion for cases where separate contexts are needed.
- **Newlines**: Always insert newlines after imports and between entities.

## Design
## API Design

- **Generics Usage**: Utilize generics when data type consistency across inports and outports is important.
- **Flow Separation**: Use outports to differentiate data paths and structs for data that always moves together.
Expand Down
44 changes: 44 additions & 0 deletions content/docs/tutorial/01/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: A Program That Does Nothing
weight: 1
---

Here is the smallest program in Nevalang that compiles. It absolutely does nothing, but by looking at it, you can learn a lot about Nevalang.

```neva
component Main(start any) (stop any) {
net { in:start -> out:stop }
}
```

Let's break down what's written here.

A Nevalang program consists of _components_ that send _messages_ to each other through _ports_ but ports cannot be connected randomly. Each port has its own _data type_, and when we connect one port to another, the compiler checks if they are _compatible_. Otherwise, it throws an error.

It states that there is a "Main" component (every component has a name), with two ports - one for input - `start` - and one for output - `stop`. The data type of both ports is `any` - a universal data type, saying "I am compatible with any types of data."

```neva
Main (start any) (stop any)
```

Next, we see a block of curly braces `{}` and inside another one with the keyword `net`.

```neva
{
net { in:start -> out:stop }
}
```

Ports are the _interface_ of a component, but in addition to the interface, a component also needs a _body_ - code that describes what exactly the component does, what work it performs. In this case, the curly braces are the body, and `net` is the _network_ - the computational scheme of the component.

In Nevalang, programming is _flow-based_, and instead of controlling the flow of execution, as in conventional languages, we control the flow of data. We don't call functions, don't execute instructions; we just route messages from one place to another, thus creating a graph that describes how data flows through the program. That's why such programming is called flow-based.

In this case, we see that data flows directly from the input port `start` to the output port `stop`.

```
in:start -> out:stop
```

In other words, our Main component does nothing. It just lets data pass through itself without having any impact on the external world. Essentially, it could be called a bypass, but in a Nevalang program, there must always be at least one `Main` component (we'll understand why later).

The curious reader may wonder, what about `in:` and `out:`? Why couldn't we just write `start -> stop`? The fact is that there can be any number of ports for both input and output (although typically there are no more than three on each side). Input and output ports can sometimes have the same names. To avoid confusion, we specify the direction - `in` is input, and `out` is output.
Original file line number Diff line number Diff line change
@@ -1,56 +1,8 @@
---
title: Tutorial
weight: 3
title: Echo
weight: 2
---

Welcome to the "Learn Nevalang the Hard Way" tutorial! This comprehensive guide is designed to teach you the Nevalang programming language through detailed examples, covering everything you need to grasp the full scope of the language.

In this tutorial, you'll explore and simplify many small programs, moving from complex and wordy to simple and clear. By breaking these down step by step, you'll fully understand how things work in Nevalang, ensuring that nothing feels like magic. Let's dive in!

## A Program That Does Nothing

Here is the smallest program in Nevalang that compiles. It absolutely does nothing, but by looking at it, you can learn a lot about Nevalang.

```neva
component Main(start any) (stop any) {
net { in:start -> out:stop }
}
```

Let's break down what's written here.

A Nevalang program consists of _components_ that send _messages_ to each other through _ports_ but ports cannot be connected randomly. Each port has its own _data type_, and when we connect one port to another, the compiler checks if they are _compatible_. Otherwise, it throws an error.

It states that there is a "Main" component (every component has a name), with two ports - one for input - `start` - and one for output - `stop`. The data type of both ports is `any` - a universal data type, saying "I am compatible with any types of data."

```neva
Main (start any) (stop any)
```

Next, we see a block of curly braces `{}` and inside another one with the keyword `net`.

```neva
{
net { in:start -> out:stop }
}
```

Ports are the _interface_ of a component, but in addition to the interface, a component also needs a _body_ - code that describes what exactly the component does, what work it performs. In this case, the curly braces are the body, and `net` is the _network_ - the computational scheme of the component.

In Nevalang, programming is _flow-based_, and instead of controlling the flow of execution, as in conventional languages, we control the flow of data. We don't call functions, don't execute instructions; we just route messages from one place to another, thus creating a graph that describes how data flows through the program. That's why such programming is called flow-based.

In this case, we see that data flows directly from the input port `start` to the output port `stop`.

```
in:start -> out:stop
```

In other words, our Main component does nothing. It just lets data pass through itself without having any impact on the external world. Essentially, it could be called a bypass, but in a Nevalang program, there must always be at least one `Main` component (we'll understand why later).

The curious reader may wonder, what about `in:` and `out:`? Why couldn't we just write `start -> stop`? The fact is that there can be any number of ports for both input and output (although typically there are no more than three on each side). Input and output ports can sometimes have the same names. To avoid confusion, we specify the direction - `in` is input, and `out` is output.

## Echo

If you've gone through the quick start, you should have already created your first project. In that case, simply update the code in `main.neva` to include the `Echo` component from this example. For everyone else, let's execute the following commands:

```bash
Expand Down Expand Up @@ -146,16 +98,16 @@ Are you still here? It's quite a lot for an introductory lesson, isn't it? But t
Let's finally take another look at the network of our Main component:

```
net {
in:start -> reader:sig
reader:data -> printer:data
printer:sig -> reader:sig
}
net {
in:start -> reader:sig
reader:data -> printer:data
printer:sig -> out:stop
}
```

Now that we know what "nodes" are, we can understand this syntax a bit deeper. So, the network consists of connections. In this case, three. The order in which connections are declared in the code is absolutely not important. Remember - we do not control the flow of execution, but merely set the direction in which data flows.
Now that we know what nodes are, we can understand this syntax a bit deeper. So, the network consists of connections. In this case, three. The order in which connections are declared in the code is absolutely not important. Remember - we do not control the flow of execution, but merely set the direction in which data flows.

Each connection consists of a sender and a receiver. Both the sender and the receiver are described by constructs called "port addresses," which in turn consist of a node and a port. For example, in the connection:
Each connection consists of a _sender_ and a _receiver_. Both are described by constructs called _port addresses_ which in turn consist of a node and a port. For example, in the connection:

```
reader:data -> printer:data
Expand All @@ -165,7 +117,7 @@ The output port `data` of the `reader` node is directed into the input port `dat

Finally, the curious reader might wonder, aren't `in` and `out` also nodes? After all, they are not instances of some components?

Correct, they are not. The fact is that there are indeed two types of "nodes" - component instances and the so-called IO nodes, of which there are always two in the network of each component - the `in` node and the `out` node.
Correct, they are not. The fact is that there are indeed two types of nodes - _component instances_ and the so-called _IO nodes_, of which there are always two in the network of each component - the `in` node and the `out` node.

Now, if you don't understand the following paragraph, that's absolutely fine. But for the most demanding readers, it is necessary to clarify that the `in` node contains only output ports, and the `out` node only input ports. This inversion might be confusing, but it is actually quite natural - a component reads data from its input ports as if they are the output ports of some node and correspondingly writes to its output ports as if they are someone else's input ports.

Expand All @@ -174,7 +126,25 @@ Finally, let's dissect the algorithm our network executes. So, we have 3 connect
```
in:start -> reader:sig
reader:data -> printer:data
printer:sig -> reader:sig
printer:sig -> out:stop
```

As we see, the `start` signal goes to the `reader` node into the `sig` port. The `sig` port typically signifies a _signal_ to start performing work. The `Reader` component is designed in such a way that upon receiving this signal, it will _block_, waiting for input from the keyboard. After the user enters text and presses Enter, the program will be unblocked, and the entered data will be sent to the `Printer` component, which, in turn, will print it out and emit a `sig` signal on its output. We use this signal to close our loop, forming a cycle. The program will terminate if "ctrl+c" is pressed, but until then, it will continuously operate, constantly waiting for input and then printing it, ad infinitum.

Before we move on, let's simplify our program just a bit. We'll remove the `import { std/builtin }` line and also eliminate every `builtin.` prefix from our nodes' instantiations.

```neva
component Main(start any) (stop any) {
nodes {
reader Reader
printer Printer<string>
}
net {
in:start -> reader:sig
reader:data -> printer:data
printer:sig -> reader:sig
}
}
```

It still works! In fact, the compiler implicitly injects the `std/builtin` import into every file and checks if the entity we refer to is defined there. However, if we, for example, define our own `Reader` in this package, it will _shadow_ the built-in one.
29 changes: 29 additions & 0 deletions content/docs/tutorial/03/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
title: Hello World
weight: 3
---

Isn't it odd to reach the "Hello, World!" moment only in the third lesson - the starting point that most tutorials begin with? Well, many peculiarities await us in Nevalang. However, we hope that by the end of this tutorial, they will no longer seem like oddities. Who knows, you might even start thinking, "Could it have been any other way?". Of course, we could have started with "Hello, World!" too, without delving into the intricate details of how every little thing works, but our goal, once again, is to achieve a deep understanding of how Nevalang is structured. And, actually, "Hello, World!" is not as straightforward as it seems.

```neva
const greeting string = 'Hello, World!'
component Main(start any) (stop any) {
nodes {
#bind(greeting)
greeting Emitter<string>
printer Printer<string>
blocker Blocker<string>
}
net {
in:start -> blocker:sig
greeting:msg -> blocker:data
blocker:data -> printer:msg
printer:msg -> out:stop
}
}
```

You might be thinking right now - "This is the most verbose 'Hello, World!' I've ever seen!" And, quite likely, you are correct. But don't rush to close the page; by dissecting this example, we'll learn how to write code more concisely. Without going through this example and jumping straight to the shorter version, we would never understand how the short version actually works.

TODO...
7 changes: 7 additions & 0 deletions content/docs/tutorial/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: Tutorial
weight: 3
description: "Welcome to the 'Learn Nevalang the Hard Way' tutorial! This comprehensive guide is designed to teach you the Nevalang programming language through detailed examples, covering everything you need to grasp the full scope of the language.
In this tutorial, you'll explore and simplify many small programs, moving from complex and wordy to simple and clear. By breaking these down step by step, you'll fully understand how things work in Nevalang, ensuring that nothing feels like magic. Let's dive in!"
---
16 changes: 9 additions & 7 deletions layouts/docs/list.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
{{ define "main" }}
<div class="row">
<aside class="col-3">{{ partial "docs-nav.html" . }}</aside>
<div class="col-9">
<h1>{{ .Title }}</h1>
{{ .Content }}
<h1 class="text-center">{{.Title}}</h1>
<div>
{{ range .Pages }}
<a href="{{ .RelPermalink }}" class="card docs-card">
<h2>{{ .Title }}</h2>
<p>{{ .Description }}</p>
</a>
{{ end }}
</div>
</div>
{{ end }}
{{ end }}
1 change: 1 addition & 0 deletions layouts/docs/single.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<aside class="col-3">{{ partial "docs-nav.html" . }}</aside>
<div class="col-9">
<h1>{{ .Title }}</h1>
{{ .Description }}
{{ .Content }}
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion layouts/partials/footer.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<div>
<span class="pull-left">© {{ now.Year }} Emil Valeev</span>
<a class="pull-right" href="javascript:void(0)" onclick="toggleDarkMode(this)"
<a class="pull-right theme-toggle" href="javascript:void(0)" onclick="toggleDarkMode(this)"
>🌙</a
>
</div>

0 comments on commit 597173f

Please sign in to comment.