Implement type system; Modify use; Write docs

This commit is contained in:
Jeff 2023-12-06 13:48:38 -05:00
parent 984b66b0aa
commit b064d23719
11 changed files with 8865 additions and 8493 deletions

View File

@ -4,6 +4,7 @@ use tree_sitter::Node;
use crate::{AbstractTree, Block, Error, Expression, Identifier, Map, Result, Type, Value}; 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)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct For { pub struct For {
is_async: bool, is_async: bool,

View File

@ -3,6 +3,10 @@ use tree_sitter::Node;
use crate::{AbstractTree, Error, Map, Result, Type, Value, BUILT_IN_FUNCTIONS}; 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)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Identifier(String); pub struct Identifier(String);

View File

@ -6,21 +6,97 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; 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)] #[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 { impl AbstractTree for Match {
fn from_syntax_node(_source: &str, _node: Node, _context: &Map) -> Result<Self> { fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
todo!() 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)?);
} }
fn run(&self, _source: &str, _context: &Map) -> Result<Value> { if child.kind() == "statement" {
todo!() 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> {
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> { fn expected_type(&self, _context: &Map) -> Result<Type> {
todo!() 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);
}
}

View File

@ -34,32 +34,39 @@ impl AbstractTree for Statement {
"return" => { "return" => {
let expression_node = child.child(1).unwrap(); 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( "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( "if_else" => Ok(Statement::IfElse(Box::new(IfElse::from_syntax_node(
source, child, context source, child, context,
)?))),
"tool" => Ok(Statement::IfElse(Box::new(IfElse::from_syntax_node(
source, child, context
)?))), )?))),
"while" => Ok(Statement::While(Box::new(While::from_syntax_node( "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( "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( "for" => Ok(Statement::For(Box::new(For::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
)?))), )?))),
"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 { _ => 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(), actual: child.kind(),
location: child.start_position(), location: child.start_position(),
relevant_source: source[child.byte_range()].to_string(), relevant_source: source[child.byte_range()].to_string(),

View File

@ -5,6 +5,11 @@ use tree_sitter::Node;
use crate::{evaluate_with_context, AbstractTree, Error, Map, Result, Type, Value}; 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)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Use { pub struct Use {
path: String, path: String,
@ -20,12 +25,16 @@ impl AbstractTree for Use {
Ok(Use { path }) 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 file_contents = read_to_string(&self.path)?;
let mut file_context = Map::new(); let mut file_context = Map::new();
evaluate_with_context(&file_contents, &mut file_context)?; 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)) Ok(Value::Map(file_context))
} }

View File

@ -1,3 +1,4 @@
/// Built-in functions that are available to all Dust programs.
use crate::{Map, Result, Type, Value}; use crate::{Map, Result, Type, Value};
mod assert; mod assert;
@ -9,7 +10,11 @@ mod output;
mod random; mod random;
mod r#type; 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::Assert,
&assert::AssertEqual, &assert::AssertEqual,
&collections::Length, &collections::Length,
@ -18,6 +23,7 @@ pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 14] = [
&fs::Read, &fs::Read,
&fs::Write, &fs::Write,
&fs::Append, &fs::Append,
&network::Download,
&output::Output, &output::Output,
&random::Random, &random::Random,
&random::RandomBoolean, &random::RandomBoolean,

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

View File

@ -282,13 +282,15 @@ module.exports = grammar({
seq( seq(
'match', 'match',
$.expression, $.expression,
'{',
repeat1( repeat1(
seq( seq(
$.expression, $.expression,
'=>', '=>',
$.block, $.statement,
), ),
), ),
'}',
), ),
), ),

View File

@ -886,6 +886,10 @@
"type": "SYMBOL", "type": "SYMBOL",
"name": "expression" "name": "expression"
}, },
{
"type": "STRING",
"value": "{"
},
{ {
"type": "REPEAT1", "type": "REPEAT1",
"content": { "content": {
@ -901,10 +905,14 @@
}, },
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "block" "name": "statement"
} }
] ]
} }
},
{
"type": "STRING",
"value": "}"
} }
] ]
} }

View File

@ -328,11 +328,11 @@
"required": true, "required": true,
"types": [ "types": [
{ {
"type": "block", "type": "expression",
"named": true "named": true
}, },
{ {
"type": "expression", "type": "statement",
"named": true "named": true
} }
] ]

File diff suppressed because it is too large Load Diff