Implement type system; Modify use; Write docs
This commit is contained in:
parent
984b66b0aa
commit
b064d23719
@ -4,6 +4,7 @@ use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Block, Error, Expression, Identifier, Map, Result, Type, Value};
|
||||
|
||||
/// Abstract representation of a for loop statement.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct For {
|
||||
is_async: bool,
|
||||
|
@ -3,6 +3,10 @@ use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Map, Result, Type, Value, BUILT_IN_FUNCTIONS};
|
||||
|
||||
/// A string by which a variable is known to a context.
|
||||
///
|
||||
/// Every variable is a key-value pair. An identifier holds the key part of that
|
||||
/// pair. Its inner value can be used to retrieve a Value instance from a Map.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Identifier(String);
|
||||
|
||||
|
@ -6,21 +6,97 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Map, Result, Type, Value};
|
||||
use crate::{AbstractTree, Error, Expression, Map, Result, Statement, Type, Value};
|
||||
|
||||
/// Abstract representation of a match statement.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Match {}
|
||||
pub struct Match {
|
||||
matcher: Expression,
|
||||
options: Vec<(Expression, Statement)>,
|
||||
}
|
||||
|
||||
impl AbstractTree for Match {
|
||||
fn from_syntax_node(_source: &str, _node: Node, _context: &Map) -> Result<Self> {
|
||||
todo!()
|
||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
||||
Error::expect_syntax_node(source, "match", node)?;
|
||||
|
||||
let matcher_node = node.child(1).unwrap();
|
||||
let matcher = Expression::from_syntax_node(source, matcher_node, context)?;
|
||||
|
||||
let mut options = Vec::new();
|
||||
let mut previous_expression = None;
|
||||
|
||||
for index in 2..node.child_count() {
|
||||
let child = node.child(index).unwrap();
|
||||
|
||||
if child.kind() == "expression" {
|
||||
previous_expression = Some(Expression::from_syntax_node(source, child, context)?);
|
||||
}
|
||||
|
||||
if child.kind() == "statement" {
|
||||
if let Some(expression) = &previous_expression {
|
||||
let statement = Statement::from_syntax_node(source, child, context)?;
|
||||
|
||||
options.push((expression.clone(), statement));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Match { matcher, options })
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||
todo!()
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
let matcher_value = self.matcher.run(source, context)?;
|
||||
|
||||
for (expression, statement) in &self.options {
|
||||
let option_value = expression.run(source, context)?;
|
||||
|
||||
if matcher_value == option_value {
|
||||
return statement.run(source, context);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::Empty)
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{evaluate, Value};
|
||||
|
||||
#[test]
|
||||
fn evaluate_match() {
|
||||
let test = evaluate(
|
||||
"
|
||||
match 1 {
|
||||
3 => false
|
||||
2 => { false }
|
||||
1 => true
|
||||
}
|
||||
",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(Value::Boolean(true), test);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn evaluate_match_assignment() {
|
||||
let test = evaluate(
|
||||
"
|
||||
x = match 1 {
|
||||
3 => false
|
||||
2 => { false }
|
||||
1 => true
|
||||
}
|
||||
x
|
||||
",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(Value::Boolean(true), test);
|
||||
}
|
||||
}
|
||||
|
@ -34,32 +34,39 @@ impl AbstractTree for Statement {
|
||||
"return" => {
|
||||
let expression_node = child.child(1).unwrap();
|
||||
|
||||
Ok(Statement::Return(Expression::from_syntax_node(source, expression_node, context)?))
|
||||
},
|
||||
Ok(Statement::Return(Expression::from_syntax_node(
|
||||
source,
|
||||
expression_node,
|
||||
context,
|
||||
)?))
|
||||
}
|
||||
"expression" => Ok(Statement::Expression(Expression::from_syntax_node(
|
||||
source, child, context
|
||||
source, child, context,
|
||||
)?)),
|
||||
"if_else" => Ok(Statement::IfElse(Box::new(IfElse::from_syntax_node(
|
||||
source, child, context
|
||||
)?))),
|
||||
"tool" => Ok(Statement::IfElse(Box::new(IfElse::from_syntax_node(
|
||||
source, child, context
|
||||
source, child, context,
|
||||
)?))),
|
||||
"while" => Ok(Statement::While(Box::new(While::from_syntax_node(
|
||||
source, child, context
|
||||
source, child, context,
|
||||
)?))),
|
||||
"block" => Ok(Statement::Block(Box::new(Block::from_syntax_node(
|
||||
source, child, context
|
||||
source, child, context,
|
||||
)?))),
|
||||
"for" => Ok(Statement::For(Box::new(For::from_syntax_node(
|
||||
source, child, context
|
||||
)?))),
|
||||
"use" => Ok(Statement::Use(Use::from_syntax_node(source, child, context)?)),
|
||||
"index_assignment" => Ok(Statement::IndexAssignment(Box::new(IndexAssignment::from_syntax_node(
|
||||
source, child, context
|
||||
source, child, context,
|
||||
)?))),
|
||||
"use" => Ok(Statement::Use(Use::from_syntax_node(
|
||||
source, child, context,
|
||||
)?)),
|
||||
"index_assignment" => Ok(Statement::IndexAssignment(Box::new(
|
||||
IndexAssignment::from_syntax_node(source, child, context)?,
|
||||
))),
|
||||
"match" => Ok(Statement::Match(Match::from_syntax_node(
|
||||
source, child, context,
|
||||
)?)),
|
||||
_ => Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "assignment, expression, if...else, while, for, transform, filter, tool, async, find, remove, select, insert, index_assignment or yield",
|
||||
expected:
|
||||
"assignment, expression, block, return, if...else, while, for, index_assignment or match",
|
||||
actual: child.kind(),
|
||||
location: child.start_position(),
|
||||
relevant_source: source[child.byte_range()].to_string(),
|
||||
|
@ -5,6 +5,11 @@ use tree_sitter::Node;
|
||||
|
||||
use crate::{evaluate_with_context, AbstractTree, Error, Map, Result, Type, Value};
|
||||
|
||||
/// Abstract representation of a use statement.
|
||||
///
|
||||
/// Use will evaluate the Dust file at the given path. It will create an empty
|
||||
/// context to do so, then apply every value from that context to the current
|
||||
/// context.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Use {
|
||||
path: String,
|
||||
@ -20,12 +25,16 @@ impl AbstractTree for Use {
|
||||
Ok(Use { path })
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, _context: &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();
|
||||
|
||||
evaluate_with_context(&file_contents, &mut file_context)?;
|
||||
|
||||
for (key, value) in file_context.variables()?.iter() {
|
||||
context.variables_mut()?.insert(key.clone(), value.clone());
|
||||
}
|
||||
|
||||
Ok(Value::Map(file_context))
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
/// Built-in functions that are available to all Dust programs.
|
||||
use crate::{Map, Result, Type, Value};
|
||||
|
||||
mod assert;
|
||||
@ -9,7 +10,11 @@ mod output;
|
||||
mod random;
|
||||
mod r#type;
|
||||
|
||||
pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 14] = [
|
||||
/// All built-in functions recognized by the interpreter.
|
||||
///
|
||||
/// This is the public interface to access built-in functions by iterating over
|
||||
/// the references it holds.
|
||||
pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 15] = [
|
||||
&assert::Assert,
|
||||
&assert::AssertEqual,
|
||||
&collections::Length,
|
||||
@ -18,6 +23,7 @@ pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 14] = [
|
||||
&fs::Read,
|
||||
&fs::Write,
|
||||
&fs::Append,
|
||||
&network::Download,
|
||||
&output::Output,
|
||||
&random::Random,
|
||||
&random::RandomBoolean,
|
||||
|
34
tree-sitter-dust/corpus/match.txt
Normal file
34
tree-sitter-dust/corpus/match.txt
Normal file
@ -0,0 +1,34 @@
|
||||
================================================================================
|
||||
Match Values
|
||||
================================================================================
|
||||
|
||||
match x {
|
||||
1 => {
|
||||
true
|
||||
}
|
||||
2 => false
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(match
|
||||
(expression
|
||||
(identifier))
|
||||
(expression
|
||||
(value
|
||||
(integer)))
|
||||
(statement
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
(value
|
||||
(boolean))))))
|
||||
(expression
|
||||
(value
|
||||
(integer)))
|
||||
(statement
|
||||
(expression
|
||||
(value
|
||||
(boolean)))))))
|
@ -282,13 +282,15 @@ module.exports = grammar({
|
||||
seq(
|
||||
'match',
|
||||
$.expression,
|
||||
'{',
|
||||
repeat1(
|
||||
seq(
|
||||
$.expression,
|
||||
'=>',
|
||||
$.block,
|
||||
$.statement,
|
||||
),
|
||||
),
|
||||
'}',
|
||||
),
|
||||
),
|
||||
|
||||
|
@ -886,6 +886,10 @@
|
||||
"type": "SYMBOL",
|
||||
"name": "expression"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "{"
|
||||
},
|
||||
{
|
||||
"type": "REPEAT1",
|
||||
"content": {
|
||||
@ -901,10 +905,14 @@
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "block"
|
||||
"name": "statement"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "}"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -328,11 +328,11 @@
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "block",
|
||||
"type": "expression",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"type": "statement",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user