Prepare for new version

This commit is contained in:
Jeff 2023-10-29 19:31:06 -04:00
parent c2a5f5e972
commit f33eef9c5a
32 changed files with 10261 additions and 10228 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

@ -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()));
} }
_ => {} _ => {}
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,14 +118,15 @@ 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()
row_index.to_string(), .insert(
Value::List(List::with_items(row.clone())), row_index.to_string(),
) Value::List(List::with_items(row.clone())),
.unwrap(); )
.unwrap();
} }
map map
@ -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()
);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,61 +21,65 @@
} }
}, },
"statement": { "statement": {
"type": "CHOICE", "type": "PREC_LEFT",
"members": [ "value": 0,
{ "content": {
"type": "SYMBOL", "type": "CHOICE",
"name": "comment" "members": [
}, {
{ "type": "SYMBOL",
"type": "SYMBOL", "name": "comment"
"name": "assignment" },
}, {
{ "type": "SYMBOL",
"type": "SYMBOL", "name": "assignment"
"name": "expression" },
}, {
{ "type": "SYMBOL",
"type": "SYMBOL", "name": "expression"
"name": "if_else" },
}, {
{ "type": "SYMBOL",
"type": "SYMBOL", "name": "if_else"
"name": "insert" },
}, {
{ "type": "SYMBOL",
"type": "SYMBOL", "name": "insert"
"name": "select" },
}, {
{ "type": "SYMBOL",
"type": "SYMBOL", "name": "select"
"name": "while" },
}, {
{ "type": "SYMBOL",
"type": "SYMBOL", "name": "while"
"name": "async" },
}, {
{ "type": "SYMBOL",
"type": "SYMBOL", "name": "async"
"name": "for" },
}, {
{ "type": "SYMBOL",
"type": "SYMBOL", "name": "for"
"name": "transform" },
}, {
{ "type": "SYMBOL",
"type": "SYMBOL", "name": "transform"
"name": "filter" },
}, {
{ "type": "SYMBOL",
"type": "SYMBOL", "name": "filter"
"name": "find" },
}, {
{ "type": "SYMBOL",
"type": "SYMBOL", "name": "find"
"name": "remove" },
} {
] "type": "SYMBOL",
"name": "remove"
}
]
}
}, },
"comment": { "comment": {
"type": "SEQ", "type": "SEQ",
@ -113,45 +117,41 @@
] ]
}, },
"_expression_kind": { "_expression_kind": {
"type": "PREC_RIGHT", "type": "CHOICE",
"value": 0, "members": [
"content": { {
"type": "CHOICE", "type": "SYMBOL",
"members": [ "name": "value"
{ },
"type": "SYMBOL", {
"name": "value" "type": "SYMBOL",
}, "name": "identifier"
{ },
"type": "SYMBOL", {
"name": "identifier" "type": "SYMBOL",
}, "name": "index"
{ },
"type": "SYMBOL", {
"name": "function_call" "type": "SYMBOL",
}, "name": "math"
{ },
"type": "SYMBOL", {
"name": "tool" "type": "SYMBOL",
}, "name": "logic"
{ },
"type": "SYMBOL", {
"name": "math" "type": "SYMBOL",
}, "name": "function_call"
{ },
"type": "SYMBOL", {
"name": "logic" "type": "SYMBOL",
}, "name": "tool"
{ }
"type": "SYMBOL", ]
"name": "sublist"
}
]
}
}, },
"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": [

View File

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