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]
|
||||
|
||||
new_list = filter i in list {
|
||||
i == 2
|
||||
filter item in (from_json (read 'examples/assets/jq_data.json')) {
|
||||
(length item.commit.committer.name) <= 10
|
||||
}
|
||||
|
||||
(assert_equal [2 2] new_list)
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
list = [1 2 3]
|
||||
|
||||
for i in list {
|
||||
async for i in list {
|
||||
i += 1
|
||||
(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 {
|
||||
i + 1
|
||||
transform item in data {
|
||||
item.commit.committer.name
|
||||
}
|
||||
|
||||
(assert_equal [2 3 4] new_list)
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
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};
|
||||
|
||||
@ -9,6 +11,7 @@ use super::{function_call::FunctionCall, logic::Logic, math::Math};
|
||||
pub enum Expression {
|
||||
Value(ValueNode),
|
||||
Identifier(Identifier),
|
||||
Sublist(Box<Sublist>),
|
||||
Math(Box<Math>),
|
||||
Logic(Box<Logic>),
|
||||
FunctionCall(FunctionCall),
|
||||
@ -23,7 +26,12 @@ impl AbstractTree for Expression {
|
||||
let child = node.child(index).unwrap();
|
||||
let expression = match child.kind() {
|
||||
"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)?)),
|
||||
"logic" => Expression::Logic(Box::new(Logic::from_syntax_node(source, child)?)),
|
||||
"function_call" => {
|
||||
@ -39,7 +47,7 @@ impl AbstractTree for Expression {
|
||||
let child = node.child(0).unwrap();
|
||||
|
||||
Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "value, identifier, math or function_call",
|
||||
expected: "value, identifier, sublist, math or function_call",
|
||||
actual: child.kind(),
|
||||
location: child.start_position(),
|
||||
relevant_source: source[child.byte_range()].to_string(),
|
||||
@ -50,6 +58,7 @@ impl AbstractTree for Expression {
|
||||
match self {
|
||||
Expression::Value(value_node) => value_node.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::Logic(logic) => logic.run(source, context),
|
||||
Expression::FunctionCall(function_call) => function_call.run(source, context),
|
||||
|
@ -1,7 +1,8 @@
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
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)]
|
||||
pub struct Filter {
|
||||
@ -32,21 +33,22 @@ impl AbstractTree for Filter {
|
||||
let value = self.expression.run(source, context)?;
|
||||
let values = value.as_list()?.items();
|
||||
let key = self.identifier.inner();
|
||||
let mut context = context.clone();
|
||||
let mut new_values = Vec::with_capacity(values.len());
|
||||
let new_values = List::new();
|
||||
|
||||
values.par_iter().try_for_each(|value| {
|
||||
let mut context = Map::new();
|
||||
|
||||
for value in values.iter() {
|
||||
context.set_value(key.clone(), value.clone())?;
|
||||
|
||||
let should_include = self.item.run(source, &mut context)?.as_boolean()?;
|
||||
|
||||
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 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)]
|
||||
pub struct For {
|
||||
is_async: bool,
|
||||
identifier: Identifier,
|
||||
expression: Expression,
|
||||
item: Item,
|
||||
@ -12,6 +14,20 @@ pub struct For {
|
||||
|
||||
impl AbstractTree for For {
|
||||
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 = Identifier::from_syntax_node(source, identifier_node)?;
|
||||
|
||||
@ -22,6 +38,7 @@ impl AbstractTree for For {
|
||||
let item = Item::from_syntax_node(source, item_node)?;
|
||||
|
||||
Ok(For {
|
||||
is_async,
|
||||
identifier,
|
||||
expression,
|
||||
item,
|
||||
@ -33,6 +50,15 @@ impl AbstractTree for For {
|
||||
let values = expression_run.as_list()?.items();
|
||||
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)?;
|
||||
|
||||
for value in values.iter() {
|
||||
@ -46,6 +72,7 @@ impl AbstractTree for For {
|
||||
} else {
|
||||
context.set_value(key.clone(), 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 = match operator_node.kind() {
|
||||
"==" => LogicOperator::Equal,
|
||||
"!=" => LogicOperator::NotEqual,
|
||||
"&&" => LogicOperator::And,
|
||||
"||" => LogicOperator::Or,
|
||||
">" => LogicOperator::Greater,
|
||||
@ -26,7 +27,7 @@ impl AbstractTree for Logic {
|
||||
"<=" => LogicOperator::LessOrEqaul,
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "==, && ||, >, <, >= or <=",
|
||||
expected: "==, !=, &&, ||, >, <, >= or <=",
|
||||
actual: operator_node.kind(),
|
||||
location: operator_node.start_position(),
|
||||
relevant_source: source[operator_node.byte_range()].to_string(),
|
||||
@ -55,6 +56,13 @@ impl AbstractTree for Logic {
|
||||
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::Or => left.as_boolean()? || right.as_boolean()?,
|
||||
LogicOperator::Greater => left > right,
|
||||
@ -70,6 +78,7 @@ impl AbstractTree for Logic {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum LogicOperator {
|
||||
Equal,
|
||||
NotEqual,
|
||||
And,
|
||||
Or,
|
||||
Greater,
|
||||
|
@ -23,6 +23,7 @@ pub mod math;
|
||||
pub mod remove;
|
||||
pub mod select;
|
||||
pub mod statement;
|
||||
pub mod sublist;
|
||||
pub mod tool;
|
||||
pub mod transform;
|
||||
pub mod value_node;
|
||||
@ -31,7 +32,7 @@ pub mod r#while;
|
||||
pub use {
|
||||
assignment::*, expression::*, filter::*, find::*, function_call::*, identifier::*, if_else::*,
|
||||
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;
|
||||
|
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),
|
||||
ToJson(Expression),
|
||||
ToString(Expression),
|
||||
ToFloat(Expression),
|
||||
|
||||
// Command
|
||||
Bash(Vec<Expression>),
|
||||
@ -52,9 +53,12 @@ pub enum Tool {
|
||||
RandomInteger,
|
||||
RandomFloat,
|
||||
|
||||
// Random
|
||||
// Table
|
||||
Columns(Expression),
|
||||
Rows(Expression),
|
||||
|
||||
// List
|
||||
Reverse(Expression, Option<(Expression, Expression)>),
|
||||
}
|
||||
|
||||
impl AbstractTree for Tool {
|
||||
@ -185,6 +189,12 @@ impl AbstractTree for Tool {
|
||||
|
||||
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" => {
|
||||
let expressions = parse_expressions(source, node)?;
|
||||
|
||||
@ -230,6 +240,22 @@ impl AbstractTree for Tool {
|
||||
|
||||
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 {
|
||||
expected: "built-in tool",
|
||||
@ -287,7 +313,18 @@ impl AbstractTree for Tool {
|
||||
Ok(Value::String(data))
|
||||
}
|
||||
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))
|
||||
}
|
||||
@ -443,6 +480,17 @@ impl AbstractTree for Tool {
|
||||
|
||||
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) => {
|
||||
let mut command = Command::new("bash");
|
||||
|
||||
@ -569,6 +617,21 @@ impl AbstractTree for Tool {
|
||||
|
||||
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 values = expression_run.as_list()?.items();
|
||||
let key = self.identifier.inner();
|
||||
let new_list = values
|
||||
let new_values = values
|
||||
.par_iter()
|
||||
.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();
|
||||
|
||||
@ -47,8 +47,9 @@ impl AbstractTree for Transform {
|
||||
Err(_) => Value::Empty,
|
||||
}
|
||||
})
|
||||
.filter(|value| !value.is_empty())
|
||||
.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,
|
||||
"empty" => ValueType::Empty,
|
||||
"list" => {
|
||||
let mut child_nodes = Vec::new();
|
||||
let mut expressions = Vec::new();
|
||||
|
||||
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() {
|
||||
let expression = Expression::from_syntax_node(source, child_syntax_node)?;
|
||||
child_nodes.push(expression);
|
||||
if current_node.is_named() {
|
||||
let expression = Expression::from_syntax_node(source, current_node)?;
|
||||
expressions.push(expression);
|
||||
}
|
||||
}
|
||||
|
||||
ValueType::ListExact(child_nodes)
|
||||
ValueType::List(expressions)
|
||||
}
|
||||
"table" => {
|
||||
let child_count = child.child_count();
|
||||
@ -148,7 +148,7 @@ impl AbstractTree for ValueNode {
|
||||
ValueType::Float => Value::Float(value_source.parse().unwrap()),
|
||||
ValueType::Integer => Value::Integer(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());
|
||||
|
||||
for node in nodes {
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
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>;
|
||||
|
||||
@ -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 {
|
||||
fn from(value: csv::Error) -> Self {
|
||||
Error::ToolFailure(value.to_string())
|
||||
|
@ -42,6 +42,12 @@ fn main() {
|
||||
|
||||
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 {
|
||||
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`.
|
||||
pub fn as_int(&self) -> Result<i64> {
|
||||
pub fn as_integer(&self) -> Result<i64> {
|
||||
match self {
|
||||
Value::Integer(i) => Ok(*i),
|
||||
value => Err(Error::ExpectedInt {
|
||||
@ -219,7 +219,7 @@ impl Add for Value {
|
||||
type Output = Result<Value>;
|
||||
|
||||
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)),
|
||||
_ => {}
|
||||
}
|
||||
@ -250,7 +250,7 @@ impl Sub for Value {
|
||||
type Output = Result<Self>;
|
||||
|
||||
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)),
|
||||
_ => {}
|
||||
}
|
||||
@ -271,8 +271,8 @@ impl Mul for Value {
|
||||
|
||||
fn mul(self, other: Self) -> Self::Output {
|
||||
if self.is_integer() && other.is_integer() {
|
||||
let left = self.as_int().unwrap();
|
||||
let right = other.as_int().unwrap();
|
||||
let left = self.as_integer().unwrap();
|
||||
let right = other.as_integer().unwrap();
|
||||
let value = Value::Integer(left.saturating_mul(right));
|
||||
|
||||
Ok(value)
|
||||
@ -307,8 +307,8 @@ impl Rem for Value {
|
||||
type Output = Result<Self>;
|
||||
|
||||
fn rem(self, other: Self) -> Self::Output {
|
||||
let left = self.as_int()?;
|
||||
let right = other.as_int()?;
|
||||
let left = self.as_integer()?;
|
||||
let right = other.as_integer()?;
|
||||
let result = left % right;
|
||||
|
||||
Ok(Value::Integer(result))
|
||||
@ -370,8 +370,16 @@ impl Ord for Value {
|
||||
(Value::String(left), Value::String(right)) => left.cmp(right),
|
||||
(Value::String(_), _) => Ordering::Greater,
|
||||
(Value::Float(left), Value::Float(right)) => left.total_cmp(right),
|
||||
(Value::Float(_), _) => Ordering::Greater,
|
||||
(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::Boolean(left), Value::Boolean(right)) => left.cmp(right),
|
||||
(Value::Boolean(_), _) => Ordering::Greater,
|
||||
|
@ -15,7 +15,7 @@ pub enum ValueType {
|
||||
Float,
|
||||
Integer,
|
||||
Boolean,
|
||||
ListExact(Vec<Expression>),
|
||||
List(Vec<Expression>),
|
||||
Empty,
|
||||
Map(BTreeMap<String, Expression>),
|
||||
Table {
|
||||
@ -36,7 +36,7 @@ impl PartialEq for ValueType {
|
||||
(ValueType::Float, ValueType::Float) => true,
|
||||
(ValueType::Integer, ValueType::Integer) => 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::Map(left), ValueType::Map(right)) => left == right,
|
||||
(
|
||||
@ -63,7 +63,7 @@ impl Display for ValueType {
|
||||
ValueType::Float => write!(f, "float"),
|
||||
ValueType::Integer => write!(f, "integer"),
|
||||
ValueType::Boolean => write!(f, "boolean"),
|
||||
ValueType::ListExact(list) => {
|
||||
ValueType::List(list) => {
|
||||
write!(f, "(")?;
|
||||
for (index, item) in list.into_iter().enumerate() {
|
||||
if index > 0 {
|
||||
@ -109,7 +109,7 @@ impl From<&Value> for ValueType {
|
||||
.map(|value| Expression::Value(ValueNode::new(value.value_type(), 0, 0)))
|
||||
.collect();
|
||||
|
||||
ValueType::ListExact(value_nodes)
|
||||
ValueType::List(value_nodes)
|
||||
}
|
||||
Value::Map(map) => {
|
||||
let mut value_nodes = BTreeMap::new();
|
||||
@ -134,7 +134,7 @@ impl From<&Value> for ValueType {
|
||||
.map(|column_name| Identifier::new(column_name.clone()))
|
||||
.collect(),
|
||||
rows: Box::new(Expression::Value(ValueNode::new(
|
||||
ValueType::ListExact(Vec::with_capacity(0)),
|
||||
ValueType::List(Vec::with_capacity(0)),
|
||||
0,
|
||||
0,
|
||||
))),
|
||||
|
@ -86,3 +86,39 @@ for list in list_of_lists {
|
||||
(expression
|
||||
(value
|
||||
(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
|
||||
(value
|
||||
(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 <text, number> [
|
||||
['answer', 42]
|
||||
table <messages, numbers> [
|
||||
['hiya', 42]
|
||||
['foo', 57]
|
||||
['bar', 99.99]
|
||||
]
|
||||
|
||||
---
|
||||
@ -27,7 +29,26 @@ table <text, number> [
|
||||
(string)))
|
||||
(expression
|
||||
(value
|
||||
(integer)))))))))))))))
|
||||
(integer))))))
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(string)))
|
||||
(expression
|
||||
(value
|
||||
(integer))))))
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(string)))
|
||||
(expression
|
||||
(value
|
||||
(float)))))))))))))))
|
||||
|
||||
==================
|
||||
Table Assignment
|
||||
==================
|
||||
|
@ -38,6 +38,7 @@ module.exports = grammar({
|
||||
$.tool,
|
||||
$.math,
|
||||
$.logic,
|
||||
$.sublist,
|
||||
)),
|
||||
|
||||
identifier: $ => /[a-zA-Z|_]+[._a-zA-Z0-9]*/,
|
||||
@ -55,7 +56,7 @@ module.exports = grammar({
|
||||
|
||||
integer: $ => /[-]?[0-9]+/,
|
||||
|
||||
float: $ => /[-]?[0-9]+[.]{1}[0-9]*/,
|
||||
float: $ => /[-]?[0-9]+[.]{1}[0-9]+/,
|
||||
|
||||
string: $ => /("[^"]*?")|('[^']*?')|(`[^`]*?`)/,
|
||||
|
||||
@ -67,7 +68,7 @@ module.exports = grammar({
|
||||
list: $ => seq(
|
||||
'[',
|
||||
repeat(seq($.expression, optional(','))),
|
||||
']'
|
||||
']',
|
||||
),
|
||||
|
||||
function: $ => seq(
|
||||
@ -78,7 +79,7 @@ module.exports = grammar({
|
||||
'}',
|
||||
),
|
||||
|
||||
table: $ => prec.right(seq(
|
||||
table: $ => prec(2, seq(
|
||||
'table',
|
||||
seq('<', repeat1(seq($.identifier, optional(','))), '>'),
|
||||
$.expression,
|
||||
@ -90,6 +91,14 @@ module.exports = grammar({
|
||||
'}',
|
||||
),
|
||||
|
||||
sublist: $ => prec.right(seq(
|
||||
$.expression,
|
||||
'.',
|
||||
$.expression,
|
||||
'..',
|
||||
$.expression,
|
||||
)),
|
||||
|
||||
math: $ => prec.left(seq(
|
||||
$.expression,
|
||||
$.math_operator,
|
||||
@ -178,7 +187,7 @@ module.exports = grammar({
|
||||
),
|
||||
|
||||
for: $ => seq(
|
||||
'for',
|
||||
choice('for', 'async for'),
|
||||
$.identifier,
|
||||
'in',
|
||||
$.expression,
|
||||
@ -282,6 +291,7 @@ module.exports = grammar({
|
||||
'from_json',
|
||||
'to_json',
|
||||
'to_string',
|
||||
'to_float',
|
||||
|
||||
// Command
|
||||
'bash',
|
||||
@ -299,6 +309,9 @@ module.exports = grammar({
|
||||
// Tables
|
||||
'columns',
|
||||
'rows',
|
||||
|
||||
// Lists
|
||||
'reverse',
|
||||
),
|
||||
}
|
||||
});
|
@ -141,6 +141,10 @@
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "logic"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "sublist"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -192,7 +196,7 @@
|
||||
},
|
||||
"float": {
|
||||
"type": "PATTERN",
|
||||
"value": "[-]?[0-9]+[.]{1}[0-9]*"
|
||||
"value": "[-]?[0-9]+[.]{1}[0-9]+"
|
||||
},
|
||||
"string": {
|
||||
"type": "PATTERN",
|
||||
@ -315,8 +319,8 @@
|
||||
]
|
||||
},
|
||||
"table": {
|
||||
"type": "PREC_RIGHT",
|
||||
"value": 0,
|
||||
"type": "PREC",
|
||||
"value": 2,
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"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": {
|
||||
"type": "PREC_LEFT",
|
||||
"value": 0,
|
||||
@ -728,11 +761,20 @@
|
||||
},
|
||||
"for": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "for"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "async for"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
@ -1138,6 +1180,10 @@
|
||||
"type": "STRING",
|
||||
"value": "to_string"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "to_float"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "bash"
|
||||
@ -1181,6 +1227,10 @@
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "rows"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "reverse"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -110,6 +110,10 @@
|
||||
"type": "math",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "sublist",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "tool",
|
||||
"named": true
|
||||
@ -510,6 +514,21 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "sublist",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "table",
|
||||
"named": true,
|
||||
@ -673,6 +692,14 @@
|
||||
"type": "-=",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": ".",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "..",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "/",
|
||||
"named": false
|
||||
@ -725,6 +752,10 @@
|
||||
"type": "async",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "async for",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "bash",
|
||||
"named": false
|
||||
@ -857,6 +888,10 @@
|
||||
"type": "remove",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "reverse",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "rows",
|
||||
"named": false
|
||||
@ -877,6 +912,10 @@
|
||||
"type": "table",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "to_float",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "to_json",
|
||||
"named": false
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user