dust-lang 0.4.2

General purpose programming language
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
# Dust Language Reference

!!! This is a **work in progress** and has incomplete information. !!!

This is an in-depth description of the syntax and abstractions used by the Dust language. It is not
necessary to read or understand all of it before you start using Dust. Instead, refer to it when
you need help with the syntax or understanding how the code is run.

Each section of this document corresponds to a node in the concrete syntax tree. Creating this tree
is the first step in interpreting Dust code. Second, the syntax tree is traversed and an abstract
tree is generated. Each node in the syntax tree corresponds to a node in the abstract tree. Third,
the abstract tree is verified to ensure that it will not generate any values that violate the type
restrictions. Finally, the abstract tree is run, beginning at the [root](#root).

You may reference the [grammar file](tree-sitter-dust/grammar.js) and the [Tree Sitter docs]
(https://tree-sitter.github.io/) while reading this guide to understand how the language is parsed.

<!--toc:start-->
- [Dust Language Reference]#dust-language-reference
  - [Root]#root
  - [Values]#values
    - [Boolean]#boolean
    - [Integer]#integer
    - [Float]#float
    - [Range]#range
    - [String]#string
    - [List]#list
    - [Map]#map
    - [Function]#function
    - [Option]#option
    - [Structure]#structure
  - [Types]#types
    - [Basic Types]#basic-types
    - [Number]#number
    - [Any]#any
    - [None]#none
    - [List Type]#list-type
    - [Map Type]#map-type
    - [Iter]#iter
    - [Function Type]#function-type
    - [Option Type]#option-type
    - [Custom Types]#custom-types
  - [Statements]#statements
    - [Assignment]#assignment
    - [Blocks]#blocks
      - [Synchronous Blocks]#synchronous-blocks
      - [Asynchronous Blocks]#asynchronous-blocks
    - [Break]#break
    - [For Loop]#for-loop
    - [While Loop]#while-loop
    - [If/Else]#ifelse
    - [Match]#match
    - [Pipe]#pipe
    - [Expression]#expression
  - [Expressions]#expressions
      - [Identifier]#identifier
      - [Index]#index
      - [Logic]#logic
      - [Math]#math
      - [Value]#value
      - [New]#new
      - [Command]#command
  - [Built-In Values]#built-in-values
  - [Comments]#comments
<!--toc:end-->

## Root

The root node represents all of the source code. It is a sequence of [statements](#statements) that
are executed synchronously, in order. The output of the program is always the result of the final
statement or the first error encountered.

## Values

There are ten kinds of value in Dust. Some are very simple and are parsed directly from the source
code, some are collections and others are used in special ways, like functions and structures. All
values can be assinged to an [identifier](#identifiers).

Dust does not have a null type. Absent values are represented with the `none` value, which is a
kind of [option](#option). You may not create a variable without a value and no variable can ever
be in an 'undefined' state during execution.

### Boolean

Booleans are true or false. They are represented by the literal tokens `true` and `false`.

### Integer

Integers are whole numbers that may be positive, negative or zero. Internally, an integer is a
signed 64-bit value.

```dust
42
```

Integers always **overflow** when their maximum or minimum value is reached. Overflowing means that
if the value is too high or low for the 64-bit integer, it will wrap around. You can use the built-
in values `int:max` and `int:min` to get the highest and lowest possible values.

```dust
assert_equal(int:max + 1, int:min)
assert_equal(int:min - 1, int:max)
```

### Float

A float is a numeric value with a decimal. Floats are 64-bit and, like integers, will **overflow**
at their bounds.

```dust
42.0
```

### Range

A range represents a contiguous sequence of integers. Dust ranges are **inclusive** so both the high
and low bounds will be represented.

```dust
0..100
```

### String

A string is a **utf-8** sequence used to represent text. Strings can be wrapped in single or double quotes as well as backticks.

```dust
'42'
"42"
`42`
'forty-two'
```

### List

A list is **collection** of values stored as a sequence and accessible by [indexing](#index) their position with an integer. Lists indexes begin at zero for the first item.

```dust
[ 42 'forty-two' ]
[ 123, 'one', 'two', 'three' ]
```

Note that the commas are optional, including trailing commas.

```dust
[1 2 3 4 5]:2
# Output: 3
```

### Map

Maps are flexible collections with arbitrary **key-value pairs**, similar to JSON objects. A map is
created with a pair of curly braces and its entries are variables declared inside those braces. Map
contents can be accessed using a colon `:`. Commas may optionally be included after the key-value
pairs.

```dust
reminder = {
    message = "Buy milk"
    tags = ["groceries", "home"]
}

reminder:message
# Output: Buy milk
```

Internally a map is represented by a B-tree. The implicit advantage of using a B-tree instead of a
hash map is that a B-tree is sorted and therefore can be easily compared to another. Maps are also
used by the interpreter as the data structure for holding variables. You can even inspect the active
**execution context** by calling the built-in `context()` function.

The map stores each [identifier](#identifiers)'s key with a value and the value's type. For internal
use by the interpreter, a type can be set to a key without a value. This makes it possible to check
the types of values before they are computed.

### Function

A function encapsulates a section of the abstract tree so that it can be run seperately and with
different arguments. The function body is a [block](#block), so adding `async` will cause the body
to run like any other `async` block. Unlike some languages, there are no concepts like futures or
async functions in Dust.

Functions are **first-class values** in Dust, so they can be assigned to variables like any other
value.

```dust
# This simple function has no arguments and no return value.
say_hi = () <none> {
    output("hi") # The "output" function is a built-in that prints to stdout.
}

# This function has one argument and will return a value.
add_one = (number <num>) <num> {
    number + 1
}

say_hi()
assert_equal(add_one(3), 4)
```

Functions can also be **anonymous**. This is useful for using **callbacks** (i.e. functions that are
called by another function).

```dust
# Use a callback to retain only the numeric characters in a string.
str:retain(
	'a1b2c3'
	(char <str>) <bool> {
		is_some(int:parse(char))
	}
)
```

### Option

An option represents a value that may not be present. It has two variants: **some** and **none**. 

```dust
say_something = (message <option(str)>) <str> {
    either_or(message, "hiya")
}

say_something(some("goodbye"))
# goodbye

say_something(none)
# hiya
```

Dust includes built-in functions to work with option values: `is_none`, `is_some` and `either_or`.

### Structure

A structure is a **concrete type value**. It is a value, like any other, and can be [assigned]
(#assignment) to an [identifier](#identifier). It can then be instantiated as a [map](#map) that
will only allow the variables present in the structure. Default values may be provided for each
variable in the structure, which will be propagated to the map it creates. Values without defaults
must be given a value during instantiation.

```dust
struct User {
    name <str>
    email <str>
    id <int> = generate_id()
}

bob = new User {
    name = "Bob"
    email = "bob@example.com"
}

# The variable "bob" is a structured map.
```

A map created by using [new](#new) is called a **structured map**. In other languages it may be
called a "homomorphic mapped type". Dust will generate errors if you try to set any values on the
structured map that are not allowed by the structure.

## Types

Dust enforces strict type checking. To make the language easier to write, **type inference** is used
to allow variables to be declared without specifying the type. Instead, the interpreter will figure
it out and set the strictest type possible.

To make the type-setting syntax easier to distinguish from the rest of your code, a **type
specification** is wrapped in pointed brackets. So variable assignment using types looks like this:

```dust
my_float <float> = 666.0
```

### Basic Types

The simple types, and their notation are:

- boolean `bool`
- integer `int`
- float `float`
- string `str`

### Number

The `num` type may represent a value of type `int` or `float`.

### Any

The `any` type does not enforce type bounds.

### None

The `none` type indicates that no value should be found after executing the statement or block, with
one expection: the `none` variant of the `option` type.

### List Type

A list's contents can be specified to create type-safe lists. The `list(str)` type would only allow
string values. Writing `list` without the parentheses and content type is equivalent to writing
`list(any)`.

### Map Type

The `map` type is unstructured and can hold any key-value pair.

### Iter

The `iter` type refers to types that can be used with a [for loop](#for-loop). These include `list`,
`range`, `string` and `map`.

### Function Type

A function's type specification is more complex than other types. A function value must always have
its arguments and return type specified when the **function value** is created.

```dust
my_function = (number <int>, text <str>) <none> {
    output(number)
    output(text)
}
```

But what if we need to specify a **function type** without creating the function value? This is
necessary when using callbacks or defining structures that have functions set at instantiation.

```dust
use_adder = (adder <(int) -> int>, number <int>) -> <int> {
    adder(number)
}

use_adder(
    (i <int>) <int> { i + 2 }
    40
)

# Output: 42
```

```dust
struct Message {
    send_n_times <(str, int) -> none>
}

stdout_message = new Message {
    send_n_times = (content <str>, n <int>) <none> {
        for _ in 0..n {
            output(content)
        }
    }
}
```

### Option Type

The `option(type)` type is expected to be either `some(value)` or `none`. The type of the value
inside the `some` is always specified.

```dust
result <option(str)> = none

for file in fs:read_dir("./") {
    if file:size > 100 {
        result = some(file:path)
        break
    }
}

output(result)
```

```dust
get_line_break_index(text <str>) <some(int)> {
    str:find(text, '\n')
}
```

### Custom Types

Custom types such as **structures** are referenced by their variable identifier.

```dust
File = struct {
    path <str>
    size <int>
    type <str>
}

print_file_info(file <File>) <none> {
  	info = file:path
    		+ '\n'
    		+ file:size
    		+ '\n' 
    		+ file:type
		
  	output(info)
}
```

## Statements

TODO

### Assignment

TODO

### Blocks

TODO

#### Synchronous Blocks

TODO

#### Asynchronous Blocks

```dust
# An async block will run each statement in its own thread.
async {
    output(random_integer())
    output(random_float())
    output(random_boolean())
}
```

```dust
data = async {
    output("Reading a file...")
    read("examples/assets/faithful.csv")
}
```

### Break

TODO

### For Loop

TODO

```dust
list = [ 1, 2, 3 ]

for number in list {
    output(number + 1)
}
```

### While Loop

TODO

A **while** loop continues until a predicate is false.

```dust
i = 0
while i < 10 {
    output(i)
    i += 1
}
```

### If/Else

TODO

### Match

TODO

### Pipe

TODO

### Expression

TODO

## Expressions

TODO

#### Identifier

TODO

#### Index

TODO

#### Logic

TODO

#### Math

TODO

#### Value

TODO

#### New

TODO

#### Command

TODO

## Built-In Values

TODO

## Comments

TODO