Begin changes for new type definitions
This commit is contained in:
parent
5ffb797b5f
commit
bc2615a1ed
407
grammar.js
Normal file
407
grammar.js
Normal file
@ -0,0 +1,407 @@
|
||||
module.exports = grammar({
|
||||
name: "dust",
|
||||
|
||||
word: $ => $.identifier,
|
||||
|
||||
extras: $ => [/\s/, $._comment],
|
||||
|
||||
rules: {
|
||||
root: $ =>
|
||||
prec(1, repeat1($.statement)),
|
||||
|
||||
_comment: $ => /[#][^#\n]*[#|\n]/,
|
||||
|
||||
block: $ =>
|
||||
seq(
|
||||
optional("async"),
|
||||
"{",
|
||||
repeat1($.statement),
|
||||
"}",
|
||||
),
|
||||
|
||||
statement: $ =>
|
||||
prec.left(
|
||||
seq(
|
||||
choice(
|
||||
$.assignment,
|
||||
$.block,
|
||||
$.expression,
|
||||
$.for,
|
||||
$.if_else,
|
||||
$.index_assignment,
|
||||
$.match,
|
||||
$.return,
|
||||
$.use,
|
||||
$.while,
|
||||
),
|
||||
optional(";"),
|
||||
),
|
||||
),
|
||||
|
||||
expression: $ =>
|
||||
prec.right(
|
||||
choice(
|
||||
$._expression_kind,
|
||||
seq(
|
||||
"(",
|
||||
$._expression_kind,
|
||||
")",
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
_expression_kind: $ =>
|
||||
prec.right(
|
||||
choice(
|
||||
$.function_call,
|
||||
$.identifier,
|
||||
$.index,
|
||||
$.logic,
|
||||
$.math,
|
||||
$.value,
|
||||
$.yield,
|
||||
),
|
||||
),
|
||||
|
||||
_expression_list: $ =>
|
||||
repeat1(
|
||||
prec.right(
|
||||
seq(
|
||||
$.expression,
|
||||
optional(","),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
identifier: $ =>
|
||||
/[_a-zA-Z]+[_a-zA-Z0-9]?/,
|
||||
|
||||
value: $ =>
|
||||
choice(
|
||||
$.integer,
|
||||
$.float,
|
||||
$.string,
|
||||
$.boolean,
|
||||
$.list,
|
||||
$.function,
|
||||
$.table,
|
||||
$.map,
|
||||
),
|
||||
|
||||
integer: $ =>
|
||||
token(
|
||||
prec.left(
|
||||
seq(
|
||||
optional("-"),
|
||||
repeat1(
|
||||
choice(
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"0",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
float: $ =>
|
||||
token(
|
||||
prec.left(
|
||||
seq(
|
||||
optional("-"),
|
||||
repeat1(
|
||||
choice(
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"0",
|
||||
),
|
||||
),
|
||||
".",
|
||||
repeat1(
|
||||
choice(
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"0",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
string: $ =>
|
||||
/("[^"]*?")|('[^']*?')|(`[^`]*?`)/,
|
||||
|
||||
boolean: $ =>
|
||||
choice("true", "false"),
|
||||
|
||||
list: $ =>
|
||||
seq(
|
||||
"[",
|
||||
repeat(
|
||||
prec.left(
|
||||
seq(
|
||||
$.expression,
|
||||
optional(","),
|
||||
),
|
||||
),
|
||||
),
|
||||
"]",
|
||||
),
|
||||
|
||||
map: $ =>
|
||||
seq(
|
||||
"{",
|
||||
repeat(
|
||||
seq(
|
||||
$.identifier,
|
||||
"=",
|
||||
$.statement,
|
||||
optional(","),
|
||||
),
|
||||
),
|
||||
"}",
|
||||
),
|
||||
|
||||
index: $ =>
|
||||
prec.left(
|
||||
1,
|
||||
seq(
|
||||
$.expression,
|
||||
":",
|
||||
$.expression,
|
||||
optional(
|
||||
seq("..", $.expression),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
math: $ =>
|
||||
prec.left(
|
||||
seq(
|
||||
$.expression,
|
||||
$.math_operator,
|
||||
$.expression,
|
||||
),
|
||||
),
|
||||
|
||||
math_operator: $ =>
|
||||
choice("+", "-", "*", "/", "%"),
|
||||
|
||||
logic: $ =>
|
||||
prec.right(
|
||||
seq(
|
||||
$.expression,
|
||||
$.logic_operator,
|
||||
$.expression,
|
||||
),
|
||||
),
|
||||
|
||||
logic_operator: $ =>
|
||||
choice(
|
||||
"==",
|
||||
"!=",
|
||||
"&&",
|
||||
"||",
|
||||
">",
|
||||
"<",
|
||||
">=",
|
||||
"<=",
|
||||
),
|
||||
|
||||
assignment: $ =>
|
||||
seq(
|
||||
field(
|
||||
"identifier",
|
||||
$.identifier,
|
||||
),
|
||||
optional(
|
||||
field(
|
||||
"type",
|
||||
$.type_definition,
|
||||
),
|
||||
),
|
||||
field(
|
||||
"assignment_operator",
|
||||
$.assignment_operator,
|
||||
),
|
||||
field("statement", $.statement),
|
||||
),
|
||||
|
||||
index_assignment: $ =>
|
||||
seq(
|
||||
$.index,
|
||||
$.assignment_operator,
|
||||
$.statement,
|
||||
),
|
||||
|
||||
assignment_operator: $ =>
|
||||
prec.right(
|
||||
choice("=", "+=", "-="),
|
||||
),
|
||||
|
||||
if_else: $ =>
|
||||
prec.right(
|
||||
seq(
|
||||
$.if,
|
||||
repeat($.else_if),
|
||||
optional($.else),
|
||||
),
|
||||
),
|
||||
|
||||
if: $ =>
|
||||
seq("if", $.expression, $.block),
|
||||
|
||||
else_if: $ =>
|
||||
seq(
|
||||
"else if",
|
||||
$.expression,
|
||||
$.block,
|
||||
),
|
||||
|
||||
else: $ => seq("else", $.block),
|
||||
|
||||
match: $ =>
|
||||
prec.right(
|
||||
seq(
|
||||
"match",
|
||||
$.expression,
|
||||
repeat1(
|
||||
seq(
|
||||
$.expression,
|
||||
"=>",
|
||||
$.block,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
while: $ =>
|
||||
seq(
|
||||
"while",
|
||||
$.expression,
|
||||
$.block,
|
||||
),
|
||||
|
||||
for: $ =>
|
||||
seq(
|
||||
choice("for", "async for"),
|
||||
$.identifier,
|
||||
"in",
|
||||
$.expression,
|
||||
$.block,
|
||||
),
|
||||
|
||||
identifier_list: $ =>
|
||||
prec.right(
|
||||
choice(
|
||||
seq(
|
||||
"|",
|
||||
repeat(
|
||||
seq(
|
||||
$.identifier,
|
||||
optional(","),
|
||||
),
|
||||
),
|
||||
"|",
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
table: $ =>
|
||||
prec.right(
|
||||
seq(
|
||||
"table",
|
||||
$.identifier_list,
|
||||
$.expression,
|
||||
),
|
||||
),
|
||||
|
||||
return: $ =>
|
||||
seq("return", $.expression),
|
||||
|
||||
use: $ => seq("use", $.string),
|
||||
|
||||
type_definition: $ =>
|
||||
seq("<", $.type, ">"),
|
||||
|
||||
type: $ =>
|
||||
prec.right(
|
||||
choice(
|
||||
"any",
|
||||
"bool",
|
||||
seq(
|
||||
"fn",
|
||||
repeat(
|
||||
seq(
|
||||
$.type,
|
||||
optional(","),
|
||||
),
|
||||
),
|
||||
optional(seq("->", $.type)),
|
||||
),
|
||||
"int",
|
||||
seq("list", $.type),
|
||||
"map",
|
||||
"num",
|
||||
"str",
|
||||
),
|
||||
),
|
||||
|
||||
function: $ =>
|
||||
seq(
|
||||
"|",
|
||||
repeat(
|
||||
seq(
|
||||
$.identifier,
|
||||
optional(","),
|
||||
),
|
||||
),
|
||||
"|",
|
||||
$.block,
|
||||
),
|
||||
|
||||
function_call: $ =>
|
||||
prec.right(
|
||||
1,
|
||||
seq(
|
||||
"(",
|
||||
$.expression,
|
||||
optional($._expression_list),
|
||||
")",
|
||||
),
|
||||
),
|
||||
|
||||
yield: $ =>
|
||||
prec.left(
|
||||
seq(
|
||||
$.expression,
|
||||
"->",
|
||||
"(",
|
||||
$.expression,
|
||||
optional($._expression_list),
|
||||
")",
|
||||
),
|
||||
),
|
||||
},
|
||||
});
|
@ -1,12 +1,12 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Identifier, Map, Result, Statement, Type, Value};
|
||||
use crate::{AbstractTree, Error, Identifier, Map, Result, Statement, TypeDefinition, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Assignment {
|
||||
identifier: Identifier,
|
||||
r#type: Option<Type>,
|
||||
r#type: Option<TypeDefinition>,
|
||||
operator: AssignmentOperator,
|
||||
statement: Statement,
|
||||
}
|
||||
@ -27,7 +27,7 @@ impl AbstractTree for Assignment {
|
||||
|
||||
let type_node = node.child_by_field_name("type");
|
||||
let r#type = if let Some(type_node) = type_node {
|
||||
Some(Type::from_syntax_node(source, type_node)?)
|
||||
Some(TypeDefinition::from_syntax_node(source, type_node)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -62,7 +62,7 @@ impl AbstractTree for Assignment {
|
||||
})
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
let key = self.identifier.inner();
|
||||
let value = self.statement.run(source, context)?;
|
||||
|
||||
@ -86,12 +86,12 @@ impl AbstractTree for Assignment {
|
||||
AssignmentOperator::Equal => value,
|
||||
};
|
||||
|
||||
if let Some(r#type) = &self.r#type {
|
||||
r#type.check(&new_value)?;
|
||||
}
|
||||
|
||||
context.variables_mut()?.insert(key.clone(), new_value);
|
||||
|
||||
Ok(Value::Empty)
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
||||
Ok(TypeDefinition::Empty)
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Map, Result, Statement, Value};
|
||||
use crate::{AbstractTree, Error, Map, Result, Statement, TypeDefinition, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Block {
|
||||
@ -41,7 +41,7 @@ impl AbstractTree for Block {
|
||||
})
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
if self.is_async {
|
||||
let statements = &self.statements;
|
||||
let final_result = RwLock::new(Ok(Value::Empty));
|
||||
@ -81,4 +81,8 @@ impl AbstractTree for Block {
|
||||
prev_result.unwrap_or(Ok(Value::Empty))
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||
self.statements.last().unwrap().expected_type(context)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{
|
||||
value_node::ValueNode, AbstractTree, Error, Identifier, Index, Map, Result, Value, Yield,
|
||||
value_node::ValueNode, AbstractTree, Error, Identifier, Index, Map, Result, TypeDefinition,
|
||||
Value, Yield,
|
||||
};
|
||||
|
||||
use super::{function_call::FunctionCall, logic::Logic, math::Math};
|
||||
@ -51,7 +52,7 @@ impl AbstractTree for Expression {
|
||||
Ok(expression)
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
match self {
|
||||
Expression::Value(value_node) => value_node.run(source, context),
|
||||
Expression::Identifier(identifier) => identifier.run(source, context),
|
||||
@ -62,4 +63,16 @@ impl AbstractTree for Expression {
|
||||
Expression::Yield(r#yield) => r#yield.run(source, context),
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||
match self {
|
||||
Expression::Value(value_node) => value_node.expected_type(context),
|
||||
Expression::Identifier(identifier) => identifier.expected_type(context),
|
||||
Expression::Math(math) => math.expected_type(context),
|
||||
Expression::Logic(logic) => logic.expected_type(context),
|
||||
Expression::FunctionCall(function_call) => function_call.expected_type(context),
|
||||
Expression::Index(index) => index.expected_type(context),
|
||||
Expression::Yield(r#yield) => r#yield.expected_type(context),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,77 +0,0 @@
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Block, Error, Expression, Identifier, List, Map, Result, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Filter {
|
||||
count: Option<Expression>,
|
||||
item_id: Identifier,
|
||||
collection: Expression,
|
||||
predicate: Block,
|
||||
}
|
||||
|
||||
impl AbstractTree for Filter {
|
||||
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
|
||||
let count = match node.child_by_field_name("count") {
|
||||
Some(node) => Some(Expression::from_syntax_node(source, node)?),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let item_id_node = node.child_by_field_name("item_id").unwrap();
|
||||
let item_id = Identifier::from_syntax_node(source, item_id_node)?;
|
||||
|
||||
let collection_node = node.child_by_field_name("collection").unwrap();
|
||||
let collection = Expression::from_syntax_node(source, collection_node)?;
|
||||
|
||||
let predicate_node = node.child_by_field_name("predicate").unwrap();
|
||||
let predicate = Block::from_syntax_node(source, predicate_node)?;
|
||||
|
||||
Ok(Filter {
|
||||
count,
|
||||
item_id,
|
||||
collection,
|
||||
predicate,
|
||||
})
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
let value = self.collection.run(source, context)?;
|
||||
let values = value.as_list()?.items();
|
||||
let key = self.item_id.inner();
|
||||
let new_values = List::new();
|
||||
let count = match &self.count {
|
||||
Some(expression) => Some(expression.run(source, context)?.as_integer()? as usize),
|
||||
None => None,
|
||||
};
|
||||
let loop_context = Map::clone_from(context)?;
|
||||
|
||||
values.par_iter().try_for_each(|value| {
|
||||
if let Some(max) = count {
|
||||
if new_values.items().len() == max {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
let mut iter_context = loop_context.clone();
|
||||
|
||||
iter_context
|
||||
.variables_mut()?
|
||||
.insert(key.clone(), value.clone());
|
||||
|
||||
let should_include = self
|
||||
.predicate
|
||||
.run(source, &mut iter_context)?
|
||||
.as_boolean()?;
|
||||
|
||||
if should_include {
|
||||
new_values.items_mut().push(value.clone());
|
||||
}
|
||||
|
||||
Ok::<(), Error>(())
|
||||
})?;
|
||||
|
||||
Ok(Value::List(new_values))
|
||||
}
|
||||
}
|
@ -2,7 +2,9 @@ use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Block, Error, Expression, Identifier, Map, Result, Value};
|
||||
use crate::{
|
||||
AbstractTree, Block, Error, Expression, Identifier, Map, Result, TypeDefinition, Value,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct For {
|
||||
@ -47,7 +49,7 @@ impl AbstractTree for For {
|
||||
})
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
let expression_run = self.collection.run(source, context)?;
|
||||
let values = expression_run.as_list()?.items();
|
||||
let key = self.item_id.inner();
|
||||
@ -76,4 +78,8 @@ impl AbstractTree for For {
|
||||
|
||||
Ok(Value::Empty)
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
||||
Ok(TypeDefinition::Empty)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Map, Result, Value, BUILT_IN_FUNCTIONS};
|
||||
use crate::{AbstractTree, Error, Map, Result, TypeDefinition, Value, BUILT_IN_FUNCTIONS};
|
||||
|
||||
use super::expression::Expression;
|
||||
|
||||
@ -45,7 +45,7 @@ impl AbstractTree for FunctionCall {
|
||||
})
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
let function = if let Expression::Identifier(identifier) = &self.function {
|
||||
let key = identifier.inner();
|
||||
|
||||
@ -77,15 +77,17 @@ impl AbstractTree for FunctionCall {
|
||||
let mut function_context = Map::clone_from(context)?;
|
||||
let parameter_expression_pairs = function.parameters().iter().zip(self.arguments.iter());
|
||||
|
||||
for ((identifier, r#type), expression) in parameter_expression_pairs {
|
||||
for (identifier, expression) in parameter_expression_pairs {
|
||||
let key = identifier.clone().take_inner();
|
||||
let value = expression.run(source, context)?;
|
||||
|
||||
r#type.check(&value)?;
|
||||
|
||||
function_context.variables_mut()?.insert(key, value);
|
||||
}
|
||||
|
||||
function.run(source, &mut function_context)
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||
self.function.expected_type(context)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Map, Result, Value};
|
||||
use crate::{AbstractTree, Error, Map, Result, TypeDefinition, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Identifier(String);
|
||||
@ -29,11 +29,19 @@ impl AbstractTree for Identifier {
|
||||
Ok(Identifier(identifier.to_string()))
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, _source: &str, context: &Map) -> Result<Value> {
|
||||
if let Some(value) = context.variables()?.get(&self.0) {
|
||||
Ok(value.clone())
|
||||
} else {
|
||||
Err(Error::VariableIdentifierNotFound(self.inner().clone()))
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||
if let Some(value) = context.variables()?.get(&self.0) {
|
||||
Ok(value.r#type(context)?)
|
||||
} else {
|
||||
Ok(TypeDefinition::Empty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Block, Expression, Map, Result, Value};
|
||||
use crate::{AbstractTree, Block, Expression, Map, Result, TypeDefinition, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct IfElse {
|
||||
@ -55,7 +55,7 @@ impl AbstractTree for IfElse {
|
||||
})
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
let if_boolean = self.if_expression.run(source, context)?.as_boolean()?;
|
||||
|
||||
if if_boolean {
|
||||
@ -80,4 +80,8 @@ impl AbstractTree for IfElse {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||
self.if_block.expected_type(context)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Expression, List, Map, Result, Value};
|
||||
use crate::{AbstractTree, Error, Expression, List, Map, Result, TypeDefinition, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Index {
|
||||
@ -32,7 +32,7 @@ impl AbstractTree for Index {
|
||||
})
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
let collection = self.collection.run(source, context)?;
|
||||
|
||||
match collection {
|
||||
@ -73,6 +73,10 @@ impl AbstractTree for Index {
|
||||
_ => Err(Error::ExpectedCollection { actual: collection }),
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||
self.collection.expected_type(context)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Index, Map, Result, Statement, Value};
|
||||
use crate::{AbstractTree, Error, Index, Map, Result, Statement, TypeDefinition, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct IndexAssignment {
|
||||
@ -49,7 +49,7 @@ impl AbstractTree for IndexAssignment {
|
||||
})
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
let index_collection = self.index.collection.run(source, context)?;
|
||||
let index_context = index_collection.as_map().unwrap_or(&context);
|
||||
let index_key = if let crate::Expression::Identifier(identifier) = &self.index.index {
|
||||
@ -90,4 +90,8 @@ impl AbstractTree for IndexAssignment {
|
||||
|
||||
Ok(Value::Empty)
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
||||
Ok(TypeDefinition::Empty)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Expression, Map, Result, Value};
|
||||
use crate::{AbstractTree, Error, Expression, Map, Result, TypeDefinition, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Logic {
|
||||
@ -45,7 +45,7 @@ impl AbstractTree for Logic {
|
||||
})
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
let left = self.left.run(source, context)?;
|
||||
let right = self.right.run(source, context)?;
|
||||
let result = match self.operator {
|
||||
@ -73,6 +73,10 @@ impl AbstractTree for Logic {
|
||||
|
||||
Ok(Value::Boolean(result))
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
||||
Ok(TypeDefinition::Boolean)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
|
@ -6,7 +6,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Map, Result, Value};
|
||||
use crate::{AbstractTree, Map, Result, TypeDefinition, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Match {}
|
||||
@ -16,7 +16,11 @@ impl AbstractTree for Match {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, _context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Expression, Map, Result, Value};
|
||||
use crate::{AbstractTree, Error, Expression, Map, Result, TypeDefinition, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Math {
|
||||
@ -42,7 +42,7 @@ impl AbstractTree for Math {
|
||||
})
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
let left = self.left.run(source, context)?;
|
||||
let right = self.right.run(source, context)?;
|
||||
let value = match self.operator {
|
||||
@ -55,6 +55,10 @@ impl AbstractTree for Math {
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
||||
Ok(TypeDefinition::Number)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
|
@ -9,38 +9,67 @@
|
||||
pub mod assignment;
|
||||
pub mod block;
|
||||
pub mod expression;
|
||||
pub mod filter;
|
||||
pub mod find;
|
||||
pub mod r#for;
|
||||
pub mod function_call;
|
||||
pub mod identifier;
|
||||
pub mod if_else;
|
||||
pub mod index;
|
||||
pub mod index_assignment;
|
||||
pub mod insert;
|
||||
pub mod logic;
|
||||
pub mod r#match;
|
||||
pub mod math;
|
||||
pub mod remove;
|
||||
pub mod select;
|
||||
pub mod statement;
|
||||
pub mod transform;
|
||||
pub mod r#type;
|
||||
pub mod type_defintion;
|
||||
pub mod r#use;
|
||||
pub mod value_node;
|
||||
pub mod r#while;
|
||||
pub mod r#yield;
|
||||
|
||||
pub use {
|
||||
assignment::*, block::*, expression::*, filter::*, find::*, function_call::*, identifier::*,
|
||||
if_else::*, index::*, index_assignment::IndexAssignment, insert::*, logic::*, math::*,
|
||||
r#for::*, r#match::*, r#type::*, r#use::*, r#while::*, r#yield::*, remove::*, select::*,
|
||||
statement::*, transform::*, value_node::*,
|
||||
assignment::*, block::*, expression::*, function_call::*, identifier::*, if_else::*, index::*,
|
||||
index_assignment::IndexAssignment, logic::*, math::*, r#for::*, r#match::*, r#use::*,
|
||||
r#while::*, r#yield::*, statement::*, type_defintion::*, value_node::*,
|
||||
};
|
||||
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{Map, Result, Value};
|
||||
use crate::{Error, Map, Result, Value};
|
||||
|
||||
pub struct Root {
|
||||
statements: Vec<Statement>,
|
||||
}
|
||||
|
||||
impl AbstractTree for Root {
|
||||
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
|
||||
Error::expect_syntax_node(source, "root", node)?;
|
||||
|
||||
let statement_count = node.child_count();
|
||||
let mut statements = Vec::with_capacity(statement_count);
|
||||
|
||||
for index in 0..statement_count {
|
||||
let statement_node = node.child(index).unwrap();
|
||||
let statement = Statement::from_syntax_node(source, statement_node)?;
|
||||
|
||||
statements.push(statement);
|
||||
}
|
||||
|
||||
Ok(Root { statements })
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
let mut value = Value::Empty;
|
||||
|
||||
for statement in &self.statements {
|
||||
value = statement.run(source, context)?;
|
||||
}
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||
self.statements.last().unwrap().expected_type(context)
|
||||
}
|
||||
}
|
||||
|
||||
/// This trait is implemented by the Evaluator's internal types to form an
|
||||
/// executable tree that resolves to a single value.
|
||||
@ -57,5 +86,7 @@ pub trait AbstractTree: Sized {
|
||||
fn from_syntax_node(source: &str, node: Node) -> Result<Self>;
|
||||
|
||||
/// Execute dust code by traversing the tree.
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value>;
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value>;
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition>;
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{
|
||||
AbstractTree, Assignment, Block, Error, Expression, Filter, Find, For, IfElse, IndexAssignment,
|
||||
Insert, Map, Match, Remove, Result, Select, Transform, Use, Value, While,
|
||||
AbstractTree, Assignment, Block, Error, Expression, For, IfElse, IndexAssignment, Map, Match,
|
||||
Result, TypeDefinition, Use, Value, While,
|
||||
};
|
||||
|
||||
/// Abstract representation of a statement.
|
||||
@ -17,13 +17,7 @@ pub enum Statement {
|
||||
While(Box<While>),
|
||||
Block(Box<Block>),
|
||||
For(Box<For>),
|
||||
Transform(Box<Transform>),
|
||||
Filter(Box<Filter>),
|
||||
Find(Box<Find>),
|
||||
Remove(Box<Remove>),
|
||||
Use(Use),
|
||||
Select(Box<Select>),
|
||||
Insert(Box<Insert>),
|
||||
IndexAssignment(Box<IndexAssignment>),
|
||||
}
|
||||
|
||||
@ -60,25 +54,7 @@ impl AbstractTree for Statement {
|
||||
"for" => Ok(Statement::For(Box::new(For::from_syntax_node(
|
||||
source, child,
|
||||
)?))),
|
||||
"transform" => Ok(Statement::Transform(Box::new(Transform::from_syntax_node(
|
||||
source, child,
|
||||
)?))),
|
||||
"filter" => Ok(Statement::Filter(Box::new(Filter::from_syntax_node(
|
||||
source, child,
|
||||
)?))),
|
||||
"find" => Ok(Statement::Find(Box::new(Find::from_syntax_node(
|
||||
source, child,
|
||||
)?))),
|
||||
"remove" => Ok(Statement::Remove(Box::new(Remove::from_syntax_node(
|
||||
source, child,
|
||||
)?))),
|
||||
"select" => Ok(Statement::Select(Box::new(Select::from_syntax_node(
|
||||
source, child,
|
||||
)?))),
|
||||
"use" => Ok(Statement::Use(Use::from_syntax_node(source, child)?)),
|
||||
"insert" => Ok(Statement::Insert(Box::new(Insert::from_syntax_node(
|
||||
source, child,
|
||||
)?))),
|
||||
"index_assignment" => Ok(Statement::IndexAssignment(Box::new(IndexAssignment::from_syntax_node(
|
||||
source, child,
|
||||
)?))),
|
||||
@ -91,7 +67,7 @@ impl AbstractTree for Statement {
|
||||
}
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
match self {
|
||||
Statement::Assignment(assignment) => assignment.run(source, context),
|
||||
Statement::Return(expression) => expression.run(source, context),
|
||||
@ -101,14 +77,23 @@ impl AbstractTree for Statement {
|
||||
Statement::While(r#while) => r#while.run(source, context),
|
||||
Statement::Block(block) => block.run(source, context),
|
||||
Statement::For(r#for) => r#for.run(source, context),
|
||||
Statement::Transform(transform) => transform.run(source, context),
|
||||
Statement::Filter(filter) => filter.run(source, context),
|
||||
Statement::Find(find) => find.run(source, context),
|
||||
Statement::Remove(remove) => remove.run(source, context),
|
||||
Statement::Use(run) => run.run(source, context),
|
||||
Statement::Select(select) => select.run(source, context),
|
||||
Statement::Insert(insert) => insert.run(source, context),
|
||||
Statement::IndexAssignment(index_assignment) => index_assignment.run(source, context),
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||
match self {
|
||||
Statement::Assignment(assignment) => assignment.expected_type(context),
|
||||
Statement::Return(expression) => expression.expected_type(context),
|
||||
Statement::Expression(expression) => expression.expected_type(context),
|
||||
Statement::IfElse(if_else) => if_else.expected_type(context),
|
||||
Statement::Match(r#match) => r#match.expected_type(context),
|
||||
Statement::While(r#while) => r#while.expected_type(context),
|
||||
Statement::Block(block) => block.expected_type(context),
|
||||
Statement::For(r#for) => r#for.expected_type(context),
|
||||
Statement::Use(r#use) => r#use.expected_type(context),
|
||||
Statement::IndexAssignment(index_assignment) => index_assignment.expected_type(context),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,117 +0,0 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Map, Result, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Type {
|
||||
Any,
|
||||
Boolean,
|
||||
Float,
|
||||
Function,
|
||||
Integer,
|
||||
List,
|
||||
Map,
|
||||
String,
|
||||
Table,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn check(&self, value: &Value) -> Result<()> {
|
||||
match (self, value.r#type()) {
|
||||
(Type::Any, _)
|
||||
| (Type::Boolean, Type::Boolean)
|
||||
| (Type::Float, Type::Float)
|
||||
| (Type::Function, Type::Function)
|
||||
| (Type::Integer, Type::Integer)
|
||||
| (Type::List, Type::List)
|
||||
| (Type::Map, Type::Map)
|
||||
| (Type::String, Type::String)
|
||||
| (Type::Table, Type::Table) => Ok(()),
|
||||
(Type::Boolean, _) => Err(Error::TypeCheck {
|
||||
expected: Type::Boolean,
|
||||
actual: value.clone(),
|
||||
}),
|
||||
(Type::Float, _) => Err(Error::TypeCheck {
|
||||
expected: Type::Float,
|
||||
actual: value.clone(),
|
||||
}),
|
||||
(Type::Function, _) => Err(Error::TypeCheck {
|
||||
expected: Type::Function,
|
||||
actual: value.clone(),
|
||||
}),
|
||||
(Type::Integer, _) => Err(Error::TypeCheck {
|
||||
expected: Type::Integer,
|
||||
actual: value.clone(),
|
||||
}),
|
||||
(Type::List, _) => Err(Error::TypeCheck {
|
||||
expected: Type::List,
|
||||
actual: value.clone(),
|
||||
}),
|
||||
(Type::Map, _) => Err(Error::TypeCheck {
|
||||
expected: Type::Map,
|
||||
actual: value.clone(),
|
||||
}),
|
||||
(Type::String, _) => Err(Error::TypeCheck {
|
||||
expected: Type::String,
|
||||
actual: value.clone(),
|
||||
}),
|
||||
(Type::Table, _) => Err(Error::TypeCheck {
|
||||
expected: Type::Table,
|
||||
actual: value.clone(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractTree for Type {
|
||||
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
|
||||
Error::expect_syntax_node(source, "type", node)?;
|
||||
|
||||
let range_without_punctuation = node.start_byte() + 1..node.end_byte() - 1;
|
||||
|
||||
let r#type = match &source[range_without_punctuation] {
|
||||
"any" => Type::Any,
|
||||
"bool" => Type::Boolean,
|
||||
"float" => Type::Float,
|
||||
"fn" => Type::Function,
|
||||
"int" => Type::Integer,
|
||||
"list" => Type::List,
|
||||
"map" => Type::Map,
|
||||
"str" => Type::String,
|
||||
"table" => Type::Table,
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "any, bool, float, fn, int, list, map, str or table",
|
||||
actual: node.kind(),
|
||||
location: node.start_position(),
|
||||
relevant_source: source[node.byte_range()].to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Ok(r#type)
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, _context: &mut Map) -> Result<Value> {
|
||||
Ok(Value::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Type {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Type::Any => write!(f, "any"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::Float => write!(f, "float"),
|
||||
Type::Function => write!(f, "function"),
|
||||
Type::Integer => write!(f, "integer"),
|
||||
Type::List => write!(f, "list"),
|
||||
Type::Map => write!(f, "map"),
|
||||
Type::String => write!(f, "string"),
|
||||
Type::Table => write!(f, "table"),
|
||||
}
|
||||
}
|
||||
}
|
170
src/abstract_tree/type_defintion.rs
Normal file
170
src/abstract_tree/type_defintion.rs
Normal file
@ -0,0 +1,170 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Map, Result, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum TypeDefinition {
|
||||
Any,
|
||||
Boolean,
|
||||
Empty,
|
||||
Float,
|
||||
Function {
|
||||
parameter_types: Vec<TypeDefinition>,
|
||||
return_type: Box<TypeDefinition>,
|
||||
},
|
||||
Integer,
|
||||
List(Box<TypeDefinition>),
|
||||
Map,
|
||||
Number,
|
||||
String,
|
||||
Table,
|
||||
}
|
||||
|
||||
impl TypeDefinition {
|
||||
// pub fn check(&self, value: &Value) -> Result<()> {
|
||||
// match (self, value.r#type()?) {
|
||||
// (Type::Any, _)
|
||||
// | (Type::Boolean, Type::Boolean)
|
||||
// | (Type::Empty, Type::Empty)
|
||||
// | (Type::Float, Type::Float)
|
||||
// | (Type::Integer, Type::Integer)
|
||||
// | (Type::Map, Type::Map)
|
||||
// | (Type::Number, Type::Number)
|
||||
// | (Type::Number, Type::Integer)
|
||||
// | (Type::Number, Type::Float)
|
||||
// | (Type::Integer, Type::Number)
|
||||
// | (Type::Float, Type::Number)
|
||||
// | (Type::String, Type::String)
|
||||
// | (Type::Table, Type::Table) => Ok(()),
|
||||
// (Type::List(expected), Type::List(actual)) => {
|
||||
// if expected != &actual {
|
||||
// Err(Error::TypeCheck {
|
||||
// expected: Type::List(expected.clone()),
|
||||
// actual: value.clone(),
|
||||
// })
|
||||
// } else {
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
// (
|
||||
// Type::Function {
|
||||
// parameter_types: left_parameters,
|
||||
// return_type: left_return,
|
||||
// },
|
||||
// Type::Function {
|
||||
// parameter_types: right_parameters,
|
||||
// return_type: right_return,
|
||||
// },
|
||||
// ) => {
|
||||
// if left_parameters != &right_parameters || left_return != &right_return {
|
||||
// Err(Error::TypeCheck {
|
||||
// expected: Type::Function {
|
||||
// parameter_types: left_parameters.clone(),
|
||||
// return_type: left_return.clone(),
|
||||
// },
|
||||
// actual: value.clone(),
|
||||
// })
|
||||
// } else {
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
// (Type::Boolean, _) => Err(Error::TypeCheck {
|
||||
// expected: Type::Boolean,
|
||||
// actual: value.clone(),
|
||||
// }),
|
||||
// (Type::Empty, _) => Err(Error::TypeCheck {
|
||||
// expected: Type::Empty,
|
||||
// actual: value.clone(),
|
||||
// }),
|
||||
// (Type::Float, _) => Err(Error::TypeCheck {
|
||||
// expected: Type::Float,
|
||||
// actual: value.clone(),
|
||||
// }),
|
||||
// (expected, _) => Err(Error::TypeCheck {
|
||||
// expected: expected.clone(),
|
||||
// actual: value.clone(),
|
||||
// }),
|
||||
// (Type::Integer, _) => Err(Error::TypeCheck {
|
||||
// expected: Type::Integer,
|
||||
// actual: value.clone(),
|
||||
// }),
|
||||
// (expected, _) => Err(Error::TypeCheck {
|
||||
// expected: expected.clone(),
|
||||
// actual: value.clone(),
|
||||
// }),
|
||||
// (Type::Map, _) => Err(Error::TypeCheck {
|
||||
// expected: Type::Map,
|
||||
// actual: value.clone(),
|
||||
// }),
|
||||
// (Type::String, _) => Err(Error::TypeCheck {
|
||||
// expected: Type::String,
|
||||
// actual: value.clone(),
|
||||
// }),
|
||||
// (Type::Table, _) => Err(Error::TypeCheck {
|
||||
// expected: Type::Table,
|
||||
// actual: value.clone(),
|
||||
// }),
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
impl AbstractTree for TypeDefinition {
|
||||
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
|
||||
Error::expect_syntax_node(source, "type_definition", node)?;
|
||||
|
||||
let type_node = node.child(1).unwrap();
|
||||
let type_symbol = &source[type_node.byte_range()];
|
||||
|
||||
let r#type = match type_symbol {
|
||||
"any" => TypeDefinition::Any,
|
||||
"bool" => TypeDefinition::Boolean,
|
||||
"float" => TypeDefinition::Float,
|
||||
"fn" => {
|
||||
todo!()
|
||||
}
|
||||
"int" => TypeDefinition::Integer,
|
||||
"map" => TypeDefinition::Map,
|
||||
"str" => TypeDefinition::String,
|
||||
"table" => TypeDefinition::Table,
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "any, bool, float, fn, int, list, map, str or table",
|
||||
actual: type_node.kind(),
|
||||
location: type_node.start_position(),
|
||||
relevant_source: source[type_node.byte_range()].to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Ok(r#type)
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||
Ok(Value::Empty)
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
||||
Ok(TypeDefinition::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for TypeDefinition {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
TypeDefinition::Any => write!(f, "any"),
|
||||
TypeDefinition::Boolean => write!(f, "bool"),
|
||||
TypeDefinition::Empty => write!(f, "empty"),
|
||||
TypeDefinition::Float => write!(f, "float"),
|
||||
TypeDefinition::Function { .. } => write!(f, "function"),
|
||||
TypeDefinition::Integer => write!(f, "integer"),
|
||||
TypeDefinition::List(_) => write!(f, "list"),
|
||||
TypeDefinition::Map => write!(f, "map"),
|
||||
TypeDefinition::Number => write!(f, "number"),
|
||||
TypeDefinition::String => write!(f, "string"),
|
||||
TypeDefinition::Table => write!(f, "table"),
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ use std::fs::read_to_string;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{evaluate_with_context, AbstractTree, Error, Map, Result, Value};
|
||||
use crate::{evaluate_with_context, AbstractTree, Error, Map, Result, TypeDefinition, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Use {
|
||||
@ -21,7 +21,7 @@ impl AbstractTree for Use {
|
||||
Ok(Use { path })
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, _context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||
let file_contents = read_to_string(&self.path)?;
|
||||
let mut file_context = Map::new();
|
||||
|
||||
@ -29,4 +29,8 @@ impl AbstractTree for Use {
|
||||
|
||||
Ok(Value::Map(file_context))
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
||||
Ok(TypeDefinition::Map)
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use tree_sitter::Node;
|
||||
|
||||
use crate::{
|
||||
AbstractTree, Error, Expression, Function, Identifier, List, Map, Result, Statement, Table,
|
||||
Value,
|
||||
TypeDefinition, Value,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
@ -112,7 +112,7 @@ impl AbstractTree for ValueNode {
|
||||
Ok(value_node)
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
let value = match self {
|
||||
ValueNode::Boolean(value_source) => Value::Boolean(value_source.parse().unwrap()),
|
||||
ValueNode::Float(value_source) => Value::Float(value_source.parse().unwrap()),
|
||||
@ -176,4 +176,31 @@ impl AbstractTree for ValueNode {
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||
let r#type = match self {
|
||||
ValueNode::Boolean(_) => TypeDefinition::Boolean,
|
||||
ValueNode::Float(_) => TypeDefinition::Float,
|
||||
ValueNode::Integer(_) => TypeDefinition::Integer,
|
||||
ValueNode::String(_) => TypeDefinition::String,
|
||||
ValueNode::List(expressions) => {
|
||||
let first_expression_type = if let Some(first) = expressions.first() {
|
||||
first.expected_type(context)?
|
||||
} else {
|
||||
TypeDefinition::Empty
|
||||
};
|
||||
|
||||
TypeDefinition::List(Box::new(first_expression_type))
|
||||
}
|
||||
ValueNode::Empty => TypeDefinition::Any,
|
||||
ValueNode::Map(_) => TypeDefinition::Map,
|
||||
ValueNode::Table {
|
||||
column_names: _,
|
||||
rows: _,
|
||||
} => TypeDefinition::Table,
|
||||
ValueNode::Function(function) => function.expected_type(context)?,
|
||||
};
|
||||
|
||||
Ok(r#type)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Block, Expression, Map, Result, Value};
|
||||
use crate::{AbstractTree, Block, Expression, Map, Result, TypeDefinition, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct While {
|
||||
@ -22,13 +22,17 @@ impl AbstractTree for While {
|
||||
Ok(While { expression, block })
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
while self.expression.run(source, context)?.as_boolean()? {
|
||||
self.block.run(source, context)?;
|
||||
}
|
||||
|
||||
Ok(Value::Empty)
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||
self.block.expected_type(context)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Expression, FunctionCall, Result, Value};
|
||||
use crate::{AbstractTree, Expression, FunctionCall, Map, Result, TypeDefinition, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Yield {
|
||||
@ -35,7 +35,11 @@ impl AbstractTree for Yield {
|
||||
Ok(Yield { call })
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut crate::Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
self.call.run(source, context)
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||
self.call.expected_type(context)
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
use tree_sitter::{Node, Point};
|
||||
|
||||
use crate::{value::Value, Identifier, Type};
|
||||
use crate::{value::Value, Identifier, TypeDefinition};
|
||||
|
||||
use std::{fmt, io, num::ParseFloatError, string::FromUtf8Error, sync::PoisonError, time};
|
||||
|
||||
@ -21,7 +21,7 @@ pub enum Error {
|
||||
},
|
||||
|
||||
TypeCheck {
|
||||
expected: Type,
|
||||
expected: TypeDefinition,
|
||||
actual: Value,
|
||||
},
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
//! functions or by constructing your own Evaluator.
|
||||
use tree_sitter::{Parser, Tree as TSTree};
|
||||
|
||||
use crate::{language, AbstractTree, Map, Result, Statement, Value};
|
||||
use crate::{language, AbstractTree, Map, Result, Root, Value};
|
||||
|
||||
/// Evaluate the given source code.
|
||||
///
|
||||
@ -50,41 +50,34 @@ pub fn evaluate_with_context(source: &str, context: &mut Map) -> Result<Value> {
|
||||
let mut parser = Parser::new();
|
||||
parser.set_language(language()).unwrap();
|
||||
|
||||
Evaluator::new(parser, context, source).run()
|
||||
Interpreter::parse(parser, context, source)?.run()
|
||||
}
|
||||
|
||||
/// A source code interpreter for the Dust language.
|
||||
pub struct Evaluator<'c, 's> {
|
||||
pub struct Interpreter<'c, 's> {
|
||||
_parser: Parser,
|
||||
context: &'c mut Map,
|
||||
source: &'s str,
|
||||
syntax_tree: TSTree,
|
||||
abstract_tree: Root,
|
||||
}
|
||||
|
||||
impl<'c, 's> Evaluator<'c, 's> {
|
||||
pub fn new(mut parser: Parser, context: &'c mut Map, source: &'s str) -> Self {
|
||||
impl<'c, 's> Interpreter<'c, 's> {
|
||||
pub fn parse(mut parser: Parser, context: &'c mut Map, source: &'s str) -> Result<Self> {
|
||||
let syntax_tree = parser.parse(source, None).unwrap();
|
||||
let abstract_tree = Root::from_syntax_node(source, syntax_tree.root_node())?;
|
||||
|
||||
Evaluator {
|
||||
Ok(Interpreter {
|
||||
_parser: parser,
|
||||
context,
|
||||
source,
|
||||
syntax_tree,
|
||||
}
|
||||
abstract_tree,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn run(self) -> Result<Value> {
|
||||
let root_node = self.syntax_tree.root_node();
|
||||
let mut value = Value::Empty;
|
||||
|
||||
for index in 0..root_node.child_count() {
|
||||
let statement_node = root_node.child(index).unwrap();
|
||||
let statement = Statement::from_syntax_node(self.source, statement_node)?;
|
||||
|
||||
value = statement.run(self.source, self.context)?;
|
||||
}
|
||||
|
||||
Ok(value)
|
||||
pub fn run(&mut self) -> Result<Value> {
|
||||
self.abstract_tree.run(self.source, self.context)
|
||||
}
|
||||
|
||||
pub fn syntax_tree(&self) -> String {
|
||||
@ -247,7 +240,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
evaluate(
|
||||
"
|
||||
foobar = |message <str>| <str> { message }
|
||||
foobar <fn str -> str> = |message| { message }
|
||||
(foobar 'Hiya')
|
||||
",
|
||||
),
|
@ -8,14 +8,14 @@ pub use crate::{
|
||||
abstract_tree::*,
|
||||
built_in_functions::{BuiltInFunction, BUILT_IN_FUNCTIONS},
|
||||
error::*,
|
||||
evaluator::*,
|
||||
evaluate::*,
|
||||
value::{function::Function, list::List, map::Map, table::Table, Value},
|
||||
};
|
||||
|
||||
mod abstract_tree;
|
||||
pub mod built_in_functions;
|
||||
mod error;
|
||||
mod evaluator;
|
||||
mod evaluate;
|
||||
mod value;
|
||||
|
||||
use tree_sitter::Language;
|
||||
|
24
src/main.rs
24
src/main.rs
@ -12,7 +12,7 @@ use tree_sitter::Parser as TSParser;
|
||||
|
||||
use std::{borrow::Cow, fs::read_to_string};
|
||||
|
||||
use dust_lang::{evaluate_with_context, language, Evaluator, Map, Value};
|
||||
use dust_lang::{evaluate_with_context, language, Interpreter, Map, Value};
|
||||
|
||||
/// Command-line arguments to be parsed.
|
||||
#[derive(Parser, Debug)]
|
||||
@ -30,10 +30,14 @@ struct Args {
|
||||
#[arg(short = 'p', long)]
|
||||
input_path: Option<String>,
|
||||
|
||||
/// A path to file whose contents will be assigned to the "input" variable.
|
||||
/// Show the syntax tree.
|
||||
#[arg(short = 't', long = "tree")]
|
||||
show_syntax_tree: bool,
|
||||
|
||||
/// Launch in interactive mode.
|
||||
#[arg(short, long)]
|
||||
interactive: bool,
|
||||
|
||||
/// Location of the file to run.
|
||||
path: Option<String>,
|
||||
}
|
||||
@ -74,13 +78,21 @@ fn main() {
|
||||
let mut parser = TSParser::new();
|
||||
parser.set_language(language()).unwrap();
|
||||
|
||||
let evaluator = Evaluator::new(parser, &mut context, &source);
|
||||
let mut interpreter = Interpreter::parse(parser, &mut context, &source).unwrap();
|
||||
|
||||
if args.show_syntax_tree {
|
||||
println!("{}", evaluator.syntax_tree());
|
||||
if args.interactive {
|
||||
loop {
|
||||
let result = interpreter.run();
|
||||
|
||||
println!("{result:?}")
|
||||
}
|
||||
}
|
||||
|
||||
let eval_result = evaluator.run();
|
||||
if args.show_syntax_tree {
|
||||
println!("{}", interpreter.syntax_tree());
|
||||
}
|
||||
|
||||
let eval_result = interpreter.run();
|
||||
|
||||
match eval_result {
|
||||
Ok(value) => {
|
||||
|
@ -3,19 +3,22 @@ use std::fmt::{self, Display, Formatter};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Block, Error, Identifier, Map, Result, Type, Value};
|
||||
use crate::{AbstractTree, Block, Error, Identifier, Map, Result, TypeDefinition, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Function {
|
||||
parameters: Vec<(Identifier, Type)>,
|
||||
return_type: Option<Type>,
|
||||
parameters: Vec<Identifier>,
|
||||
body: Block,
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn parameters(&self) -> &Vec<(Identifier, Type)> {
|
||||
pub fn parameters(&self) -> &Vec<Identifier> {
|
||||
&self.parameters
|
||||
}
|
||||
|
||||
pub fn body(&self) -> &Block {
|
||||
&self.body
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractTree for Function {
|
||||
@ -25,57 +28,29 @@ impl AbstractTree for Function {
|
||||
let child_count = node.child_count();
|
||||
let mut parameters = Vec::new();
|
||||
|
||||
for index in 1..child_count - 2 {
|
||||
let parameter_node = {
|
||||
for index in 0..child_count {
|
||||
let child = node.child(index).unwrap();
|
||||
|
||||
if child.is_named() {
|
||||
child
|
||||
} else {
|
||||
continue;
|
||||
let identifier = Identifier::from_syntax_node(source, child)?;
|
||||
parameters.push(identifier);
|
||||
}
|
||||
};
|
||||
|
||||
Error::expect_syntax_node(source, "parameter", parameter_node)?;
|
||||
|
||||
let identifier_node = parameter_node.child(0).unwrap();
|
||||
let identifier = Identifier::from_syntax_node(source, identifier_node)?;
|
||||
|
||||
let type_node = parameter_node.child(1).unwrap();
|
||||
let r#type = Type::from_syntax_node(source, type_node)?;
|
||||
|
||||
parameters.push((identifier, r#type))
|
||||
}
|
||||
|
||||
let return_type_node = node.child(child_count - 2).unwrap();
|
||||
let return_type = if return_type_node.is_named() {
|
||||
Some(Type::from_syntax_node(source, return_type_node)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let body_node = node.child(child_count - 1).unwrap();
|
||||
let body = Block::from_syntax_node(source, body_node)?;
|
||||
|
||||
Ok(Function {
|
||||
parameters,
|
||||
return_type,
|
||||
body,
|
||||
})
|
||||
Ok(Function { parameters, body })
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
let return_value = self.body.run(source, context)?;
|
||||
|
||||
if let Some(r#type) = &self.return_type {
|
||||
r#type.check(&return_value)?;
|
||||
} else if !return_value.is_empty() {
|
||||
return Err(Error::ExpectedEmpty {
|
||||
actual: return_value.clone(),
|
||||
});
|
||||
Ok(return_value)
|
||||
}
|
||||
|
||||
Ok(return_value)
|
||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||
self.body.expected_type(context)
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,8 +58,8 @@ impl Display for Function {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Function {{ parameters: {:?}, return_type: {:?}, body: {:?} }}",
|
||||
self.parameters, self.return_type, self.body
|
||||
"Function {{ parameters: {:?}, body: {:?} }}",
|
||||
self.parameters, self.body
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Types that represent runtime values.
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
Function, List, Map, Table, Type,
|
||||
AbstractTree, Function, List, Map, Table, TypeDefinition,
|
||||
};
|
||||
|
||||
use serde::{
|
||||
@ -43,18 +43,41 @@ pub enum Value {
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn r#type(&self) -> Type {
|
||||
match self {
|
||||
Value::List(_) => Type::List,
|
||||
Value::Map(_) => Type::Map,
|
||||
Value::Table(_) => Type::Table,
|
||||
Value::Function(_) => Type::Function,
|
||||
Value::String(_) => Type::String,
|
||||
Value::Float(_) => Type::Float,
|
||||
Value::Integer(_) => Type::Integer,
|
||||
Value::Boolean(_) => Type::Boolean,
|
||||
Value::Empty => Type::Any,
|
||||
pub fn r#type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||
let r#type = match self {
|
||||
Value::List(list) => {
|
||||
let first_item_type = if let Some(first) = list.items().first() {
|
||||
first.r#type(context)?
|
||||
} else {
|
||||
TypeDefinition::Empty
|
||||
};
|
||||
|
||||
TypeDefinition::List(Box::new(first_item_type))
|
||||
}
|
||||
Value::Map(_) => TypeDefinition::Map,
|
||||
Value::Table(_) => TypeDefinition::Table,
|
||||
Value::Function(function) => {
|
||||
let parameter_types = Vec::new();
|
||||
|
||||
for identifier in function.parameters() {
|
||||
let _type = identifier.expected_type(context)?;
|
||||
}
|
||||
|
||||
let return_type = function.body().expected_type(context)?;
|
||||
|
||||
TypeDefinition::Function {
|
||||
parameter_types,
|
||||
return_type: Box::new(return_type),
|
||||
}
|
||||
}
|
||||
Value::String(_) => TypeDefinition::String,
|
||||
Value::Float(_) => TypeDefinition::Float,
|
||||
Value::Integer(_) => TypeDefinition::Integer,
|
||||
Value::Boolean(_) => TypeDefinition::Boolean,
|
||||
Value::Empty => TypeDefinition::Empty,
|
||||
};
|
||||
|
||||
Ok(r#type)
|
||||
}
|
||||
|
||||
pub fn is_table(&self) -> bool {
|
||||
|
1
tree-sitter-dust/.prettierignore
Normal file
1
tree-sitter-dust/.prettierignore
Normal file
@ -0,0 +1 @@
|
||||
src/
|
5
tree-sitter-dust/.prettierrc
Normal file
5
tree-sitter-dust/.prettierrc
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"arrowParens": "avoid",
|
||||
"printWidth": 40,
|
||||
"singleQuote": true
|
||||
}
|
@ -27,7 +27,8 @@ x <int> = y
|
||||
(statement
|
||||
(assignment
|
||||
(identifier)
|
||||
(type)
|
||||
(type_definition
|
||||
(type))
|
||||
(assignment_operator)
|
||||
(statement
|
||||
(expression
|
||||
|
@ -12,10 +12,11 @@ async { (output 'Whaddup') }
|
||||
(statement
|
||||
(expression
|
||||
(function_call
|
||||
(built_in_function
|
||||
(expression
|
||||
(identifier))
|
||||
(expression
|
||||
(value
|
||||
(string))))))))))
|
||||
(string)))))))))
|
||||
|
||||
================================================================================
|
||||
Complex Async Statements
|
||||
|
@ -10,10 +10,11 @@ Simple Function Call
|
||||
(statement
|
||||
(expression
|
||||
(function_call
|
||||
(built_in_function
|
||||
(expression
|
||||
(identifier))
|
||||
(expression
|
||||
(value
|
||||
(string))))))))
|
||||
(string)))))))
|
||||
|
||||
================================================================================
|
||||
Nested Function Call
|
||||
@ -27,10 +28,10 @@ Nested Function Call
|
||||
(statement
|
||||
(expression
|
||||
(function_call
|
||||
(built_in_function
|
||||
(expression
|
||||
(function_call
|
||||
(built_in_function)))
|
||||
(identifier))
|
||||
(expression
|
||||
(identifier))
|
||||
(expression
|
||||
(value
|
||||
(integer))))))))
|
||||
(integer)))))))
|
||||
|
@ -28,9 +28,10 @@ for i in [1, 2, 3] {
|
||||
(statement
|
||||
(expression
|
||||
(function_call
|
||||
(built_in_function
|
||||
(expression
|
||||
(identifier))))))))))
|
||||
(identifier))
|
||||
(expression
|
||||
(identifier)))))))))
|
||||
|
||||
================================================================================
|
||||
Nested For Loop
|
||||
@ -60,6 +61,7 @@ for list in list_of_lists {
|
||||
(statement
|
||||
(expression
|
||||
(function_call
|
||||
(built_in_function
|
||||
(expression
|
||||
(identifier)))))))))))))
|
||||
(identifier))
|
||||
(expression
|
||||
(identifier))))))))))))
|
||||
|
@ -2,7 +2,7 @@
|
||||
Simple Function
|
||||
================================================================================
|
||||
|
||||
|| <str> { "Hiya" }
|
||||
|| { "Hiya" }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -11,7 +11,6 @@ Simple Function
|
||||
(expression
|
||||
(value
|
||||
(function
|
||||
(type)
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
@ -22,7 +21,7 @@ Simple Function
|
||||
Function Assignment
|
||||
================================================================================
|
||||
|
||||
x = || <str> { "Hiya" }
|
||||
x <fn num -> str> = |number| { "Hiya" }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -30,12 +29,16 @@ x = || <str> { "Hiya" }
|
||||
(statement
|
||||
(assignment
|
||||
(identifier)
|
||||
(type_definition
|
||||
(type
|
||||
(type)
|
||||
(type)))
|
||||
(assignment_operator)
|
||||
(statement
|
||||
(expression
|
||||
(value
|
||||
(function
|
||||
(type)
|
||||
(identifier)
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
@ -64,7 +67,7 @@ Function Call
|
||||
Complex Function
|
||||
================================================================================
|
||||
|
||||
|message <str> number <int>| {
|
||||
|message number| {
|
||||
(output message)
|
||||
(output number)
|
||||
}
|
||||
@ -76,25 +79,23 @@ Complex Function
|
||||
(expression
|
||||
(value
|
||||
(function
|
||||
(parameter
|
||||
(identifier)
|
||||
(type))
|
||||
(parameter
|
||||
(identifier)
|
||||
(type))
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
(function_call
|
||||
(built_in_function
|
||||
(expression
|
||||
(identifier))))))
|
||||
(identifier))
|
||||
(expression
|
||||
(identifier)))))
|
||||
(statement
|
||||
(expression
|
||||
(function_call
|
||||
(built_in_function
|
||||
(expression
|
||||
(identifier))))))))))))
|
||||
(identifier))
|
||||
(expression
|
||||
(identifier)))))))))))
|
||||
|
||||
================================================================================
|
||||
Complex Function Call
|
||||
|
@ -1,105 +0,0 @@
|
||||
================================================================================
|
||||
Table Declaration
|
||||
================================================================================
|
||||
|
||||
table |messages numbers| [
|
||||
['hiya' 42]
|
||||
['foo' 57]
|
||||
['bar' 99.99]
|
||||
]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(expression
|
||||
(value
|
||||
(table
|
||||
(identifier_list
|
||||
(identifier)
|
||||
(identifier))
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(string)))
|
||||
(expression
|
||||
(value
|
||||
(integer))))))
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(string)))
|
||||
(expression
|
||||
(value
|
||||
(integer))))))
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(string)))
|
||||
(expression
|
||||
(value
|
||||
(float))))))))))))))
|
||||
|
||||
================================================================================
|
||||
Table Access
|
||||
================================================================================
|
||||
|
||||
select |number| from foobar {
|
||||
text == 'answer'
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(select
|
||||
(identifier_list
|
||||
(identifier))
|
||||
(expression
|
||||
(identifier))
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
(logic
|
||||
(expression
|
||||
(identifier))
|
||||
(logic_operator)
|
||||
(expression
|
||||
(value
|
||||
(string))))))))))
|
||||
|
||||
================================================================================
|
||||
Table Insert
|
||||
================================================================================
|
||||
|
||||
insert into foobar [
|
||||
['bob was here', 0]
|
||||
]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(insert
|
||||
(identifier)
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(string)))
|
||||
(expression
|
||||
(value
|
||||
(integer))))))))))))
|
@ -18,10 +18,11 @@ while true {
|
||||
(statement
|
||||
(expression
|
||||
(function_call
|
||||
(built_in_function
|
||||
(expression
|
||||
(identifier))
|
||||
(expression
|
||||
(value
|
||||
(string)))))))))))
|
||||
(string))))))))))
|
||||
|
||||
================================================================================
|
||||
Nested While Loop
|
||||
|
@ -13,7 +13,8 @@ Simple Yield
|
||||
(expression
|
||||
(value
|
||||
(integer)))
|
||||
(built_in_function)))))
|
||||
(expression
|
||||
(identifier))))))
|
||||
|
||||
================================================================================
|
||||
Yield Chain
|
||||
|
@ -6,18 +6,22 @@ module.exports = grammar({
|
||||
extras: $ => [/\s/, $._comment],
|
||||
|
||||
rules: {
|
||||
root: $ => prec(1, repeat1($.statement)),
|
||||
root: $ =>
|
||||
prec(1, repeat1($.statement)),
|
||||
|
||||
_comment: $ => /[#][^#\n]*[#|\n]/,
|
||||
|
||||
block: $ => seq(
|
||||
block: $ =>
|
||||
seq(
|
||||
optional('async'),
|
||||
'{',
|
||||
repeat1($.statement),
|
||||
'}',
|
||||
),
|
||||
|
||||
statement: $ => prec.left(seq(
|
||||
statement: $ =>
|
||||
prec.left(
|
||||
seq(
|
||||
choice(
|
||||
$.assignment,
|
||||
$.block,
|
||||
@ -25,22 +29,30 @@ module.exports = grammar({
|
||||
$.for,
|
||||
$.if_else,
|
||||
$.index_assignment,
|
||||
$.insert,
|
||||
$.match,
|
||||
$.return,
|
||||
$.select,
|
||||
$.use,
|
||||
$.while,
|
||||
),
|
||||
optional(';'),
|
||||
)),
|
||||
),
|
||||
),
|
||||
|
||||
expression: $ => prec.right(choice(
|
||||
expression: $ =>
|
||||
prec.right(
|
||||
choice(
|
||||
$._expression_kind,
|
||||
seq('(', $._expression_kind, ')'),
|
||||
)),
|
||||
seq(
|
||||
'(',
|
||||
$._expression_kind,
|
||||
')',
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
_expression_kind: $ => prec.right(choice(
|
||||
_expression_kind: $ =>
|
||||
prec.right(
|
||||
choice(
|
||||
$.function_call,
|
||||
$.identifier,
|
||||
$.index,
|
||||
@ -48,16 +60,24 @@ module.exports = grammar({
|
||||
$.math,
|
||||
$.value,
|
||||
$.yield,
|
||||
)),
|
||||
),
|
||||
),
|
||||
|
||||
_expression_list: $ => repeat1(prec.right(seq(
|
||||
_expression_list: $ =>
|
||||
repeat1(
|
||||
prec.right(
|
||||
seq(
|
||||
$.expression,
|
||||
optional(','),
|
||||
))),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
identifier: $ => /[_a-zA-Z]+[_a-zA-Z0-9]?/,
|
||||
identifier: $ =>
|
||||
/[_a-zA-Z]+[_a-zA-Z0-9]?/,
|
||||
|
||||
value: $ => choice(
|
||||
value: $ =>
|
||||
choice(
|
||||
$.integer,
|
||||
$.float,
|
||||
$.string,
|
||||
@ -68,236 +88,320 @@ module.exports = grammar({
|
||||
$.map,
|
||||
),
|
||||
|
||||
integer: $ => token(prec.left(seq(
|
||||
integer: $ =>
|
||||
token(
|
||||
prec.left(
|
||||
seq(
|
||||
optional('-'),
|
||||
repeat1(
|
||||
choice('1', '2', '3', '4', '5', '6', '7', '8', '9', '0')
|
||||
choice(
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'0',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
))),
|
||||
|
||||
float: $ => token(prec.left(seq(
|
||||
float: $ =>
|
||||
token(
|
||||
prec.left(
|
||||
seq(
|
||||
optional('-'),
|
||||
repeat1(choice('1', '2', '3', '4', '5', '6', '7', '8', '9', '0')),
|
||||
repeat1(
|
||||
choice(
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'0',
|
||||
),
|
||||
),
|
||||
'.',
|
||||
repeat1(choice('1', '2', '3', '4', '5', '6', '7', '8', '9', '0')),
|
||||
))),
|
||||
|
||||
string: $ => /("[^"]*?")|('[^']*?')|(`[^`]*?`)/,
|
||||
|
||||
boolean: $ => choice(
|
||||
'true',
|
||||
'false',
|
||||
repeat1(
|
||||
choice(
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'0',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
list: $ => seq(
|
||||
string: $ =>
|
||||
/("[^"]*?")|('[^']*?')|(`[^`]*?`)/,
|
||||
|
||||
boolean: $ =>
|
||||
choice('true', 'false'),
|
||||
|
||||
list: $ =>
|
||||
seq(
|
||||
'[',
|
||||
repeat(prec.left(seq($.expression, optional(',')))),
|
||||
repeat(
|
||||
prec.left(
|
||||
seq(
|
||||
$.expression,
|
||||
optional(','),
|
||||
),
|
||||
),
|
||||
),
|
||||
']',
|
||||
),
|
||||
|
||||
map: $ => seq(
|
||||
map: $ =>
|
||||
seq(
|
||||
'{',
|
||||
repeat(seq(
|
||||
repeat(
|
||||
seq(
|
||||
$.identifier,
|
||||
"=",
|
||||
'=',
|
||||
$.statement,
|
||||
optional(',')
|
||||
)),
|
||||
optional(','),
|
||||
),
|
||||
),
|
||||
'}',
|
||||
),
|
||||
|
||||
index: $ => prec.left(1, seq(
|
||||
index: $ =>
|
||||
prec.left(
|
||||
1,
|
||||
seq(
|
||||
$.expression,
|
||||
':',
|
||||
$.expression,
|
||||
optional(seq(
|
||||
'..',
|
||||
$.expression,
|
||||
)),
|
||||
)),
|
||||
optional(
|
||||
seq('..', $.expression),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
math: $ => prec.left(seq(
|
||||
math: $ =>
|
||||
prec.left(
|
||||
seq(
|
||||
$.expression,
|
||||
$.math_operator,
|
||||
$.expression,
|
||||
)),
|
||||
|
||||
math_operator: $ => choice(
|
||||
'+',
|
||||
'-',
|
||||
'*',
|
||||
'/',
|
||||
'%',
|
||||
),
|
||||
),
|
||||
|
||||
logic: $ => prec.right(seq(
|
||||
math_operator: $ =>
|
||||
choice('+', '-', '*', '/', '%'),
|
||||
|
||||
logic: $ =>
|
||||
prec.right(
|
||||
seq(
|
||||
$.expression,
|
||||
$.logic_operator,
|
||||
$.expression,
|
||||
)),
|
||||
),
|
||||
),
|
||||
|
||||
logic_operator: $ => choice(
|
||||
logic_operator: $ =>
|
||||
choice(
|
||||
'==',
|
||||
'!=',
|
||||
'&&',
|
||||
'||',
|
||||
'>',
|
||||
'<',
|
||||
">=",
|
||||
"<=",
|
||||
'>=',
|
||||
'<=',
|
||||
),
|
||||
|
||||
assignment: $ => seq(
|
||||
field('identifier', $.identifier),
|
||||
optional(field('type', $.type)),
|
||||
field('assignment_operator', $.assignment_operator),
|
||||
assignment: $ =>
|
||||
seq(
|
||||
field(
|
||||
'identifier',
|
||||
$.identifier,
|
||||
),
|
||||
optional(
|
||||
field(
|
||||
'type',
|
||||
$.type_definition,
|
||||
),
|
||||
),
|
||||
field(
|
||||
'assignment_operator',
|
||||
$.assignment_operator,
|
||||
),
|
||||
field('statement', $.statement),
|
||||
),
|
||||
|
||||
index_assignment: $ => seq(
|
||||
index_assignment: $ =>
|
||||
seq(
|
||||
$.index,
|
||||
$.assignment_operator,
|
||||
$.statement,
|
||||
),
|
||||
|
||||
assignment_operator: $ => prec.right(choice(
|
||||
"=",
|
||||
"+=",
|
||||
"-=",
|
||||
)),
|
||||
assignment_operator: $ =>
|
||||
prec.right(
|
||||
choice('=', '+=', '-='),
|
||||
),
|
||||
|
||||
if_else: $ => prec.right(seq(
|
||||
if_else: $ =>
|
||||
prec.right(
|
||||
seq(
|
||||
$.if,
|
||||
repeat($.else_if),
|
||||
optional($.else),
|
||||
)),
|
||||
|
||||
if: $ => seq(
|
||||
'if',
|
||||
$.expression,
|
||||
$.block,
|
||||
),
|
||||
),
|
||||
|
||||
else_if: $ => seq(
|
||||
if: $ =>
|
||||
seq('if', $.expression, $.block),
|
||||
|
||||
else_if: $ =>
|
||||
seq(
|
||||
'else if',
|
||||
$.expression,
|
||||
$.block,
|
||||
),
|
||||
|
||||
else: $ => seq(
|
||||
'else',
|
||||
$.block,
|
||||
),
|
||||
else: $ => seq('else', $.block),
|
||||
|
||||
match: $ => prec.right(seq(
|
||||
match: $ =>
|
||||
prec.right(
|
||||
seq(
|
||||
'match',
|
||||
$.expression,
|
||||
repeat1(seq(
|
||||
repeat1(
|
||||
seq(
|
||||
$.expression,
|
||||
'=>',
|
||||
$.block,
|
||||
)),
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
while: $ => seq(
|
||||
while: $ =>
|
||||
seq(
|
||||
'while',
|
||||
$.expression,
|
||||
$.block,
|
||||
),
|
||||
|
||||
for: $ => seq(
|
||||
choice(
|
||||
'for',
|
||||
'async for',
|
||||
),
|
||||
for: $ =>
|
||||
seq(
|
||||
choice('for', 'async for'),
|
||||
$.identifier,
|
||||
'in',
|
||||
$.expression,
|
||||
$.block,
|
||||
),
|
||||
|
||||
select: $ => prec.right(seq(
|
||||
'select',
|
||||
$.identifier_list,
|
||||
'from',
|
||||
$.expression,
|
||||
optional($.block),
|
||||
)),
|
||||
|
||||
insert: $ => prec.right(seq(
|
||||
'insert',
|
||||
'into',
|
||||
$.identifier,
|
||||
$.expression,
|
||||
)),
|
||||
|
||||
identifier_list: $ => prec.right(choice(
|
||||
identifier_list: $ =>
|
||||
prec.right(
|
||||
choice(
|
||||
seq(
|
||||
'|',
|
||||
repeat(seq($.identifier, optional(','))),
|
||||
repeat(
|
||||
seq(
|
||||
$.identifier,
|
||||
optional(','),
|
||||
),
|
||||
),
|
||||
'|',
|
||||
),
|
||||
)),
|
||||
),
|
||||
),
|
||||
|
||||
table: $ => prec.right(seq(
|
||||
table: $ =>
|
||||
prec.right(
|
||||
seq(
|
||||
'table',
|
||||
$.identifier_list,
|
||||
$.expression,
|
||||
)),
|
||||
|
||||
return: $ => seq(
|
||||
'return',
|
||||
$.expression,
|
||||
),
|
||||
),
|
||||
|
||||
use: $ => seq(
|
||||
'use',
|
||||
$.string,
|
||||
),
|
||||
return: $ =>
|
||||
seq('return', $.expression),
|
||||
|
||||
type: $ => seq(
|
||||
'<',
|
||||
use: $ => seq('use', $.string),
|
||||
|
||||
type_definition: $ =>
|
||||
seq('<', $.type, '>'),
|
||||
|
||||
type: $ =>
|
||||
prec.right(
|
||||
choice(
|
||||
'any',
|
||||
'bool',
|
||||
seq(
|
||||
'fn',
|
||||
'int',
|
||||
'list',
|
||||
'map',
|
||||
'str',
|
||||
'table',
|
||||
),
|
||||
'>',
|
||||
),
|
||||
|
||||
function: $ => seq(
|
||||
'|',
|
||||
repeat($.parameter),
|
||||
'|',
|
||||
optional($.type),
|
||||
$.block,
|
||||
),
|
||||
|
||||
parameter: $ => seq(
|
||||
$.identifier,
|
||||
repeat(
|
||||
seq(
|
||||
$.type,
|
||||
optional(','),
|
||||
),
|
||||
),
|
||||
optional(seq('->', $.type)),
|
||||
),
|
||||
'int',
|
||||
seq('list', $.type),
|
||||
'map',
|
||||
'num',
|
||||
'str',
|
||||
),
|
||||
),
|
||||
|
||||
function_call: $ => prec.right(1, seq(
|
||||
function: $ =>
|
||||
seq(
|
||||
'|',
|
||||
repeat(
|
||||
seq(
|
||||
$.identifier,
|
||||
optional(','),
|
||||
),
|
||||
),
|
||||
'|',
|
||||
$.block,
|
||||
),
|
||||
|
||||
function_call: $ =>
|
||||
prec.right(
|
||||
1,
|
||||
seq(
|
||||
'(',
|
||||
$.expression,
|
||||
optional($._expression_list),
|
||||
')',
|
||||
)),
|
||||
),
|
||||
),
|
||||
|
||||
yield: $ => prec.left(seq(
|
||||
yield: $ =>
|
||||
prec.left(
|
||||
seq(
|
||||
$.expression,
|
||||
'->',
|
||||
'(',
|
||||
$.expression,
|
||||
optional($._expression_list),
|
||||
')',
|
||||
)),
|
||||
}
|
||||
),
|
||||
),
|
||||
},
|
||||
});
|
||||
|
407
tree-sitter-dust/grammar.js.new
Normal file
407
tree-sitter-dust/grammar.js.new
Normal file
@ -0,0 +1,407 @@
|
||||
module.exports = grammar({
|
||||
name: "dust",
|
||||
|
||||
word: $ => $.identifier,
|
||||
|
||||
extras: $ => [/\s/, $._comment],
|
||||
|
||||
rules: {
|
||||
root: $ =>
|
||||
prec(1, repeat1($.statement)),
|
||||
|
||||
_comment: $ => /[#][^#\n]*[#|\n]/,
|
||||
|
||||
block: $ =>
|
||||
seq(
|
||||
optional("async"),
|
||||
"{",
|
||||
repeat1($.statement),
|
||||
"}",
|
||||
),
|
||||
|
||||
statement: $ =>
|
||||
prec.left(
|
||||
seq(
|
||||
choice(
|
||||
$.assignment,
|
||||
$.block,
|
||||
$.expression,
|
||||
$.for,
|
||||
$.if_else,
|
||||
$.index_assignment,
|
||||
$.match,
|
||||
$.return,
|
||||
$.use,
|
||||
$.while,
|
||||
),
|
||||
optional(";"),
|
||||
),
|
||||
),
|
||||
|
||||
expression: $ =>
|
||||
prec.right(
|
||||
choice(
|
||||
$._expression_kind,
|
||||
seq(
|
||||
"(",
|
||||
$._expression_kind,
|
||||
")",
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
_expression_kind: $ =>
|
||||
prec.right(
|
||||
choice(
|
||||
$.function_call,
|
||||
$.identifier,
|
||||
$.index,
|
||||
$.logic,
|
||||
$.math,
|
||||
$.value,
|
||||
$.yield,
|
||||
),
|
||||
),
|
||||
|
||||
_expression_list: $ =>
|
||||
repeat1(
|
||||
prec.right(
|
||||
seq(
|
||||
$.expression,
|
||||
optional(","),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
identifier: $ =>
|
||||
/[_a-zA-Z]+[_a-zA-Z0-9]?/,
|
||||
|
||||
value: $ =>
|
||||
choice(
|
||||
$.integer,
|
||||
$.float,
|
||||
$.string,
|
||||
$.boolean,
|
||||
$.list,
|
||||
$.function,
|
||||
$.table,
|
||||
$.map,
|
||||
),
|
||||
|
||||
integer: $ =>
|
||||
token(
|
||||
prec.left(
|
||||
seq(
|
||||
optional("-"),
|
||||
repeat1(
|
||||
choice(
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"0",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
float: $ =>
|
||||
token(
|
||||
prec.left(
|
||||
seq(
|
||||
optional("-"),
|
||||
repeat1(
|
||||
choice(
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"0",
|
||||
),
|
||||
),
|
||||
".",
|
||||
repeat1(
|
||||
choice(
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"0",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
string: $ =>
|
||||
/("[^"]*?")|('[^']*?')|(`[^`]*?`)/,
|
||||
|
||||
boolean: $ =>
|
||||
choice("true", "false"),
|
||||
|
||||
list: $ =>
|
||||
seq(
|
||||
"[",
|
||||
repeat(
|
||||
prec.left(
|
||||
seq(
|
||||
$.expression,
|
||||
optional(","),
|
||||
),
|
||||
),
|
||||
),
|
||||
"]",
|
||||
),
|
||||
|
||||
map: $ =>
|
||||
seq(
|
||||
"{",
|
||||
repeat(
|
||||
seq(
|
||||
$.identifier,
|
||||
"=",
|
||||
$.statement,
|
||||
optional(","),
|
||||
),
|
||||
),
|
||||
"}",
|
||||
),
|
||||
|
||||
index: $ =>
|
||||
prec.left(
|
||||
1,
|
||||
seq(
|
||||
$.expression,
|
||||
":",
|
||||
$.expression,
|
||||
optional(
|
||||
seq("..", $.expression),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
math: $ =>
|
||||
prec.left(
|
||||
seq(
|
||||
$.expression,
|
||||
$.math_operator,
|
||||
$.expression,
|
||||
),
|
||||
),
|
||||
|
||||
math_operator: $ =>
|
||||
choice("+", "-", "*", "/", "%"),
|
||||
|
||||
logic: $ =>
|
||||
prec.right(
|
||||
seq(
|
||||
$.expression,
|
||||
$.logic_operator,
|
||||
$.expression,
|
||||
),
|
||||
),
|
||||
|
||||
logic_operator: $ =>
|
||||
choice(
|
||||
"==",
|
||||
"!=",
|
||||
"&&",
|
||||
"||",
|
||||
">",
|
||||
"<",
|
||||
">=",
|
||||
"<=",
|
||||
),
|
||||
|
||||
assignment: $ =>
|
||||
seq(
|
||||
field(
|
||||
"identifier",
|
||||
$.identifier,
|
||||
),
|
||||
optional(
|
||||
field(
|
||||
"type",
|
||||
$.type_definition,
|
||||
),
|
||||
),
|
||||
field(
|
||||
"assignment_operator",
|
||||
$.assignment_operator,
|
||||
),
|
||||
field("statement", $.statement),
|
||||
),
|
||||
|
||||
index_assignment: $ =>
|
||||
seq(
|
||||
$.index,
|
||||
$.assignment_operator,
|
||||
$.statement,
|
||||
),
|
||||
|
||||
assignment_operator: $ =>
|
||||
prec.right(
|
||||
choice("=", "+=", "-="),
|
||||
),
|
||||
|
||||
if_else: $ =>
|
||||
prec.right(
|
||||
seq(
|
||||
$.if,
|
||||
repeat($.else_if),
|
||||
optional($.else),
|
||||
),
|
||||
),
|
||||
|
||||
if: $ =>
|
||||
seq("if", $.expression, $.block),
|
||||
|
||||
else_if: $ =>
|
||||
seq(
|
||||
"else if",
|
||||
$.expression,
|
||||
$.block,
|
||||
),
|
||||
|
||||
else: $ => seq("else", $.block),
|
||||
|
||||
match: $ =>
|
||||
prec.right(
|
||||
seq(
|
||||
"match",
|
||||
$.expression,
|
||||
repeat1(
|
||||
seq(
|
||||
$.expression,
|
||||
"=>",
|
||||
$.block,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
while: $ =>
|
||||
seq(
|
||||
"while",
|
||||
$.expression,
|
||||
$.block,
|
||||
),
|
||||
|
||||
for: $ =>
|
||||
seq(
|
||||
choice("for", "async for"),
|
||||
$.identifier,
|
||||
"in",
|
||||
$.expression,
|
||||
$.block,
|
||||
),
|
||||
|
||||
identifier_list: $ =>
|
||||
prec.right(
|
||||
choice(
|
||||
seq(
|
||||
"|",
|
||||
repeat(
|
||||
seq(
|
||||
$.identifier,
|
||||
optional(","),
|
||||
),
|
||||
),
|
||||
"|",
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
table: $ =>
|
||||
prec.right(
|
||||
seq(
|
||||
"table",
|
||||
$.identifier_list,
|
||||
$.expression,
|
||||
),
|
||||
),
|
||||
|
||||
return: $ =>
|
||||
seq("return", $.expression),
|
||||
|
||||
use: $ => seq("use", $.string),
|
||||
|
||||
type_definition: $ =>
|
||||
seq("<", $.type, ">"),
|
||||
|
||||
type: $ =>
|
||||
prec.right(
|
||||
choice(
|
||||
"any",
|
||||
"bool",
|
||||
seq(
|
||||
"fn",
|
||||
repeat(
|
||||
seq(
|
||||
$.type,
|
||||
optional(","),
|
||||
),
|
||||
),
|
||||
optional(seq("->", $.type)),
|
||||
),
|
||||
"int",
|
||||
seq("list", $.type),
|
||||
"map",
|
||||
"num",
|
||||
"str",
|
||||
),
|
||||
),
|
||||
|
||||
function: $ =>
|
||||
seq(
|
||||
"|",
|
||||
repeat(
|
||||
seq(
|
||||
$.identifier,
|
||||
optional(","),
|
||||
),
|
||||
),
|
||||
"|",
|
||||
$.block,
|
||||
),
|
||||
|
||||
function_call: $ =>
|
||||
prec.right(
|
||||
1,
|
||||
seq(
|
||||
"(",
|
||||
$.expression,
|
||||
optional($._expression_list),
|
||||
")",
|
||||
),
|
||||
),
|
||||
|
||||
yield: $ =>
|
||||
prec.left(
|
||||
seq(
|
||||
$.expression,
|
||||
"->",
|
||||
"(",
|
||||
$.expression,
|
||||
optional($._expression_list),
|
||||
")",
|
||||
),
|
||||
),
|
||||
},
|
||||
});
|
18
tree-sitter-dust/package-lock.json
generated
18
tree-sitter-dust/package-lock.json
generated
@ -7,11 +7,12 @@
|
||||
"": {
|
||||
"name": "tree-sitter-dust",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nan": "^2.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "3.1.0",
|
||||
"tree-sitter-cli": "^0.20.8"
|
||||
}
|
||||
},
|
||||
@ -20,6 +21,21 @@
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz",
|
||||
"integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w=="
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz",
|
||||
"integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/tree-sitter-cli": {
|
||||
"version": "0.20.8",
|
||||
"resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.20.8.tgz",
|
||||
|
@ -18,6 +18,7 @@
|
||||
"nan": "^2.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "3.1.0",
|
||||
"tree-sitter-cli": "^0.20.8"
|
||||
},
|
||||
"main": "bindings/node"
|
||||
|
@ -82,10 +82,6 @@
|
||||
"type": "SYMBOL",
|
||||
"name": "index_assignment"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "insert"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "match"
|
||||
@ -94,10 +90,6 @@
|
||||
"type": "SYMBOL",
|
||||
"name": "return"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "select"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "use"
|
||||
@ -723,7 +715,7 @@
|
||||
"name": "type",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "type"
|
||||
"name": "type_definition"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -954,68 +946,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"select": {
|
||||
"type": "PREC_RIGHT",
|
||||
"value": 0,
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "select"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier_list"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "from"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "expression"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "block"
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"insert": {
|
||||
"type": "PREC_RIGHT",
|
||||
"value": 0,
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "insert"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "into"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "expression"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"identifier_list": {
|
||||
"type": "PREC_RIGHT",
|
||||
"value": 0,
|
||||
@ -1109,7 +1039,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type_definition": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
@ -1117,6 +1047,19 @@
|
||||
"value": "<"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ">"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "PREC_RIGHT",
|
||||
"value": 0,
|
||||
"content": {
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
@ -1127,37 +1070,74 @@
|
||||
"type": "STRING",
|
||||
"value": "bool"
|
||||
},
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "fn"
|
||||
},
|
||||
{
|
||||
"type": "REPEAT",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "type"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "->"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "int"
|
||||
},
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "list"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "map"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "num"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "str"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "table"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ">"
|
||||
}
|
||||
]
|
||||
},
|
||||
"function": {
|
||||
"type": "SEQ",
|
||||
@ -1169,43 +1149,12 @@
|
||||
{
|
||||
"type": "REPEAT",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "parameter"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "|"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type"
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "block"
|
||||
}
|
||||
]
|
||||
},
|
||||
"parameter": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
@ -1219,6 +1168,17 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "|"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "block"
|
||||
}
|
||||
]
|
||||
},
|
||||
"function_call": {
|
||||
"type": "PREC_RIGHT",
|
||||
|
@ -38,7 +38,7 @@
|
||||
"required": false,
|
||||
"types": [
|
||||
{
|
||||
"type": "type",
|
||||
"type": "type_definition",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
@ -179,11 +179,7 @@
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "parameter",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "type",
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
@ -299,25 +295,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "insert",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"named": true,
|
||||
@ -419,25 +396,6 @@
|
||||
"named": true,
|
||||
"fields": {}
|
||||
},
|
||||
{
|
||||
"type": "parameter",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "type",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "return",
|
||||
"named": true,
|
||||
@ -468,29 +426,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "block",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "identifier_list",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "statement",
|
||||
"named": true,
|
||||
@ -523,10 +458,6 @@
|
||||
"type": "index_assignment",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "insert",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "match",
|
||||
"named": true
|
||||
@ -535,10 +466,6 @@
|
||||
"type": "return",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "use",
|
||||
"named": true
|
||||
@ -572,7 +499,32 @@
|
||||
{
|
||||
"type": "type",
|
||||
"named": true,
|
||||
"fields": {}
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": false,
|
||||
"types": [
|
||||
{
|
||||
"type": "type",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "type_definition",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "type",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "use",
|
||||
@ -806,10 +758,6 @@
|
||||
"type": "for",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "from",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
@ -822,10 +770,6 @@
|
||||
"type": "in",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "insert",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "int",
|
||||
"named": false
|
||||
@ -834,10 +778,6 @@
|
||||
"type": "integer",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "into",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"named": false
|
||||
@ -851,11 +791,11 @@
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "return",
|
||||
"type": "num",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"type": "return",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,14 +0,0 @@
|
||||
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|
||||
|:---|---:|---:|---:|---:|
|
||||
| `dust -c '(length (from_json input))' -p seaCreatures.json` | 2.9 ± 0.4 | 2.5 | 6.7 | 1.00 |
|
||||
| `jq 'length' seaCreatures.json` | 36.7 ± 4.4 | 34.7 | 65.0 | 12.59 ± 2.14 |
|
||||
| `node --eval "require('node:fs').readFile('seaCreatures.json', (err, data)=>{console.log(JSON.parse(data).length)})"` | 241.2 ± 13.3 | 227.7 | 273.2 | 82.63 ± 11.00 |
|
||||
| `nu -c 'open seaCreatures.json \| length'` | 54.0 ± 3.3 | 50.3 | 69.2 | 18.49 ± 2.51 |
|
||||
| `dust -c '(length (from_json input))' -p jq_data.json` | 7.9 ± 0.8 | 6.6 | 12.5 | 2.70 ± 0.43 |
|
||||
| `jq 'length' jq_data.json` | 44.8 ± 0.6 | 43.5 | 47.3 | 15.36 ± 1.87 |
|
||||
| `node --eval "require('node:fs').readFile('jq_data.json', (err, data)=>{console.log(JSON.parse(data).length)})"` | 245.2 ± 7.1 | 235.4 | 259.7 | 84.00 ± 10.46 |
|
||||
| `nu -c 'open jq_data.json \| length'` | 65.9 ± 5.0 | 62.0 | 90.5 | 22.57 ± 3.22 |
|
||||
| `dust -c '(length (from_json input))' -p dielectron.json` | 1079.5 ± 22.7 | 1043.8 | 1121.5 | 369.86 ± 45.46 |
|
||||
| `jq 'length' dielectron.json` | 1365.0 ± 20.3 | 1318.5 | 1400.1 | 467.67 ± 57.07 |
|
||||
| `node --eval "require('node:fs').readFile('dielectron.json', (err, data)=>{console.log(JSON.parse(data).length)})"` | 1910.8 ± 47.9 | 1855.9 | 1985.7 | 654.66 ± 80.97 |
|
||||
| `nu -c 'open dielectron.json \| length'` | 2001.2 ± 65.1 | 1923.2 | 2112.7 | 685.65 ± 85.98 |
|
Loading…
Reference in New Issue
Block a user