1
0

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)
{
(output 'It was '
+ suspects.0
+ suspects.{0}
+ ' in the '
+ rooms.0
+ rooms.{0}
+ ' with the '
+ weapons.0
+ weapons.{0}
+ '!')
} else {
(output 'I accuse '

View File

@ -1,9 +1,60 @@
foo = "bar"
func = function <> { "foo" }
# Function
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"))
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> {
let key = self.identifier.inner().clone();
let value = self.statement.run(source, context)?;
let mut context = context.variables_mut();
let new_value = match self.operator {
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
} else {
@ -63,7 +64,7 @@ impl AbstractTree for Assignment {
}
}
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
} else {
@ -73,7 +74,7 @@ impl AbstractTree for Assignment {
AssignmentOperator::Equal => value,
};
context.set_value(key, new_value)?;
context.insert(key, new_value);
Ok(Value::Empty)
}

View File

@ -2,7 +2,8 @@ use serde::{Deserialize, Serialize};
use tree_sitter::Node;
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};
@ -12,6 +13,7 @@ pub enum Expression {
Value(ValueNode),
Identifier(Identifier),
Sublist(Box<Sublist>),
Index(Box<Index>),
Math(Box<Math>),
Logic(Box<Logic>),
FunctionCall(FunctionCall),
@ -32,6 +34,7 @@ impl AbstractTree for Expression {
"sublist" => {
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)?)),
"logic" => Expression::Logic(Box::new(Logic::from_syntax_node(source, child)?)),
"function_call" => {
@ -47,7 +50,7 @@ impl AbstractTree for Expression {
let child = node.child(0).unwrap();
Err(Error::UnexpectedSyntaxNode {
expected: "value, identifier, sublist, math or function_call",
expected: "value, identifier, sublist, index, math or function_call",
actual: child.kind(),
location: child.start_position(),
relevant_source: source[child.byte_range()].to_string(),
@ -63,6 +66,7 @@ impl AbstractTree for Expression {
Expression::Logic(logic) => logic.run(source, context),
Expression::FunctionCall(function_call) => function_call.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| {
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()?;

View File

@ -35,7 +35,7 @@ impl AbstractTree for Find {
let mut context = context.clone();
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()?;

View File

@ -52,26 +52,20 @@ impl AbstractTree for For {
if self.is_async {
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| ())
})?;
} else {
let original_value = context.get_value(key)?;
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)?;
}
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)

View File

@ -35,7 +35,7 @@ impl AbstractTree for FunctionCall {
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
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()?
} else {
return Err(Error::FunctionIdentifierNotFound(self.name.clone()));
@ -47,7 +47,7 @@ impl AbstractTree for FunctionCall {
let key = identifier.inner().clone();
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)

View File

@ -30,12 +30,10 @@ impl AbstractTree for Identifier {
}
fn run(&self, _source: &str, context: &mut Map) -> Result<Value> {
let value = if let Some(value) = context.get_value(&self.0)? {
value
if let Some(value) = context.variables().get(&self.0) {
Ok(value.clone())
} else {
return Err(Error::VariableIdentifierNotFound(self.inner().clone()));
};
Ok(value)
Err(Error::VariableIdentifierNotFound(self.inner().clone()))
}
}
}

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())?;
}
context.set_value(table_name, Value::Table(table))?;
context
.variables_mut()
.insert(table_name, Value::Table(table));
Ok(Value::Empty)
}

View File

@ -15,6 +15,7 @@ pub mod r#for;
pub mod function_call;
pub mod identifier;
pub mod if_else;
pub mod index;
pub mod insert;
pub mod item;
pub mod logic;
@ -31,8 +32,8 @@ pub mod r#while;
pub use {
assignment::*, expression::*, filter::*, find::*, function_call::*, identifier::*, if_else::*,
insert::*, item::*, logic::*, math::*, r#async::*, r#for::*, r#match::*, r#while::*, remove::*,
select::*, statement::*, sublist::*, tool::*, transform::*, value_node::*,
index::*, insert::*, item::*, logic::*, math::*, r#async::*, r#for::*, r#match::*, r#while::*,
remove::*, select::*, statement::*, sublist::*, tool::*, transform::*, value_node::*,
};
use tree_sitter::Node;

View File

@ -36,7 +36,9 @@ impl AbstractTree for Remove {
let mut should_remove_index = None;
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()?;
@ -45,8 +47,9 @@ impl AbstractTree for Remove {
match &self.expression {
Expression::Identifier(identifier) => {
context
.set_value(identifier.inner().clone(), Value::List(values.clone()))?;
sub_context
.variables_mut()
.insert(identifier.inner().clone(), Value::List(values.clone()));
}
_ => {}
}

View File

@ -65,7 +65,6 @@ impl AbstractTree for Select {
} else {
old_table.headers().clone()
};
let mut new_table = Table::new(column_names.to_vec());
for row in old_table.rows() {
@ -75,7 +74,9 @@ impl AbstractTree for Select {
for (i, value) in row.iter().enumerate() {
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 =
new_table

View File

@ -12,6 +12,7 @@ use crate::{
/// Expression, it will always return a non-empty value when run.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum Statement {
Comment(String),
Assignment(Box<Assignment>),
Expression(Expression),
IfElse(Box<IfElse>),
@ -34,6 +35,12 @@ impl AbstractTree for Statement {
let child = node.child(0).unwrap();
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::from_syntax_node(source, child)?,
))),
@ -74,7 +81,7 @@ impl AbstractTree for Statement {
source, child,
)?))),
_ => 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(),
location: child.start_position(),
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> {
match self {
Statement::Comment(comment) => Ok(Value::String(comment.clone())),
Statement::Assignment(assignment) => assignment.run(source, context),
Statement::Expression(expression) => expression.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 modified = metadata.modified()?.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))?;
metadata_output.set_value("created".to_string(), Value::Integer(created))?;
metadata_output.set_value("modified".to_string(), Value::Integer(modified))?;
metadata_output.set_value("accessed".to_string(), Value::Integer(accessed))?;
{
let mut metadata_variables = metadata_output.variables_mut();
metadata_variables.insert("type".to_string(), Value::String(file_type));
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))
}

