1
0

Continue reimplementing the language

This commit is contained in:
Jeff 2024-08-17 04:06:13 -04:00
parent 207d155a25
commit b024d81148
11 changed files with 478 additions and 288 deletions

View File

@ -13,9 +13,10 @@ use crate::{
ast::{ ast::{
AbstractSyntaxTree, BlockExpression, CallExpression, ElseExpression, FieldAccessExpression, AbstractSyntaxTree, BlockExpression, CallExpression, ElseExpression, FieldAccessExpression,
IfExpression, LetStatement, ListExpression, ListIndexExpression, LoopExpression, Node, IfExpression, LetStatement, ListExpression, ListIndexExpression, LoopExpression, Node,
OperatorExpression, RangeExpression, Statement, StructExpression, TupleAccessExpression, OperatorExpression, RangeExpression, Span, Statement, StructExpression,
TupleAccessExpression,
}, },
parse, Context, DustError, Expression, Identifier, Span, Type, parse, Context, DustError, Expression, Identifier, Type,
}; };
/// Analyzes the abstract syntax tree for errors. /// Analyzes the abstract syntax tree for errors.

View File

@ -1,13 +1,14 @@
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::HashMap,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{Context, FunctionType, Identifier, Span, StructType, Type, Value}; use crate::{Context, FieldsStructType, FunctionType, Identifier, StructType, TupleType, Type};
use super::{Node, Statement}; use super::{Node, Span, Statement};
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Expression { pub enum Expression {
@ -221,6 +222,13 @@ impl Expression {
Self::Literal(Node::new(Box::new(literal), position)) Self::Literal(Node::new(Box::new(literal), position))
} }
pub fn has_block(&self) -> bool {
matches!(
self,
Expression::Block(_) | Expression::If(_) | Expression::Loop(_)
)
}
pub fn as_identifier(&self) -> Option<&Identifier> { pub fn as_identifier(&self) -> Option<&Identifier> {
if let Expression::Identifier(identifier) = self { if let Expression::Identifier(identifier) = self {
Some(&identifier.inner) Some(&identifier.inner)
@ -253,7 +261,9 @@ impl Expression {
let container_type = container.return_type(context)?; let container_type = container.return_type(context)?;
if let Type::Struct(StructType::Fields { fields, .. }) = container_type { if let Type::Struct(StructType::Fields(FieldsStructType { fields, .. })) =
container_type
{
fields fields
.into_iter() .into_iter()
.find(|(name, _)| name == &field.inner) .find(|(name, _)| name == &field.inner)
@ -325,26 +335,30 @@ impl Expression {
}, },
Expression::Range(_) => Some(Type::Range), Expression::Range(_) => Some(Type::Range),
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() { Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
StructExpression::Fields { name, fields } => { StructExpression::Fields { fields, .. } => {
let mut field_types = Vec::with_capacity(fields.len()); let mut types = HashMap::with_capacity(fields.len());
for (field_name, expression) in fields { for (field, expression) in fields {
let r#type = expression.return_type(context)?; let r#type = expression.return_type(context)?;
field_types.push((field_name.inner.clone(), r#type)); types.insert(field.inner.clone(), r#type);
} }
Some(Type::Struct(StructType::Fields { Some(Type::Struct(StructType::Fields(FieldsStructType {
name: name.inner.clone(), fields: types,
fields: field_types, })))
}))
} }
StructExpression::Unit { name } => Some(Type::Struct(StructType::Unit { StructExpression::Unit { .. } => Some(Type::Struct(StructType::Unit)),
name: name.inner.clone(),
})),
}, },
Expression::TupleAccess(tuple_access_expression) => { Expression::TupleAccess(tuple_access_expression) => {
todo!() let TupleAccessExpression { tuple, index } = tuple_access_expression.inner.as_ref();
let tuple_value = tuple.return_type(context)?;
if let Type::Tuple(TupleType { fields }) = tuple_value {
fields.get(index.inner).cloned()
} else {
None
}
} }
} }
} }

View File

@ -12,7 +12,7 @@ use std::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::Span; pub type Span = (usize, usize);
/// In-memory representation of a Dust program. /// In-memory representation of a Dust program.
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]

View File

@ -2,9 +2,9 @@ use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{Context, Identifier, Span, Type}; use crate::{Context, Identifier, Type};
use super::{Expression, Node}; use super::{Expression, Node, Span};
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Statement { pub enum Statement {

View File

@ -4,7 +4,7 @@ use std::{
sync::{Arc, PoisonError as StdPoisonError, RwLock, RwLockWriteGuard}, sync::{Arc, PoisonError as StdPoisonError, RwLock, RwLockWriteGuard},
}; };
use crate::{Identifier, Span, Type, Value}; use crate::{ast::Span, Identifier, Type, Value};
pub type Variables = HashMap<Identifier, (VariableData, Span)>; pub type Variables = HashMap<Identifier, (VariableData, Span)>;

View File

@ -8,7 +8,7 @@ use std::{
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
}; };
use crate::{Span, Token}; use crate::{ast::Span, Token};
/// Lexes the input and return a vector of tokens and their positions. /// Lexes the input and return a vector of tokens and their positions.
/// ///

View File

@ -29,16 +29,14 @@ pub mod value;
pub mod vm; pub mod vm;
pub use analyzer::{analyze, Analyzer, AnalyzerError}; pub use analyzer::{analyze, Analyzer, AnalyzerError};
pub use ast::{AbstractSyntaxTree, Expression, Node, Statement}; pub use ast::{AbstractSyntaxTree, Expression, Statement};
pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; pub use built_in_function::{BuiltInFunction, BuiltInFunctionError};
pub use context::{Context, VariableData}; pub use context::{Context, VariableData};
pub use dust_error::DustError; pub use dust_error::DustError;
pub use identifier::Identifier; pub use identifier::Identifier;
pub use lexer::{lex, LexError, Lexer}; pub use lexer::{lex, LexError, Lexer};
pub use parser::{parse, ParseError, Parser}; pub use parser::{parse, ParseError, Parser};
pub use r#type::{EnumType, FunctionType, StructType, Type}; pub use r#type::*;
pub use token::{Token, TokenKind, TokenOwned}; pub use token::{Token, TokenKind, TokenOwned};
pub use value::{Struct, Value, ValueError}; pub use value::*;
pub use vm::{run, run_with_context, Vm, VmError}; pub use vm::{run, run_with_context, Vm, VmError};
pub type Span = (usize, usize);

View File

@ -11,9 +11,7 @@ use std::{
str::ParseBoolError, str::ParseBoolError,
}; };
use crate::{ use crate::{ast::*, DustError, Identifier, LexError, Lexer, Token, TokenKind, TokenOwned, Type};
ast::*, DustError, Identifier, LexError, Lexer, Span, Token, TokenKind, TokenOwned, Type,
};
/// Parses the input into an abstract syntax tree. /// Parses the input into an abstract syntax tree.
/// ///
@ -146,6 +144,8 @@ impl<'src> Parser<'src> {
let start_position = self.current_position; let start_position = self.current_position;
if let Token::Let = self.current_token { if let Token::Let = self.current_token {
log::trace!("Parsing let statement");
self.next_token()?; self.next_token()?;
let is_mutable = if let Token::Mut = self.current_token { let is_mutable = if let Token::Mut = self.current_token {
@ -170,21 +170,33 @@ impl<'src> Parser<'src> {
let value = self.parse_expression(0)?; let value = self.parse_expression(0)?;
if let Token::Semicolon = self.current_token { let end = if let Token::Semicolon = self.current_token {
let end = self.current_position.1;
self.next_token()?; self.next_token()?;
}
end
} else {
return Err(ParseError::ExpectedToken {
expected: TokenKind::Semicolon,
actual: self.current_token.to_owned(),
position: self.current_position,
});
};
let r#let = if is_mutable { let r#let = if is_mutable {
LetStatement::LetMut { identifier, value } LetStatement::LetMut { identifier, value }
} else { } else {
LetStatement::Let { identifier, value } LetStatement::Let { identifier, value }
}; };
let position = (start_position.0, self.current_position.1); let position = (start_position.0, end);
return Ok(Statement::Let(Node::new(r#let, position))); return Ok(Statement::Let(Node::new(r#let, position)));
} }
if let Token::Struct = self.current_token { if let Token::Struct = self.current_token {
log::trace!("Parsing struct definition");
self.next_token()?; self.next_token()?;
let (name, name_end) = if let Token::Identifier(_) = self.current_token { let (name, name_end) = if let Token::Identifier(_) = self.current_token {
@ -276,18 +288,27 @@ impl<'src> Parser<'src> {
} }
let expression = self.parse_expression(0)?; let expression = self.parse_expression(0)?;
let end = self.current_position.1;
let statement = if let Token::Semicolon = self.current_token { let is_nullified = if let Token::Semicolon = self.current_token {
let position = (start_position.0, self.current_position.1);
self.next_token()?; self.next_token()?;
Statement::ExpressionNullified(Node::new(expression, position)) true
} else { } else {
Statement::Expression(expression) matches!(
expression,
Expression::Block(_) | Expression::Loop(_) | Expression::If(_)
)
}; };
Ok(statement) if is_nullified {
let position = (start_position.0, end);
Ok(Statement::ExpressionNullified(Node::new(
expression, position,
)))
} else {
Ok(Statement::Expression(expression))
}
} }
fn next_token(&mut self) -> Result<(), ParseError> { fn next_token(&mut self) -> Result<(), ParseError> {
@ -348,7 +369,8 @@ impl<'src> Parser<'src> {
Ok(Expression::negation(operand, position)) Ok(Expression::negation(operand, position))
} }
_ => Err(ParseError::UnexpectedToken { _ => Err(ParseError::ExpectedTokenMultiple {
expected: vec![TokenKind::Bang, TokenKind::Minus],
actual: self.current_token.to_owned(), actual: self.current_token.to_owned(),
position: self.current_position, position: self.current_position,
}), }),
@ -363,7 +385,7 @@ impl<'src> Parser<'src> {
match self.current_token { match self.current_token {
Token::Async => { Token::Async => {
let block = self.parse_block()?; let block = self.parse_block()?;
let position = (start_position.0, self.current_position.1); let position = (start_position.0, block.position.1);
Ok(Expression::block(block.inner, position)) Ok(Expression::block(block.inner, position))
} }
@ -460,12 +482,10 @@ impl<'src> Parser<'src> {
)) ))
} }
Token::If => { Token::If => {
let start = self.current_position.0;
self.next_token()?; self.next_token()?;
let r#if = self.parse_if()?; let r#if = self.parse_if()?;
let position = (start, self.current_position.1); let position = (start_position.0, self.current_position.1);
Ok(Expression::r#if(r#if, position)) Ok(Expression::r#if(r#if, position))
} }
@ -577,7 +597,20 @@ impl<'src> Parser<'src> {
Ok(Expression::while_loop(condition, block, position)) Ok(Expression::while_loop(condition, block, position))
} }
_ => Err(ParseError::UnexpectedToken { _ => Err(ParseError::ExpectedTokenMultiple {
expected: vec![
TokenKind::Async,
TokenKind::Boolean,
TokenKind::Float,
TokenKind::Identifier,
TokenKind::Integer,
TokenKind::If,
TokenKind::LeftCurlyBrace,
TokenKind::LeftParenthesis,
TokenKind::LeftSquareBrace,
TokenKind::String,
TokenKind::While,
],
actual: self.current_token.to_owned(), actual: self.current_token.to_owned(),
position: self.current_position, position: self.current_position,
}), }),
@ -798,7 +831,12 @@ impl<'src> Parser<'src> {
Expression::list_index(ListIndexExpression { list: left, index }, position) Expression::list_index(ListIndexExpression { list: left, index }, position)
} }
_ => { _ => {
return Err(ParseError::UnexpectedToken { return Err(ParseError::ExpectedTokenMultiple {
expected: vec![
TokenKind::Dot,
TokenKind::LeftParenthesis,
TokenKind::LeftSquareBrace,
],
actual: self.current_token.to_owned(), actual: self.current_token.to_owned(),
position: self.current_position, position: self.current_position,
}); });
@ -1064,9 +1102,58 @@ mod tests {
use super::*; use super::*;
#[test]
fn let_mut_while_loop() {
env_logger::builder().is_test(true).try_init().ok();
let source = "let mut x = 0; while x < 10 { x += 1 };";
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree {
statements: [
Statement::Let(Node::new(
LetStatement::LetMut {
identifier: Node::new(Identifier::new("x"), (8, 9)),
value: Expression::literal(LiteralExpression::Integer(0), (12, 13)),
},
(0, 14),
)),
Statement::ExpressionNullified(Node::new(
Expression::while_loop(
Expression::comparison(
Expression::identifier(Identifier::new("x"), (21, 22)),
Node::new(ComparisonOperator::LessThan, (23, 24)),
Expression::literal(LiteralExpression::Integer(10), (25, 27)),
(21, 27),
),
Node::new(
BlockExpression::Sync(vec![Statement::Expression(
Expression::compound_assignment(
Expression::identifier(Identifier::new("x"), (30, 31)),
Node::new(MathOperator::Add, (32, 34)),
Expression::literal(
LiteralExpression::Integer(1),
(35, 36)
),
(30, 36),
),
)]),
(28, 38),
),
(15, 39),
),
(15, 39)
))
]
.into()
})
);
}
#[test] #[test]
fn let_statement() { fn let_statement() {
let source = "let x = 42"; let source = "let x = 42;";
assert_eq!( assert_eq!(
parse(source), parse(source),
@ -1076,7 +1163,7 @@ mod tests {
identifier: Node::new(Identifier::new("x"), (4, 5)), identifier: Node::new(Identifier::new("x"), (4, 5)),
value: Expression::literal(LiteralExpression::Integer(42), (8, 10)), value: Expression::literal(LiteralExpression::Integer(42), (8, 10)),
}, },
(0, 10), (0, 11),
))] ))]
.into() .into()
}) })
@ -1085,7 +1172,7 @@ mod tests {
#[test] #[test]
fn let_mut_statement() { fn let_mut_statement() {
let source = "let mut x = false"; let source = "let mut x = false;";
assert_eq!( assert_eq!(
parse(source), parse(source),
@ -1095,7 +1182,7 @@ mod tests {
identifier: Node::new(Identifier::new("x"), (8, 9)), identifier: Node::new(Identifier::new("x"), (8, 9)),
value: Expression::literal(LiteralExpression::Boolean(false), (12, 17)), value: Expression::literal(LiteralExpression::Boolean(false), (12, 17)),
}, },
(0, 17), (0, 18),
))] ))]
.into() .into()
}) })
@ -1109,31 +1196,43 @@ mod tests {
assert_eq!( assert_eq!(
parse(source), parse(source),
Ok(AbstractSyntaxTree { Ok(AbstractSyntaxTree {
statements: [Statement::Expression(Expression::block( statements: [Statement::ExpressionNullified(Node::new(
BlockExpression::Async(vec![ Expression::block(
Statement::ExpressionNullified(Node::new( BlockExpression::Async(vec![
Expression::operator( Statement::ExpressionNullified(Node::new(
Expression::operator(
OperatorExpression::Assignment {
assignee: Expression::identifier(
Identifier::new("x"),
(8, 9)
),
value: Expression::literal(
LiteralExpression::Integer(42),
(12, 14)
),
},
(8, 14)
),
(8, 15)
)),
Statement::Expression(Expression::operator(
OperatorExpression::Assignment { OperatorExpression::Assignment {
assignee: Expression::identifier(Identifier::new("x"), (8, 9)), assignee: Expression::identifier(
Identifier::new("y"),
(16, 17)
),
value: Expression::literal( value: Expression::literal(
LiteralExpression::Integer(42), LiteralExpression::Float(4.0),
(12, 14) (20, 23)
), ),
}, },
(8, 14) (16, 23)
), ))
(8, 15) ]),
)), (0, 25)
Statement::Expression(Expression::operator( ),
OperatorExpression::Assignment {
assignee: Expression::identifier(Identifier::new("y"), (16, 17)),
value: Expression::literal(LiteralExpression::Float(4.0), (20, 23)),
},
(16, 23)
))
]),
(0, 25) (0, 25)
),)] ))]
.into() .into()
}) })
); );
@ -1454,16 +1553,19 @@ mod tests {
assert_eq!( assert_eq!(
parse(source), parse(source),
Ok(AbstractSyntaxTree::with_statements([ Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::r#if( Statement::ExpressionNullified(Node::new(
IfExpression::If { Expression::r#if(
condition: Expression::identifier(Identifier::new("x"), (3, 4)), IfExpression::If {
if_block: Node::new( condition: Expression::identifier(Identifier::new("x"), (3, 4)),
BlockExpression::Sync(vec![Statement::Expression( if_block: Node::new(
Expression::identifier(Identifier::new("y"), (7, 8)) BlockExpression::Sync(vec![Statement::Expression(
)]), Expression::identifier(Identifier::new("y"), (7, 8))
(5, 10) )]),
) (5, 10)
}, )
},
(0, 10)
),
(0, 10) (0, 10)
)) ))
])) ]))
@ -1477,22 +1579,25 @@ mod tests {
assert_eq!( assert_eq!(
parse(source), parse(source),
Ok(AbstractSyntaxTree::with_statements([ Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::r#if( Statement::ExpressionNullified(Node::new(
IfExpression::IfElse { Expression::r#if(
condition: Expression::identifier(Identifier::new("x"), (3, 4)), IfExpression::IfElse {
if_block: Node::new( condition: Expression::identifier(Identifier::new("x"), (3, 4)),
BlockExpression::Sync(vec![Statement::Expression( if_block: Node::new(
Expression::identifier(Identifier::new("y"), (7, 8)) BlockExpression::Sync(vec![Statement::Expression(
)]), Expression::identifier(Identifier::new("y"), (7, 8))
(5, 10) )]),
), (5, 10)
r#else: ElseExpression::Block(Node::new( ),
BlockExpression::Sync(vec![Statement::Expression( r#else: ElseExpression::Block(Node::new(
Expression::identifier(Identifier::new("z"), (18, 19)) BlockExpression::Sync(vec![Statement::Expression(
)]), Expression::identifier(Identifier::new("z"), (18, 19))
(16, 21) )]),
)) (16, 21)
}, ))
},
(0, 21)
),
(0, 21) (0, 21)
)) ))
])) ]))
@ -1506,34 +1611,40 @@ mod tests {
assert_eq!( assert_eq!(
parse(source), parse(source),
Ok(AbstractSyntaxTree::with_statements([ Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::r#if( Statement::ExpressionNullified(Node::new(
IfExpression::IfElse { Expression::r#if(
condition: Expression::identifier(Identifier::new("x"), (3, 4)), IfExpression::IfElse {
if_block: Node::new( condition: Expression::identifier(Identifier::new("x"), (3, 4)),
BlockExpression::Sync(vec![Statement::Expression( if_block: Node::new(
Expression::identifier(Identifier::new("y"), (7, 8)) BlockExpression::Sync(vec![Statement::Expression(
)]), Expression::identifier(Identifier::new("y"), (7, 8))
(5, 10) )]),
), (5, 10)
r#else: ElseExpression::If(Node::new( ),
Box::new(IfExpression::IfElse { r#else: ElseExpression::If(Node::new(
condition: Expression::identifier(Identifier::new("z"), (19, 20)), Box::new(IfExpression::IfElse {
if_block: Node::new( condition: Expression::identifier(
BlockExpression::Sync(vec![Statement::Expression( Identifier::new("z"),
Expression::identifier(Identifier::new("a"), (23, 24)) (19, 20)
)]), ),
(21, 26) if_block: Node::new(
), BlockExpression::Sync(vec![Statement::Expression(
r#else: ElseExpression::Block(Node::new( Expression::identifier(Identifier::new("a"), (23, 24))
BlockExpression::Sync(vec![Statement::Expression( )]),
Expression::identifier(Identifier::new("b"), (34, 35)) (21, 26)
)]), ),
(32, 37) r#else: ElseExpression::Block(Node::new(
)), BlockExpression::Sync(vec![Statement::Expression(
}), Expression::identifier(Identifier::new("b"), (34, 35))
(16, 37) )]),
)), (32, 37)
}, )),
}),
(16, 37)
)),
},
(0, 37)
),
(0, 37) (0, 37)
)) ))
])) ]))
@ -1547,28 +1658,39 @@ mod tests {
assert_eq!( assert_eq!(
parse(source), parse(source),
Ok(AbstractSyntaxTree::with_statements([ Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::while_loop( Statement::ExpressionNullified(Node::new(
Expression::operator( Expression::while_loop(
OperatorExpression::Comparison { Expression::operator(
left: Expression::identifier(Identifier::new("x"), (6, 7)), OperatorExpression::Comparison {
operator: Node::new(ComparisonOperator::LessThan, (8, 9)), left: Expression::identifier(Identifier::new("x"), (6, 7)),
right: Expression::literal(LiteralExpression::Integer(10), (10, 12)), operator: Node::new(ComparisonOperator::LessThan, (8, 9)),
}, right: Expression::literal(
(6, 12) LiteralExpression::Integer(10),
), (10, 12)
Node::new(
BlockExpression::Sync(vec![Statement::Expression(Expression::operator(
OperatorExpression::CompoundAssignment {
assignee: Expression::identifier(Identifier::new("x"), (15, 16)),
operator: Node::new(MathOperator::Add, (17, 19)),
modifier: Expression::literal(
LiteralExpression::Integer(1),
(20, 21)
), ),
}, },
(15, 21) (6, 12)
))]), ),
(13, 23) Node::new(
BlockExpression::Sync(vec![Statement::Expression(
Expression::operator(
OperatorExpression::CompoundAssignment {
assignee: Expression::identifier(
Identifier::new("x"),
(15, 16)
),
operator: Node::new(MathOperator::Add, (17, 19)),
modifier: Expression::literal(
LiteralExpression::Integer(1),
(20, 21)
),
},
(15, 21)
)
)]),
(13, 23)
),
(0, 23)
), ),
(0, 23) (0, 23)
)) ))
@ -1621,15 +1743,18 @@ mod tests {
assert_eq!( assert_eq!(
parse(source), parse(source),
Ok(AbstractSyntaxTree::with_statements([ Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::block( Statement::ExpressionNullified(Node::new(
BlockExpression::Sync(vec![Statement::Expression(Expression::operator( Expression::block(
OperatorExpression::Math { BlockExpression::Sync(vec![Statement::Expression(Expression::operator(
left: Expression::literal(LiteralExpression::Integer(40), (2, 4)), OperatorExpression::Math {
operator: Node::new(MathOperator::Add, (5, 6)), left: Expression::literal(LiteralExpression::Integer(40), (2, 4)),
right: Expression::literal(LiteralExpression::Integer(2), (7, 8)), operator: Node::new(MathOperator::Add, (5, 6)),
}, right: Expression::literal(LiteralExpression::Integer(2), (7, 8)),
(2, 8) },
))]), (2, 8)
))]),
(0, 10)
),
(0, 10) (0, 10)
)) ))
])) ]))
@ -1643,51 +1768,57 @@ mod tests {
assert_eq!( assert_eq!(
parse(source), parse(source),
Ok(AbstractSyntaxTree::with_statements([ Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::block( Statement::ExpressionNullified(Node::new(
BlockExpression::Sync(vec![ Expression::block(
Statement::ExpressionNullified(Node::new( BlockExpression::Sync(vec![
Expression::operator( Statement::ExpressionNullified(Node::new(
OperatorExpression::Assignment { Expression::operator(
assignee: Expression::identifier( OperatorExpression::Assignment {
Identifier::new("foo"), assignee: Expression::identifier(
(2, 5) Identifier::new("foo"),
), (2, 5)
value: Expression::literal( ),
LiteralExpression::Integer(42), value: Expression::literal(
(8, 10) LiteralExpression::Integer(42),
), (8, 10)
}, ),
(2, 10) },
), (2, 10)
(2, 11)
),),
Statement::ExpressionNullified(Node::new(
Expression::operator(
OperatorExpression::Assignment {
assignee: Expression::identifier(
Identifier::new("bar"),
(12, 15)
),
value: Expression::literal(
LiteralExpression::Integer(42),
(18, 20)
),
},
(12, 20)
),
(12, 21)
),),
Statement::Expression(Expression::operator(
OperatorExpression::Assignment {
assignee: Expression::identifier(Identifier::new("baz"), (22, 25)),
value: Expression::literal(
LiteralExpression::String("42".to_string()),
(28, 32)
), ),
}, (2, 11)
(22, 32) ),),
)), Statement::ExpressionNullified(Node::new(
]), Expression::operator(
OperatorExpression::Assignment {
assignee: Expression::identifier(
Identifier::new("bar"),
(12, 15)
),
value: Expression::literal(
LiteralExpression::Integer(42),
(18, 20)
),
},
(12, 20)
),
(12, 21)
),),
Statement::Expression(Expression::operator(
OperatorExpression::Assignment {
assignee: Expression::identifier(
Identifier::new("baz"),
(22, 25)
),
value: Expression::literal(
LiteralExpression::String("42".to_string()),
(28, 32)
),
},
(22, 32)
)),
]),
(0, 34)
),
(0, 34) (0, 34)
)) ))
])) ]))

View File

@ -10,6 +10,8 @@
//! library's "length" function does not care about the type of item in the list, only the list //! library's "length" function does not care about the type of item in the list, only the list
//! itself. So the input is defined as `[any]`, i.e. `Type::ListOf(Box::new(Type::Any))`. //! itself. So the input is defined as `[any]`, i.e. `Type::ListOf(Box::new(Type::Any))`.
use std::{ use std::{
cmp::Ordering,
collections::HashMap,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
sync::Arc, sync::Arc,
}; };
@ -47,7 +49,7 @@ pub enum Type {
Range, Range,
String, String,
Struct(StructType), Struct(StructType),
Tuple(Vec<Type>), Tuple(TupleType),
} }
impl Type { impl Type {
@ -264,7 +266,7 @@ impl Display for Type {
Type::Range => write!(f, "range"), Type::Range => write!(f, "range"),
Type::String => write!(f, "str"), Type::String => write!(f, "str"),
Type::Struct(struct_type) => write!(f, "{struct_type}"), Type::Struct(struct_type) => write!(f, "{struct_type}"),
Type::Tuple(fields) => { Type::Tuple(TupleType { fields }) => {
write!(f, "(")?; write!(f, "(")?;
for (index, r#type) in fields.iter().enumerate() { for (index, r#type) in fields.iter().enumerate() {
@ -331,24 +333,16 @@ impl Display for FunctionType {
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum StructType { pub enum StructType {
Unit { Unit,
name: Identifier, Tuple(TupleType),
}, Fields(FieldsStructType),
Tuple {
name: Identifier,
fields: Vec<Type>,
},
Fields {
name: Identifier,
fields: Vec<(Identifier, Type)>,
},
} }
impl Display for StructType { impl Display for StructType {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
StructType::Unit { .. } => write!(f, "()"), StructType::Unit => write!(f, "()"),
StructType::Tuple { fields, .. } => { StructType::Tuple(TupleType { fields, .. }) => {
write!(f, "(")?; write!(f, "(")?;
for (index, r#type) in fields.iter().enumerate() { for (index, r#type) in fields.iter().enumerate() {
@ -361,12 +355,8 @@ impl Display for StructType {
write!(f, ")") write!(f, ")")
} }
StructType::Fields { StructType::Fields(FieldsStructType { fields, .. }) => {
name: identifier, write!(f, "{{ ")?;
fields,
..
} => {
write!(f, "{identifier} {{ ")?;
for (index, (identifier, r#type)) in fields.iter().enumerate() { for (index, (identifier, r#type)) in fields.iter().enumerate() {
write!(f, "{identifier}: {type}")?; write!(f, "{identifier}: {type}")?;
@ -382,6 +372,28 @@ impl Display for StructType {
} }
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct TupleType {
pub fields: Vec<Type>,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct FieldsStructType {
pub fields: HashMap<Identifier, Type>,
}
impl PartialOrd for FieldsStructType {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for FieldsStructType {
fn cmp(&self, other: &Self) -> Ordering {
self.fields.iter().cmp(other.fields.iter())
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct EnumType { pub struct EnumType {
name: Identifier, name: Identifier,

View File

@ -1,6 +1,7 @@
//! Dust value representation //! Dust value representation
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::HashMap,
error::Error, error::Error,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
ops::{Range, RangeInclusive}, ops::{Range, RangeInclusive},
@ -14,7 +15,8 @@ use serde::{
}; };
use crate::{ use crate::{
AbstractSyntaxTree, Context, EnumType, FunctionType, Identifier, StructType, Type, Vm, VmError, AbstractSyntaxTree, Context, EnumType, FieldsStructType, FunctionType, Identifier, StructType,
TupleType, Type, Vm, VmError,
}; };
/// Dust value representation /// Dust value representation
@ -197,14 +199,25 @@ impl Value {
Value::RangeInclusive(_) => Type::Range, Value::RangeInclusive(_) => Type::Range,
Value::String(_) => Type::String, Value::String(_) => Type::String,
Value::Struct(r#struct) => match r#struct { Value::Struct(r#struct) => match r#struct {
Struct::Unit { r#type } => Type::Struct(r#type.clone()), Struct::Unit { .. } => Type::Struct(StructType::Unit),
Struct::Tuple { r#type, .. } => Type::Struct(r#type.clone()), Struct::Tuple { fields, .. } => {
Struct::Fields { r#type, .. } => Type::Struct(r#type.clone()), let types = fields.iter().map(|field| field.r#type()).collect();
Type::Struct(StructType::Tuple(TupleType { fields: types }))
}
Struct::Fields { fields, .. } => {
let types = fields
.iter()
.map(|(identifier, value)| (identifier.clone(), value.r#type()))
.collect();
Type::Struct(StructType::Fields(FieldsStructType { fields: types }))
}
}, },
Value::Tuple(values) => { Value::Tuple(values) => {
let item_types = values.iter().map(Value::r#type).collect(); let fields = values.iter().map(|value| value.r#type()).collect();
Type::Tuple(item_types) Type::Tuple(TupleType { fields })
} }
} }
} }
@ -212,23 +225,7 @@ impl Value {
pub fn get_field(&self, field: &Identifier) -> Option<Value> { pub fn get_field(&self, field: &Identifier) -> Option<Value> {
match self { match self {
Value::Mutable(inner) => inner.read().unwrap().get_field(field), Value::Mutable(inner) => inner.read().unwrap().get_field(field),
Value::Struct(Struct::Fields { Value::Struct(Struct::Fields { fields, .. }) => fields.get(field).cloned(),
fields,
r#type:
StructType::Fields {
fields: field_types,
..
},
}) => field_types
.iter()
.zip(fields.iter())
.find_map(|((identifier, _), value)| {
if identifier == field {
Some(value.clone())
} else {
None
}
}),
_ => None, _ => None,
} }
} }
@ -237,6 +234,7 @@ impl Value {
match self { match self {
Value::List(values) => values.get(index).cloned(), Value::List(values) => values.get(index).cloned(),
Value::Mutable(inner) => inner.read().unwrap().get_index(index), Value::Mutable(inner) => inner.read().unwrap().get_index(index),
Value::Struct(Struct::Tuple { fields, .. }) => fields.get(index).cloned(),
_ => None, _ => None,
} }
} }
@ -1055,21 +1053,74 @@ impl<'de> Deserialize<'de> for Function {
} }
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum Struct { pub enum Struct {
Unit { Unit {
r#type: StructType, name: Identifier,
}, },
Tuple { Tuple {
r#type: StructType, name: Identifier,
fields: Vec<Value>, fields: Vec<Value>,
}, },
Fields { Fields {
r#type: StructType, name: Identifier,
fields: Vec<Value>, fields: HashMap<Identifier, Value>,
}, },
} }
impl PartialOrd for Struct {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Struct {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Struct::Unit { name: left }, Struct::Unit { name: right }) => left.cmp(right),
(Struct::Unit { .. }, _) => Ordering::Greater,
(
Struct::Tuple {
name: left_name,
fields: left_fields,
},
Struct::Tuple {
name: right_name,
fields: right_fields,
},
) => {
let type_cmp = left_name.cmp(right_name);
if type_cmp != Ordering::Equal {
return type_cmp;
}
left_fields.cmp(right_fields)
}
(Struct::Tuple { .. }, _) => Ordering::Greater,
(
Struct::Fields {
name: left_name,
fields: left_fields,
},
Struct::Fields {
name: right_name,
fields: right_fields,
},
) => {
let type_cmp = left_name.cmp(right_name);
if type_cmp != Ordering::Equal {
return type_cmp;
}
left_fields.into_iter().cmp(right_fields.into_iter())
}
(Struct::Fields { .. }, _) => Ordering::Greater,
}
}
}
impl Display for Struct { impl Display for Struct {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
@ -1087,19 +1138,10 @@ impl Display for Struct {
write!(f, ")") write!(f, ")")
} }
Struct::Fields { Struct::Fields { fields, .. } => {
fields,
r#type:
StructType::Fields {
fields: field_types,
..
},
} => {
write!(f, "{{ ")?; write!(f, "{{ ")?;
for (index, ((identifier, _), value)) in for (index, (identifier, value)) in fields.iter().enumerate() {
field_types.iter().zip(fields.iter()).enumerate()
{
if index > 0 { if index > 0 {
write!(f, ", ")?; write!(f, ", ")?;
} }
@ -1115,7 +1157,7 @@ impl Display for Struct {
} }
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
enum Rangeable { pub enum Rangeable {
Byte(u8), Byte(u8),
Character(char), Character(char),
Float(f64), Float(f64),

View File

@ -16,10 +16,10 @@ use crate::{
AbstractSyntaxTree, BlockExpression, CallExpression, ComparisonOperator, ElseExpression, AbstractSyntaxTree, BlockExpression, CallExpression, ComparisonOperator, ElseExpression,
FieldAccessExpression, IfExpression, LetStatement, ListExpression, ListIndexExpression, FieldAccessExpression, IfExpression, LetStatement, ListExpression, ListIndexExpression,
LiteralExpression, LogicOperator, LoopExpression, MathOperator, Node, OperatorExpression, LiteralExpression, LogicOperator, LoopExpression, MathOperator, Node, OperatorExpression,
RangeExpression, Statement, StructDefinition, RangeExpression, Span, Statement, StructDefinition,
}, },
parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, Identifier, ParseError, parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, Identifier, ParseError,
Span, StructType, Type, Value, ValueError, StructType, TupleType, Type, Value, ValueError,
}; };
/// Run the source code and return the result. /// Run the source code and return the result.
@ -121,10 +121,12 @@ impl Vm {
} }
Statement::StructDefinition(struct_definition) => { Statement::StructDefinition(struct_definition) => {
let (name, struct_type) = match struct_definition.inner { let (name, struct_type) = match struct_definition.inner {
StructDefinition::Unit { name } => { StructDefinition::Unit { name } => (name.inner.clone(), StructType::Unit),
(name.inner.clone(), StructType::Unit { name: name.inner }) StructDefinition::Tuple { name, items } => {
let fields = items.into_iter().map(|item| item.inner).collect();
(name.inner.clone(), StructType::Tuple(TupleType { fields }))
} }
StructDefinition::Tuple { name, items } => todo!(),
StructDefinition::Fields { name, fields } => todo!(), StructDefinition::Fields { name, fields } => todo!(),
}; };
@ -988,7 +990,9 @@ impl Display for VmError {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{Struct, StructType, Type}; use std::collections::HashMap;
use crate::Struct;
use super::*; use super::*;
@ -1006,14 +1010,11 @@ mod tests {
assert_eq!( assert_eq!(
run(input), run(input),
Ok(Some(Value::Struct(Struct::Fields { Ok(Some(Value::Struct(Struct::Fields {
r#type: StructType::Fields { name: Identifier::new("Foo"),
name: Identifier::new("Foo"), fields: HashMap::from([
fields: vec![ (Identifier::new("bar"), Value::Integer(42)),
(Identifier::new("bar"), Type::Integer), (Identifier::new("baz"), Value::Float(4.0))
(Identifier::new("baz"), Type::Float) ])
]
},
fields: vec![Value::Integer(42), Value::Float(4.0)]
}))) })))
); );
} }
@ -1029,10 +1030,7 @@ mod tests {
assert_eq!( assert_eq!(
run(input), run(input),
Ok(Some(Value::Struct(Struct::Tuple { Ok(Some(Value::Struct(Struct::Tuple {
r#type: StructType::Tuple { name: Identifier::new("Foo"),
name: Identifier::new("Foo"),
fields: vec![Type::Integer]
},
fields: vec![Value::Integer(42)] fields: vec![Value::Integer(42)]
}))) })))
) )
@ -1045,9 +1043,7 @@ mod tests {
assert_eq!( assert_eq!(
run(input), run(input),
Ok(Some(Value::Struct(Struct::Tuple { Ok(Some(Value::Struct(Struct::Tuple {
r#type: StructType::Unit { name: Identifier::new("Foo"),
name: Identifier::new("Foo")
},
fields: vec![Value::Integer(42)] fields: vec![Value::Integer(42)]
}))) })))
); );
@ -1064,9 +1060,7 @@ mod tests {
assert_eq!( assert_eq!(
run(input), run(input),
Ok(Some(Value::Struct(Struct::Unit { Ok(Some(Value::Struct(Struct::Unit {
r#type: StructType::Unit { name: Identifier::new("Foo")
name: Identifier::new("Foo")
}
}))) })))
) )
} }
@ -1078,9 +1072,7 @@ mod tests {
assert_eq!( assert_eq!(
run(input), run(input),
Ok(Some(Value::Struct(Struct::Unit { Ok(Some(Value::Struct(Struct::Unit {
r#type: StructType::Unit { name: Identifier::new("Foo")
name: Identifier::new("Foo")
}
}))) })))
); );
} }
@ -1163,7 +1155,7 @@ mod tests {
#[test] #[test]
fn if_else() { fn if_else() {
let input = "if false { 1 } else { 2 }"; let input = "let x = if false { 1 } else { 2 }; x";
assert_eq!(run(input), Ok(Some(Value::Integer(2)))); assert_eq!(run(input), Ok(Some(Value::Integer(2))));
} }
@ -1184,7 +1176,7 @@ mod tests {
#[test] #[test]
fn while_loop() { fn while_loop() {
let input = "let mut x = 0; while x < 5 { x += 1; } x"; let input = "let mut x = 0; while x < 5 { x += 1 } x";
assert_eq!(run(input), Ok(Some(Value::Integer(5)))); assert_eq!(run(input), Ok(Some(Value::Integer(5))));
} }