Prepare for new version
This commit is contained in:
parent
c2a5f5e972
commit
f33eef9c5a
@ -26,11 +26,11 @@ make_guess = function <current_room> {
|
|||||||
&& ((length weapons) == 1)
|
&& ((length weapons) == 1)
|
||||||
{
|
{
|
||||||
(output 'It was '
|
(output 'It was '
|
||||||
+ suspects.0
|
+ suspects.{0}
|
||||||
+ ' in the '
|
+ ' in the '
|
||||||
+ rooms.0
|
+ rooms.{0}
|
||||||
+ ' with the '
|
+ ' with the '
|
||||||
+ weapons.0
|
+ weapons.{0}
|
||||||
+ '!')
|
+ '!')
|
||||||
} else {
|
} else {
|
||||||
(output 'I accuse '
|
(output 'I accuse '
|
||||||
|
@ -1,9 +1,60 @@
|
|||||||
foo = "bar"
|
# Function
|
||||||
func = function <> { "foo" }
|
x = "bar"
|
||||||
|
|
||||||
assert_equal("bar", (func))
|
func = function <> {
|
||||||
|
x = "foo"
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
foo = "xyz"
|
assert_equal("foo", (func))
|
||||||
|
assert_equal("bar", x)
|
||||||
|
|
||||||
assert_equal("xyz", (func))
|
# For Loop
|
||||||
|
x = 42
|
||||||
|
|
||||||
|
for number in [1 2 3] {
|
||||||
|
x += number
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal(48, x)
|
||||||
|
|
||||||
|
# Async Loops
|
||||||
|
|
||||||
|
## Transform Loop
|
||||||
|
|
||||||
|
x = 42
|
||||||
|
y = [1 2 3]
|
||||||
|
|
||||||
|
transform number in y {
|
||||||
|
number += x
|
||||||
|
x = 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal([43, 44, 45], y)
|
||||||
|
assert_equal(42, x)
|
||||||
|
|
||||||
|
## Filter Loop
|
||||||
|
|
||||||
|
x = 42
|
||||||
|
y = [1 2 3]
|
||||||
|
|
||||||
|
transform number in y {
|
||||||
|
number += x
|
||||||
|
x = 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal([43, 44, 45], y)
|
||||||
|
assert_equal(42, x)
|
||||||
|
|
||||||
|
## Filter Loop
|
||||||
|
|
||||||
|
x = 42
|
||||||
|
y = [1 2 3]
|
||||||
|
|
||||||
|
filter number in y {
|
||||||
|
number += x
|
||||||
|
x = 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal([43, 44, 45], y)
|
||||||
|
assert_equal(42, x)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
data = (from_json (read "examples/assets/jq_data.json"))
|
data = (from_json (read "examples/assets/jq_data.json"))
|
||||||
|
|
||||||
transform item in data {
|
transform item in data {
|
||||||
item.commit.committer.name
|
item.{commit}.{committer}.{name}
|
||||||
}
|
}
|
||||||
|
@ -52,10 +52,11 @@ impl AbstractTree for Assignment {
|
|||||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let key = self.identifier.inner().clone();
|
let key = self.identifier.inner().clone();
|
||||||
let value = self.statement.run(source, context)?;
|
let value = self.statement.run(source, context)?;
|
||||||
|
let mut context = context.variables_mut();
|
||||||
|
|
||||||
let new_value = match self.operator {
|
let new_value = match self.operator {
|
||||||
AssignmentOperator::PlusEqual => {
|
AssignmentOperator::PlusEqual => {
|
||||||
if let Some(mut previous_value) = context.get_value(&key)? {
|
if let Some(mut previous_value) = context.get(&key).cloned() {
|
||||||
previous_value += value;
|
previous_value += value;
|
||||||
previous_value
|
previous_value
|
||||||
} else {
|
} else {
|
||||||
@ -63,7 +64,7 @@ impl AbstractTree for Assignment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssignmentOperator::MinusEqual => {
|
AssignmentOperator::MinusEqual => {
|
||||||
if let Some(mut previous_value) = context.get_value(&key)? {
|
if let Some(mut previous_value) = context.get(&key).cloned() {
|
||||||
previous_value -= value;
|
previous_value -= value;
|
||||||
previous_value
|
previous_value
|
||||||
} else {
|
} else {
|
||||||
@ -73,7 +74,7 @@ impl AbstractTree for Assignment {
|
|||||||
AssignmentOperator::Equal => value,
|
AssignmentOperator::Equal => value,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.set_value(key, new_value)?;
|
context.insert(key, new_value);
|
||||||
|
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
value_node::ValueNode, AbstractTree, Error, Identifier, Map, Result, Sublist, Tool, Value,
|
value_node::ValueNode, AbstractTree, Error, Identifier, Index, Map, Result, Sublist, Tool,
|
||||||
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{function_call::FunctionCall, logic::Logic, math::Math};
|
use super::{function_call::FunctionCall, logic::Logic, math::Math};
|
||||||
@ -12,6 +13,7 @@ pub enum Expression {
|
|||||||
Value(ValueNode),
|
Value(ValueNode),
|
||||||
Identifier(Identifier),
|
Identifier(Identifier),
|
||||||
Sublist(Box<Sublist>),
|
Sublist(Box<Sublist>),
|
||||||
|
Index(Box<Index>),
|
||||||
Math(Box<Math>),
|
Math(Box<Math>),
|
||||||
Logic(Box<Logic>),
|
Logic(Box<Logic>),
|
||||||
FunctionCall(FunctionCall),
|
FunctionCall(FunctionCall),
|
||||||
@ -32,6 +34,7 @@ impl AbstractTree for Expression {
|
|||||||
"sublist" => {
|
"sublist" => {
|
||||||
Expression::Sublist(Box::new(Sublist::from_syntax_node(source, child)?))
|
Expression::Sublist(Box::new(Sublist::from_syntax_node(source, child)?))
|
||||||
}
|
}
|
||||||
|
"index" => Expression::Index(Box::new(Index::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" => {
|
||||||
@ -47,7 +50,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, sublist, math or function_call",
|
expected: "value, identifier, sublist, index, 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(),
|
||||||
@ -63,6 +66,7 @@ impl AbstractTree for Expression {
|
|||||||
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),
|
||||||
Expression::Tool(tool) => tool.run(source, context),
|
Expression::Tool(tool) => tool.run(source, context),
|
||||||
|
Expression::Index(index) => index.run(source, context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ impl AbstractTree for Filter {
|
|||||||
values.par_iter().try_for_each(|value| {
|
values.par_iter().try_for_each(|value| {
|
||||||
let mut context = Map::new();
|
let mut context = Map::new();
|
||||||
|
|
||||||
context.set_value(key.clone(), value.clone())?;
|
context.variables_mut().insert(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()?;
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ impl AbstractTree for Find {
|
|||||||
let mut context = context.clone();
|
let mut context = context.clone();
|
||||||
|
|
||||||
for value in values.iter() {
|
for value in values.iter() {
|
||||||
context.set_value(key.clone(), value.clone())?;
|
context.variables_mut().insert(key.clone(), value.clone());
|
||||||
|
|
||||||
let should_return = self.item.run(source, &mut context)?.as_boolean()?;
|
let should_return = self.item.run(source, &mut context)?.as_boolean()?;
|
||||||
|
|
||||||
|
@ -52,26 +52,20 @@ impl AbstractTree for For {
|
|||||||
|
|
||||||
if self.is_async {
|
if self.is_async {
|
||||||
values.par_iter().try_for_each(|value| {
|
values.par_iter().try_for_each(|value| {
|
||||||
let mut iter_context = Map::clone_from(context);
|
let mut iter_context = Map::new();
|
||||||
|
|
||||||
iter_context.set_value(key.clone(), value.clone())?;
|
iter_context
|
||||||
|
.variables_mut()
|
||||||
|
.insert(key.clone(), value.clone());
|
||||||
|
|
||||||
self.item.run(source, &mut iter_context).map(|_value| ())
|
self.item.run(source, &mut iter_context).map(|_value| ())
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
let original_value = context.get_value(key)?;
|
|
||||||
|
|
||||||
for value in values.iter() {
|
for value in values.iter() {
|
||||||
context.set_value(key.clone(), value.clone())?;
|
context.variables_mut().insert(key.clone(), value.clone());
|
||||||
|
|
||||||
self.item.run(source, context)?;
|
self.item.run(source, context)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(original_value) = original_value {
|
|
||||||
context.set_value(key.clone(), original_value)?;
|
|
||||||
} else {
|
|
||||||
context.set_value(key.clone(), Value::Empty)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
|
@ -35,7 +35,7 @@ impl AbstractTree for FunctionCall {
|
|||||||
|
|
||||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let key = self.name.inner();
|
let key = self.name.inner();
|
||||||
let definition = if let Some(value) = context.get_value(key)? {
|
let definition = if let Some(value) = context.variables().get(key) {
|
||||||
value.as_function().cloned()?
|
value.as_function().cloned()?
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::FunctionIdentifierNotFound(self.name.clone()));
|
return Err(Error::FunctionIdentifierNotFound(self.name.clone()));
|
||||||
@ -47,7 +47,7 @@ impl AbstractTree for FunctionCall {
|
|||||||
let key = identifier.inner().clone();
|
let key = identifier.inner().clone();
|
||||||
let value = expression.run(source, context)?;
|
let value = expression.run(source, context)?;
|
||||||
|
|
||||||
function_context.set_value(key, value)?;
|
function_context.variables_mut().insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
definition.body().run(source, &mut function_context)
|
definition.body().run(source, &mut function_context)
|
||||||
|
@ -30,12 +30,10 @@ impl AbstractTree for Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, context: &mut Map) -> Result<Value> {
|
fn run(&self, _source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let value = if let Some(value) = context.get_value(&self.0)? {
|
if let Some(value) = context.variables().get(&self.0) {
|
||||||
value
|
Ok(value.clone())
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::VariableIdentifierNotFound(self.inner().clone()));
|
Err(Error::VariableIdentifierNotFound(self.inner().clone()))
|
||||||
};
|
}
|
||||||
|
|
||||||
Ok(value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
69
src/abstract_tree/index.rs
Normal file
69
src/abstract_tree/index.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tree_sitter::Node;
|
||||||
|
|
||||||
|
use crate::{AbstractTree, Error, Expression, List, Result, Value};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
|
pub struct Index {
|
||||||
|
collection: Expression,
|
||||||
|
index: Expression,
|
||||||
|
index_end: Option<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbstractTree for Index {
|
||||||
|
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
|
||||||
|
let collection_node = node.child(0).unwrap();
|
||||||
|
let collection = Expression::from_syntax_node(source, collection_node)?;
|
||||||
|
|
||||||
|
let index_node = node.child(3).unwrap();
|
||||||
|
let index = Expression::from_syntax_node(source, index_node)?;
|
||||||
|
|
||||||
|
let index_end_node = node.child(5);
|
||||||
|
let index_end = if let Some(index_end_node) = index_end_node {
|
||||||
|
Some(Expression::from_syntax_node(source, index_end_node)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Index {
|
||||||
|
collection,
|
||||||
|
index,
|
||||||
|
index_end,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, source: &str, context: &mut crate::Map) -> crate::Result<crate::Value> {
|
||||||
|
let value = self.collection.run(source, context)?;
|
||||||
|
|
||||||
|
match value {
|
||||||
|
Value::List(list) => {
|
||||||
|
let index = self.index.run(source, context)?.as_integer()? as usize;
|
||||||
|
|
||||||
|
let item = if let Some(index_end) = &self.index_end {
|
||||||
|
let index_end = index_end.run(source, context)?.as_integer()? as usize;
|
||||||
|
let sublist = list.items()[index..=index_end].to_vec();
|
||||||
|
|
||||||
|
Value::List(List::with_items(sublist))
|
||||||
|
} else {
|
||||||
|
list.items().get(index).cloned().unwrap_or_default()
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(item)
|
||||||
|
}
|
||||||
|
Value::Map(mut map) => {
|
||||||
|
let value = self.index.run(source, &mut map)?;
|
||||||
|
let index = value.as_string()?;
|
||||||
|
let item = map.variables().get(index).cloned().unwrap_or_default();
|
||||||
|
|
||||||
|
Ok(item)
|
||||||
|
}
|
||||||
|
Value::String(string) => {
|
||||||
|
let index = self.index.run(source, context)?.as_integer()? as usize;
|
||||||
|
let item = string.chars().nth(index).unwrap_or_default();
|
||||||
|
|
||||||
|
Ok(Value::String(item.to_string()))
|
||||||
|
}
|
||||||
|
_ => return Err(Error::ExpectedCollection { actual: value }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,7 +35,9 @@ impl AbstractTree for Insert {
|
|||||||
table.insert(row_values.items().clone())?;
|
table.insert(row_values.items().clone())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.set_value(table_name, Value::Table(table))?;
|
context
|
||||||
|
.variables_mut()
|
||||||
|
.insert(table_name, Value::Table(table));
|
||||||
|
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ pub mod r#for;
|
|||||||
pub mod function_call;
|
pub mod function_call;
|
||||||
pub mod identifier;
|
pub mod identifier;
|
||||||
pub mod if_else;
|
pub mod if_else;
|
||||||
|
pub mod index;
|
||||||
pub mod insert;
|
pub mod insert;
|
||||||
pub mod item;
|
pub mod item;
|
||||||
pub mod logic;
|
pub mod logic;
|
||||||
@ -31,8 +32,8 @@ 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::*,
|
index::*, insert::*, item::*, logic::*, math::*, r#async::*, r#for::*, r#match::*, r#while::*,
|
||||||
select::*, statement::*, sublist::*, tool::*, transform::*, value_node::*,
|
remove::*, select::*, statement::*, sublist::*, tool::*, transform::*, value_node::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
@ -36,7 +36,9 @@ impl AbstractTree for Remove {
|
|||||||
let mut should_remove_index = None;
|
let mut should_remove_index = None;
|
||||||
|
|
||||||
for (index, value) in values.items().iter().enumerate() {
|
for (index, value) in values.items().iter().enumerate() {
|
||||||
sub_context.set_value(key.clone(), value.clone())?;
|
sub_context
|
||||||
|
.variables_mut()
|
||||||
|
.insert(key.clone(), value.clone());
|
||||||
|
|
||||||
let should_remove = self.item.run(source, &mut sub_context)?.as_boolean()?;
|
let should_remove = self.item.run(source, &mut sub_context)?.as_boolean()?;
|
||||||
|
|
||||||
@ -45,8 +47,9 @@ impl AbstractTree for Remove {
|
|||||||
|
|
||||||
match &self.expression {
|
match &self.expression {
|
||||||
Expression::Identifier(identifier) => {
|
Expression::Identifier(identifier) => {
|
||||||
context
|
sub_context
|
||||||
.set_value(identifier.inner().clone(), Value::List(values.clone()))?;
|
.variables_mut()
|
||||||
|
.insert(identifier.inner().clone(), Value::List(values.clone()));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,6 @@ impl AbstractTree for Select {
|
|||||||
} else {
|
} else {
|
||||||
old_table.headers().clone()
|
old_table.headers().clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut new_table = Table::new(column_names.to_vec());
|
let mut new_table = Table::new(column_names.to_vec());
|
||||||
|
|
||||||
for row in old_table.rows() {
|
for row in old_table.rows() {
|
||||||
@ -75,7 +74,9 @@ impl AbstractTree for Select {
|
|||||||
for (i, value) in row.iter().enumerate() {
|
for (i, value) in row.iter().enumerate() {
|
||||||
let column_name = old_table.headers().get(i).unwrap();
|
let column_name = old_table.headers().get(i).unwrap();
|
||||||
|
|
||||||
row_context.set_value(column_name.clone(), value.clone())?;
|
row_context
|
||||||
|
.variables_mut()
|
||||||
|
.insert(column_name.clone(), value.clone());
|
||||||
|
|
||||||
let new_table_column_index =
|
let new_table_column_index =
|
||||||
new_table
|
new_table
|
||||||
|
@ -12,6 +12,7 @@ use crate::{
|
|||||||
/// Expression, it will always return a non-empty value when run.
|
/// Expression, it will always return a non-empty value when run.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
|
Comment(String),
|
||||||
Assignment(Box<Assignment>),
|
Assignment(Box<Assignment>),
|
||||||
Expression(Expression),
|
Expression(Expression),
|
||||||
IfElse(Box<IfElse>),
|
IfElse(Box<IfElse>),
|
||||||
@ -34,6 +35,12 @@ impl AbstractTree for Statement {
|
|||||||
let child = node.child(0).unwrap();
|
let child = node.child(0).unwrap();
|
||||||
|
|
||||||
match child.kind() {
|
match child.kind() {
|
||||||
|
"comment" => {
|
||||||
|
let comment_node = node.child(0).unwrap();
|
||||||
|
let text = &source[comment_node.byte_range()];
|
||||||
|
|
||||||
|
Ok(Statement::Comment(text.to_string()))
|
||||||
|
}
|
||||||
"assignment" => Ok(Statement::Assignment(Box::new(
|
"assignment" => Ok(Statement::Assignment(Box::new(
|
||||||
Assignment::from_syntax_node(source, child)?,
|
Assignment::from_syntax_node(source, child)?,
|
||||||
))),
|
))),
|
||||||
@ -74,7 +81,7 @@ impl AbstractTree for Statement {
|
|||||||
source, child,
|
source, child,
|
||||||
)?))),
|
)?))),
|
||||||
_ => Err(Error::UnexpectedSyntaxNode {
|
_ => Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "assignment, expression, if...else, while, for, transform, filter, tool, async, find, remove, select or insert",
|
expected: "comment, assignment, expression, if...else, while, for, transform, filter, tool, async, find, remove, select or insert",
|
||||||
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(),
|
||||||
@ -84,6 +91,7 @@ impl AbstractTree for Statement {
|
|||||||
|
|
||||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
match self {
|
match self {
|
||||||
|
Statement::Comment(comment) => Ok(Value::String(comment.clone())),
|
||||||
Statement::Assignment(assignment) => assignment.run(source, context),
|
Statement::Assignment(assignment) => assignment.run(source, context),
|
||||||
Statement::Expression(expression) => expression.run(source, context),
|
Statement::Expression(expression) => expression.run(source, context),
|
||||||
Statement::IfElse(if_else) => if_else.run(source, context),
|
Statement::IfElse(if_else) => if_else.run(source, context),
|
||||||
|
@ -401,13 +401,17 @@ impl AbstractTree for Tool {
|
|||||||
let created = metadata.created()?.elapsed()?.as_secs() as i64;
|
let created = metadata.created()?.elapsed()?.as_secs() as i64;
|
||||||
let modified = metadata.modified()?.elapsed()?.as_secs() as i64;
|
let modified = metadata.modified()?.elapsed()?.as_secs() as i64;
|
||||||
let accessed = metadata.accessed()?.elapsed()?.as_secs() as i64;
|
let accessed = metadata.accessed()?.elapsed()?.as_secs() as i64;
|
||||||
let mut metadata_output = Map::new();
|
let metadata_output = Map::new();
|
||||||
|
|
||||||
metadata_output.set_value("type".to_string(), Value::String(file_type))?;
|
{
|
||||||
metadata_output.set_value("size".to_string(), Value::Integer(size))?;
|
let mut metadata_variables = metadata_output.variables_mut();
|
||||||
metadata_output.set_value("created".to_string(), Value::Integer(created))?;
|
|
||||||
metadata_output.set_value("modified".to_string(), Value::Integer(modified))?;
|
metadata_variables.insert("type".to_string(), Value::String(file_type));
|
||||||
metadata_output.set_value("accessed".to_string(), Value::Integer(accessed))?;
|
metadata_variables.insert("size".to_string(), Value::Integer(size));
|
||||||
|
metadata_variables.insert("created".to_string(), Value::Integer(created));
|
||||||
|
metadata_variables.insert("modified".to_string(), Value::Integer(modified));
|
||||||
|
metadata_variables.insert("accessed".to_string(), Value::Integer(accessed));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Value::Map(metadata_output))
|
Ok(Value::Map(metadata_output))
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,9 @@ impl AbstractTree for Transform {
|
|||||||
.map(|value| {
|
.map(|value| {
|
||||||
let mut iter_context = Map::new();
|
let mut iter_context = Map::new();
|
||||||
|
|
||||||
iter_context.set_value(key.clone(), value.clone()).unwrap();
|
iter_context
|
||||||
|
.variables_mut()
|
||||||
|
.insert(key.clone(), value.clone());
|
||||||
|
|
||||||
let item_run = self.item.run(source, &mut iter_context);
|
let item_run = self.item.run(source, &mut iter_context);
|
||||||
|
|
||||||
|
@ -161,15 +161,15 @@ impl AbstractTree for ValueNode {
|
|||||||
}
|
}
|
||||||
ValueType::Empty => Value::Empty,
|
ValueType::Empty => Value::Empty,
|
||||||
ValueType::Map(nodes) => {
|
ValueType::Map(nodes) => {
|
||||||
let mut values = Map::new();
|
let map = Map::new();
|
||||||
|
|
||||||
for (key, node) in nodes {
|
for (key, node) in nodes {
|
||||||
let value = node.run(source, context)?;
|
let value = node.run(source, context)?;
|
||||||
|
|
||||||
values.set_value(key.clone(), value)?;
|
map.variables_mut().insert(key.clone(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Map(values)
|
Value::Map(map)
|
||||||
}
|
}
|
||||||
ValueType::Table {
|
ValueType::Table {
|
||||||
column_names,
|
column_names,
|
||||||
|
@ -147,11 +147,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn evaluate_map() {
|
fn evaluate_map() {
|
||||||
let mut map = Map::new();
|
let map = Map::new();
|
||||||
|
|
||||||
map.set_value("x".to_string(), Value::Integer(1)).unwrap();
|
map.variables_mut()
|
||||||
map.set_value("foo".to_string(), Value::String("bar".to_string()))
|
.insert("x".to_string(), Value::Integer(1));
|
||||||
.unwrap();
|
map.variables_mut()
|
||||||
|
.insert("foo".to_string(), Value::String("bar".to_string()));
|
||||||
|
|
||||||
assert_eq!(evaluate("{ x = 1 foo = 'bar' }"), Ok(Value::Map(map)));
|
assert_eq!(evaluate("{ x = 1 foo = 'bar' }"), Ok(Value::Map(map)));
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,8 @@ fn main() {
|
|||||||
|
|
||||||
if let Some(input) = args.input {
|
if let Some(input) = args.input {
|
||||||
context
|
context
|
||||||
.set_value("input".to_string(), Value::String(input))
|
.variables_mut()
|
||||||
|
.insert("input".to_string(), Value::String(input))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +53,8 @@ fn main() {
|
|||||||
let file_contents = read_to_string(path).unwrap();
|
let file_contents = read_to_string(path).unwrap();
|
||||||
|
|
||||||
context
|
context
|
||||||
.set_value("input".to_string(), Value::String(file_contents))
|
.variables_mut()
|
||||||
|
.insert("input".to_string(), Value::String(file_contents))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
136
src/value/map.rs
136
src/value/map.rs
@ -3,10 +3,10 @@ use std::{
|
|||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{value::Value, Error, List, Result, Table};
|
use crate::{value::Value, List, Table};
|
||||||
|
|
||||||
/// A collection dust variables comprised of key-value pairs.
|
/// A collection dust variables comprised of key-value pairs.
|
||||||
///
|
///
|
||||||
@ -37,98 +37,12 @@ impl Map {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a Value assigned to the identifer, allowing dot notation to retrieve Values that are /// nested in Lists or Maps. Returns None if there is no variable with a key matching the /// identifier. Returns an error if a Map or List is indexed incorrectly.
|
pub fn variables(&self) -> RwLockReadGuard<BTreeMap<String, Value>> {
|
||||||
pub fn get_value(&self, identifier: &str) -> Result<Option<Value>> {
|
self.variables.read().unwrap()
|
||||||
let variables = self.variables.read().unwrap();
|
|
||||||
|
|
||||||
let split = identifier.rsplit_once('.');
|
|
||||||
let (found_value, next_identifier) = if let Some((identifier, next_identifier)) = split {
|
|
||||||
if identifier.contains('.') {
|
|
||||||
(self.get_value(identifier)?, next_identifier)
|
|
||||||
} else {
|
|
||||||
(variables.get(identifier).cloned(), next_identifier)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Ok(variables.get(identifier).cloned());
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(value) = found_value {
|
|
||||||
if let Value::List(list) = value {
|
|
||||||
let index = if let Ok(index) = next_identifier.parse::<usize>() {
|
|
||||||
index
|
|
||||||
} else {
|
|
||||||
return Err(Error::ExpectedInt {
|
|
||||||
actual: Value::String(next_identifier.to_string()),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(list.items().get(index).cloned())
|
|
||||||
} else if let Value::Map(map) = value {
|
|
||||||
map.get_value(next_identifier)
|
|
||||||
} else {
|
|
||||||
Ok(Some(value))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assigns a variable with a Value and the identifier as its key, allowing dot notation to
|
pub fn variables_mut(&self) -> RwLockWriteGuard<BTreeMap<String, Value>> {
|
||||||
/// assign nested lists and maps. Returns an error if a List or Map is indexed incorrectly.
|
self.variables.write().unwrap()
|
||||||
pub fn set_value(&mut self, key: String, value: Value) -> Result<()> {
|
|
||||||
let split = key.split_once('.');
|
|
||||||
|
|
||||||
if let Some((identifier, next_identifier)) = split {
|
|
||||||
let mut variables = self.variables.write().unwrap();
|
|
||||||
let get_value = variables.get_mut(identifier);
|
|
||||||
|
|
||||||
if let Some(found_value) = get_value {
|
|
||||||
if let Value::List(list) = found_value {
|
|
||||||
let index = if let Ok(index) = next_identifier.parse::<usize>() {
|
|
||||||
index
|
|
||||||
} else {
|
|
||||||
return Err(Error::ExpectedInt {
|
|
||||||
actual: Value::String(next_identifier.to_string()),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut missing_elements = index.saturating_sub(list.items().len()) + 1;
|
|
||||||
let mut items = list.items_mut();
|
|
||||||
|
|
||||||
while missing_elements > 0 {
|
|
||||||
items.push(value.clone());
|
|
||||||
|
|
||||||
missing_elements -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
} else if let Value::Map(map) = found_value {
|
|
||||||
map.set_value(next_identifier.to_string(), value)
|
|
||||||
} else {
|
|
||||||
Err(Error::ExpectedMap {
|
|
||||||
actual: found_value.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let mut new_map = Map::new();
|
|
||||||
|
|
||||||
new_map.set_value(next_identifier.to_string(), value)?;
|
|
||||||
|
|
||||||
self.variables
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.insert(identifier.to_string(), Value::Map(new_map));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.variables
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.insert(key.to_string(), value);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes an assigned variable.
|
/// Removes an assigned variable.
|
||||||
@ -204,10 +118,11 @@ impl Display for Map {
|
|||||||
|
|
||||||
impl From<&Table> for Map {
|
impl From<&Table> for Map {
|
||||||
fn from(value: &Table) -> Self {
|
fn from(value: &Table) -> Self {
|
||||||
let mut map = Map::new();
|
let map = Map::new();
|
||||||
|
|
||||||
for (row_index, row) in value.rows().iter().enumerate() {
|
for (row_index, row) in value.rows().iter().enumerate() {
|
||||||
map.set_value(
|
map.variables_mut()
|
||||||
|
.insert(
|
||||||
row_index.to_string(),
|
row_index.to_string(),
|
||||||
Value::List(List::with_items(row.clone())),
|
Value::List(List::with_items(row.clone())),
|
||||||
)
|
)
|
||||||
@ -226,36 +141,3 @@ impl Serialize for Map {
|
|||||||
self.variables.serialize(serializer)
|
self.variables.serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_and_set_simple_value() {
|
|
||||||
let mut map = Map::new();
|
|
||||||
|
|
||||||
map.set_value("x".to_string(), Value::Integer(1)).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(Value::Integer(1), map.get_value("x").unwrap().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_and_set_nested_maps() {
|
|
||||||
let mut map = Map::new();
|
|
||||||
|
|
||||||
map.set_value("x".to_string(), Value::Map(Map::new()))
|
|
||||||
.unwrap();
|
|
||||||
map.set_value("x.x".to_string(), Value::Map(Map::new()))
|
|
||||||
.unwrap();
|
|
||||||
map.set_value("x.x.x".to_string(), Value::Map(Map::new()))
|
|
||||||
.unwrap();
|
|
||||||
map.set_value("x.x.x.x".to_string(), Value::Map(Map::new()))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
Value::Map(Map::new()),
|
|
||||||
map.get_value("x.x.x.x").unwrap().unwrap()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -508,12 +508,12 @@ impl TryFrom<JsonValue> for Value {
|
|||||||
Number(number) => Ok(Value::Float(f64::from(number))),
|
Number(number) => Ok(Value::Float(f64::from(number))),
|
||||||
Boolean(boolean) => Ok(Value::Boolean(boolean)),
|
Boolean(boolean) => Ok(Value::Boolean(boolean)),
|
||||||
Object(object) => {
|
Object(object) => {
|
||||||
let mut map = Map::new();
|
let map = Map::new();
|
||||||
|
|
||||||
for (key, node_value) in object.iter() {
|
for (key, node_value) in object.iter() {
|
||||||
let value = Value::try_from(node_value)?;
|
let value = Value::try_from(node_value)?;
|
||||||
|
|
||||||
map.set_value(key.to_string(), value)?;
|
map.variables_mut().insert(key.to_string(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Map(map))
|
Ok(Value::Map(map))
|
||||||
@ -546,12 +546,12 @@ impl TryFrom<&JsonValue> for Value {
|
|||||||
Number(number) => Ok(Value::Float(f64::from(*number))),
|
Number(number) => Ok(Value::Float(f64::from(*number))),
|
||||||
Boolean(boolean) => Ok(Value::Boolean(*boolean)),
|
Boolean(boolean) => Ok(Value::Boolean(*boolean)),
|
||||||
Object(object) => {
|
Object(object) => {
|
||||||
let mut map = Map::new();
|
let map = Map::new();
|
||||||
|
|
||||||
for (key, node_value) in object.iter() {
|
for (key, node_value) in object.iter() {
|
||||||
let value = Value::try_from(node_value)?;
|
let value = Value::try_from(node_value)?;
|
||||||
|
|
||||||
map.set_value(key.to_string(), value)?;
|
map.variables_mut().insert(key.to_string(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Map(map))
|
Ok(Value::Map(map))
|
||||||
@ -839,11 +839,10 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
|||||||
where
|
where
|
||||||
M: MapAccess<'de>,
|
M: MapAccess<'de>,
|
||||||
{
|
{
|
||||||
let mut map = Map::new();
|
let map = Map::new();
|
||||||
|
|
||||||
while let Some((key, value)) = access.next_entry()? {
|
while let Some((key, value)) = access.next_entry()? {
|
||||||
map.set_value(key, value)
|
map.variables_mut().insert(key, value);
|
||||||
.expect("Failed to deserialize Value. This is a no-op.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Map(map))
|
Ok(Value::Map(map))
|
||||||
|
@ -19,6 +19,57 @@ if true { "True" }
|
|||||||
(value
|
(value
|
||||||
(string)))))))))
|
(string)))))))))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Complex If
|
||||||
|
==================
|
||||||
|
|
||||||
|
if (1 == 1) && (2 == 2) && (3 == 3) { "True" }
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(root
|
||||||
|
(item
|
||||||
|
(statement
|
||||||
|
(if_else
|
||||||
|
(if
|
||||||
|
(expression
|
||||||
|
(logic
|
||||||
|
(expression
|
||||||
|
(logic
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))
|
||||||
|
(logic_operator)
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))))
|
||||||
|
(logic_operator)
|
||||||
|
(expression
|
||||||
|
(logic
|
||||||
|
(expression
|
||||||
|
(logic
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))
|
||||||
|
(logic_operator)
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))))
|
||||||
|
(logic_operator)
|
||||||
|
(expression
|
||||||
|
(logic
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))
|
||||||
|
(logic_operator)
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))))))))
|
||||||
|
(statement
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(string)))))))))
|
||||||
|
|
||||||
==================
|
==================
|
||||||
If Assignment
|
If Assignment
|
||||||
==================
|
==================
|
||||||
|
@ -26,9 +26,11 @@ __xyz__
|
|||||||
Dot Notation
|
Dot Notation
|
||||||
==================
|
==================
|
||||||
|
|
||||||
dust_data.0.name
|
dust_data.{1}.{name}
|
||||||
# Separator
|
|
||||||
creature.total_clams
|
creature.{total_clams}
|
||||||
|
|
||||||
|
foobar.{1}.{42}
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -36,11 +38,35 @@ creature.total_clams
|
|||||||
(item
|
(item
|
||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(identifier))))
|
(index
|
||||||
(item
|
(expression
|
||||||
(statement
|
(index
|
||||||
(comment)))
|
(expression
|
||||||
|
(identifier))
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))))
|
||||||
|
(expression
|
||||||
|
(identifier))))))
|
||||||
(item
|
(item
|
||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(identifier)))))
|
(index
|
||||||
|
(expression
|
||||||
|
(identifier))
|
||||||
|
(expression
|
||||||
|
(identifier))))))
|
||||||
|
(item
|
||||||
|
(statement
|
||||||
|
(expression
|
||||||
|
(index
|
||||||
|
(expression
|
||||||
|
(index
|
||||||
|
(expression
|
||||||
|
(identifier))
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))))
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer))))))))
|
||||||
|
@ -82,10 +82,10 @@ List Nesting
|
|||||||
(integer)))))))))))))))
|
(integer)))))))))))))))
|
||||||
|
|
||||||
==================
|
==================
|
||||||
Sublist
|
List Index
|
||||||
==================
|
==================
|
||||||
|
|
||||||
['answers', 42, 666].1..2
|
['answers', 42, 666].{1}
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -93,7 +93,36 @@ Sublist
|
|||||||
(item
|
(item
|
||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(sublist
|
(index
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(list
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(string)))
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer))))))
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer))))))))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Sublist
|
||||||
|
==================
|
||||||
|
|
||||||
|
['answers', 42, 666].{1..2}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(root
|
||||||
|
(item
|
||||||
|
(statement
|
||||||
|
(expression
|
||||||
|
(index
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(list
|
(list
|
||||||
|
@ -48,7 +48,7 @@ x = {
|
|||||||
Map Access
|
Map Access
|
||||||
==================
|
==================
|
||||||
|
|
||||||
x.answer
|
x.{answer}
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -56,4 +56,8 @@ x.answer
|
|||||||
(item
|
(item
|
||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(identifier)))))
|
(index
|
||||||
|
(expression
|
||||||
|
(identifier))
|
||||||
|
(expression
|
||||||
|
(identifier)))))))
|
@ -36,6 +36,7 @@ Equality
|
|||||||
==================
|
==================
|
||||||
|
|
||||||
4 + 2 == 42 && true
|
4 + 2 == 42 && true
|
||||||
|
(((4 + 2) == 42) && true)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -62,13 +63,36 @@ Equality
|
|||||||
(logic_operator)
|
(logic_operator)
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(boolean))))))))))
|
(boolean)))))))))
|
||||||
|
(item
|
||||||
|
(statement
|
||||||
|
(expression
|
||||||
|
(logic
|
||||||
|
(expression
|
||||||
|
(logic
|
||||||
|
(expression
|
||||||
|
(math
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))
|
||||||
|
(math_operator)
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))))
|
||||||
|
(logic_operator)
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))))
|
||||||
|
(logic_operator)
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(boolean))))))))
|
||||||
==================
|
==================
|
||||||
\||
|
\||
|
||||||
==================
|
==================
|
||||||
|
|
||||||
4 + 2 == 42 || true
|
4 + 2 == 42 || true
|
||||||
|
((4 + 2) == 42) || true
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -95,4 +119,27 @@ Equality
|
|||||||
(logic_operator)
|
(logic_operator)
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(boolean))))))))))
|
(boolean)))))))))
|
||||||
|
(item
|
||||||
|
(statement
|
||||||
|
(expression
|
||||||
|
(logic
|
||||||
|
(expression
|
||||||
|
(logic
|
||||||
|
(expression
|
||||||
|
(math
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))
|
||||||
|
(math_operator)
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))))
|
||||||
|
(logic_operator)
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(integer)))))
|
||||||
|
(logic_operator)
|
||||||
|
(expression
|
||||||
|
(value
|
||||||
|
(boolean))))))))
|
@ -8,7 +8,7 @@ module.exports = grammar({
|
|||||||
|
|
||||||
item: $ => prec.left(repeat1($.statement)),
|
item: $ => prec.left(repeat1($.statement)),
|
||||||
|
|
||||||
statement: $ => choice(
|
statement: $ => prec.left(choice(
|
||||||
$.comment,
|
$.comment,
|
||||||
$.assignment,
|
$.assignment,
|
||||||
$.expression,
|
$.expression,
|
||||||
@ -22,7 +22,7 @@ module.exports = grammar({
|
|||||||
$.filter,
|
$.filter,
|
||||||
$.find,
|
$.find,
|
||||||
$.remove,
|
$.remove,
|
||||||
),
|
)),
|
||||||
|
|
||||||
comment: $ => seq(/[#]+.*/),
|
comment: $ => seq(/[#]+.*/),
|
||||||
|
|
||||||
@ -31,17 +31,17 @@ module.exports = grammar({
|
|||||||
seq('(', $._expression_kind, ')'),
|
seq('(', $._expression_kind, ')'),
|
||||||
),
|
),
|
||||||
|
|
||||||
_expression_kind: $ => prec.right(choice(
|
_expression_kind: $ => choice(
|
||||||
$.value,
|
$.value,
|
||||||
$.identifier,
|
$.identifier,
|
||||||
$.function_call,
|
$.index,
|
||||||
$.tool,
|
|
||||||
$.math,
|
$.math,
|
||||||
$.logic,
|
$.logic,
|
||||||
$.sublist,
|
$.function_call,
|
||||||
)),
|
$.tool,
|
||||||
|
),
|
||||||
|
|
||||||
identifier: $ => /[a-zA-Z|_]+[._a-zA-Z0-9]*/,
|
identifier: $ => /[_a-zA-Z]+[_a-zA-Z0-9]?/,
|
||||||
|
|
||||||
value: $ => choice(
|
value: $ => choice(
|
||||||
$.integer,
|
$.integer,
|
||||||
@ -54,9 +54,21 @@ module.exports = grammar({
|
|||||||
$.map,
|
$.map,
|
||||||
),
|
),
|
||||||
|
|
||||||
integer: $ => /[-]?[0-9]+/,
|
_numeric: $ => token(repeat1(
|
||||||
|
choice('1', '2', '3', '4', '5', '6', '7', '8', '9', '0')
|
||||||
|
)),
|
||||||
|
|
||||||
float: $ => /[-]?[0-9]+[.]{1}[0-9]+/,
|
integer: $ => prec.left(seq(
|
||||||
|
optional(token.immediate('-')),
|
||||||
|
$._numeric,
|
||||||
|
)),
|
||||||
|
|
||||||
|
float: $ => prec.left(seq(
|
||||||
|
optional(token.immediate('-')),
|
||||||
|
$._numeric,
|
||||||
|
token.immediate('.'),
|
||||||
|
$._numeric,
|
||||||
|
)),
|
||||||
|
|
||||||
string: $ => /("[^"]*?")|('[^']*?')|(`[^`]*?`)/,
|
string: $ => /("[^"]*?")|('[^']*?')|(`[^`]*?`)/,
|
||||||
|
|
||||||
@ -71,6 +83,24 @@ module.exports = grammar({
|
|||||||
']',
|
']',
|
||||||
),
|
),
|
||||||
|
|
||||||
|
map: $ => seq(
|
||||||
|
'{',
|
||||||
|
repeat(seq($.identifier, "=", $.expression)),
|
||||||
|
'}',
|
||||||
|
),
|
||||||
|
|
||||||
|
index: $ => prec.left(seq(
|
||||||
|
$.expression,
|
||||||
|
'.',
|
||||||
|
'{',
|
||||||
|
$.expression,
|
||||||
|
optional(seq(
|
||||||
|
'..',
|
||||||
|
$.expression,
|
||||||
|
)),
|
||||||
|
'}'
|
||||||
|
)),
|
||||||
|
|
||||||
function: $ => seq(
|
function: $ => seq(
|
||||||
'function',
|
'function',
|
||||||
optional(seq('<', repeat(seq($.identifier, optional(','))), '>')),
|
optional(seq('<', repeat(seq($.identifier, optional(','))), '>')),
|
||||||
@ -79,27 +109,13 @@ module.exports = grammar({
|
|||||||
'}',
|
'}',
|
||||||
),
|
),
|
||||||
|
|
||||||
table: $ => prec(2, seq(
|
table: $ => prec.right(seq(
|
||||||
'table',
|
'table',
|
||||||
seq('<', repeat1(seq($.identifier, optional(','))), '>'),
|
seq('<', repeat1(seq($.identifier, optional(','))), '>'),
|
||||||
$.expression,
|
$.expression,
|
||||||
)),
|
)),
|
||||||
|
|
||||||
map: $ => seq(
|
math: $ => prec.left(1, seq(
|
||||||
'{',
|
|
||||||
repeat(seq($.identifier, "=", $.expression)),
|
|
||||||
'}',
|
|
||||||
),
|
|
||||||
|
|
||||||
sublist: $ => prec.right(seq(
|
|
||||||
$.expression,
|
|
||||||
'.',
|
|
||||||
$.expression,
|
|
||||||
'..',
|
|
||||||
$.expression,
|
|
||||||
)),
|
|
||||||
|
|
||||||
math: $ => prec.left(seq(
|
|
||||||
$.expression,
|
$.expression,
|
||||||
$.math_operator,
|
$.math_operator,
|
||||||
$.expression,
|
$.expression,
|
||||||
@ -113,7 +129,7 @@ module.exports = grammar({
|
|||||||
'%',
|
'%',
|
||||||
),
|
),
|
||||||
|
|
||||||
logic: $ => prec.right(seq(
|
logic: $ => prec.right(1, seq(
|
||||||
$.expression,
|
$.expression,
|
||||||
$.logic_operator,
|
$.logic_operator,
|
||||||
$.expression,
|
$.expression,
|
||||||
@ -171,7 +187,7 @@ module.exports = grammar({
|
|||||||
'}',
|
'}',
|
||||||
),
|
),
|
||||||
|
|
||||||
function_call: $ => prec.right(seq(
|
function_call: $ => prec(1, seq(
|
||||||
'(',
|
'(',
|
||||||
$.identifier,
|
$.identifier,
|
||||||
repeat(seq($.expression, optional(','))),
|
repeat(seq($.expression, optional(','))),
|
||||||
|
@ -21,6 +21,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"statement": {
|
"statement": {
|
||||||
|
"type": "PREC_LEFT",
|
||||||
|
"value": 0,
|
||||||
|
"content": {
|
||||||
"type": "CHOICE",
|
"type": "CHOICE",
|
||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
@ -76,6 +79,7 @@
|
|||||||
"name": "remove"
|
"name": "remove"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"comment": {
|
"comment": {
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
@ -113,9 +117,6 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"_expression_kind": {
|
"_expression_kind": {
|
||||||
"type": "PREC_RIGHT",
|
|
||||||
"value": 0,
|
|
||||||
"content": {
|
|
||||||
"type": "CHOICE",
|
"type": "CHOICE",
|
||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
@ -128,11 +129,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "function_call"
|
"name": "index"
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "SYMBOL",
|
|
||||||
"name": "tool"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
@ -144,14 +141,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "sublist"
|
"name": "function_call"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "tool"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"identifier": {
|
"identifier": {
|
||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[a-zA-Z|_]+[._a-zA-Z0-9]*"
|
"value": "[_a-zA-Z]+[_a-zA-Z0-9]?"
|
||||||
},
|
},
|
||||||
"value": {
|
"value": {
|
||||||
"type": "CHOICE",
|
"type": "CHOICE",
|
||||||
@ -190,13 +190,123 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"_numeric": {
|
||||||
|
"type": "TOKEN",
|
||||||
|
"content": {
|
||||||
|
"type": "REPEAT1",
|
||||||
|
"content": {
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "0"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"integer": {
|
"integer": {
|
||||||
"type": "PATTERN",
|
"type": "PREC_LEFT",
|
||||||
"value": "[-]?[0-9]+"
|
"value": 0,
|
||||||
|
"content": {
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "IMMEDIATE_TOKEN",
|
||||||
|
"content": {
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "-"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_numeric"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"float": {
|
"float": {
|
||||||
"type": "PATTERN",
|
"type": "PREC_LEFT",
|
||||||
"value": "[-]?[0-9]+[.]{1}[0-9]+"
|
"value": 0,
|
||||||
|
"content": {
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "IMMEDIATE_TOKEN",
|
||||||
|
"content": {
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "-"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_numeric"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "IMMEDIATE_TOKEN",
|
||||||
|
"content": {
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_numeric"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"string": {
|
"string": {
|
||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
@ -252,6 +362,89 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"map": {
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "{"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "REPEAT",
|
||||||
|
"content": {
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "identifier"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "expression"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"index": {
|
||||||
|
"type": "PREC_LEFT",
|
||||||
|
"value": 0,
|
||||||
|
"content": {
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "expression"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "{"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "expression"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": ".."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "expression"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"function": {
|
"function": {
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
"members": [
|
"members": [
|
||||||
@ -319,8 +512,8 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"table": {
|
"table": {
|
||||||
"type": "PREC",
|
"type": "PREC_RIGHT",
|
||||||
"value": 2,
|
"value": 0,
|
||||||
"content": {
|
"content": {
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
"members": [
|
"members": [
|
||||||
@ -372,71 +565,9 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"map": {
|
|
||||||
"type": "SEQ",
|
|
||||||
"members": [
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "{"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "REPEAT",
|
|
||||||
"content": {
|
|
||||||
"type": "SEQ",
|
|
||||||
"members": [
|
|
||||||
{
|
|
||||||
"type": "SYMBOL",
|
|
||||||
"name": "identifier"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "="
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "SYMBOL",
|
|
||||||
"name": "expression"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "}"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"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": 1,
|
||||||
"content": {
|
"content": {
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
"members": [
|
"members": [
|
||||||
@ -482,7 +613,7 @@
|
|||||||
},
|
},
|
||||||
"logic": {
|
"logic": {
|
||||||
"type": "PREC_RIGHT",
|
"type": "PREC_RIGHT",
|
||||||
"value": 0,
|
"value": 1,
|
||||||
"content": {
|
"content": {
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
"members": [
|
"members": [
|
||||||
@ -690,8 +821,8 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"function_call": {
|
"function_call": {
|
||||||
"type": "PREC_RIGHT",
|
"type": "PREC",
|
||||||
"value": 0,
|
"value": 1,
|
||||||
"content": {
|
"content": {
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
"members": [
|
"members": [
|
||||||
|
@ -102,6 +102,10 @@
|
|||||||
"type": "identifier",
|
"type": "identifier",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "index",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "logic",
|
"type": "logic",
|
||||||
"named": true
|
"named": true
|
||||||
@ -110,10 +114,6 @@
|
|||||||
"type": "math",
|
"type": "math",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "sublist",
|
|
||||||
"named": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "tool",
|
"type": "tool",
|
||||||
"named": true
|
"named": true
|
||||||
@ -171,6 +171,11 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "float",
|
||||||
|
"named": true,
|
||||||
|
"fields": {}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "for",
|
"type": "for",
|
||||||
"named": true,
|
"named": true,
|
||||||
@ -274,6 +279,21 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "index",
|
||||||
|
"named": true,
|
||||||
|
"fields": {},
|
||||||
|
"children": {
|
||||||
|
"multiple": true,
|
||||||
|
"required": true,
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"type": "expression",
|
||||||
|
"named": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "insert",
|
"type": "insert",
|
||||||
"named": true,
|
"named": true,
|
||||||
@ -293,6 +313,11 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"named": true,
|
||||||
|
"fields": {}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "item",
|
"type": "item",
|
||||||
"named": true,
|
"named": true,
|
||||||
@ -514,21 +539,6 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "sublist",
|
|
||||||
"named": true,
|
|
||||||
"fields": {},
|
|
||||||
"children": {
|
|
||||||
"multiple": true,
|
|
||||||
"required": true,
|
|
||||||
"types": [
|
|
||||||
{
|
|
||||||
"type": "expression",
|
|
||||||
"named": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "table",
|
"type": "table",
|
||||||
"named": true,
|
"named": true,
|
||||||
@ -792,10 +802,6 @@
|
|||||||
"type": "fish",
|
"type": "fish",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "float",
|
|
||||||
"named": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "for",
|
"type": "for",
|
||||||
"named": false
|
"named": false
|
||||||
@ -832,10 +838,6 @@
|
|||||||
"type": "insert",
|
"type": "insert",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"named": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "into",
|
"type": "into",
|
||||||
"named": false
|
"named": false
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user