diff --git a/dust-lang/src/abstract_tree.rs b/dust-lang/src/abstract_tree.rs new file mode 100644 index 0000000..c9e35c9 --- /dev/null +++ b/dust-lang/src/abstract_tree.rs @@ -0,0 +1,28 @@ +use crate::{Identifier, Span, Value}; + +#[derive(Debug, PartialEq, Clone)] +pub struct Node { + pub operation: Statement, + pub span: Span, +} + +impl Node { + pub fn new(operation: Statement, span: Span) -> Self { + Self { operation, span } + } +} + +#[derive(Debug, PartialEq, Clone)] +pub enum Statement { + // Top-level statements + Assign(Box<(Node, Node)>), + + // Expressions + Add(Box<(Node, Node)>), + List(Vec), + Multiply(Box<(Node, Node)>), + + // Hard-coded values + Constant(Value), + Identifier(Identifier), +} diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs new file mode 100644 index 0000000..26d1659 --- /dev/null +++ b/dust-lang/src/analyzer.rs @@ -0,0 +1,85 @@ +use crate::{Node, Span, Statement}; + +pub struct Analyzer { + abstract_tree: Vec, +} + +impl Analyzer { + pub fn new(abstract_tree: Vec) -> Self { + Analyzer { abstract_tree } + } + + pub fn analyze(&self) -> Result<(), AnalyzerError> { + for node in &self.abstract_tree { + self.analyze_node(node)?; + } + + Ok(()) + } + + fn analyze_node(&self, node: &Node) -> Result<(), AnalyzerError> { + match &node.operation { + Statement::Add(instructions) => { + self.analyze_node(&instructions.0)?; + self.analyze_node(&instructions.1)?; + } + Statement::Assign(instructions) => { + if let Statement::Identifier(_) = &instructions.0.operation { + // Identifier + } else { + return Err(AnalyzerError::ExpectedIdentifier { + actual: instructions.0.clone(), + }); + } + + self.analyze_node(&instructions.0)?; + self.analyze_node(&instructions.1)?; + } + Statement::Constant(_) => {} + Statement::Identifier(_) => {} + Statement::List(instructions) => { + for instruction in instructions { + self.analyze_node(instruction)?; + } + } + Statement::Multiply(instructions) => { + self.analyze_node(&instructions.0)?; + self.analyze_node(&instructions.1)?; + } + } + + Ok(()) + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum AnalyzerError { + ExpectedIdentifier { actual: Node }, +} + +#[cfg(test)] +mod tests { + use crate::Value; + + use super::*; + + #[test] + fn analyze() { + let abstract_tree = vec![Node::new( + Statement::Assign(Box::new(( + Node::new(Statement::Constant(Value::integer(1)), (0, 1)), + Node::new(Statement::Constant(Value::integer(2)), (1, 2)), + ))), + (0, 1), + )]; + + let analyzer = Analyzer::new(abstract_tree); + + assert_eq!( + analyzer.analyze(), + Err(AnalyzerError::ExpectedIdentifier { + actual: Node::new(Statement::Constant(Value::integer(1)), (0, 1)) + }) + ) + } +} diff --git a/dust-lang/src/instruction.rs b/dust-lang/src/instruction.rs deleted file mode 100644 index bb683f6..0000000 --- a/dust-lang/src/instruction.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::{Identifier, Span, Value}; - -#[derive(Debug, PartialEq, Clone)] -pub struct Instruction { - pub operation: Operation, - pub span: Span, -} - -impl Instruction { - pub fn new(operation: Operation, span: Span) -> Self { - Self { operation, span } - } -} - -#[derive(Debug, PartialEq, Clone)] -pub enum Operation { - Add(Box<(Instruction, Instruction)>), - Assign(Box<(Instruction, Instruction)>), - Constant(Value), - Identifier(Identifier), - List(Vec), - Multiply(Box<(Instruction, Instruction)>), -} diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 06a69a3..62796ba 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -7,8 +7,9 @@ The [interpreter] module contains the `Interpreter` struct, which is used to lex interpret Dust code. The `interpret` function is a convenience function that creates a new `Interpreter` and runs the given source code. */ +pub mod abstract_tree; +pub mod analyzer; pub mod identifier; -pub mod instruction; pub mod lex; pub mod parse; pub mod token; @@ -16,8 +17,9 @@ pub mod r#type; pub mod value; pub mod vm; +pub use abstract_tree::{Node, Statement}; +pub use analyzer::Analyzer; pub use identifier::Identifier; -pub use instruction::{Instruction, Operation}; pub use lex::{lex, LexError, Lexer}; pub use parse::{parse, ParseError, Parser}; pub use r#type::Type; diff --git a/dust-lang/src/parse.rs b/dust-lang/src/parse.rs index 37ec5a1..286f75f 100644 --- a/dust-lang/src/parse.rs +++ b/dust-lang/src/parse.rs @@ -1,9 +1,9 @@ use crate::{ lex::{LexError, Lexer}, - Instruction, Operation, Span, Token, Value, + Node, Span, Statement, Token, Value, }; -pub fn parse(input: &str) -> Result, ParseError> { +pub fn parse(input: &str) -> Result, ParseError> { let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); let mut instructions = Vec::new(); @@ -34,7 +34,7 @@ impl<'src> Parser<'src> { Parser { lexer, current } } - pub fn parse(&mut self) -> Result { + pub fn parse(&mut self) -> Result { self.parse_instruction(0) } @@ -44,7 +44,7 @@ impl<'src> Parser<'src> { Ok(()) } - fn parse_instruction(&mut self, precedence: u8) -> Result { + fn parse_instruction(&mut self, precedence: u8) -> Result { let left_instruction = self.parse_primary()?; let left_start = left_instruction.span.0; @@ -56,8 +56,8 @@ impl<'src> Parser<'src> { let right_instruction = self.parse_instruction(self.current_precedence())?; let right_end = right_instruction.span.1; - return Ok(Instruction::new( - Operation::Add(Box::new((left_instruction, right_instruction))), + return Ok(Node::new( + Statement::Add(Box::new((left_instruction, right_instruction))), (left_start, right_end), )); } @@ -67,8 +67,8 @@ impl<'src> Parser<'src> { let right_instruction = self.parse_instruction(self.current_precedence())?; let right_end = right_instruction.span.1; - return Ok(Instruction::new( - Operation::Multiply(Box::new((left_instruction, right_instruction))), + return Ok(Node::new( + Statement::Multiply(Box::new((left_instruction, right_instruction))), (left_start, right_end), )); } @@ -78,8 +78,8 @@ impl<'src> Parser<'src> { let right_instruction = self.parse_instruction(self.current_precedence())?; let right_end = right_instruction.span.1; - return Ok(Instruction::new( - Operation::Assign(Box::new((left_instruction, right_instruction))), + return Ok(Node::new( + Statement::Assign(Box::new((left_instruction, right_instruction))), (left_start, right_end), )); } @@ -90,28 +90,22 @@ impl<'src> Parser<'src> { Ok(left_instruction) } - fn parse_primary(&mut self) -> Result { + fn parse_primary(&mut self) -> Result { match self.current.clone() { (Token::Float(float), span) => { self.next_token()?; - Ok(Instruction::new( - Operation::Constant(Value::float(float)), - span, - )) + Ok(Node::new(Statement::Constant(Value::float(float)), span)) } (Token::Integer(int), span) => { self.next_token()?; - Ok(Instruction::new( - Operation::Constant(Value::integer(int)), - span, - )) + Ok(Node::new(Statement::Constant(Value::integer(int)), span)) } (Token::Identifier(identifier), span) => { self.next_token()?; - Ok(Instruction::new(Operation::Identifier(identifier), span)) + Ok(Node::new(Statement::Identifier(identifier), span)) } (Token::LeftParenthesis, left_span) => { self.next_token()?; @@ -121,7 +115,7 @@ impl<'src> Parser<'src> { if let (Token::RightParenthesis, right_span) = self.current { self.next_token()?; - Ok(Instruction::new( + Ok(Node::new( instruction.operation, (left_span.0, right_span.1), )) @@ -141,8 +135,8 @@ impl<'src> Parser<'src> { if let (Token::RightSquareBrace, right_span) = self.current { self.next_token()?; - return Ok(Instruction::new( - Operation::List(instructions), + return Ok(Node::new( + Statement::List(instructions), (left_span.0, right_span.1), )); } @@ -203,29 +197,23 @@ mod tests { assert_eq!( parse(input), - Ok(vec![Instruction::new( - Operation::List(vec![ - Instruction::new(Operation::Constant(Value::integer(1)), (1, 2)), - Instruction::new( - Operation::Add(Box::new(( - Instruction::new(Operation::Constant(Value::integer(1)), (4, 5)), - Instruction::new(Operation::Constant(Value::integer(1)), (8, 9)), + Ok(vec![Node::new( + Statement::List(vec![ + Node::new(Statement::Constant(Value::integer(1)), (1, 2)), + Node::new( + Statement::Add(Box::new(( + Node::new(Statement::Constant(Value::integer(1)), (4, 5)), + Node::new(Statement::Constant(Value::integer(1)), (8, 9)), ))), (4, 9) ), - Instruction::new( - Operation::Add(Box::new(( - Instruction::new(Operation::Constant(Value::integer(2)), (11, 12)), - Instruction::new( - Operation::Multiply(Box::new(( - Instruction::new( - Operation::Constant(Value::integer(4)), - (16, 17) - ), - Instruction::new( - Operation::Constant(Value::integer(10)), - (20, 22) - ), + Node::new( + Statement::Add(Box::new(( + Node::new(Statement::Constant(Value::integer(2)), (11, 12)), + Node::new( + Statement::Multiply(Box::new(( + Node::new(Statement::Constant(Value::integer(4)), (16, 17)), + Node::new(Statement::Constant(Value::integer(10)), (20, 22)), ))), (15, 23) ), @@ -244,10 +232,10 @@ mod tests { assert_eq!( parse(input), - Ok(vec![Instruction::new( - Operation::List(vec![ - Instruction::new(Operation::Constant(Value::integer(1)), (1, 2)), - Instruction::new(Operation::Constant(Value::integer(2)), (4, 5)), + Ok(vec![Node::new( + Statement::List(vec![ + Node::new(Statement::Constant(Value::integer(1)), (1, 2)), + Node::new(Statement::Constant(Value::integer(2)), (4, 5)), ]), (0, 6) )]) @@ -260,7 +248,7 @@ mod tests { assert_eq!( parse(input), - Ok(vec![Instruction::new(Operation::List(vec![]), (0, 2))]) + Ok(vec![Node::new(Statement::List(vec![]), (0, 2))]) ); } @@ -270,8 +258,8 @@ mod tests { assert_eq!( parse(input), - Ok(vec![Instruction::new( - Operation::Constant(Value::float(42.0)), + Ok(vec![Node::new( + Statement::Constant(Value::float(42.0)), (0, 4) )]) ); @@ -283,10 +271,10 @@ mod tests { assert_eq!( parse(input), - Ok(vec![Instruction::new( - Operation::Add(Box::new(( - Instruction::new(Operation::Constant(Value::integer(1)), (0, 1)), - Instruction::new(Operation::Constant(Value::integer(2)), (4, 5)), + Ok(vec![Node::new( + Statement::Add(Box::new(( + Node::new(Statement::Constant(Value::integer(1)), (0, 1)), + Node::new(Statement::Constant(Value::integer(2)), (4, 5)), ))), (0, 5) )]) @@ -299,10 +287,10 @@ mod tests { assert_eq!( parse(input), - Ok(vec![Instruction::new( - Operation::Multiply(Box::new(( - Instruction::new(Operation::Constant(Value::integer(1)), (0, 1)), - Instruction::new(Operation::Constant(Value::integer(2)), (4, 5)), + Ok(vec![Node::new( + Statement::Multiply(Box::new(( + Node::new(Statement::Constant(Value::integer(1)), (0, 1)), + Node::new(Statement::Constant(Value::integer(2)), (4, 5)), ))), (0, 5) )]) @@ -315,13 +303,13 @@ mod tests { assert_eq!( parse(input), - Ok(vec![Instruction::new( - Operation::Add(Box::new(( - Instruction::new(Operation::Constant(Value::integer(1)), (0, 1)), - Instruction::new( - Operation::Multiply(Box::new(( - Instruction::new(Operation::Constant(Value::integer(2)), (4, 5)), - Instruction::new(Operation::Constant(Value::integer(3)), (8, 9)), + Ok(vec![Node::new( + Statement::Add(Box::new(( + Node::new(Statement::Constant(Value::integer(1)), (0, 1)), + Node::new( + Statement::Multiply(Box::new(( + Node::new(Statement::Constant(Value::integer(2)), (4, 5)), + Node::new(Statement::Constant(Value::integer(3)), (8, 9)), ))), (4, 9) ), @@ -337,22 +325,16 @@ mod tests { assert_eq!( parse(input), - Ok(vec![Instruction::new( - Operation::Assign(Box::new(( - Instruction::new(Operation::Identifier(Identifier::new("a")), (0, 1)), - Instruction::new( - Operation::Add(Box::new(( - Instruction::new(Operation::Constant(Value::integer(1)), (4, 5)), - Instruction::new( - Operation::Multiply(Box::new(( - Instruction::new( - Operation::Constant(Value::integer(2)), - (8, 9) - ), - Instruction::new( - Operation::Constant(Value::integer(3)), - (12, 13) - ), + Ok(vec![Node::new( + Statement::Assign(Box::new(( + Node::new(Statement::Identifier(Identifier::new("a")), (0, 1)), + Node::new( + Statement::Add(Box::new(( + Node::new(Statement::Constant(Value::integer(1)), (4, 5)), + Node::new( + Statement::Multiply(Box::new(( + Node::new(Statement::Constant(Value::integer(2)), (8, 9)), + Node::new(Statement::Constant(Value::integer(3)), (12, 13)), ))), (8, 13) ), diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index b0c9acc..73d182f 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -1,4 +1,4 @@ -use crate::{parse, Instruction, Operation, ParseError, Parser, Value, ValueError}; +use crate::{parse, Node, ParseError, Parser, Statement, Value, ValueError}; pub fn run(input: &str) -> Result, VmError> { let instructions = parse(input)?; @@ -8,11 +8,11 @@ pub fn run(input: &str) -> Result, VmError> { } pub struct Vm { - instructions: Vec, + instructions: Vec, } impl Vm { - pub fn new(instructions: Vec) -> Self { + pub fn new(instructions: Vec) -> Self { Vm { instructions } } @@ -26,9 +26,9 @@ impl Vm { Ok(previous_value) } - fn run_instruction(&self, instruction: &Instruction) -> Result, VmError> { + fn run_instruction(&self, instruction: &Node) -> Result, VmError> { match &instruction.operation { - Operation::Add(instructions) => { + Statement::Add(instructions) => { let left = if let Some(value) = self.run_instruction(&instructions.0)? { value } else { @@ -43,19 +43,19 @@ impl Vm { Ok(Some(sum)) } - Operation::Assign(_) => todo!(), - Operation::Constant(value) => Ok(Some(value.clone())), - Operation::Identifier(_) => todo!(), - Operation::List(_) => todo!(), - Operation::Multiply(_) => todo!(), + Statement::Assign(_) => todo!(), + Statement::Constant(value) => Ok(Some(value.clone())), + Statement::Identifier(_) => todo!(), + Statement::List(_) => todo!(), + Statement::Multiply(_) => todo!(), } } } #[derive(Clone, Debug, PartialEq)] pub enum VmError { - ExpectedValue(Operation), - InvalidOperation(Operation), + ExpectedValue(Statement), + InvalidOperation(Statement), ParseError(ParseError), ValueError(ValueError), } @@ -82,4 +82,11 @@ mod tests { assert_eq!(run(input), Ok(Some(Value::integer(3)))); } + + #[test] + fn add_multiple() { + let input = "(a + b = 1)"; + + assert_eq!(run(input), Ok(Some(Value::integer(6)))); + } }