From 7e7448fe5249b59f0d129ca8745dae52a71bdd5c Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 13 Aug 2024 13:54:16 -0400 Subject: [PATCH] Add parsing for unit struct defintions --- dust-lang/src/abstract_tree.rs | 20 +++++++++++ dust-lang/src/analyzer.rs | 1 + dust-lang/src/lib.rs | 6 ++-- dust-lang/src/parser.rs | 62 ++++++++++++++++++++++++++++------ dust-lang/src/vm.rs | 15 ++++++-- 5 files changed, 89 insertions(+), 15 deletions(-) diff --git a/dust-lang/src/abstract_tree.rs b/dust-lang/src/abstract_tree.rs index c7f212b..055a66f 100644 --- a/dust-lang/src/abstract_tree.rs +++ b/dust-lang/src/abstract_tree.rs @@ -103,6 +103,9 @@ pub enum Statement { // A statement that always returns None. Created with a semicolon, it causes the preceding // statement to return None. This is analagous to the semicolon or unit type in Rust. Nil(Box>), + + // Type definitions + StructDefinition(StructDefinition), } impl Statement { @@ -186,6 +189,7 @@ impl Statement { UnaryOperator::Negate => Some(operand.inner.expected_type(context)?), UnaryOperator::Not => Some(Type::Boolean), }, + Statement::StructDefinition(_) => None, Statement::While { .. } => None, } } @@ -391,6 +395,9 @@ impl Display for Statement { write!(f, "{operator}{operand}") } + Statement::StructDefinition(struct_definition) => { + write!(f, "{struct_definition}") + } Statement::While { condition, body } => { write!(f, "while {condition} {body}") } @@ -432,3 +439,16 @@ pub enum UnaryOperator { Negate, Not, } + +#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +pub enum StructDefinition { + Unit { name: Node }, +} + +impl Display for StructDefinition { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + StructDefinition::Unit { name } => write!(f, "struct {name}"), + } + } +} diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index 0d79a58..28856bd 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -420,6 +420,7 @@ impl<'a> Analyzer<'a> { Statement::Nil(node) => { self.analyze_statement(node)?; } + Statement::StructDefinition(_) => {} Statement::UnaryOperation { operator, operand } => { self.analyze_statement(operand)?; diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 6a83b9a..12d77bc 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -14,7 +14,9 @@ pub mod r#type; pub mod value; pub mod vm; -pub use abstract_tree::{AbstractSyntaxTree, BinaryOperator, Node, Statement, UnaryOperator}; +pub use abstract_tree::{ + AbstractSyntaxTree, BinaryOperator, Node, Statement, StructDefinition, UnaryOperator, +}; pub use analyzer::{analyze, Analyzer, AnalyzerError}; pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; pub use context::{Context, VariableData}; @@ -24,7 +26,7 @@ pub use lexer::{lex, LexError, Lexer}; pub use parser::{parse, ParseError, Parser}; pub use r#type::Type; pub use token::{Token, TokenKind, TokenOwned}; -pub use value::{Value, ValueError}; +pub use value::{Struct, Value, ValueError}; pub use vm::{run, run_with_context, Vm, VmError}; pub type Span = (usize, usize); diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 87e1f21..6c7ad98 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -13,7 +13,7 @@ use std::{ use crate::{ AbstractSyntaxTree, BinaryOperator, BuiltInFunction, DustError, Identifier, LexError, Lexer, - Node, Span, Statement, Token, TokenKind, TokenOwned, UnaryOperator, Value, + Node, Span, Statement, StructDefinition, Token, TokenKind, TokenOwned, UnaryOperator, Value, }; /// Parses the input into an abstract syntax tree. @@ -572,20 +572,26 @@ impl<'src> Parser<'src> { left_position, )) } + (Token::Struct, left_position) => { + self.next_token()?; + + if let Token::Identifier(_) = self.current.0 { + let name = self.parse_identifier()?; + let name_end = name.position.1; + + Ok(Node::new( + Statement::StructDefinition(StructDefinition::Unit { name }), + (left_position.0, name_end), + )) + } else { + todo!() + } + } (Token::While, left_position) => { self.next_token()?; let condition = self.parse_statement(0)?; - if let Token::LeftCurlyBrace = self.current.0 { - } else { - return Err(ParseError::ExpectedToken { - expected: TokenKind::LeftCurlyBrace, - actual: self.current.0.to_owned(), - position: self.current.1, - }); - } - let body = self.parse_block()?; let body_end = body.position.1; @@ -772,6 +778,22 @@ impl<'src> Parser<'src> { } } + fn parse_identifier(&mut self) -> Result, ParseError> { + let identifier = if let Token::Identifier(text) = &self.current.0 { + Node::new(Identifier::new(text), self.current.1) + } else { + return Err(ParseError::ExpectedToken { + expected: TokenKind::Identifier, + actual: self.current.0.to_owned(), + position: self.current.1, + }); + }; + + self.next_token()?; + + Ok(identifier) + } + fn parse_block(&mut self) -> Result, ParseError> { let left_start = self.current.1 .0; @@ -890,10 +912,28 @@ impl Display for ParseError { #[cfg(test)] mod tests { - use crate::{abstract_tree::BinaryOperator, Identifier, UnaryOperator}; + use crate::{abstract_tree::BinaryOperator, Identifier, StructDefinition, UnaryOperator}; use super::*; + #[test] + fn unit_struct() { + let input = "struct Foo"; + + assert_eq!( + parse(input), + Ok(AbstractSyntaxTree { + nodes: [Node::new( + Statement::StructDefinition(StructDefinition::Unit { + name: Node::new(Identifier::new("Foo"), (7, 10)), + }), + (0, 10) + )] + .into() + }) + ); + } + #[test] fn list_index_nested() { let input = "[1, [2], 3][1][0]"; diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index ebf490d..c6cfd7c 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -11,8 +11,8 @@ use std::{ use crate::{ parse, value::ValueInner, AbstractSyntaxTree, Analyzer, BinaryOperator, BuiltInFunctionError, - Context, DustError, Identifier, Node, ParseError, Span, Statement, UnaryOperator, Value, - ValueError, + Context, DustError, Identifier, Node, ParseError, Span, Statement, StructDefinition, Type, + UnaryOperator, Value, ValueError, }; /// Run the source code and return the result. @@ -576,6 +576,17 @@ impl Vm { Ok(None) } + Statement::StructDefinition(struct_definition) => { + let (type_name, r#type) = match struct_definition { + StructDefinition::Unit { name } => { + (name.inner.clone(), Type::Defined(name.inner.clone())) + } + }; + + self.context.set_type(type_name, r#type, node.position); + + Ok(None) + } Statement::UnaryOperation { operator, operand } => { let position = operand.position; let value = if let Some(value) = self.run_statement(*operand)? {