1
0
dust/README.md

276 lines
8.8 KiB
Markdown
Raw Normal View History

2023-08-22 15:40:50 +00:00
# Dust
2023-10-13 15:37:07 +00:00
Dust is a programming language and interactive shell. Dust can be used as a replacement for a traditional command line shell, as a scripting language and as a data format. Dust is fast, efficient and easy to learn.
2023-08-22 15:40:50 +00:00
A basic dust program:
```dust
2023-10-06 12:17:37 +00:00
(output "Hello world!")
2023-08-22 15:40:50 +00:00
```
2023-08-23 04:38:51 +00:00
Dust can do two (or more) things at the same time with effortless concurrency:
2023-08-22 15:40:50 +00:00
```dust
2023-10-17 01:13:58 +00:00
async {
(output 'will this one finish first?')
(output 'or will this one?')
}
2023-10-06 02:07:54 +00:00
```
2023-10-13 15:37:07 +00:00
Dust is an interpreted, general purpose language with first class functions. It is *data-oriented*, with extensive tools to manage structured and relational data. Dust also includes built-in tooling to import and export data in a variety of formats, including JSON, TOML, YAML and CSV.
2023-08-23 21:28:19 +00:00
<!--toc:start-->
- [Dust](#dust)
- [Features](#features)
- [Usage](#usage)
- [Installation](#installation)
- [The Dust Programming Language](#the-dust-programming-language)
2023-10-06 02:07:54 +00:00
- [Declaring Variables](#declaring-variables)
2023-08-23 21:28:19 +00:00
- [Lists](#lists)
- [Maps](#maps)
- [Tables](#tables)
- [Functions](#functions)
2023-10-17 01:13:58 +00:00
- [Concurrency](#concurrency)
2023-10-06 02:07:54 +00:00
- [Implementation](#implementation)
2023-08-23 21:28:19 +00:00
<!--toc:end-->
2023-08-22 15:40:50 +00:00
## Features
2023-10-13 15:37:07 +00:00
- Simplicity: Dust is designed to be easy to learn.
2023-10-06 02:07:54 +00:00
- Speed: Dust is built on [Tree Sitter] and [Rust] to prioritize performance and correctness.
2023-10-13 15:37:07 +00:00
- Data format: Dust is data-oriented, making it a great language for defining data.
2023-08-23 04:38:51 +00:00
- Format conversion: Effortlessly convert between dust and formats like JSON, CSV and TOML.
- Structured data: Dust can represent data with more than just strings. Lists, maps and tables are easy to make and manage.
2023-08-22 15:40:50 +00:00
## Usage
Dust is an experimental project under active development. At this stage, features come and go and the API is always changing. It should not be considered for serious use yet.
2023-08-28 22:05:49 +00:00
To get help with the shell you can use the "help" tool.
```dust
2023-10-25 20:41:51 +00:00
(help) # Returns a table with tool info.
2023-08-28 22:05:49 +00:00
```
2023-08-22 15:40:50 +00:00
## Installation
2023-10-06 02:07:54 +00:00
You must have the default rust toolchain installed and up-to-date. Install [rustup] if it is not already installed. Run `cargo install dust-lang` then run `dust` to start the interactive shell. Use `dust --help` to see the full command line options.
2023-08-23 21:28:19 +00:00
2023-10-06 02:07:54 +00:00
To build from source, clone the repository and build the parser. To do so, enter the `tree-sitter-dust` directory and run `tree-sitter-generate`. In the project root, run `cargo run` to start the shell. To see other command line options, use `cargo run -- --help`.
2023-08-23 21:28:19 +00:00
2023-08-23 04:38:51 +00:00
## The Dust Programming Language
2023-10-22 20:14:26 +00:00
Dust is easy to learn. Aside from this guide, the best way to learn Dust is to read the examples and tests to get a better idea of what it can do.
2023-08-22 15:40:50 +00:00
2023-10-06 02:07:54 +00:00
### Declaring Variables
2023-08-22 15:40:50 +00:00
2023-10-06 02:07:54 +00:00
Variables have two parts: a key and a value. The key is always a string. The value can be any of the following data types:
2023-08-22 15:40:50 +00:00
- string
- integer
- floating point value
- boolean
- list
- map
- table
- function
Here are some examples of variables in dust.
2023-08-23 04:38:51 +00:00
```dust
2023-10-06 02:07:54 +00:00
string = "The answer is 42."
integer = 42
float = 42.42
list = [1 2 string integer float] # Commas are optional when writing lists.
map = {
2023-10-11 17:10:06 +00:00
key = 'value'
2023-10-06 02:07:54 +00:00
}
2023-08-22 15:40:50 +00:00
```
2023-10-11 17:10:06 +00:00
Note that strings can be wrapped with any kind of quote: single, double or backticks. Numbers are always integers by default. Floats are declared by adding a decimal. If you divide integers or do any kind of math with a float, you will create a float value.
2023-08-22 15:40:50 +00:00
### Lists
2023-10-13 15:37:07 +00:00
Lists are sequential collections. They can be built by grouping values with square brackets. Commas are optional. Values can be indexed by their position using dot notation with an integer. Dust lists are zero-indexed.
2023-08-22 15:40:50 +00:00
2023-08-23 04:38:51 +00:00
```dust
2023-10-06 02:07:54 +00:00
list = [true 41 "Ok"]
2023-08-22 15:40:50 +00:00
2023-10-11 17:10:06 +00:00
(assert_equal list.0 true)
2023-08-29 02:07:20 +00:00
2023-10-06 02:07:54 +00:00
the_answer = list.1 + 1
2023-08-29 02:07:20 +00:00
2023-10-13 15:37:07 +00:00
(assert_equal the_answer, 42) # You can also use commas when passing values to
# a function.
2023-08-22 15:40:50 +00:00
```
### Maps
2023-10-22 19:52:33 +00:00
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 dot notation.
2023-08-22 15:40:50 +00:00
2023-08-23 04:38:51 +00:00
```dust
2023-10-06 02:07:54 +00:00
reminder = {
message = "Buy milk"
tags = ["groceries", "home"]
}
2023-08-22 15:40:50 +00:00
2023-10-11 17:10:06 +00:00
(output reminder.message)
2023-08-22 15:40:50 +00:00
```
2023-10-17 20:21:59 +00:00
### Loops
A **while** loop continues until a predicate is false.
```dust
i = 0
while i < 10 {
(output i)
i += 1
}
```
A **for** loop operates on a list without mutating it or the items inside. It does not return a value.
```dust
list = [ 1, 2, 3 ]
for number in list {
2023-10-22 19:52:33 +00:00
(output number + 1)
2023-10-17 20:21:59 +00:00
}
```
2023-10-22 19:52:33 +00:00
To create a new list, use a **transform** loop, which modifies the values into a new list without changing the original.
2023-10-17 20:21:59 +00:00
```dust
2023-10-22 19:52:33 +00:00
list = [1 2 3]
2023-10-22 20:14:26 +00:00
new_list = transform number in list {
2023-10-17 20:21:59 +00:00
number - 1
}
2023-11-04 10:02:27 +00:00
list
-> filter()
-> ()
2023-10-22 19:52:33 +00:00
(output new_list)
2023-10-17 20:21:59 +00:00
# Output: [ 0 1 2 ]
2023-10-22 19:52:33 +00:00
(output list)
# Output: [ 1 2 3 ]
2023-10-17 20:21:59 +00:00
```
To filter out some of the values in a list, use a **filter** loop.
```dust
list = filter number in [1 2 3] {
number >= 2
}
(output list)
# Output: [ 2 3 ]
```
A **find** loop will return a single value, the first item that satisfies the predicate.
```dust
found = find number in [1 2 1] {
number != 1
}
(output found)
# Output: 2
```
2023-08-22 15:40:50 +00:00
### Tables
2023-10-22 19:52:33 +00:00
Tables are strict collections, each row must have a value for each column. If a value is "missing" it should be set to an appropriate value for that type. For example, a string can be empty and a number can be set to zero. Dust table declarations consist of a list of column names, which are identifiers enclosed in pointed braces, followed by a list of rows.
2023-08-22 15:40:50 +00:00
2023-08-23 04:38:51 +00:00
```dust
2023-10-22 19:52:33 +00:00
animals = table <name species age> [
2023-10-06 02:07:54 +00:00
["rover" "cat" 14]
["spot" "snake" 9]
["bob" "giraffe" 2]
2023-10-22 19:52:33 +00:00
]
2023-08-22 15:40:50 +00:00
```
2023-08-23 04:38:51 +00:00
Querying a table is similar to SQL.
```dust
2023-10-06 02:07:54 +00:00
names = select name from animals
youngins = select species from animals {
age <= 10
}
2023-08-22 15:40:50 +00:00
```
2023-10-06 02:07:54 +00:00
The keywords `table` and `insert` make sure that all of the memory used to hold the rows is allocated at once, so it is good practice to group your rows together instead of using a call for each row.
2023-08-22 15:40:50 +00:00
2023-08-23 04:38:51 +00:00
```dust
2023-10-22 19:52:33 +00:00
insert into animals [
2023-10-06 02:07:54 +00:00
["eliza" "ostrich" 4]
["pat" "white rhino" 7]
["jim" "walrus" 9]
2023-10-22 19:52:33 +00:00
]
2023-08-22 15:40:50 +00:00
2023-10-11 17:10:06 +00:00
(assert_equal 6 (length animals))
2023-08-22 15:40:50 +00:00
```
### Functions
2023-10-22 19:52:33 +00:00
Functions are first-class values in dust, so they are assigned to variables like any other value. The function body is wrapped in single parentheses. To create a function, use the "function" keyword. The function's arguments are identifiers inside of a set of pointed braces and the function body is enclosed in curly braces. To call a fuction, invoke its variable name inside a set of parentheses. You don't need commas when listing arguments and you don't need to add whitespace inside the function body but doing so may make your code easier to read.
2023-08-22 15:40:50 +00:00
2023-08-23 04:38:51 +00:00
```dust
2023-10-06 02:07:54 +00:00
say_hi = function <> {
2023-10-11 17:10:06 +00:00
(output "hi")
2023-10-06 02:07:54 +00:00
}
2023-08-22 15:40:50 +00:00
2023-10-06 02:07:54 +00:00
add_one = function <number> {
2023-10-11 17:10:06 +00:00
(number + 1)
2023-10-06 02:07:54 +00:00
}
2023-10-11 17:10:06 +00:00
(say_hi)
(assert_equal (add_one 3), 4)
2023-08-22 15:40:50 +00:00
```
This function simply passes the input to the shell's standard output.
2023-08-23 04:38:51 +00:00
```dust
2023-10-06 02:07:54 +00:00
print = function <input> {
2023-10-11 17:10:06 +00:00
(output input)
2023-10-06 02:07:54 +00:00
}
2023-08-22 15:40:50 +00:00
```
2023-10-16 20:48:02 +00:00
### Concurrency
As a language written in Rust, Dust features effortless concurrency anywhere in your code.
```dust
2023-10-17 01:13:58 +00:00
async {
2023-10-22 20:14:26 +00:00
(output (random_integer))
(output (random_float))
(output (random_boolean))
2023-10-16 20:48:02 +00:00
}
```
2023-10-22 19:52:33 +00:00
In an **async** block, each statement is run in parallel. In this case, we want to read from a file and assign the data to a variable. It doesn't matter which statement finishes first, the last statement in the block will be used as the assigned value. If one of the statements in an **async** block produces an error, the other statements will stop running if they have not already finished.
2023-10-17 01:13:58 +00:00
```dust
data = async {
(output "Reading a file...")
(read "examples/assets/faithful.csv")
}
```
2023-10-06 02:07:54 +00:00
## Implementation
2023-08-22 15:40:50 +00:00
2023-10-22 19:52:33 +00:00
Dust is formally defined as a Tree Sitter grammar in the tree-sitter-dust directory. Tree sitter generates a parser, written in C, from a set of rules defined in Javascript. Dust itself is a rust binary that calls the C parser using FFI.
2023-08-22 15:40:50 +00:00
2023-10-22 19:52:33 +00:00
Tests are written in three places: in the Rust library, in Dust as examples and in the Tree Sitter test format. Generally, features are added by implementing and testing the syntax in the tree-sitter-dust repository, then writing library tests to evaluate the new syntax. Implementation tests run the Dust files in the "examples" directory and should be used to demonstrate and verify that features work together.
2023-08-22 15:40:50 +00:00
2023-10-22 19:52:33 +00:00
Tree Sitter generates a concrete syntax tree, which Dust traverses to create an abstract syntax tree that can run the Dust code. The CST generation is an extra step but it allows easy testing of the parser, defining the language in one file and makes the syntax easy to modify and expand. Because it uses Tree Sitter, developer-friendly features like syntax highlighting and code navigation are already available in any text editor that supports Tree Sitter.
2023-08-22 15:40:50 +00:00
2023-10-22 19:52:33 +00:00
[Tree Sitter]: https://tree-sitter.github.io/tree-sitter/
[Rust]: https://rust-lang.org
2023-08-22 15:40:50 +00:00
[dnf]: https://dnf.readthedocs.io/en/latest/index.html
[evalexpr]: https://github.com/ISibboI/evalexpr
2023-08-28 14:18:55 +00:00
[rustup]: https://rustup.rs