Start std library; Write README; Change map syntax

This commit is contained in:
Jeff 2023-11-16 01:59:48 -05:00
parent ee87d322db
commit ff836b4f0a
16 changed files with 16221 additions and 20173 deletions

118
README.md
View File

@ -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

View File

@ -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);
}
Ok(prev_result.unwrap_or(Value::Empty))
prev_result = Some(statement.run(source, context));
}
prev_result.unwrap_or(Ok(Value::Empty))
}
}
}

View File

@ -75,4 +75,3 @@ impl AbstractTree for For {
Ok(Value::Empty)
}
}

View File

@ -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
View 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 })

View File

@ -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)))))))))))))

View File

@ -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))))))))))))

View File

@ -97,10 +97,10 @@ Complex Function Call
(foobar
"hi"
42
{
(
x = 1
y = 2
}
)
)
--------------------------------------------------------------------------------

View File

@ -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

View File

@ -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)))))))))

View File

@ -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)))))))))))))

View File

@ -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)))))))))))))

View File

@ -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,

View File

@ -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,44 +119,19 @@
]
}
},
"yield": {
"type": "PREC_LEFT",
"value": 0,
"content": {
"return": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "return"
},
{
"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": ")"
}
]
}
},
"expression": {
"type": "PREC_RIGHT",
"value": 0,
@ -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": [

View File

@ -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