Prepare for new version

This commit is contained in:
Jeff 2023-10-28 10:28:43 -04:00
parent 674d3c91f9
commit c2a5f5e972
25 changed files with 10461 additions and 7519 deletions

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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',
), ),
} }
}); });

View File

@ -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"
} }
] ]
} }

View File

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