Start std library; Write README; Change map syntax
This commit is contained in:
parent
ee87d322db
commit
ff836b4f0a
118
README.md
118
README.md
@ -62,34 +62,34 @@ To build from source, clone the repository and build the parser. To do so, enter
|
||||
|
||||
## Benchmarks
|
||||
|
||||
Dust is at a very early development stage but performs strongly in preliminary benchmarks. The examples given were tested using [Hyperfine] on a single-core cloud instance with 1024 MB RAM. Each test was run 1000 times. The test script is shown below. Each test asks the program to read a JSON file and count the objects. The programs produced identical output with the exception that NodeJS printed in color.
|
||||
Dust is at a very early development stage but performs strongly in preliminary benchmarks. The examples given were tested using [Hyperfine] on a single-core cloud instance with 1024 MB RAM. Each test was run 1000 times. The test script is shown below. Each test asks the program to read a JSON file and count the objects. Dust is a command line shell, programming language and data manipulation tool so three appropriate targets were chosen for comparison: nushell, NodeJS and jq. The programs produced identical output with the exception that NodeJS printed in color.
|
||||
|
||||
For the first test, a file with four entries was used.
|
||||
|
||||
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|
||||
|:---|---:|---:|---:|---:|
|
||||
| `dust -c '(length (from_json input))' -p seaCreatures.json` | 3.1 ± 0.5 | 2.4 | 8.4 | 1.00 |
|
||||
| `jq 'length' seaCreatures.json` | 33.7 ± 2.2 | 30.0 | 61.8 | 10.85 ± 1.87 |
|
||||
| `node --eval "require('node:fs').readFile('seaCreatures.json', (err, data)=>{console.log(JSON.parse(data).length)})"` | 226.4 ± 13.1 | 197.6 | 346.2 | 73.02 ± 12.33 |
|
||||
| `nu -c 'open seaCreatures.json \| length'` | 51.6 ± 3.7 | 45.4 | 104.3 | 16.65 ± 2.90 |
|
||||
| Command | Mean [ms] | Min [ms] | Max [ms]
|
||||
|:---|---:|---:|---:|
|
||||
| Dust | 3.1 ± 0.5 | 2.4 | 8.4 |
|
||||
| jq | 33.7 ± 2.2 | 30.0 | 61.8 |
|
||||
| NodeJS | 226.4 ± 13.1 | 197.6 | 346.2 |
|
||||
| Nushell | 51.6 ± 3.7 | 45.4 | 104.3 |
|
||||
|
||||
The second set of data is from the GitHub API, it consists of 100 commits from the jq GitHub repo.
|
||||
|
||||
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|
||||
|:---|---:|---:|---:|---:|
|
||||
| `dust -c '(length (from_json input))' -p jq_data.json` | 6.8 ± 0.6 | 5.7 | 12.0 | 2.20 ± 0.40 |
|
||||
| `jq 'length' jq_data.json` | 43.3 ± 3.6 | 37.6 | 81.6 | 13.95 ± 2.49 |
|
||||
| `node --eval "require('node:fs').readFile('jq_data.json', (err, data)=>{console.log(JSON.parse(data).length)})"` | 224.9 ± 12.3 | 194.8 | 298.5 | 72.52 ± 12.17 |
|
||||
| `nu -c 'open jq_data.json \| length'` | 59.2 ± 5.7 | 49.7 | 125.0 | 19.11 ± 3.55 |
|
||||
| Command | Mean [ms] | Min [ms] | Max [ms] |
|
||||
|:---|---:|---:|---:|
|
||||
| Dust | 6.8 ± 0.6 | 5.7 | 12.0 | 2.20 ± 0.40 |
|
||||
| jq | 43.3 ± 3.6 | 37.6 | 81.6 | 13.95 ± 2.49 |
|
||||
| NodeJS | 224.9 ± 12.3 | 194.8 | 298.5 |
|
||||
| Nushell | 59.2 ± 5.7 | 49.7 | 125.0 | 19.11 ± 3.55 |
|
||||
|
||||
This data came from CERN, it is a massive file of 100,000 entries.
|
||||
|
||||
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|
||||
|:---|---:|---:|---:|---:|
|
||||
| `dust -c '(length (from_json input))' -p dielectron.json` | 1080.8 ± 38.7 | 975.3 | 1326.6 | 348.61 ± 56.71 |
|
||||
| `jq 'length' dielectron.json` | 1305.3 ± 64.3 | 1159.7 | 1925.1 | 421.00 ± 69.94 |
|
||||
| `node --eval "require('node:fs').readFile('dielectron.json', (err, data)=>{console.log(JSON.parse(data).length)})"` | 1850.5 ± 72.5 | 1641.9 | 2395.1 | 596.85 ± 97.54 |
|
||||
| `nu -c 'open dielectron.json \| length'` | 1850.5 ± 86.2 | 1625.5 | 2400.7 | 596.87 ± 98.70 |
|
||||
| Command | Mean [ms] | Min [ms] | Max [ms] |
|
||||
|:---|---:|---:|---:|
|
||||
| Dust | 1080.8 ± 38.7 | 975.3 | 1326.6 |
|
||||
| jq | 1305.3 ± 64.3 | 1159.7 | 1925.1 |
|
||||
| NodeJS | 1850.5 ± 72.5 | 1641.9 | 2395.1 |
|
||||
| Nushell | 1850.5 ± 86.2 | 1625.5 | 2400.7 |
|
||||
|
||||
The tests were run after 5 warmup runs and the cache was cleared before each run.
|
||||
|
||||
@ -148,14 +148,14 @@ Note that strings can be wrapped with any kind of quote: single, double or backt
|
||||
|
||||
### Lists
|
||||
|
||||
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.
|
||||
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 a colon `:` followed by an integer. Dust lists are zero-indexed.
|
||||
|
||||
```dust
|
||||
list = [true 41 "Ok"]
|
||||
|
||||
(assert_equal list.0 true)
|
||||
(assert_equal list:0 true)
|
||||
|
||||
the_answer = list.1 + 1
|
||||
the_answer = list:1 + 1
|
||||
|
||||
(assert_equal the_answer, 42) # You can also use commas when passing values to
|
||||
# a function.
|
||||
@ -163,7 +163,7 @@ the_answer = list.1 + 1
|
||||
|
||||
### Maps
|
||||
|
||||
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.
|
||||
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 `:`.
|
||||
|
||||
```dust
|
||||
reminder = {
|
||||
@ -171,7 +171,7 @@ reminder = {
|
||||
tags = ["groceries", "home"]
|
||||
}
|
||||
|
||||
(output reminder.message)
|
||||
(output reminder:message)
|
||||
```
|
||||
|
||||
### Loops
|
||||
@ -196,48 +196,6 @@ for number in list {
|
||||
}
|
||||
```
|
||||
|
||||
To create a new list, use a **transform** loop, which modifies the values into a new list without changing the original.
|
||||
|
||||
```dust
|
||||
list = [1 2 3]
|
||||
|
||||
new_list = transform number in list {
|
||||
number - 1
|
||||
}
|
||||
|
||||
list
|
||||
-> filter()
|
||||
-> ()
|
||||
|
||||
(output new_list)
|
||||
# Output: [ 0 1 2 ]
|
||||
|
||||
(output list)
|
||||
# Output: [ 1 2 3 ]
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
### Tables
|
||||
|
||||
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.
|
||||
@ -273,34 +231,31 @@ insert into animals [
|
||||
|
||||
### Functions
|
||||
|
||||
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.
|
||||
Functions are first-class values in dust, so they are assigned to variables like any other value.
|
||||
|
||||
```dust
|
||||
say_hi = function <> {
|
||||
# This simple function has no arguments.
|
||||
say_hi = || => {
|
||||
(output "hi")
|
||||
}
|
||||
|
||||
add_one = function <number> {
|
||||
(number + 1)
|
||||
# This function has one argument and will return a value.
|
||||
add_one = |number| => {
|
||||
number + 1
|
||||
}
|
||||
|
||||
(say_hi)
|
||||
(assert_equal (add_one 3), 4)
|
||||
```
|
||||
|
||||
This function simply passes the input to the shell's standard output.
|
||||
|
||||
```dust
|
||||
print = function <input> {
|
||||
(output input)
|
||||
}
|
||||
```
|
||||
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.
|
||||
|
||||
### Concurrency
|
||||
|
||||
As a language written in Rust, Dust features effortless concurrency anywhere in your code.
|
||||
Dust features effortless concurrency anywhere in your code. Any block of code can be made to run its contents asynchronously. Dust's concurrency is written in safe Rust and uses a thread pool whose size depends on the number of cores available.
|
||||
|
||||
```dust
|
||||
# An async block will run each statement in its own thread.
|
||||
async {
|
||||
(output (random_integer))
|
||||
(output (random_float))
|
||||
@ -308,7 +263,6 @@ async {
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
```dust
|
||||
data = async {
|
||||
@ -317,8 +271,12 @@ data = async {
|
||||
}
|
||||
```
|
||||
|
||||
### Acknowledgements
|
||||
|
||||
Dust began as a fork of [evalexpr]. Some of the original code is still in place but the project has dramatically changed and no longer uses any of its parsing or interpreting.
|
||||
|
||||
[Tree Sitter]: https://tree-sitter.github.io/tree-sitter/
|
||||
[Rust]: https://rust-lang.org
|
||||
[dnf]: https://dnf.readthedocs.io/en/latest/index.html
|
||||
[evalexpr]: https://github.com/ISibboI/evalexpr
|
||||
[rustup]: https://rustup.rs
|
||||
[Hyperfine]: https://github.com/sharkdp/hyperfine
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::sync::RwLock;
|
||||
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
@ -24,7 +26,7 @@ impl AbstractTree for Block {
|
||||
};
|
||||
let mut statements = Vec::with_capacity(statement_count);
|
||||
|
||||
for index in 1..statement_count + 1 {
|
||||
for index in 1..node.child_count() - 1 {
|
||||
let child_node = node.child(index).unwrap();
|
||||
|
||||
if child_node.is_named() {
|
||||
@ -40,33 +42,45 @@ impl AbstractTree for Block {
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
println!("Running {} statements.", self.statements.len());
|
||||
|
||||
if self.is_async {
|
||||
let statements = &self.statements;
|
||||
let final_result = RwLock::new(Ok(Value::Empty));
|
||||
|
||||
statements
|
||||
.into_par_iter()
|
||||
.enumerate()
|
||||
.find_map_first(|(index, statement)| {
|
||||
let mut context = context.clone();
|
||||
let result = statement.run(source, &mut context);
|
||||
if let Statement::Return(expression) = statement {
|
||||
return Some(expression.run(source, &mut context.clone()));
|
||||
}
|
||||
|
||||
let result = statement.run(source, &mut context.clone());
|
||||
|
||||
if result.is_err() {
|
||||
Some(result)
|
||||
} else if index == statements.len() - 1 {
|
||||
Some(result)
|
||||
let _ = final_result.write().unwrap().as_mut().map(|_| result);
|
||||
|
||||
None
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or(Ok(Value::Empty))
|
||||
.unwrap_or(final_result.into_inner().unwrap())
|
||||
} else {
|
||||
let mut prev_result = None;
|
||||
|
||||
for statement in &self.statements {
|
||||
prev_result = Some(statement.run(source, context)?);
|
||||
if let Statement::Return(expression) = statement {
|
||||
return expression.run(source, context);
|
||||
}
|
||||
|
||||
prev_result = Some(statement.run(source, context));
|
||||
}
|
||||
|
||||
Ok(prev_result.unwrap_or(Value::Empty))
|
||||
prev_result.unwrap_or(Ok(Value::Empty))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,4 +75,3 @@ impl AbstractTree for For {
|
||||
Ok(Value::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,12 +7,10 @@ use crate::{
|
||||
};
|
||||
|
||||
/// Abstract representation of a statement.
|
||||
///
|
||||
/// A statement may evaluate to an Empty value when run. If a Statement is an
|
||||
/// Expression, it will always return a non-empty value when run.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Statement {
|
||||
Assignment(Box<Assignment>),
|
||||
Return(Expression),
|
||||
Expression(Expression),
|
||||
IfElse(Box<IfElse>),
|
||||
Match(Match),
|
||||
@ -38,6 +36,11 @@ impl AbstractTree for Statement {
|
||||
"assignment" => Ok(Statement::Assignment(Box::new(
|
||||
Assignment::from_syntax_node(source, child)?,
|
||||
))),
|
||||
"return" => {
|
||||
let expression_node = child.child(1).unwrap();
|
||||
|
||||
Ok(Statement::Return(Expression::from_syntax_node(source, expression_node)?))
|
||||
},
|
||||
"expression" => Ok(Self::Expression(Expression::from_syntax_node(
|
||||
source, child,
|
||||
)?)),
|
||||
@ -89,6 +92,7 @@ impl AbstractTree for Statement {
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
match self {
|
||||
Statement::Assignment(assignment) => assignment.run(source, context),
|
||||
Statement::Return(expression) => expression.run(source, context),
|
||||
Statement::Expression(expression) => expression.run(source, context),
|
||||
Statement::IfElse(if_else) => if_else.run(source, context),
|
||||
Statement::Match(r#match) => r#match.run(source, context),
|
||||
|
20
std/list_functions.ds
Normal file
20
std/list_functions.ds
Normal file
@ -0,0 +1,20 @@
|
||||
find = |list function| => {
|
||||
for i in list {
|
||||
if (function i) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
map = |list function| => {
|
||||
new_list = []
|
||||
|
||||
for i in list {
|
||||
new_list += (function i)
|
||||
}
|
||||
|
||||
new_list
|
||||
}
|
||||
|
||||
[0 1 2] -> (map |i| => { i - 1})
|
||||
-> (find |i| => { i == 1 })
|
@ -1,71 +0,0 @@
|
||||
================================================================================
|
||||
Simple Filter Loop
|
||||
================================================================================
|
||||
|
||||
filter i in [1, 2, 3] {
|
||||
i <= 1
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(filter
|
||||
(identifier)
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(integer)))
|
||||
(expression
|
||||
(value
|
||||
(integer)))
|
||||
(expression
|
||||
(value
|
||||
(integer))))))
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
(logic
|
||||
(expression
|
||||
(identifier))
|
||||
(logic_operator)
|
||||
(expression
|
||||
(value
|
||||
(integer))))))))))
|
||||
|
||||
================================================================================
|
||||
Nested Filter Loop
|
||||
================================================================================
|
||||
|
||||
filter i in big_list {
|
||||
filter j in i {
|
||||
i != 42
|
||||
}
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(filter
|
||||
(identifier)
|
||||
(expression
|
||||
(identifier))
|
||||
(block
|
||||
(statement
|
||||
(filter
|
||||
(identifier)
|
||||
(expression
|
||||
(identifier))
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
(logic
|
||||
(expression
|
||||
(identifier))
|
||||
(logic_operator)
|
||||
(expression
|
||||
(value
|
||||
(integer)))))))))))))
|
@ -1,117 +0,0 @@
|
||||
================================================================================
|
||||
Simple Find Loop
|
||||
================================================================================
|
||||
|
||||
find i in [1, 2, 3] {
|
||||
i <= 3
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(find
|
||||
(identifier)
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(integer)))
|
||||
(expression
|
||||
(value
|
||||
(integer)))
|
||||
(expression
|
||||
(value
|
||||
(integer))))))
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
(logic
|
||||
(expression
|
||||
(identifier))
|
||||
(logic_operator)
|
||||
(expression
|
||||
(value
|
||||
(integer))))))))))
|
||||
|
||||
================================================================================
|
||||
Nested Find Loop
|
||||
================================================================================
|
||||
|
||||
find i in ["one", "two", "three"] {
|
||||
found = find j in i {
|
||||
i == "e"
|
||||
}
|
||||
|
||||
if (type found) != 'empty' {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(find
|
||||
(identifier)
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(string)))
|
||||
(expression
|
||||
(value
|
||||
(string)))
|
||||
(expression
|
||||
(value
|
||||
(string))))))
|
||||
(block
|
||||
(statement
|
||||
(assignment
|
||||
(identifier)
|
||||
(assignment_operator)
|
||||
(statement
|
||||
(find
|
||||
(identifier)
|
||||
(expression
|
||||
(identifier))
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
(logic
|
||||
(expression
|
||||
(identifier))
|
||||
(logic_operator)
|
||||
(expression
|
||||
(value
|
||||
(string)))))))))))
|
||||
(statement
|
||||
(if_else
|
||||
(if
|
||||
(expression
|
||||
(logic
|
||||
(expression
|
||||
(function_call
|
||||
(built_in_function
|
||||
(expression
|
||||
(identifier)))))
|
||||
(logic_operator)
|
||||
(expression
|
||||
(value
|
||||
(string)))))
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
(value
|
||||
(boolean))))))
|
||||
(else
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
(value
|
||||
(boolean))))))))))))
|
@ -97,10 +97,10 @@ Complex Function Call
|
||||
(foobar
|
||||
"hi"
|
||||
42
|
||||
{
|
||||
(
|
||||
x = 1
|
||||
y = 2
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -2,17 +2,16 @@
|
||||
Simple Map
|
||||
================================================================================
|
||||
|
||||
{ answer = 42 }
|
||||
( answer = 42 )
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(block
|
||||
(statement
|
||||
(assignment
|
||||
(expression
|
||||
(value
|
||||
(map
|
||||
(identifier)
|
||||
(assignment_operator)
|
||||
(statement
|
||||
(expression
|
||||
(value
|
||||
@ -22,15 +21,15 @@ Simple Map
|
||||
Nested Maps
|
||||
================================================================================
|
||||
|
||||
x = {
|
||||
y = {
|
||||
x = (
|
||||
y = (
|
||||
foo = 'bar'
|
||||
z = {
|
||||
z = (
|
||||
message = 'hiya'
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
f = 12
|
||||
}
|
||||
)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -40,11 +39,10 @@ x = {
|
||||
(identifier)
|
||||
(assignment_operator)
|
||||
(statement
|
||||
(block
|
||||
(statement
|
||||
(assignment
|
||||
(expression
|
||||
(value
|
||||
(map
|
||||
(identifier)
|
||||
(assignment_operator)
|
||||
(statement
|
||||
(expression
|
||||
(value
|
||||
@ -63,11 +61,8 @@ x = {
|
||||
(statement
|
||||
(expression
|
||||
(value
|
||||
(string))))))))))))))
|
||||
(statement
|
||||
(assignment
|
||||
(string))))))))))))
|
||||
(identifier)
|
||||
(assignment_operator)
|
||||
(statement
|
||||
(expression
|
||||
(value
|
||||
|
@ -1,71 +0,0 @@
|
||||
================================================================================
|
||||
Simple Reduce Loop
|
||||
================================================================================
|
||||
|
||||
reduce i to acc in [1, 2, 3] {
|
||||
acc += i
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(reduce
|
||||
(identifier)
|
||||
(identifier)
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(integer)))
|
||||
(expression
|
||||
(value
|
||||
(integer)))
|
||||
(expression
|
||||
(value
|
||||
(integer))))))
|
||||
(block
|
||||
(statement
|
||||
(assignment
|
||||
(identifier)
|
||||
(assignment_operator)
|
||||
(statement
|
||||
(expression
|
||||
(identifier)))))))))
|
||||
|
||||
================================================================================
|
||||
Nested Reduce Loop
|
||||
================================================================================
|
||||
|
||||
reduce i to acc in ["one", "two", "three"] {
|
||||
acc += i
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(reduce
|
||||
(identifier)
|
||||
(identifier)
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(string)))
|
||||
(expression
|
||||
(value
|
||||
(string)))
|
||||
(expression
|
||||
(value
|
||||
(string))))))
|
||||
(block
|
||||
(statement
|
||||
(assignment
|
||||
(identifier)
|
||||
(assignment_operator)
|
||||
(statement
|
||||
(expression
|
||||
(identifier)))))))))
|
@ -1,71 +0,0 @@
|
||||
================================================================================
|
||||
Simple Remove
|
||||
================================================================================
|
||||
|
||||
remove i from [1, 2, 3] {
|
||||
i <= 2
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(remove
|
||||
(identifier)
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(integer)))
|
||||
(expression
|
||||
(value
|
||||
(integer)))
|
||||
(expression
|
||||
(value
|
||||
(integer))))))
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
(logic
|
||||
(expression
|
||||
(identifier))
|
||||
(logic_operator)
|
||||
(expression
|
||||
(value
|
||||
(integer))))))))))
|
||||
|
||||
================================================================================
|
||||
Nested Remove
|
||||
================================================================================
|
||||
|
||||
remove i from big_list {
|
||||
remove j from i {
|
||||
j != 42
|
||||
}
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(remove
|
||||
(identifier)
|
||||
(expression
|
||||
(identifier))
|
||||
(block
|
||||
(statement
|
||||
(remove
|
||||
(identifier)
|
||||
(expression
|
||||
(identifier))
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
(logic
|
||||
(expression
|
||||
(identifier))
|
||||
(logic_operator)
|
||||
(expression
|
||||
(value
|
||||
(integer)))))))))))))
|
@ -1,86 +0,0 @@
|
||||
================================================================================
|
||||
Transform Loop
|
||||
================================================================================
|
||||
|
||||
transform i in [1, 2, 3] {
|
||||
(output i)
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(transform
|
||||
(identifier)
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(integer)))
|
||||
(expression
|
||||
(value
|
||||
(integer)))
|
||||
(expression
|
||||
(value
|
||||
(integer))))))
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
(function_call
|
||||
(built_in_function
|
||||
(expression
|
||||
(identifier))))))))))
|
||||
|
||||
================================================================================
|
||||
Nested Transform Loop
|
||||
================================================================================
|
||||
|
||||
transform i in [['one'] ['two'] ['three']] {
|
||||
transform j in i {
|
||||
j += 'foobar'
|
||||
}
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(transform
|
||||
(identifier)
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(string))))))
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(string))))))
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(string)))))))))
|
||||
(block
|
||||
(statement
|
||||
(transform
|
||||
(identifier)
|
||||
(expression
|
||||
(identifier))
|
||||
(block
|
||||
(statement
|
||||
(assignment
|
||||
(identifier)
|
||||
(assignment_operator)
|
||||
(statement
|
||||
(expression
|
||||
(value
|
||||
(string)))))))))))))
|
@ -26,22 +26,23 @@ module.exports = grammar({
|
||||
$.assignment,
|
||||
$.block,
|
||||
$.expression,
|
||||
$.filter,
|
||||
$.find,
|
||||
$.for,
|
||||
$.if_else,
|
||||
$.index_assignment,
|
||||
$.insert,
|
||||
$.match,
|
||||
$.reduce,
|
||||
$.remove,
|
||||
$.return,
|
||||
$.select,
|
||||
$.transform,
|
||||
$.while,
|
||||
),
|
||||
optional(';'),
|
||||
)),
|
||||
|
||||
return: $ => seq(
|
||||
'return',
|
||||
$.expression,
|
||||
),
|
||||
|
||||
expression: $ => prec.right(choice(
|
||||
$._expression_kind,
|
||||
seq('(', $._expression_kind, ')'),
|
||||
@ -103,14 +104,14 @@ module.exports = grammar({
|
||||
),
|
||||
|
||||
map: $ => seq(
|
||||
'{',
|
||||
'(',
|
||||
repeat(seq(
|
||||
$.identifier,
|
||||
"=",
|
||||
$.statement,
|
||||
optional(',')
|
||||
)),
|
||||
'}',
|
||||
')',
|
||||
),
|
||||
|
||||
index: $ => prec.left(1, seq(
|
||||
@ -222,49 +223,6 @@ module.exports = grammar({
|
||||
$.block,
|
||||
),
|
||||
|
||||
transform: $ => seq(
|
||||
'transform',
|
||||
$.identifier,
|
||||
'in',
|
||||
$.expression,
|
||||
$.block,
|
||||
),
|
||||
|
||||
filter: $ => seq(
|
||||
'filter',
|
||||
field('count', optional($.expression)),
|
||||
field('item_id', $.identifier),
|
||||
'in',
|
||||
field('collection', $.expression),
|
||||
field('predicate', $.block),
|
||||
),
|
||||
|
||||
find: $ => seq(
|
||||
'find',
|
||||
$.identifier,
|
||||
'in',
|
||||
$.expression,
|
||||
$.block,
|
||||
),
|
||||
|
||||
remove: $ => seq(
|
||||
'remove',
|
||||
$.identifier,
|
||||
'from',
|
||||
$.expression,
|
||||
$.block,
|
||||
),
|
||||
|
||||
reduce: $ => seq(
|
||||
'reduce',
|
||||
$.identifier,
|
||||
'to',
|
||||
$.identifier,
|
||||
'in',
|
||||
$.expression,
|
||||
$.block,
|
||||
),
|
||||
|
||||
select: $ => prec.right(seq(
|
||||
'select',
|
||||
$.identifier_list,
|
||||
|
@ -70,14 +70,6 @@
|
||||
"type": "SYMBOL",
|
||||
"name": "expression"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "filter"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "find"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "for"
|
||||
@ -100,20 +92,12 @@
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "reduce"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "remove"
|
||||
"name": "return"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "select"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "transform"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "while"
|
||||
@ -135,43 +119,18 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"yield": {
|
||||
"type": "PREC_LEFT",
|
||||
"value": 0,
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "expression"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "->"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "("
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "built_in_function"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_context_defined_function"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ")"
|
||||
}
|
||||
]
|
||||
}
|
||||
"return": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "return"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "expression"
|
||||
}
|
||||
]
|
||||
},
|
||||
"expression": {
|
||||
"type": "PREC_RIGHT",
|
||||
@ -564,7 +523,7 @@
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "{"
|
||||
"value": "("
|
||||
},
|
||||
{
|
||||
"type": "REPEAT",
|
||||
@ -600,7 +559,7 @@
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "}"
|
||||
"value": ")"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -968,167 +927,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"transform": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "transform"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "in"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "expression"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "block"
|
||||
}
|
||||
]
|
||||
},
|
||||
"filter": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "filter"
|
||||
},
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "count",
|
||||
"content": {
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "expression"
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "item_id",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "in"
|
||||
},
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "collection",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "expression"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "predicate",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "block"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"find": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "find"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "in"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "expression"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "block"
|
||||
}
|
||||
]
|
||||
},
|
||||
"remove": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "remove"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "from"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "expression"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "block"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reduce": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "reduce"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "to"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "in"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "expression"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "block"
|
||||
}
|
||||
]
|
||||
},
|
||||
"select": {
|
||||
"type": "PREC_RIGHT",
|
||||
"value": 0,
|
||||
@ -1371,6 +1169,44 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"yield": {
|
||||
"type": "PREC_LEFT",
|
||||
"value": 0,
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "expression"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "->"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "("
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "built_in_function"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_context_defined_function"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ")"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"_built_in_function_name": {
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
|
@ -135,75 +135,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "filter",
|
||||
"named": true,
|
||||
"fields": {
|
||||
"collection": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"count": {
|
||||
"multiple": false,
|
||||
"required": false,
|
||||
"types": [
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"item_id": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"predicate": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "block",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "find",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "block",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "for",
|
||||
"named": true,
|
||||
@ -492,47 +423,16 @@
|
||||
"fields": {}
|
||||
},
|
||||
{
|
||||
"type": "reduce",
|
||||
"type": "return",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "block",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "remove",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "block",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -595,14 +495,6 @@
|
||||
"type": "expression",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "filter",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "find",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "for",
|
||||
"named": true
|
||||
@ -624,21 +516,13 @@
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "reduce",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "remove",
|
||||
"type": "return",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "transform",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "while",
|
||||
"named": true
|
||||
@ -665,29 +549,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "transform",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "block",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "value",
|
||||
"named": true,
|
||||
@ -921,14 +782,6 @@
|
||||
"type": "false",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "filter",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "find",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "fish",
|
||||
"named": false
|
||||
@ -1026,11 +879,7 @@
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "reduce",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "remove",
|
||||
"type": "return",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
@ -1057,10 +906,6 @@
|
||||
"type": "table",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "to",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "to_float",
|
||||
"named": false
|
||||
@ -1073,10 +918,6 @@
|
||||
"type": "to_string",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "transform",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "true",
|
||||
"named": false
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user