Prepare for new version
This commit is contained in:
parent
674d3c91f9
commit
c2a5f5e972
6
examples/assets/read-data.js
Normal file
6
examples/assets/read-data.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
const fs = require('node:fs');
|
||||||
|
const data = fs.readFileSync("examples/assets/jq_data.json");
|
||||||
|
const items = JSON.parse(data);
|
||||||
|
const output = items.map((item) => item.commit.committer.name);
|
||||||
|
|
||||||
|
console.log(output)
|
21
examples/fannkuch-redux.ds
Normal file
21
examples/fannkuch-redux.ds
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
numbers = (from_json input)
|
||||||
|
flip_count = 0
|
||||||
|
checksum = 0
|
||||||
|
|
||||||
|
while numbers.0 != 1 {
|
||||||
|
(reverse numbers 0 numbers.0)
|
||||||
|
|
||||||
|
if flip_count % 2 == 0 {
|
||||||
|
checksum += flip_count
|
||||||
|
} else {
|
||||||
|
checksum -= flip_count
|
||||||
|
}
|
||||||
|
|
||||||
|
checksum += flip_count * 1
|
||||||
|
|
||||||
|
flip_count += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
(output numbers)
|
||||||
|
(output flip_count)
|
||||||
|
(output checksum)
|
@ -1,8 +1,3 @@
|
|||||||
list = [1 2 1 2]
|
filter item in (from_json (read 'examples/assets/jq_data.json')) {
|
||||||
|
(length item.commit.committer.name) <= 10
|
||||||
new_list = filter i in list {
|
|
||||||
i == 2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(assert_equal [2 2] new_list)
|
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
list = [1 2 3]
|
list = [1 2 3]
|
||||||
|
|
||||||
for i in list {
|
async for i in list {
|
||||||
i += 1
|
i += 1
|
||||||
(output i)
|
(output i)
|
||||||
}
|
}
|
||||||
|
|
||||||
(output list)
|
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
list = [1 2 3]
|
data = (from_json (read "examples/assets/jq_data.json"))
|
||||||
|
|
||||||
new_list = transform i in list {
|
transform item in data {
|
||||||
i + 1
|
item.commit.committer.name
|
||||||
}
|
}
|
||||||
|
|
||||||
(assert_equal [2 3 4] new_list)
|
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{value_node::ValueNode, AbstractTree, Error, Identifier, Map, Result, Tool, Value};
|
use crate::{
|
||||||
|
value_node::ValueNode, AbstractTree, Error, Identifier, Map, Result, Sublist, Tool, Value,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{function_call::FunctionCall, logic::Logic, math::Math};
|
use super::{function_call::FunctionCall, logic::Logic, math::Math};
|
||||||
|
|
||||||
@ -9,6 +11,7 @@ use super::{function_call::FunctionCall, logic::Logic, math::Math};
|
|||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
Value(ValueNode),
|
Value(ValueNode),
|
||||||
Identifier(Identifier),
|
Identifier(Identifier),
|
||||||
|
Sublist(Box<Sublist>),
|
||||||
Math(Box<Math>),
|
Math(Box<Math>),
|
||||||
Logic(Box<Logic>),
|
Logic(Box<Logic>),
|
||||||
FunctionCall(FunctionCall),
|
FunctionCall(FunctionCall),
|
||||||
@ -23,7 +26,12 @@ impl AbstractTree for Expression {
|
|||||||
let child = node.child(index).unwrap();
|
let child = node.child(index).unwrap();
|
||||||
let expression = match child.kind() {
|
let expression = match child.kind() {
|
||||||
"value" => Expression::Value(ValueNode::from_syntax_node(source, child)?),
|
"value" => Expression::Value(ValueNode::from_syntax_node(source, child)?),
|
||||||
"identifier" => Self::Identifier(Identifier::from_syntax_node(source, child)?),
|
"identifier" => {
|
||||||
|
Expression::Identifier(Identifier::from_syntax_node(source, child)?)
|
||||||
|
}
|
||||||
|
"sublist" => {
|
||||||
|
Expression::Sublist(Box::new(Sublist::from_syntax_node(source, child)?))
|
||||||
|
}
|
||||||
"math" => Expression::Math(Box::new(Math::from_syntax_node(source, child)?)),
|
"math" => Expression::Math(Box::new(Math::from_syntax_node(source, child)?)),
|
||||||
"logic" => Expression::Logic(Box::new(Logic::from_syntax_node(source, child)?)),
|
"logic" => Expression::Logic(Box::new(Logic::from_syntax_node(source, child)?)),
|
||||||
"function_call" => {
|
"function_call" => {
|
||||||
@ -39,7 +47,7 @@ impl AbstractTree for Expression {
|
|||||||
let child = node.child(0).unwrap();
|
let child = node.child(0).unwrap();
|
||||||
|
|
||||||
Err(Error::UnexpectedSyntaxNode {
|
Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "value, identifier, math or function_call",
|
expected: "value, identifier, sublist, math or function_call",
|
||||||
actual: child.kind(),
|
actual: child.kind(),
|
||||||
location: child.start_position(),
|
location: child.start_position(),
|
||||||
relevant_source: source[child.byte_range()].to_string(),
|
relevant_source: source[child.byte_range()].to_string(),
|
||||||
@ -50,6 +58,7 @@ impl AbstractTree for Expression {
|
|||||||
match self {
|
match self {
|
||||||
Expression::Value(value_node) => value_node.run(source, context),
|
Expression::Value(value_node) => value_node.run(source, context),
|
||||||
Expression::Identifier(identifier) => identifier.run(source, context),
|
Expression::Identifier(identifier) => identifier.run(source, context),
|
||||||
|
Expression::Sublist(sublist) => sublist.run(source, context),
|
||||||
Expression::Math(math) => math.run(source, context),
|
Expression::Math(math) => math.run(source, context),
|
||||||
Expression::Logic(logic) => logic.run(source, context),
|
Expression::Logic(logic) => logic.run(source, context),
|
||||||
Expression::FunctionCall(function_call) => function_call.run(source, context),
|
Expression::FunctionCall(function_call) => function_call.run(source, context),
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
use rayon::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Expression, Identifier, Item, List, Map, Result, Value};
|
use crate::{AbstractTree, Error, Expression, Identifier, Item, List, Map, Result, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Filter {
|
pub struct Filter {
|
||||||
@ -32,21 +33,22 @@ impl AbstractTree for Filter {
|
|||||||
let value = self.expression.run(source, context)?;
|
let value = self.expression.run(source, context)?;
|
||||||
let values = value.as_list()?.items();
|
let values = value.as_list()?.items();
|
||||||
let key = self.identifier.inner();
|
let key = self.identifier.inner();
|
||||||
let mut context = context.clone();
|
let new_values = List::new();
|
||||||
let mut new_values = Vec::with_capacity(values.len());
|
|
||||||
|
values.par_iter().try_for_each(|value| {
|
||||||
|
let mut context = Map::new();
|
||||||
|
|
||||||
for value in values.iter() {
|
|
||||||
context.set_value(key.clone(), value.clone())?;
|
context.set_value(key.clone(), value.clone())?;
|
||||||
|
|
||||||
let should_include = self.item.run(source, &mut context)?.as_boolean()?;
|
let should_include = self.item.run(source, &mut context)?.as_boolean()?;
|
||||||
|
|
||||||
if should_include {
|
if should_include {
|
||||||
new_values.push(value.clone());
|
new_values.items_mut().push(value.clone());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let list = List::with_items(new_values);
|
Ok::<(), Error>(())
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(Value::List(list))
|
Ok(Value::List(new_values))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
|
use rayon::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Expression, Identifier, Item, Map, Result, Value};
|
use crate::{AbstractTree, Error, Expression, Identifier, Item, Map, Result, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct For {
|
pub struct For {
|
||||||
|
is_async: bool,
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
expression: Expression,
|
expression: Expression,
|
||||||
item: Item,
|
item: Item,
|
||||||
@ -12,6 +14,20 @@ pub struct For {
|
|||||||
|
|
||||||
impl AbstractTree for For {
|
impl AbstractTree for For {
|
||||||
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
|
||||||
|
let for_node = node.child(0).unwrap();
|
||||||
|
let is_async = match for_node.kind() {
|
||||||
|
"for" => false,
|
||||||
|
"async for" => true,
|
||||||
|
_ => {
|
||||||
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
|
expected: "\"for\" or \"async for\"",
|
||||||
|
actual: for_node.kind(),
|
||||||
|
location: for_node.start_position(),
|
||||||
|
relevant_source: source[for_node.byte_range()].to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let identifier_node = node.child(1).unwrap();
|
let identifier_node = node.child(1).unwrap();
|
||||||
let identifier = Identifier::from_syntax_node(source, identifier_node)?;
|
let identifier = Identifier::from_syntax_node(source, identifier_node)?;
|
||||||
|
|
||||||
@ -22,6 +38,7 @@ impl AbstractTree for For {
|
|||||||
let item = Item::from_syntax_node(source, item_node)?;
|
let item = Item::from_syntax_node(source, item_node)?;
|
||||||
|
|
||||||
Ok(For {
|
Ok(For {
|
||||||
|
is_async,
|
||||||
identifier,
|
identifier,
|
||||||
expression,
|
expression,
|
||||||
item,
|
item,
|
||||||
@ -33,6 +50,15 @@ impl AbstractTree for For {
|
|||||||
let values = expression_run.as_list()?.items();
|
let values = expression_run.as_list()?.items();
|
||||||
let key = self.identifier.inner();
|
let key = self.identifier.inner();
|
||||||
|
|
||||||
|
if self.is_async {
|
||||||
|
values.par_iter().try_for_each(|value| {
|
||||||
|
let mut iter_context = Map::clone_from(context);
|
||||||
|
|
||||||
|
iter_context.set_value(key.clone(), value.clone())?;
|
||||||
|
|
||||||
|
self.item.run(source, &mut iter_context).map(|_value| ())
|
||||||
|
})?;
|
||||||
|
} else {
|
||||||
let original_value = context.get_value(key)?;
|
let original_value = context.get_value(key)?;
|
||||||
|
|
||||||
for value in values.iter() {
|
for value in values.iter() {
|
||||||
@ -46,6 +72,7 @@ impl AbstractTree for For {
|
|||||||
} else {
|
} else {
|
||||||
context.set_value(key.clone(), Value::Empty)?;
|
context.set_value(key.clone(), Value::Empty)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ impl AbstractTree for Logic {
|
|||||||
let operator_node = node.child(1).unwrap().child(0).unwrap();
|
let operator_node = node.child(1).unwrap().child(0).unwrap();
|
||||||
let operator = match operator_node.kind() {
|
let operator = match operator_node.kind() {
|
||||||
"==" => LogicOperator::Equal,
|
"==" => LogicOperator::Equal,
|
||||||
|
"!=" => LogicOperator::NotEqual,
|
||||||
"&&" => LogicOperator::And,
|
"&&" => LogicOperator::And,
|
||||||
"||" => LogicOperator::Or,
|
"||" => LogicOperator::Or,
|
||||||
">" => LogicOperator::Greater,
|
">" => LogicOperator::Greater,
|
||||||
@ -26,7 +27,7 @@ impl AbstractTree for Logic {
|
|||||||
"<=" => LogicOperator::LessOrEqaul,
|
"<=" => LogicOperator::LessOrEqaul,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "==, && ||, >, <, >= or <=",
|
expected: "==, !=, &&, ||, >, <, >= or <=",
|
||||||
actual: operator_node.kind(),
|
actual: operator_node.kind(),
|
||||||
location: operator_node.start_position(),
|
location: operator_node.start_position(),
|
||||||
relevant_source: source[operator_node.byte_range()].to_string(),
|
relevant_source: source[operator_node.byte_range()].to_string(),
|
||||||
@ -55,6 +56,13 @@ impl AbstractTree for Logic {
|
|||||||
left == right
|
left == right
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LogicOperator::NotEqual => {
|
||||||
|
if let (Ok(left_num), Ok(right_num)) = (left.as_number(), right.as_number()) {
|
||||||
|
left_num != right_num
|
||||||
|
} else {
|
||||||
|
left != right
|
||||||
|
}
|
||||||
|
}
|
||||||
LogicOperator::And => left.as_boolean()? && right.as_boolean()?,
|
LogicOperator::And => left.as_boolean()? && right.as_boolean()?,
|
||||||
LogicOperator::Or => left.as_boolean()? || right.as_boolean()?,
|
LogicOperator::Or => left.as_boolean()? || right.as_boolean()?,
|
||||||
LogicOperator::Greater => left > right,
|
LogicOperator::Greater => left > right,
|
||||||
@ -70,6 +78,7 @@ impl AbstractTree for Logic {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum LogicOperator {
|
pub enum LogicOperator {
|
||||||
Equal,
|
Equal,
|
||||||
|
NotEqual,
|
||||||
And,
|
And,
|
||||||
Or,
|
Or,
|
||||||
Greater,
|
Greater,
|
||||||
|
@ -23,6 +23,7 @@ pub mod math;
|
|||||||
pub mod remove;
|
pub mod remove;
|
||||||
pub mod select;
|
pub mod select;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
|
pub mod sublist;
|
||||||
pub mod tool;
|
pub mod tool;
|
||||||
pub mod transform;
|
pub mod transform;
|
||||||
pub mod value_node;
|
pub mod value_node;
|
||||||
@ -31,7 +32,7 @@ pub mod r#while;
|
|||||||
pub use {
|
pub use {
|
||||||
assignment::*, expression::*, filter::*, find::*, function_call::*, identifier::*, if_else::*,
|
assignment::*, expression::*, filter::*, find::*, function_call::*, identifier::*, if_else::*,
|
||||||
insert::*, item::*, logic::*, math::*, r#async::*, r#for::*, r#match::*, r#while::*, remove::*,
|
insert::*, item::*, logic::*, math::*, r#async::*, r#for::*, r#match::*, r#while::*, remove::*,
|
||||||
select::*, statement::*, tool::*, transform::*, value_node::*,
|
select::*, statement::*, sublist::*, tool::*, transform::*, value_node::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
35
src/abstract_tree/sublist.rs
Normal file
35
src/abstract_tree/sublist.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{AbstractTree, Expression, List, Value};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
|
pub struct Sublist {
|
||||||
|
list: Expression,
|
||||||
|
start: Expression,
|
||||||
|
end: Expression,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbstractTree for Sublist {
|
||||||
|
fn from_syntax_node(source: &str, node: tree_sitter::Node) -> crate::Result<Self> {
|
||||||
|
let list_node = node.child(0).unwrap();
|
||||||
|
let list = Expression::from_syntax_node(source, list_node)?;
|
||||||
|
|
||||||
|
let start_node = node.child(2).unwrap();
|
||||||
|
let start = Expression::from_syntax_node(source, start_node)?;
|
||||||
|
|
||||||
|
let end_node = node.child(4).unwrap();
|
||||||
|
let end = Expression::from_syntax_node(source, end_node)?;
|
||||||
|
|
||||||
|
Ok(Sublist { list, start, end })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, source: &str, context: &mut crate::Map) -> crate::Result<crate::Value> {
|
||||||
|
let value = self.list.run(source, context)?;
|
||||||
|
let list = value.as_list()?.items();
|
||||||
|
let start = self.start.run(source, context)?.as_integer()? as usize;
|
||||||
|
let end = self.end.run(source, context)?.as_integer()? as usize;
|
||||||
|
let sublist = &list[start..=end];
|
||||||
|
|
||||||
|
Ok(Value::List(List::with_items(sublist.to_vec())))
|
||||||
|
}
|
||||||
|
}
|
@ -38,6 +38,7 @@ pub enum Tool {
|
|||||||
FromJson(Expression),
|
FromJson(Expression),
|
||||||
ToJson(Expression),
|
ToJson(Expression),
|
||||||
ToString(Expression),
|
ToString(Expression),
|
||||||
|
ToFloat(Expression),
|
||||||
|
|
||||||
// Command
|
// Command
|
||||||
Bash(Vec<Expression>),
|
Bash(Vec<Expression>),
|
||||||
@ -52,9 +53,12 @@ pub enum Tool {
|
|||||||
RandomInteger,
|
RandomInteger,
|
||||||
RandomFloat,
|
RandomFloat,
|
||||||
|
|
||||||
// Random
|
// Table
|
||||||
Columns(Expression),
|
Columns(Expression),
|
||||||
Rows(Expression),
|
Rows(Expression),
|
||||||
|
|
||||||
|
// List
|
||||||
|
Reverse(Expression, Option<(Expression, Expression)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Tool {
|
impl AbstractTree for Tool {
|
||||||
@ -185,6 +189,12 @@ impl AbstractTree for Tool {
|
|||||||
|
|
||||||
Tool::ToString(expression)
|
Tool::ToString(expression)
|
||||||
}
|
}
|
||||||
|
"to_float" => {
|
||||||
|
let expression_node = node.child(2).unwrap();
|
||||||
|
let expression = Expression::from_syntax_node(source, expression_node)?;
|
||||||
|
|
||||||
|
Tool::ToFloat(expression)
|
||||||
|
}
|
||||||
"bash" => {
|
"bash" => {
|
||||||
let expressions = parse_expressions(source, node)?;
|
let expressions = parse_expressions(source, node)?;
|
||||||
|
|
||||||
@ -230,6 +240,22 @@ impl AbstractTree for Tool {
|
|||||||
|
|
||||||
Tool::Rows(expression)
|
Tool::Rows(expression)
|
||||||
}
|
}
|
||||||
|
"reverse" => {
|
||||||
|
let list_node = node.child(2).unwrap();
|
||||||
|
let list_expression = Expression::from_syntax_node(source, list_node)?;
|
||||||
|
|
||||||
|
let slice_range_nodes =
|
||||||
|
if let (Some(start_node), Some(end_node)) = (node.child(3), node.child(4)) {
|
||||||
|
let start = Expression::from_syntax_node(source, start_node)?;
|
||||||
|
let end = Expression::from_syntax_node(source, end_node)?;
|
||||||
|
|
||||||
|
Some((start, end))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Tool::Reverse(list_expression, slice_range_nodes)
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "built-in tool",
|
expected: "built-in tool",
|
||||||
@ -287,7 +313,18 @@ impl AbstractTree for Tool {
|
|||||||
Ok(Value::String(data))
|
Ok(Value::String(data))
|
||||||
}
|
}
|
||||||
Tool::Length(expression) => {
|
Tool::Length(expression) => {
|
||||||
let length = expression.run(source, context)?.as_list()?.items().len();
|
let value = expression.run(source, context)?;
|
||||||
|
let length = match value {
|
||||||
|
Value::List(list) => list.items().len(),
|
||||||
|
Value::Map(map) => map.len(),
|
||||||
|
Value::Table(table) => table.len(),
|
||||||
|
Value::String(string) => string.chars().count(),
|
||||||
|
Value::Function(_) => todo!(),
|
||||||
|
Value::Float(_) => todo!(),
|
||||||
|
Value::Integer(_) => todo!(),
|
||||||
|
Value::Boolean(_) => todo!(),
|
||||||
|
Value::Empty => todo!(),
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Value::Integer(length as i64))
|
Ok(Value::Integer(length as i64))
|
||||||
}
|
}
|
||||||
@ -443,6 +480,17 @@ impl AbstractTree for Tool {
|
|||||||
|
|
||||||
Ok(Value::String(string))
|
Ok(Value::String(string))
|
||||||
}
|
}
|
||||||
|
Tool::ToFloat(expression) => {
|
||||||
|
let value = expression.run(source, context)?;
|
||||||
|
let float = match value {
|
||||||
|
Value::String(string) => string.parse()?,
|
||||||
|
Value::Float(float) => float,
|
||||||
|
Value::Integer(integer) => integer as f64,
|
||||||
|
_ => return Err(Error::ExpectedNumberOrString { actual: value }),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Value::Float(float))
|
||||||
|
}
|
||||||
Tool::Bash(expressions) => {
|
Tool::Bash(expressions) => {
|
||||||
let mut command = Command::new("bash");
|
let mut command = Command::new("bash");
|
||||||
|
|
||||||
@ -569,6 +617,21 @@ impl AbstractTree for Tool {
|
|||||||
|
|
||||||
Ok(Value::List(List::with_items(rows)))
|
Ok(Value::List(List::with_items(rows)))
|
||||||
}
|
}
|
||||||
|
Tool::Reverse(list_expression, slice_range) => {
|
||||||
|
let expression_run = list_expression.run(source, context)?;
|
||||||
|
let list = expression_run.as_list()?;
|
||||||
|
|
||||||
|
if let Some((start, end)) = slice_range {
|
||||||
|
let start = start.run(source, context)?.as_integer()? as usize;
|
||||||
|
let end = end.run(source, context)?.as_integer()? as usize;
|
||||||
|
|
||||||
|
list.items_mut()[start..end].reverse()
|
||||||
|
} else {
|
||||||
|
list.items_mut().reverse()
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Value::List(list.clone()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,10 +33,10 @@ impl AbstractTree for Transform {
|
|||||||
let expression_run = self.expression.run(source, context)?;
|
let expression_run = self.expression.run(source, context)?;
|
||||||
let values = expression_run.as_list()?.items();
|
let values = expression_run.as_list()?.items();
|
||||||
let key = self.identifier.inner();
|
let key = self.identifier.inner();
|
||||||
let new_list = values
|
let new_values = values
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.map(|value| {
|
.map(|value| {
|
||||||
let mut iter_context = Map::clone_from(context);
|
let mut iter_context = Map::new();
|
||||||
|
|
||||||
iter_context.set_value(key.clone(), value.clone()).unwrap();
|
iter_context.set_value(key.clone(), value.clone()).unwrap();
|
||||||
|
|
||||||
@ -47,8 +47,9 @@ impl AbstractTree for Transform {
|
|||||||
Err(_) => Value::Empty,
|
Err(_) => Value::Empty,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.filter(|value| !value.is_empty())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(Value::List(List::with_items(new_list)))
|
Ok(Value::List(List::with_items(new_values)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,18 +41,18 @@ impl AbstractTree for ValueNode {
|
|||||||
"boolean" => ValueType::Boolean,
|
"boolean" => ValueType::Boolean,
|
||||||
"empty" => ValueType::Empty,
|
"empty" => ValueType::Empty,
|
||||||
"list" => {
|
"list" => {
|
||||||
let mut child_nodes = Vec::new();
|
let mut expressions = Vec::new();
|
||||||
|
|
||||||
for index in 1..child.child_count() - 1 {
|
for index in 1..child.child_count() - 1 {
|
||||||
let child_syntax_node = child.child(index).unwrap();
|
let current_node = child.child(index).unwrap();
|
||||||
|
|
||||||
if child_syntax_node.is_named() {
|
if current_node.is_named() {
|
||||||
let expression = Expression::from_syntax_node(source, child_syntax_node)?;
|
let expression = Expression::from_syntax_node(source, current_node)?;
|
||||||
child_nodes.push(expression);
|
expressions.push(expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueType::ListExact(child_nodes)
|
ValueType::List(expressions)
|
||||||
}
|
}
|
||||||
"table" => {
|
"table" => {
|
||||||
let child_count = child.child_count();
|
let child_count = child.child_count();
|
||||||
@ -148,7 +148,7 @@ impl AbstractTree for ValueNode {
|
|||||||
ValueType::Float => Value::Float(value_source.parse().unwrap()),
|
ValueType::Float => Value::Float(value_source.parse().unwrap()),
|
||||||
ValueType::Integer => Value::Integer(value_source.parse().unwrap()),
|
ValueType::Integer => Value::Integer(value_source.parse().unwrap()),
|
||||||
ValueType::Boolean => Value::Boolean(value_source.parse().unwrap()),
|
ValueType::Boolean => Value::Boolean(value_source.parse().unwrap()),
|
||||||
ValueType::ListExact(nodes) => {
|
ValueType::List(nodes) => {
|
||||||
let mut values = Vec::with_capacity(nodes.len());
|
let mut values = Vec::with_capacity(nodes.len());
|
||||||
|
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
use crate::{value::Value, Identifier};
|
use crate::{value::Value, Identifier};
|
||||||
|
|
||||||
use std::{fmt, io, time, string::FromUtf8Error};
|
use std::{fmt, io, time, string::FromUtf8Error, num::ParseFloatError};
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
@ -151,6 +151,12 @@ impl From<FromUtf8Error> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ParseFloatError> for Error {
|
||||||
|
fn from(value: ParseFloatError) -> Self {
|
||||||
|
Error::ToolFailure(value.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<csv::Error> for Error {
|
impl From<csv::Error> for Error {
|
||||||
fn from(value: csv::Error) -> Self {
|
fn from(value: csv::Error) -> Self {
|
||||||
Error::ToolFailure(value.to_string())
|
Error::ToolFailure(value.to_string())
|
||||||
|
@ -42,6 +42,12 @@ fn main() {
|
|||||||
|
|
||||||
let mut context = Map::new();
|
let mut context = Map::new();
|
||||||
|
|
||||||
|
if let Some(input) = args.input {
|
||||||
|
context
|
||||||
|
.set_value("input".to_string(), Value::String(input))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(path) = args.input_path {
|
if let Some(path) = args.input_path {
|
||||||
let file_contents = read_to_string(path).unwrap();
|
let file_contents = read_to_string(path).unwrap();
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Copies the value stored in `self` as `i64`, or returns `Err` if `self` is not a `Value::Int`.
|
/// Copies the value stored in `self` as `i64`, or returns `Err` if `self` is not a `Value::Int`.
|
||||||
pub fn as_int(&self) -> Result<i64> {
|
pub fn as_integer(&self) -> Result<i64> {
|
||||||
match self {
|
match self {
|
||||||
Value::Integer(i) => Ok(*i),
|
Value::Integer(i) => Ok(*i),
|
||||||
value => Err(Error::ExpectedInt {
|
value => Err(Error::ExpectedInt {
|
||||||
@ -219,7 +219,7 @@ impl Add for Value {
|
|||||||
type Output = Result<Value>;
|
type Output = Result<Value>;
|
||||||
|
|
||||||
fn add(self, other: Self) -> Self::Output {
|
fn add(self, other: Self) -> Self::Output {
|
||||||
match (self.as_int(), other.as_int()) {
|
match (self.as_integer(), other.as_integer()) {
|
||||||
(Ok(left), Ok(right)) => return Ok(Value::Integer(left + right)),
|
(Ok(left), Ok(right)) => return Ok(Value::Integer(left + right)),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -250,7 +250,7 @@ impl Sub for Value {
|
|||||||
type Output = Result<Self>;
|
type Output = Result<Self>;
|
||||||
|
|
||||||
fn sub(self, other: Self) -> Self::Output {
|
fn sub(self, other: Self) -> Self::Output {
|
||||||
match (self.as_int(), other.as_int()) {
|
match (self.as_integer(), other.as_integer()) {
|
||||||
(Ok(left), Ok(right)) => return Ok(Value::Integer(left - right)),
|
(Ok(left), Ok(right)) => return Ok(Value::Integer(left - right)),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -271,8 +271,8 @@ impl Mul for Value {
|
|||||||
|
|
||||||
fn mul(self, other: Self) -> Self::Output {
|
fn mul(self, other: Self) -> Self::Output {
|
||||||
if self.is_integer() && other.is_integer() {
|
if self.is_integer() && other.is_integer() {
|
||||||
let left = self.as_int().unwrap();
|
let left = self.as_integer().unwrap();
|
||||||
let right = other.as_int().unwrap();
|
let right = other.as_integer().unwrap();
|
||||||
let value = Value::Integer(left.saturating_mul(right));
|
let value = Value::Integer(left.saturating_mul(right));
|
||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
@ -307,8 +307,8 @@ impl Rem for Value {
|
|||||||
type Output = Result<Self>;
|
type Output = Result<Self>;
|
||||||
|
|
||||||
fn rem(self, other: Self) -> Self::Output {
|
fn rem(self, other: Self) -> Self::Output {
|
||||||
let left = self.as_int()?;
|
let left = self.as_integer()?;
|
||||||
let right = other.as_int()?;
|
let right = other.as_integer()?;
|
||||||
let result = left % right;
|
let result = left % right;
|
||||||
|
|
||||||
Ok(Value::Integer(result))
|
Ok(Value::Integer(result))
|
||||||
@ -370,8 +370,16 @@ impl Ord for Value {
|
|||||||
(Value::String(left), Value::String(right)) => left.cmp(right),
|
(Value::String(left), Value::String(right)) => left.cmp(right),
|
||||||
(Value::String(_), _) => Ordering::Greater,
|
(Value::String(_), _) => Ordering::Greater,
|
||||||
(Value::Float(left), Value::Float(right)) => left.total_cmp(right),
|
(Value::Float(left), Value::Float(right)) => left.total_cmp(right),
|
||||||
(Value::Float(_), _) => Ordering::Greater,
|
|
||||||
(Value::Integer(left), Value::Integer(right)) => left.cmp(right),
|
(Value::Integer(left), Value::Integer(right)) => left.cmp(right),
|
||||||
|
(Value::Float(float), Value::Integer(integer)) => {
|
||||||
|
let int_as_float = *integer as f64;
|
||||||
|
float.total_cmp(&int_as_float)
|
||||||
|
}
|
||||||
|
(Value::Integer(integer), Value::Float(float)) => {
|
||||||
|
let int_as_float = *integer as f64;
|
||||||
|
int_as_float.total_cmp(float)
|
||||||
|
}
|
||||||
|
(Value::Float(_), _) => Ordering::Greater,
|
||||||
(Value::Integer(_), _) => Ordering::Greater,
|
(Value::Integer(_), _) => Ordering::Greater,
|
||||||
(Value::Boolean(left), Value::Boolean(right)) => left.cmp(right),
|
(Value::Boolean(left), Value::Boolean(right)) => left.cmp(right),
|
||||||
(Value::Boolean(_), _) => Ordering::Greater,
|
(Value::Boolean(_), _) => Ordering::Greater,
|
||||||
|
@ -15,7 +15,7 @@ pub enum ValueType {
|
|||||||
Float,
|
Float,
|
||||||
Integer,
|
Integer,
|
||||||
Boolean,
|
Boolean,
|
||||||
ListExact(Vec<Expression>),
|
List(Vec<Expression>),
|
||||||
Empty,
|
Empty,
|
||||||
Map(BTreeMap<String, Expression>),
|
Map(BTreeMap<String, Expression>),
|
||||||
Table {
|
Table {
|
||||||
@ -36,7 +36,7 @@ impl PartialEq for ValueType {
|
|||||||
(ValueType::Float, ValueType::Float) => true,
|
(ValueType::Float, ValueType::Float) => true,
|
||||||
(ValueType::Integer, ValueType::Integer) => true,
|
(ValueType::Integer, ValueType::Integer) => true,
|
||||||
(ValueType::Boolean, ValueType::Boolean) => true,
|
(ValueType::Boolean, ValueType::Boolean) => true,
|
||||||
(ValueType::ListExact(left), ValueType::ListExact(right)) => left == right,
|
(ValueType::List(left), ValueType::List(right)) => left == right,
|
||||||
(ValueType::Empty, ValueType::Empty) => true,
|
(ValueType::Empty, ValueType::Empty) => true,
|
||||||
(ValueType::Map(left), ValueType::Map(right)) => left == right,
|
(ValueType::Map(left), ValueType::Map(right)) => left == right,
|
||||||
(
|
(
|
||||||
@ -63,7 +63,7 @@ impl Display for ValueType {
|
|||||||
ValueType::Float => write!(f, "float"),
|
ValueType::Float => write!(f, "float"),
|
||||||
ValueType::Integer => write!(f, "integer"),
|
ValueType::Integer => write!(f, "integer"),
|
||||||
ValueType::Boolean => write!(f, "boolean"),
|
ValueType::Boolean => write!(f, "boolean"),
|
||||||
ValueType::ListExact(list) => {
|
ValueType::List(list) => {
|
||||||
write!(f, "(")?;
|
write!(f, "(")?;
|
||||||
for (index, item) in list.into_iter().enumerate() {
|
for (index, item) in list.into_iter().enumerate() {
|
||||||
if index > 0 {
|
if index > 0 {
|
||||||
@ -109,7 +109,7 @@ impl From<&Value> for ValueType {
|
|||||||
.map(|value| Expression::Value(ValueNode::new(value.value_type(), 0, 0)))
|
.map(|value| Expression::Value(ValueNode::new(value.value_type(), 0, 0)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
ValueType::ListExact(value_nodes)
|
ValueType::List(value_nodes)
|
||||||
}
|
}
|
||||||
Value::Map(map) => {
|
Value::Map(map) => {
|
||||||
let mut value_nodes = BTreeMap::new();
|
let mut value_nodes = BTreeMap::new();
|
||||||
@ -134,7 +134,7 @@ impl From<&Value> for ValueType {
|
|||||||
.map(|column_name| Identifier::new(column_name.clone()))
|
.map(|column_name| Identifier::new(column_name.clone()))
|
||||||
.collect(),
|
.collect(),
|
||||||
rows: Box::new(Expression::Value(ValueNode::new(
|
rows: Box::new(Expression::Value(ValueNode::new(
|
||||||
ValueType::ListExact(Vec::with_capacity(0)),
|
ValueType::List(Vec::with_capacity(0)),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
))),
|
))),
|
||||||
|
@ -86,3 +86,39 @@ for list in list_of_lists {
|
|||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(string))))))))))))))
|
(string))))))))))))))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Async For Loop
|
||||||
|
==================
|
||||||
|
|
||||||
|
asnyc for list in list_of_lists {
|
||||||
|
async for item in list {
|
||||||
|
(output item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(root
|
||||||
|
(item
|
||||||
|
(statement
|
||||||
|
(expression
|
||||||
|
(identifier))))
|
||||||
|
(item
|
||||||
|
(statement
|
||||||
|
(for
|
||||||
|
(identifier)
|
||||||
|
(expression
|
||||||
|
(identifier))
|
||||||
|
(item
|
||||||
|
(statement
|
||||||
|
(for
|
||||||
|
(identifier)
|
||||||
|
(expression
|
||||||
|
(identifier))
|
||||||
|
(item
|
||||||
|
(statement
|
||||||
|
(expression
|
||||||
|
(tool
|
||||||
|
(expression
|
||||||
|
(identifier)))))))))))))
|
||||||
|
@ -80,3 +80,35 @@ List Nesting
|
|||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(integer)))))))))))))))
|
(integer)))))))))))))))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Sublist
|
||||||
|
==================
|
||||||
|
|
||||||
|
['answers', 42, 666].1..2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(root
|
||||||
|
(item
|
||||||
|
(statement
|
||||||
|
(expression
|
||||||
|
(sublist
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(list
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(string)))
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer))))))
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer))))))))
|
@ -2,8 +2,10 @@
|
|||||||
Table Declaration
|
Table Declaration
|
||||||
==================
|
==================
|
||||||
|
|
||||||
table <text, number> [
|
table <messages, numbers> [
|
||||||
['answer', 42]
|
['hiya', 42]
|
||||||
|
['foo', 57]
|
||||||
|
['bar', 99.99]
|
||||||
]
|
]
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -27,7 +29,26 @@ table <text, number> [
|
|||||||
(string)))
|
(string)))
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(integer)))))))))))))))
|
(integer))))))
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(list
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(string)))
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer))))))
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(list
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(string)))
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(float)))))))))))))))
|
||||||
|
|
||||||
==================
|
==================
|
||||||
Table Assignment
|
Table Assignment
|
||||||
==================
|
==================
|
||||||
|
@ -38,6 +38,7 @@ module.exports = grammar({
|
|||||||
$.tool,
|
$.tool,
|
||||||
$.math,
|
$.math,
|
||||||
$.logic,
|
$.logic,
|
||||||
|
$.sublist,
|
||||||
)),
|
)),
|
||||||
|
|
||||||
identifier: $ => /[a-zA-Z|_]+[._a-zA-Z0-9]*/,
|
identifier: $ => /[a-zA-Z|_]+[._a-zA-Z0-9]*/,
|
||||||
@ -55,7 +56,7 @@ module.exports = grammar({
|
|||||||
|
|
||||||
integer: $ => /[-]?[0-9]+/,
|
integer: $ => /[-]?[0-9]+/,
|
||||||
|
|
||||||
float: $ => /[-]?[0-9]+[.]{1}[0-9]*/,
|
float: $ => /[-]?[0-9]+[.]{1}[0-9]+/,
|
||||||
|
|
||||||
string: $ => /("[^"]*?")|('[^']*?')|(`[^`]*?`)/,
|
string: $ => /("[^"]*?")|('[^']*?')|(`[^`]*?`)/,
|
||||||
|
|
||||||
@ -67,7 +68,7 @@ module.exports = grammar({
|
|||||||
list: $ => seq(
|
list: $ => seq(
|
||||||
'[',
|
'[',
|
||||||
repeat(seq($.expression, optional(','))),
|
repeat(seq($.expression, optional(','))),
|
||||||
']'
|
']',
|
||||||
),
|
),
|
||||||
|
|
||||||
function: $ => seq(
|
function: $ => seq(
|
||||||
@ -78,7 +79,7 @@ module.exports = grammar({
|
|||||||
'}',
|
'}',
|
||||||
),
|
),
|
||||||
|
|
||||||
table: $ => prec.right(seq(
|
table: $ => prec(2, seq(
|
||||||
'table',
|
'table',
|
||||||
seq('<', repeat1(seq($.identifier, optional(','))), '>'),
|
seq('<', repeat1(seq($.identifier, optional(','))), '>'),
|
||||||
$.expression,
|
$.expression,
|
||||||
@ -90,6 +91,14 @@ module.exports = grammar({
|
|||||||
'}',
|
'}',
|
||||||
),
|
),
|
||||||
|
|
||||||
|
sublist: $ => prec.right(seq(
|
||||||
|
$.expression,
|
||||||
|
'.',
|
||||||
|
$.expression,
|
||||||
|
'..',
|
||||||
|
$.expression,
|
||||||
|
)),
|
||||||
|
|
||||||
math: $ => prec.left(seq(
|
math: $ => prec.left(seq(
|
||||||
$.expression,
|
$.expression,
|
||||||
$.math_operator,
|
$.math_operator,
|
||||||
@ -178,7 +187,7 @@ module.exports = grammar({
|
|||||||
),
|
),
|
||||||
|
|
||||||
for: $ => seq(
|
for: $ => seq(
|
||||||
'for',
|
choice('for', 'async for'),
|
||||||
$.identifier,
|
$.identifier,
|
||||||
'in',
|
'in',
|
||||||
$.expression,
|
$.expression,
|
||||||
@ -282,6 +291,7 @@ module.exports = grammar({
|
|||||||
'from_json',
|
'from_json',
|
||||||
'to_json',
|
'to_json',
|
||||||
'to_string',
|
'to_string',
|
||||||
|
'to_float',
|
||||||
|
|
||||||
// Command
|
// Command
|
||||||
'bash',
|
'bash',
|
||||||
@ -299,6 +309,9 @@ module.exports = grammar({
|
|||||||
// Tables
|
// Tables
|
||||||
'columns',
|
'columns',
|
||||||
'rows',
|
'rows',
|
||||||
|
|
||||||
|
// Lists
|
||||||
|
'reverse',
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
});
|
});
|
@ -141,6 +141,10 @@
|
|||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "logic"
|
"name": "logic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "sublist"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -192,7 +196,7 @@
|
|||||||
},
|
},
|
||||||
"float": {
|
"float": {
|
||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[-]?[0-9]+[.]{1}[0-9]*"
|
"value": "[-]?[0-9]+[.]{1}[0-9]+"
|
||||||
},
|
},
|
||||||
"string": {
|
"string": {
|
||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
@ -315,8 +319,8 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"table": {
|
"table": {
|
||||||
"type": "PREC_RIGHT",
|
"type": "PREC",
|
||||||
"value": 0,
|
"value": 2,
|
||||||
"content": {
|
"content": {
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
"members": [
|
"members": [
|
||||||
@ -401,6 +405,35 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"sublist": {
|
||||||
|
"type": "PREC_RIGHT",
|
||||||
|
"value": 0,
|
||||||
|
"content": {
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "expression"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "expression"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": ".."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "expression"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"math": {
|
"math": {
|
||||||
"type": "PREC_LEFT",
|
"type": "PREC_LEFT",
|
||||||
"value": 0,
|
"value": 0,
|
||||||
@ -728,11 +761,20 @@
|
|||||||
},
|
},
|
||||||
"for": {
|
"for": {
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "for"
|
"value": "for"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "async for"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "identifier"
|
"name": "identifier"
|
||||||
@ -1138,6 +1180,10 @@
|
|||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "to_string"
|
"value": "to_string"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "to_float"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "bash"
|
"value": "bash"
|
||||||
@ -1181,6 +1227,10 @@
|
|||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "rows"
|
"value": "rows"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "reverse"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,10 @@
|
|||||||
"type": "math",
|
"type": "math",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "sublist",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "tool",
|
"type": "tool",
|
||||||
"named": true
|
"named": true
|
||||||
@ -510,6 +514,21 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "sublist",
|
||||||
|
"named": true,
|
||||||
|
"fields": {},
|
||||||
|
"children": {
|
||||||
|
"multiple": true,
|
||||||
|
"required": true,
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"type": "expression",
|
||||||
|
"named": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "table",
|
"type": "table",
|
||||||
"named": true,
|
"named": true,
|
||||||
@ -673,6 +692,14 @@
|
|||||||
"type": "-=",
|
"type": "-=",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": ".",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "..",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "/",
|
"type": "/",
|
||||||
"named": false
|
"named": false
|
||||||
@ -725,6 +752,10 @@
|
|||||||
"type": "async",
|
"type": "async",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "async for",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "bash",
|
"type": "bash",
|
||||||
"named": false
|
"named": false
|
||||||
@ -857,6 +888,10 @@
|
|||||||
"type": "remove",
|
"type": "remove",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "reverse",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "rows",
|
"type": "rows",
|
||||||
"named": false
|
"named": false
|
||||||
@ -877,6 +912,10 @@
|
|||||||
"type": "table",
|
"type": "table",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "to_float",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "to_json",
|
"type": "to_json",
|
||||||
"named": false
|
"named": false
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user