View File

@ -38,7 +38,9 @@ impl AbstractTree for Transform {
.map(|value| {
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);

View File

@ -161,15 +161,15 @@ impl AbstractTree for ValueNode {
}
ValueType::Empty => Value::Empty,
ValueType::Map(nodes) => {
let mut values = Map::new();
let map = Map::new();
for (key, node) in nodes {
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 {
column_names,

View File

@ -147,11 +147,12 @@ mod tests {
#[test]
fn evaluate_map() {
let mut map = Map::new();
let map = Map::new();
map.set_value("x".to_string(), Value::Integer(1)).unwrap();
map.set_value("foo".to_string(), Value::String("bar".to_string()))
.unwrap();
map.variables_mut()
.insert("x".to_string(), Value::Integer(1));
map.variables_mut()
.insert("foo".to_string(), Value::String("bar".to_string()));
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 {
context
.set_value("input".to_string(), Value::String(input))
.variables_mut()
.insert("input".to_string(), Value::String(input))
.unwrap();
}
@ -52,7 +53,8 @@ fn main() {
let file_contents = read_to_string(path).unwrap();
context
.set_value("input".to_string(), Value::String(file_contents))
.variables_mut()
.insert("input".to_string(), Value::String(file_contents))
.unwrap();
}

View File

@ -3,10 +3,10 @@ use std::{
cmp::Ordering,
collections::BTreeMap,
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.
///
@ -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 get_value(&self, identifier: &str) -> Result<Option<Value>> {
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)
}
pub fn variables(&self) -> RwLockReadGuard<BTreeMap<String, Value>> {
self.variables.read().unwrap()
}
/// Assigns a variable with a Value and the identifier as its key, allowing dot notation to
/// assign nested lists and maps. Returns an error if a List or Map is indexed incorrectly.
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(())
}
pub fn variables_mut(&self) -> RwLockWriteGuard<BTreeMap<String, Value>> {
self.variables.write().unwrap()
}
/// Removes an assigned variable.
@ -204,10 +118,11 @@ impl Display for Map {
impl From<&Table> for Map {
fn from(value: &Table) -> Self {
let mut map = Map::new();
let map = Map::new();
for (row_index, row) in value.rows().iter().enumerate() {
map.set_value(
map.variables_mut()
.insert(
row_index.to_string(),
Value::List(List::with_items(row.clone())),
)
@ -226,36 +141,3 @@ impl Serialize for Map {
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))),
Boolean(boolean) => Ok(Value::Boolean(boolean)),
Object(object) => {
let mut map = Map::new();
let map = Map::new();
for (key, node_value) in object.iter() {
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))
@ -546,12 +546,12 @@ impl TryFrom<&JsonValue> for Value {
Number(number) => Ok(Value::Float(f64::from(*number))),
Boolean(boolean) => Ok(Value::Boolean(*boolean)),
Object(object) => {
let mut map = Map::new();
let map = Map::new();
for (key, node_value) in object.iter() {
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))
@ -839,11 +839,10 @@ impl<'de> Visitor<'de> for ValueVisitor {
where
M: MapAccess<'de>,
{
let mut map = Map::new();
let map = Map::new();
while let Some((key, value)) = access.next_entry()? {
map.set_value(key, value)
.expect("Failed to deserialize Value. This is a no-op.");
map.variables_mut().insert(key, value);
}
Ok(Value::Map(map))

View File

@ -19,6 +19,57 @@ if true { "True" }
(value
(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
==================

View File

@ -26,9 +26,11 @@ __xyz__
Dot Notation
==================
dust_data.0.name
# Separator
creature.total_clams
dust_data.{1}.{name}
creature.{total_clams}
foobar.{1}.{42}
---
@ -36,11 +38,35 @@ creature.total_clams
(item
(statement
(expression
(identifier))))
(item
(statement
(comment)))
(index
(expression
(index
(expression
(identifier))
(expression
(value
(integer)))))
(expression
(identifier))))))
(item
(statement
(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)))))))))))))))
==================
Sublist
List Index
==================
['answers', 42, 666].1..2
['answers', 42, 666].{1}
---
@ -93,7 +93,36 @@ Sublist
(item
(statement
(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
(value
(list

View File

@ -48,7 +48,7 @@ x = {
Map Access
==================
x.answer
x.{answer}
---
@ -56,4 +56,8 @@ x.answer
(item
(statement
(expression
(identifier)))))
(index
(expression
(identifier))
(expression
(identifier)))))))

View File

@ -36,6 +36,7 @@ Equality
==================
4 + 2 == 42 && true
(((4 + 2) == 42) && true)
---
@ -62,13 +63,36 @@ Equality
(logic_operator)
(expression
(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
---
@ -95,4 +119,27 @@ Equality
(logic_operator)
(expression
(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)),
statement: $ => choice(
statement: $ => prec.left(choice(
$.comment,
$.assignment,
$.expression,
@ -22,7 +22,7 @@ module.exports = grammar({
$.filter,
$.find,
$.remove,
),
)),
comment: $ => seq(/[#]+.*/),
@ -31,17 +31,17 @@ module.exports = grammar({
seq('(', $._expression_kind, ')'),
),
_expression_kind: $ => prec.right(choice(
_expression_kind: $ => choice(
$.value,
$.identifier,
$.function_call,
$.tool,
$.index,
$.math,
$.logic,
$.sublist,
)),
$.function_call,
$.tool,
),
identifier: $ => /[a-zA-Z|_]+[._a-zA-Z0-9]*/,
identifier: $ => /[_a-zA-Z]+[_a-zA-Z0-9]?/,
value: $ => choice(
$.integer,
@ -54,9 +54,21 @@ module.exports = grammar({
$.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: $ => /("[^"]*?")|('[^']*?')|(`[^`]*?`)/,
@ -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',
optional(seq('<', repeat(seq($.identifier, optional(','))), '>')),
@ -79,27 +109,13 @@ module.exports = grammar({
'}',
),
table: $ => prec(2, seq(
table: $ => prec.right(seq(
'table',
seq('<', repeat1(seq($.identifier, optional(','))), '>'),
$.expression,
)),
map: $ => seq(
'{',
repeat(seq($.identifier, "=", $.expression)),
'}',
),
sublist: $ => prec.right(seq(
$.expression,
'.',
$.expression,
'..',
$.expression,
)),
math: $ => prec.left(seq(
math: $ => prec.left(1, seq(
$.expression,
$.math_operator,
$.expression,
@ -113,7 +129,7 @@ module.exports = grammar({
'%',
),
logic: $ => prec.right(seq(
logic: $ => prec.right(1, seq(
$.expression,
$.logic_operator,
$.expression,
@ -171,7 +187,7 @@ module.exports = grammar({
'}',
),
function_call: $ => prec.right(seq(
function_call: $ => prec(1, seq(
'(',
$.identifier,
repeat(seq($.expression, optional(','))),

View File

@ -21,6 +21,9 @@
}
},
"statement": {
"type": "PREC_LEFT",
"value": 0,
"content": {
"type": "CHOICE",
"members": [
{
@ -76,6 +79,7 @@
"name": "remove"
}
]
}
},
"comment": {
"type": "SEQ",
@ -113,9 +117,6 @@
]
},
"_expression_kind": {
"type": "PREC_RIGHT",
"value": 0,
"content": {
"type": "CHOICE",
"members": [
{
@ -128,11 +129,7 @@
},
{
"type": "SYMBOL",
"name": "function_call"
},
{
"type": "SYMBOL",
"name": "tool"
"name": "index"
},
{
"type": "SYMBOL",
@ -144,14 +141,17 @@
},
{
"type": "SYMBOL",
"name": "sublist"
"name": "function_call"
},
{
"type": "SYMBOL",
"name": "tool"
}
]
}
},
"identifier": {
"type": "PATTERN",
"value": "[a-zA-Z|_]+[._a-zA-Z0-9]*"
"value": "[_a-zA-Z]+[_a-zA-Z0-9]?"
},
"value": {
"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": {
"type": "PATTERN",
"value": "[-]?[0-9]+"
"type": "PREC_LEFT",
"value": 0,
"content": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "IMMEDIATE_TOKEN",
"content": {
"type": "STRING",
"value": "-"
}
},
{
"type": "BLANK"
}
]
},
{
"type": "SYMBOL",
"name": "_numeric"
}
]
}
},
"float": {
"type": "PATTERN",
"value": "[-]?[0-9]+[.]{1}[0-9]+"
"type": "PREC_LEFT",
"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": {
"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": {
"type": "SEQ",
"members": [
@ -319,8 +512,8 @@
]
},
"table": {
"type": "PREC",
"value": 2,
"type": "PREC_RIGHT",
"value": 0,
"content": {
"type": "SEQ",
"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": {
"type": "PREC_LEFT",
"value": 0,
"value": 1,
"content": {
"type": "SEQ",
"members": [
@ -482,7 +613,7 @@
},
"logic": {
"type": "PREC_RIGHT",
"value": 0,
"value": 1,
"content": {
"type": "SEQ",
"members": [
@ -690,8 +821,8 @@
]
},
"function_call": {
"type": "PREC_RIGHT",
"value": 0,
"type": "PREC",
"value": 1,
"content": {
"type": "SEQ",
"members": [

View File

@ -102,6 +102,10 @@
"type": "identifier",
"named": true
},
{
"type": "index",
"named": true
},
{
"type": "logic",
"named": true
@ -110,10 +114,6 @@
"type": "math",
"named": true
},
{
"type": "sublist",
"named": true
},
{
"type": "tool",
"named": true
@ -171,6 +171,11 @@
]
}
},
{
"type": "float",
"named": true,
"fields": {}
},
{
"type": "for",
"named": true,
@ -274,6 +279,21 @@
]
}
},
{
"type": "index",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
{
"type": "insert",
"named": true,
@ -293,6 +313,11 @@
]
}
},
{
"type": "integer",
"named": true,
"fields": {}
},
{
"type": "item",
"named": true,
@ -514,21 +539,6 @@
]
}
},
{
"type": "sublist",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
{
"type": "table",
"named": true,
@ -792,10 +802,6 @@
"type": "fish",
"named": false
},
{
"type": "float",
"named": true
},
{
"type": "for",
"named": false
@ -832,10 +838,6 @@
"type": "insert",
"named": false
},
{
"type": "integer",
"named": true
},
{
"type": "into",
"named": false

File diff suppressed because it is too large Load Diff