1
0

Extend VM, abstract tree and parser

This commit is contained in:
Jeff 2024-08-17 10:07:38 -04:00
parent fa67a568d9
commit 0b64afccb1
8 changed files with 923 additions and 256 deletions

View File

@ -12,11 +12,12 @@ use std::{
use crate::{ 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,
OperatorExpression, RangeExpression, Span, Statement, StructExpression, MapExpression, Node, OperatorExpression, RangeExpression, Span, Statement,
TupleAccessExpression, StructDefinition, StructExpression, TupleAccessExpression,
}, },
parse, Context, DustError, Expression, Identifier, Type, parse, Context, DustError, Expression, FieldsStructType, Identifier, StructType, TupleType,
Type,
}; };
/// Analyzes the abstract syntax tree for errors. /// Analyzes the abstract syntax tree for errors.
@ -129,7 +130,37 @@ impl<'a> Analyzer<'a> {
value, value,
} => todo!(), } => todo!(),
}, },
Statement::StructDefinition(_) => {} Statement::StructDefinition(struct_definition) => {
let (name, struct_type) = match &struct_definition.inner {
StructDefinition::Unit { name } => {
(name.inner.clone(), Type::Struct(StructType::Unit))
}
StructDefinition::Tuple { name, items } => {
let fields = items.iter().map(|item| item.inner.clone()).collect();
(
name.inner.clone(),
Type::Struct(StructType::Tuple(TupleType { fields })),
)
}
StructDefinition::Fields { name, fields } => {
let fields = fields
.iter()
.map(|(identifier, r#type)| {
(identifier.inner.clone(), r#type.inner.clone())
})
.collect();
(
name.inner.clone(),
Type::Struct(StructType::Fields(FieldsStructType { fields })),
)
}
};
self.context
.set_type(name, struct_type, struct_definition.position);
}
} }
Ok(()) Ok(())
@ -204,6 +235,13 @@ impl<'a> Analyzer<'a> {
self.analyze_block(&block.inner)?; self.analyze_block(&block.inner)?;
} }
}, },
Expression::Map(map_expression) => {
let MapExpression { pairs } = map_expression.inner.as_ref();
for (_, expression) in pairs {
self.analyze_expression(expression)?;
}
}
Expression::Operator(operator_expression) => match operator_expression.inner.as_ref() { Expression::Operator(operator_expression) => match operator_expression.inner.as_ref() {
OperatorExpression::Assignment { assignee, value } => { OperatorExpression::Assignment { assignee, value } => {
self.analyze_expression(assignee)?; self.analyze_expression(assignee)?;

View File

@ -6,7 +6,9 @@ use std::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{Context, FieldsStructType, FunctionType, Identifier, StructType, TupleType, Type}; use crate::{
Context, FieldsStructType, FunctionType, Identifier, RangeableType, StructType, TupleType, Type,
};
use super::{Node, Span, Statement}; use super::{Node, Span, Statement};
@ -22,6 +24,7 @@ pub enum Expression {
ListIndex(Node<Box<ListIndexExpression>>), ListIndex(Node<Box<ListIndexExpression>>),
Literal(Node<Box<LiteralExpression>>), Literal(Node<Box<LiteralExpression>>),
Loop(Node<Box<LoopExpression>>), Loop(Node<Box<LoopExpression>>),
Map(Node<Box<MapExpression>>),
Operator(Node<Box<OperatorExpression>>), Operator(Node<Box<OperatorExpression>>),
Range(Node<Box<RangeExpression>>), Range(Node<Box<RangeExpression>>),
Struct(Node<Box<StructExpression>>), Struct(Node<Box<StructExpression>>),
@ -29,6 +32,15 @@ pub enum Expression {
} }
impl Expression { impl Expression {
pub fn map(pairs: Vec<(Node<Identifier>, Expression)>, position: Span) -> Self {
Self::Map(Node::new(
Box::new(MapExpression {
pairs: pairs.into_iter().collect(),
}),
position,
))
}
pub fn operator(operator_expression: OperatorExpression, position: Span) -> Self { pub fn operator(operator_expression: OperatorExpression, position: Span) -> Self {
Self::Operator(Node::new(Box::new(operator_expression), position)) Self::Operator(Node::new(Box::new(operator_expression), position))
} }
@ -323,6 +335,19 @@ impl Expression {
LoopExpression::Infinite { .. } => None, LoopExpression::Infinite { .. } => None,
LoopExpression::While { block, .. } => block.inner.return_type(context), LoopExpression::While { block, .. } => block.inner.return_type(context),
}, },
Expression::Map(map_expression) => {
let MapExpression { pairs } = map_expression.inner.as_ref();
let mut types = HashMap::with_capacity(pairs.len());
for (key, value) in pairs {
let value_type = value.return_type(context)?;
types.insert(key.inner.clone(), value_type);
}
Some(Type::Map { pairs: types })
}
Expression::Operator(operator_expression) => match operator_expression.inner.as_ref() { Expression::Operator(operator_expression) => match operator_expression.inner.as_ref() {
OperatorExpression::Assignment { .. } => None, OperatorExpression::Assignment { .. } => None,
OperatorExpression::Comparison { .. } => Some(Type::Boolean), OperatorExpression::Comparison { .. } => Some(Type::Boolean),
@ -333,7 +358,24 @@ impl Expression {
OperatorExpression::Math { left, .. } => left.return_type(context), OperatorExpression::Math { left, .. } => left.return_type(context),
OperatorExpression::Logic { .. } => Some(Type::Boolean), OperatorExpression::Logic { .. } => Some(Type::Boolean),
}, },
Expression::Range(_) => Some(Type::Range), Expression::Range(range_expression) => {
let start = match range_expression.inner.as_ref() {
RangeExpression::Exclusive { start, .. } => start,
RangeExpression::Inclusive { start, end } => start,
};
let start_type = start.return_type(context)?;
let rangeable_type = match start_type {
Type::Byte => RangeableType::Byte,
Type::Character => RangeableType::Character,
Type::Float => RangeableType::Float,
Type::Integer => RangeableType::Integer,
_ => return None,
};
Some(Type::Range {
r#type: rangeable_type,
})
}
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() { Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
StructExpression::Fields { fields, .. } => { StructExpression::Fields { fields, .. } => {
let mut types = HashMap::with_capacity(fields.len()); let mut types = HashMap::with_capacity(fields.len());
@ -375,6 +417,7 @@ impl Expression {
Expression::ListIndex(list_index) => list_index.position, Expression::ListIndex(list_index) => list_index.position,
Expression::Literal(literal) => literal.position, Expression::Literal(literal) => literal.position,
Expression::Loop(r#loop) => r#loop.position, Expression::Loop(r#loop) => r#loop.position,
Expression::Map(map) => map.position,
Expression::Operator(operator) => operator.position, Expression::Operator(operator) => operator.position,
Expression::Range(range) => range.position, Expression::Range(range) => range.position,
Expression::Struct(r#struct) => r#struct.position, Expression::Struct(r#struct) => r#struct.position,
@ -396,6 +439,7 @@ impl Display for Expression {
Expression::ListIndex(list_index) => write!(f, "{}", list_index.inner), Expression::ListIndex(list_index) => write!(f, "{}", list_index.inner),
Expression::Literal(literal) => write!(f, "{}", literal.inner), Expression::Literal(literal) => write!(f, "{}", literal.inner),
Expression::Loop(r#loop) => write!(f, "{}", r#loop.inner), Expression::Loop(r#loop) => write!(f, "{}", r#loop.inner),
Expression::Map(map) => write!(f, "{}", map.inner),
Expression::Operator(operator) => write!(f, "{}", operator.inner), Expression::Operator(operator) => write!(f, "{}", operator.inner),
Expression::Range(range) => write!(f, "{}", range), Expression::Range(range) => write!(f, "{}", range),
Expression::Struct(r#struct) => write!(f, "{}", r#struct.inner), Expression::Struct(r#struct) => write!(f, "{}", r#struct.inner),
@ -404,6 +448,27 @@ impl Display for Expression {
} }
} }
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct MapExpression {
pub pairs: Vec<(Node<Identifier>, Expression)>,
}
impl Display for MapExpression {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{{")?;
for (index, (key, value)) in self.pairs.iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}
write!(f, "{} = {}", key.inner, value)?;
}
write!(f, "}}")
}
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct TupleAccessExpression { pub struct TupleAccessExpression {
pub tuple: Expression, pub tuple: Expression,

View File

@ -433,6 +433,7 @@ impl<'src> Lexer<'src> {
"is_odd" => Token::IsOdd, "is_odd" => Token::IsOdd,
"length" => Token::Length, "length" => Token::Length,
"let" => Token::Let, "let" => Token::Let,
"map" => Token::Map,
"mut" => Token::Mut, "mut" => Token::Mut,
"read_line" => Token::ReadLine, "read_line" => Token::ReadLine,
"struct" => Token::Struct, "struct" => Token::Struct,
@ -501,6 +502,32 @@ impl Display for LexError {
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn map_expression() {
let input = "map { x = '1', y = 2, z = 3.0 }";
assert_eq!(
lex(input),
Ok(vec![
(Token::Map, (0, 3)),
(Token::LeftCurlyBrace, (4, 5)),
(Token::Identifier("x"), (6, 7)),
(Token::Equal, (8, 9)),
(Token::String("1"), (10, 13)),
(Token::Comma, (13, 14)),
(Token::Identifier("y"), (15, 16)),
(Token::Equal, (17, 18)),
(Token::Integer("2"), (19, 20)),
(Token::Comma, (20, 21)),
(Token::Identifier("z"), (22, 23)),
(Token::Equal, (24, 25)),
(Token::Float("3.0"), (26, 29)),
(Token::RightCurlyBrace, (30, 31)),
(Token::Eof, (31, 31)),
])
);
}
#[test] #[test]
fn let_statement() { fn let_statement() {
let input = "let x = 42"; let input = "let x = 42";

View File

@ -4,7 +4,6 @@
//! - `parse` convenience function //! - `parse` convenience function
//! - `Parser` struct, which parses the input a statement at a time //! - `Parser` struct, which parses the input a statement at a time
use std::{ use std::{
collections::VecDeque,
error::Error, error::Error,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
num::{ParseFloatError, ParseIntError}, num::{ParseFloatError, ParseIntError},
@ -180,10 +179,8 @@ impl<'src> Parser<'src> {
self.next_token()?; self.next_token()?;
let (name, name_end) = if let Token::Identifier(_) = self.current_token { let name = if let Token::Identifier(_) = self.current_token {
let end = self.current_position.1; self.parse_identifier()?
(self.parse_identifier()?, end)
} else { } else {
return Err(ParseError::ExpectedToken { return Err(ParseError::ExpectedToken {
expected: TokenKind::Identifier, expected: TokenKind::Identifier,
@ -192,6 +189,17 @@ impl<'src> Parser<'src> {
}); });
}; };
if let Token::Semicolon = self.current_token {
let end = self.current_position.1;
self.next_token()?;
return Ok(Statement::struct_definition(
StructDefinition::Unit { name },
(start_position.0, end),
));
}
if let Token::LeftParenthesis = self.current_token { if let Token::LeftParenthesis = self.current_token {
self.next_token()?; self.next_token()?;
@ -199,26 +207,45 @@ impl<'src> Parser<'src> {
loop { loop {
if let Token::RightParenthesis = self.current_token { if let Token::RightParenthesis = self.current_token {
let position = (start_position.0, self.current_position.1);
self.next_token()?; self.next_token()?;
return Ok(Statement::struct_definition( if let Token::Semicolon = self.current_token {
StructDefinition::Tuple { name, items: types }, break;
position, } else {
)); return Err(ParseError::ExpectedToken {
expected: TokenKind::Semicolon,
actual: self.current_token.to_owned(),
position: self.current_position,
});
} }
}
let type_node = self.parse_type()?;
types.push(type_node);
if let Token::Comma = self.current_token { if let Token::Comma = self.current_token {
self.next_token()?; self.next_token()?;
continue; continue;
} }
let type_node = self.parse_type()?;
types.push(type_node);
} }
let position = (start_position.0, self.current_position.1);
self.next_token()?;
return if types.is_empty() {
Ok(Statement::struct_definition(
StructDefinition::Unit { name },
position,
))
} else {
Ok(Statement::struct_definition(
StructDefinition::Tuple { name, items: types },
position,
))
};
} }
if let Token::LeftCurlyBrace = self.current_token { if let Token::LeftCurlyBrace = self.current_token {
@ -228,20 +255,11 @@ impl<'src> Parser<'src> {
loop { loop {
if let Token::RightCurlyBrace = self.current_token { if let Token::RightCurlyBrace = self.current_token {
let position = (start_position.0, self.current_position.1); if let Token::Semicolon = self.current_token {
self.next_token()?; self.next_token()?;
return Ok(Statement::struct_definition(
StructDefinition::Fields { name, fields },
position,
));
} }
if let Token::Comma = self.current_token { break;
self.next_token()?;
continue;
} }
let field_name = self.parse_identifier()?; let field_name = self.parse_identifier()?;
@ -259,13 +277,40 @@ impl<'src> Parser<'src> {
let field_type = self.parse_type()?; let field_type = self.parse_type()?;
fields.push((field_name, field_type)); fields.push((field_name, field_type));
if let Token::Comma = self.current_token {
self.next_token()?;
continue;
} }
} }
return Ok(Statement::struct_definition( let position = (start_position.0, self.current_position.1);
self.next_token()?;
return if fields.is_empty() {
Ok(Statement::struct_definition(
StructDefinition::Unit { name }, StructDefinition::Unit { name },
(start_position.0, name_end), position,
)); ))
} else {
Ok(Statement::struct_definition(
StructDefinition::Fields { name, fields },
position,
))
};
}
return Err(ParseError::ExpectedTokenMultiple {
expected: vec![
TokenKind::LeftParenthesis,
TokenKind::LeftCurlyBrace,
TokenKind::Semicolon,
],
actual: self.current_token.to_owned(),
position: self.current_position,
});
} }
let expression = self.parse_expression(0)?; let expression = self.parse_expression(0)?;
@ -569,6 +614,51 @@ impl<'src> Parser<'src> {
expressions.push(expression); expressions.push(expression);
} }
} }
Token::Map => {
self.next_token()?;
if let Token::LeftCurlyBrace = self.current_token {
self.next_token()?;
} else {
return Err(ParseError::ExpectedToken {
expected: TokenKind::LeftCurlyBrace,
actual: self.current_token.to_owned(),
position: self.current_position,
});
}
let mut fields = Vec::new();
loop {
if let Token::RightCurlyBrace = self.current_token {
let position = (start_position.0, self.current_position.1);
self.next_token()?;
return Ok(Expression::map(fields, position));
}
let field_name = self.parse_identifier()?;
if let Token::Equal = self.current_token {
self.next_token()?;
} else {
return Err(ParseError::ExpectedToken {
expected: TokenKind::Equal,
actual: self.current_token.to_owned(),
position: self.current_position,
});
}
let field_value = self.parse_expression(0)?;
fields.push((field_name, field_value));
if let Token::Comma = self.current_token {
self.next_token()?;
}
}
}
Token::While => { Token::While => {
self.next_token()?; self.next_token()?;
@ -1084,9 +1174,39 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn let_mut_while_loop() { fn map_expression() {
env_logger::builder().is_test(true).try_init().ok(); let source = "map { x = '1', y = 2, z = 3.0 }";
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree {
statements: [Statement::Expression(Expression::map(
vec![
(
Node::new(Identifier::new("x"), (6, 7)),
Expression::literal(
LiteralExpression::String("1".to_string()),
(10, 13)
),
),
(
Node::new(Identifier::new("y"), (15, 16)),
Expression::literal(LiteralExpression::Integer(2), (19, 20)),
),
(
Node::new(Identifier::new("z"), (22, 23)),
Expression::literal(LiteralExpression::Float(3.0), (26, 29)),
),
],
(0, 31),
))]
.into(),
})
);
}
#[test]
fn let_mut_while_loop() {
let source = "let mut x = 0; while x < 10 { x += 1 }; x"; let source = "let mut x = 0; while x < 10 { x += 1 }; x";
assert_eq!( assert_eq!(
@ -1307,36 +1427,26 @@ mod tests {
#[test] #[test]
fn tuple_struct_instantiation() { fn tuple_struct_instantiation() {
let source = "struct Foo(int, float) Foo(1, 2.0)"; let source = "Foo(1, 2.0)";
assert_eq!( assert_eq!(
parse(source), parse(source),
Ok(AbstractSyntaxTree::with_statements([ Ok(AbstractSyntaxTree::with_statements([
Statement::struct_definition(
StructDefinition::Tuple {
name: Node::new(Identifier::new("Foo"), (7, 10)),
items: vec![
Node::new(Type::Integer, (11, 14)),
Node::new(Type::Float, (16, 21)),
]
},
(0, 22)
),
Statement::Expression(Expression::call( Statement::Expression(Expression::call(
Expression::identifier(Identifier::new("Foo"), (23, 26)), Expression::identifier(Identifier::new("Foo"), (0, 3)),
vec![ vec![
Expression::literal(LiteralExpression::Integer(1), (27, 28)), Expression::literal(LiteralExpression::Integer(1), (4, 5)),
Expression::literal(LiteralExpression::Float(2.0), (30, 33)) Expression::literal(LiteralExpression::Float(2.0), (7, 10))
], ],
(23, 34) (0, 11)
)) ))
])) ]))
); );
} }
#[test] #[test]
fn tuple_struct() { fn tuple_struct_definition() {
let source = "struct Foo(int, float)"; let source = "struct Foo(int, float);";
assert_eq!( assert_eq!(
parse(source), parse(source),
@ -1349,7 +1459,7 @@ mod tests {
Node::new(Type::Float, (16, 21)), Node::new(Type::Float, (16, 21)),
], ],
}, },
(0, 22) (0, 23)
)) ))
])) ]))
); );
@ -1357,7 +1467,7 @@ mod tests {
#[test] #[test]
fn unit_struct() { fn unit_struct() {
let source = "struct Foo"; let source = "struct Foo;";
assert_eq!( assert_eq!(
parse(source), parse(source),
@ -1366,7 +1476,7 @@ mod tests {
StructDefinition::Unit { StructDefinition::Unit {
name: Node::new(Identifier::new("Foo"), (7, 10)), name: Node::new(Identifier::new("Foo"), (7, 10)),
}, },
(0, 10) (0, 11)
)) ))
])) ]))
); );

View File

@ -27,6 +27,7 @@ pub enum Token<'src> {
IsOdd, IsOdd,
Length, Length,
Let, Let,
Map,
Mut, Mut,
ReadLine, ReadLine,
Str, Str,
@ -101,6 +102,7 @@ impl<'src> Token<'src> {
Token::Let => TokenOwned::Let, Token::Let => TokenOwned::Let,
Token::Less => TokenOwned::Less, Token::Less => TokenOwned::Less,
Token::LessEqual => TokenOwned::LessOrEqual, Token::LessEqual => TokenOwned::LessOrEqual,
Token::Map => TokenOwned::Map,
Token::Minus => TokenOwned::Minus, Token::Minus => TokenOwned::Minus,
Token::MinusEqual => TokenOwned::MinusEqual, Token::MinusEqual => TokenOwned::MinusEqual,
Token::Mut => TokenOwned::Mut, Token::Mut => TokenOwned::Mut,
@ -159,6 +161,7 @@ impl<'src> Token<'src> {
Token::Length => "length", Token::Length => "length",
Token::Less => "<", Token::Less => "<",
Token::LessEqual => "<=", Token::LessEqual => "<=",
Token::Map => "map",
Token::Minus => "-", Token::Minus => "-",
Token::MinusEqual => "-=", Token::MinusEqual => "-=",
Token::Mut => "mut", Token::Mut => "mut",
@ -214,6 +217,7 @@ impl<'src> Token<'src> {
Token::Length => TokenKind::Length, Token::Length => TokenKind::Length,
Token::Less => TokenKind::Less, Token::Less => TokenKind::Less,
Token::LessEqual => TokenKind::LessOrEqual, Token::LessEqual => TokenKind::LessOrEqual,
Token::Map => TokenKind::Map,
Token::Minus => TokenKind::Minus, Token::Minus => TokenKind::Minus,
Token::MinusEqual => TokenKind::MinusEqual, Token::MinusEqual => TokenKind::MinusEqual,
Token::Mut => TokenKind::Mut, Token::Mut => TokenKind::Mut,
@ -320,6 +324,7 @@ pub enum TokenOwned {
IsOdd, IsOdd,
Let, Let,
Length, Length,
Map,
Mut, Mut,
ReadLine, ReadLine,
Str, Str,
@ -395,6 +400,7 @@ impl Display for TokenOwned {
TokenOwned::Let => Token::Let.fmt(f), TokenOwned::Let => Token::Let.fmt(f),
TokenOwned::Less => Token::Less.fmt(f), TokenOwned::Less => Token::Less.fmt(f),
TokenOwned::LessOrEqual => Token::LessEqual.fmt(f), TokenOwned::LessOrEqual => Token::LessEqual.fmt(f),
TokenOwned::Map => Token::Map.fmt(f),
TokenOwned::Minus => Token::Minus.fmt(f), TokenOwned::Minus => Token::Minus.fmt(f),
TokenOwned::MinusEqual => Token::MinusEqual.fmt(f), TokenOwned::MinusEqual => Token::MinusEqual.fmt(f),
TokenOwned::Mut => Token::Mut.fmt(f), TokenOwned::Mut => Token::Mut.fmt(f),
@ -442,6 +448,7 @@ pub enum TokenKind {
IsOdd, IsOdd,
Length, Length,
Let, Let,
Map,
ReadLine, ReadLine,
Str, Str,
ToString, ToString,
@ -516,6 +523,7 @@ impl Display for TokenKind {
TokenKind::Let => Token::Let.fmt(f), TokenKind::Let => Token::Let.fmt(f),
TokenKind::Less => Token::Less.fmt(f), TokenKind::Less => Token::Less.fmt(f),
TokenKind::LessOrEqual => Token::LessEqual.fmt(f), TokenKind::LessOrEqual => Token::LessEqual.fmt(f),
TokenKind::Map => Token::Map.fmt(f),
TokenKind::Minus => Token::Minus.fmt(f), TokenKind::Minus => Token::Minus.fmt(f),
TokenKind::MinusEqual => Token::MinusEqual.fmt(f), TokenKind::MinusEqual => Token::MinusEqual.fmt(f),
TokenKind::Mut => Token::Mut.fmt(f), TokenKind::Mut => Token::Mut.fmt(f),
@ -543,31 +551,17 @@ impl Display for TokenKind {
pub(crate) mod tests { pub(crate) mod tests {
use super::*; use super::*;
pub fn all_tokens<'src>() -> [Token<'src>; 51] { pub fn all_tokens<'src>() -> [Token<'src>; 52] {
[ [
Token::Eof, Token::Identifier("foobar"),
Token::Identifier("identifier"),
Token::Boolean("true"), Token::Boolean("true"),
Token::Float("1.0"), Token::Float("1.0"),
Token::Integer("1"), Token::Integer("1"),
Token::String("string"), Token::String("string"),
Token::Async, Token::Async,
Token::Bool,
Token::Else,
Token::FloatKeyword,
Token::If,
Token::Int,
Token::IsEven,
Token::IsOdd,
Token::Length,
Token::Let,
Token::ReadLine,
Token::Str,
Token::ToString,
Token::While,
Token::WriteLine,
Token::BangEqual,
Token::Bang, Token::Bang,
Token::BangEqual,
Token::Bool,
Token::Colon, Token::Colon,
Token::Comma, Token::Comma,
Token::Dot, Token::Dot,
@ -575,27 +569,42 @@ pub(crate) mod tests {
Token::DoubleDot, Token::DoubleDot,
Token::DoubleEqual, Token::DoubleEqual,
Token::DoublePipe, Token::DoublePipe,
Token::Else,
Token::Eof,
Token::Equal, Token::Equal,
Token::FloatKeyword,
Token::Greater, Token::Greater,
Token::GreaterEqual, Token::GreaterEqual,
Token::If,
Token::Int,
Token::IsEven,
Token::IsOdd,
Token::LeftCurlyBrace, Token::LeftCurlyBrace,
Token::LeftParenthesis, Token::LeftParenthesis,
Token::LeftSquareBrace, Token::LeftSquareBrace,
Token::Length,
Token::Less, Token::Less,
Token::LessEqual, Token::LessEqual,
Token::Let,
Token::Map,
Token::Minus, Token::Minus,
Token::MinusEqual, Token::MinusEqual,
Token::Mut, Token::Mut,
Token::Percent, Token::Percent,
Token::Plus, Token::Plus,
Token::PlusEqual, Token::PlusEqual,
Token::ReadLine,
Token::RightCurlyBrace, Token::RightCurlyBrace,
Token::RightParenthesis, Token::RightParenthesis,
Token::RightSquareBrace, Token::RightSquareBrace,
Token::Semicolon, Token::Semicolon,
Token::Star,
Token::Struct,
Token::Slash, Token::Slash,
Token::Star,
Token::Str,
Token::Struct,
Token::ToString,
Token::While,
Token::WriteLine,
] ]
} }

View File

@ -13,17 +13,16 @@ use std::{
cmp::Ordering, cmp::Ordering,
collections::HashMap, collections::HashMap,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
sync::Arc,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{value::Function, Identifier}; use crate::Identifier;
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
/// Description of a kind of value. /// Description of a kind of value.
/// ///
/// See the [module documentation](index.html) for more information. /// See the [module documentation](index.html) for more information.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum Type { pub enum Type {
Any, Any,
Boolean, Boolean,
@ -45,8 +44,13 @@ pub enum Type {
ListOf { ListOf {
item_type: Box<Type>, item_type: Box<Type>,
}, },
Map {
pairs: HashMap<Identifier, Type>,
},
Number, Number,
Range, Range {
r#type: RangeableType,
},
String, String,
Struct(StructType), Struct(StructType),
Tuple(TupleType), Tuple(TupleType),
@ -72,7 +76,6 @@ impl Type {
| (Type::Boolean, Type::Boolean) | (Type::Boolean, Type::Boolean)
| (Type::Float, Type::Float) | (Type::Float, Type::Float)
| (Type::Integer, Type::Integer) | (Type::Integer, Type::Integer)
| (Type::Range, Type::Range)
| (Type::String, Type::String) => return Ok(()), | (Type::String, Type::String) => return Ok(()),
( (
Type::Generic { Type::Generic {
@ -192,38 +195,21 @@ impl Type {
return_type: right_return, return_type: right_return,
}), }),
) => { ) => {
if left_name != right_name { if left_name != right_name
return Err(TypeConflict { || left_return != right_return
actual: other.clone(), || left_type_parameters != right_type_parameters
expected: self.clone(), || left_value_parameters != right_value_parameters
});
}
if left_return == right_return {
for (left_parameter, right_parameter) in left_type_parameters
.iter()
.zip(right_type_parameters.iter())
{ {
if left_parameter != right_parameter {
return Err(TypeConflict { return Err(TypeConflict {
actual: other.clone(), actual: other.clone(),
expected: self.clone(), expected: self.clone(),
}); });
} }
}
for (left_parameter, right_parameter) in left_value_parameters return Ok(());
.iter()
.zip(right_value_parameters.iter())
{
if left_parameter != right_parameter {
return Err(TypeConflict {
actual: other.clone(),
expected: self.clone(),
});
} }
} (Type::Range { r#type: left_type }, Type::Range { r#type: right_type }) => {
if left_type == right_type {
return Ok(()); return Ok(());
} }
} }
@ -248,7 +234,7 @@ impl Display for Type {
Type::Boolean => write!(f, "bool"), Type::Boolean => write!(f, "bool"),
Type::Byte => write!(f, "byte"), Type::Byte => write!(f, "byte"),
Type::Character => write!(f, "char"), Type::Character => write!(f, "char"),
Type::Enum(enum_type) => write!(f, "{enum_type}"), Type::Enum(EnumType { name, .. }) => write!(f, "{name}"),
Type::Float => write!(f, "float"), Type::Float => write!(f, "float"),
Type::Function(function_type) => write!(f, "{function_type}"), Type::Function(function_type) => write!(f, "{function_type}"),
Type::Generic { concrete_type, .. } => { Type::Generic { concrete_type, .. } => {
@ -262,10 +248,53 @@ impl Display for Type {
Type::List { item_type, length } => write!(f, "[{item_type}; {length}]"), Type::List { item_type, length } => write!(f, "[{item_type}; {length}]"),
Type::ListEmpty => write!(f, "[]"), Type::ListEmpty => write!(f, "[]"),
Type::ListOf { item_type } => write!(f, "[{item_type}]"), Type::ListOf { item_type } => write!(f, "[{item_type}]"),
Type::Map { pairs } => {
write!(f, "map ")?;
write!(f, "{{")?;
for (index, (key, value)) in pairs.iter().enumerate() {
write!(f, "{key}: {value}")?;
if index != pairs.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "}}")
}
Type::Number => write!(f, "num"), Type::Number => write!(f, "num"),
Type::Range => write!(f, "range"), Type::Range { r#type } => write!(f, "{type} range"),
Type::String => write!(f, "str"), Type::String => write!(f, "str"),
Type::Struct(struct_type) => write!(f, "{struct_type}"), Type::Struct(struct_type) => match struct_type {
StructType::Unit => write!(f, "()"),
StructType::Tuple(TupleType { fields }) => {
write!(f, "(")?;
for (index, r#type) in fields.iter().enumerate() {
write!(f, "{type}")?;
if index != fields.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
StructType::Fields(FieldsStructType { fields }) => {
write!(f, "{{")?;
for (index, (name, r#type)) in fields.iter().enumerate() {
write!(f, "{name}: {type}")?;
if index != fields.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "}}")
}
},
Type::Tuple(TupleType { fields }) => { Type::Tuple(TupleType { fields }) => {
write!(f, "(")?; write!(f, "(")?;
@ -283,6 +312,85 @@ impl Display for Type {
} }
} }
impl PartialOrd for Type {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Type {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Type::Any, Type::Any) => Ordering::Equal,
(Type::Any, _) => Ordering::Greater,
(Type::Boolean, Type::Boolean) => Ordering::Equal,
(Type::Boolean, _) => Ordering::Greater,
(Type::Byte, Type::Byte) => Ordering::Equal,
(Type::Byte, _) => Ordering::Greater,
(Type::Character, Type::Character) => Ordering::Equal,
(Type::Character, _) => Ordering::Greater,
(Type::Enum(left_enum), Type::Enum(right_enum)) => left_enum.cmp(right_enum),
(Type::Enum(_), _) => Ordering::Greater,
(Type::Float, Type::Float) => Ordering::Equal,
(Type::Float, _) => Ordering::Greater,
(Type::Function(left_function), Type::Function(right_function)) => {
left_function.cmp(right_function)
}
(Type::Function(_), _) => Ordering::Greater,
(Type::Generic { .. }, Type::Generic { .. }) => Ordering::Equal,
(Type::Generic { .. }, _) => Ordering::Greater,
(Type::Integer, Type::Integer) => Ordering::Equal,
(Type::Integer, _) => Ordering::Greater,
(
Type::List {
item_type: left_item_type,
length: left_length,
},
Type::List {
item_type: right_item_type,
length: right_length,
},
) => {
if left_length == right_length {
left_item_type.cmp(right_item_type)
} else {
left_length.cmp(right_length)
}
}
(Type::List { .. }, _) => Ordering::Greater,
(Type::ListEmpty, Type::ListEmpty) => Ordering::Equal,
(Type::ListEmpty, _) => Ordering::Greater,
(
Type::ListOf {
item_type: left_item_type,
},
Type::ListOf {
item_type: right_item_type,
},
) => left_item_type.cmp(right_item_type),
(Type::ListOf { .. }, _) => Ordering::Greater,
(Type::Map { pairs: left_pairs }, Type::Map { pairs: right_pairs }) => {
left_pairs.iter().cmp(right_pairs.iter())
}
(Type::Map { .. }, _) => Ordering::Greater,
(Type::Number, Type::Number) => Ordering::Equal,
(Type::Number, _) => Ordering::Greater,
(Type::Range { r#type: left_type }, Type::Range { r#type: right_type }) => {
left_type.cmp(right_type)
}
(Type::Range { .. }, _) => Ordering::Greater,
(Type::String, Type::String) => Ordering::Equal,
(Type::String, _) => Ordering::Greater,
(Type::Struct(left_struct), Type::Struct(right_struct)) => {
left_struct.cmp(right_struct)
}
(Type::Struct(_), _) => Ordering::Greater,
(Type::Tuple(left_tuple), Type::Tuple(right_tuple)) => left_tuple.cmp(right_tuple),
(Type::Tuple(_), _) => Ordering::Greater,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct FunctionType { pub struct FunctionType {
pub name: Identifier, pub name: Identifier,
@ -339,35 +447,11 @@ pub enum StructType {
} }
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(TupleType { fields, .. }) => { StructType::Tuple(tuple) => write!(f, "{tuple}"),
write!(f, "(")?; StructType::Fields(fields) => write!(f, "{fields}"),
for (index, r#type) in fields.iter().enumerate() {
write!(f, "{type}")?;
if index != fields.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
StructType::Fields(FieldsStructType { fields, .. }) => {
write!(f, "{{ ")?;
for (index, (identifier, r#type)) in fields.iter().enumerate() {
write!(f, "{identifier}: {type}")?;
if index != fields.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, " }}")
}
} }
} }
} }
@ -377,11 +461,43 @@ pub struct TupleType {
pub fields: Vec<Type>, pub fields: Vec<Type>,
} }
impl Display for TupleType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "(")?;
for (index, field) in self.fields.iter().enumerate() {
write!(f, "{field}")?;
if index != self.fields.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct FieldsStructType { pub struct FieldsStructType {
pub fields: HashMap<Identifier, Type>, pub fields: HashMap<Identifier, Type>,
} }
impl Display for FieldsStructType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{{ ")?;
for (index, (identifier, r#type)) in self.fields.iter().enumerate() {
write!(f, "{identifier}: {type}")?;
if index != self.fields.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, " }}")
}
}
impl PartialOrd for FieldsStructType { impl PartialOrd for FieldsStructType {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
@ -401,8 +517,39 @@ pub struct EnumType {
} }
impl Display for EnumType { impl Display for EnumType {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name) let EnumType { name, variants } = self;
write!(f, "enum {name} {{")?;
for (index, variant) in variants.iter().enumerate() {
write!(f, "{variant}")?;
if index != self.variants.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "}}")
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum RangeableType {
Byte,
Character,
Float,
Integer,
}
impl Display for RangeableType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
RangeableType::Byte => Type::Byte.fmt(f),
RangeableType::Character => Type::Character.fmt(f),
RangeableType::Float => Type::Float.fmt(f),
RangeableType::Integer => Type::Integer.fmt(f),
}
} }
} }
@ -476,7 +623,9 @@ mod tests {
item_type: Box::new(Type::Integer), item_type: Box::new(Type::Integer),
length: 42, length: 42,
}, },
Type::Range, Type::Range {
r#type: RangeableType::Integer,
},
Type::String, Type::String,
]; ];

View File

@ -4,19 +4,20 @@ use std::{
collections::HashMap, collections::HashMap,
error::Error, error::Error,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
ops::{Range, RangeInclusive}, ops::{Index, Range, RangeInclusive},
rc::Weak,
sync::{Arc, RwLock}, sync::{Arc, RwLock},
}; };
use serde::{ use serde::{
de::{self, MapAccess, Visitor}, de::{self, MapAccess, Visitor},
ser::{SerializeStruct, SerializeStructVariant}, ser::{SerializeMap, SerializeStruct, SerializeStructVariant},
Deserialize, Deserializer, Serialize, Serializer, Deserialize, Deserializer, Serialize, Serializer,
}; };
use crate::{ use crate::{
AbstractSyntaxTree, Context, EnumType, FieldsStructType, FunctionType, Identifier, AbstractSyntaxTree, Context, EnumType, FieldsStructType, FunctionType, Identifier,
RuntimeError, StructType, TupleType, Type, Vm, RangeableType, RuntimeError, StructType, TupleType, Type, Vm,
}; };
/// Dust value representation /// Dust value representation
@ -61,6 +62,7 @@ pub enum Value {
Function(Function), Function(Function),
Integer(i64), Integer(i64),
List(Vec<Value>), List(Vec<Value>),
Map(HashMap<Identifier, Value>),
Mutable(Arc<RwLock<Value>>), Mutable(Arc<RwLock<Value>>),
Range(Range<Rangeable>), Range(Range<Rangeable>),
RangeInclusive(RangeInclusive<Rangeable>), RangeInclusive(RangeInclusive<Rangeable>),
@ -70,6 +72,10 @@ pub enum Value {
} }
impl Value { impl Value {
pub fn map<T: Into<HashMap<Identifier, Value>>>(pairs: T) -> Value {
Value::Map(pairs.into())
}
pub fn mutable(value: Value) -> Value { pub fn mutable(value: Value) -> Value {
Value::Mutable(Arc::new(RwLock::new(value))) Value::Mutable(Arc::new(RwLock::new(value)))
} }
@ -194,9 +200,25 @@ impl Value {
length: values.len(), length: values.len(),
} }
} }
Value::Map(map) => {
let pairs = map
.iter()
.map(|(key, value)| (key.clone(), value.r#type()))
.collect();
Type::Map { pairs }
}
Value::Mutable(locked) => locked.read().unwrap().r#type(), Value::Mutable(locked) => locked.read().unwrap().r#type(),
Value::Range(_) => Type::Range, Value::Range(range) => Type::Range {
Value::RangeInclusive(_) => Type::Range, r#type: range.start.r#type(),
},
Value::RangeInclusive(range_inclusive) => {
let rangeable_type = range_inclusive.start().r#type();
Type::Range {
r#type: rangeable_type,
}
}
Value::String(_) => Type::String, Value::String(_) => Type::String,
Value::Struct(r#struct) => match r#struct { Value::Struct(r#struct) => match r#struct {
Struct::Unit { .. } => Type::Struct(StructType::Unit), Struct::Unit { .. } => Type::Struct(StructType::Unit),
@ -230,12 +252,69 @@ impl Value {
} }
} }
pub fn get_index(&self, index: usize) -> Option<Value> { pub fn get_index(&self, index: Value) -> Result<Option<Value>, ValueError> {
match self { match (self, index) {
Value::List(values) => values.get(index).cloned(), (Value::Mutable(left), Value::Mutable(right)) => {
Value::Mutable(inner) => inner.read().unwrap().get_index(index), return left
Value::Struct(Struct::Tuple { fields, .. }) => fields.get(index).cloned(), .read()
_ => None, .unwrap()
.get_index(right.read().unwrap().clone());
}
(Value::Mutable(locked), index) => {
return locked.read().unwrap().get_index(index);
}
(left, Value::Mutable(locked)) => {
return left.get_index(locked.read().unwrap().clone());
}
(Value::List(values), Value::Integer(integer)) => {
let index = integer as usize;
return Ok(values.get(index).cloned());
}
(Value::List(values), Value::Range(range)) => match (range.start, range.end) {
(Rangeable::Integer(start), Rangeable::Integer(end)) => {
let start = start as usize;
let end = end as usize;
return Ok(values
.get(start..end)
.map(|values| Value::List(values.to_vec())));
}
(start, end) => Err(ValueError::CannotIndex {
value: self.clone(),
index: Value::Range(start..end),
}),
},
(Value::String(string), Value::Range(range)) => match (range.start, range.end) {
(Rangeable::Integer(start), Rangeable::Integer(end)) => {
let start = start as usize;
let end = end as usize;
return Ok(string.get(start..end).map(Value::string));
}
(start, end) => Err(ValueError::CannotIndex {
value: self.clone(),
index: Value::Range(start..end),
}),
},
(Value::Range(range), Value::Integer(index)) => match (range.start, range.end) {
(Rangeable::Integer(start), Rangeable::Integer(end)) => {
Ok((start..end).nth(index as usize).map(Value::Integer))
}
(start, end) => Err(ValueError::CannotIndex {
value: self.clone(),
index: Value::Range(start..end),
}),
},
(Value::String(string), Value::Integer(integer)) => {
let index = integer as usize;
return Ok(string.chars().nth(index).map(Value::Character));
}
(value, index) => Err(ValueError::CannotIndex {
value: value.clone(),
index,
}),
} }
} }
@ -295,7 +374,7 @@ impl Value {
_ => {} _ => {}
} }
Err(ValueError::CannotAdd(self.clone(), other.clone())) Err(ValueError::CannotMutate(self.clone()))
} }
pub fn subtract(&self, other: &Value) -> Result<Value, ValueError> { pub fn subtract(&self, other: &Value) -> Result<Value, ValueError> {
@ -698,6 +777,19 @@ impl Display for Value {
Value::Float(float) => write!(f, "{float}"), Value::Float(float) => write!(f, "{float}"),
Value::Function(function) => write!(f, "{function}"), Value::Function(function) => write!(f, "{function}"),
Value::Integer(integer) => write!(f, "{integer}"), Value::Integer(integer) => write!(f, "{integer}"),
Value::Map(pairs) => {
write!(f, "{{ ")?;
for (index, (key, value)) in pairs.iter().enumerate() {
write!(f, "{key}: {value}")?;
if index < pairs.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, " }}")
}
Value::List(list) => { Value::List(list) => {
write!(f, "[")?; write!(f, "[")?;
@ -751,6 +843,7 @@ impl PartialEq for Value {
(Value::Function(left), Value::Function(right)) => left == right, (Value::Function(left), Value::Function(right)) => left == right,
(Value::Integer(left), Value::Integer(right)) => left == right, (Value::Integer(left), Value::Integer(right)) => left == right,
(Value::List(left), Value::List(right)) => left == right, (Value::List(left), Value::List(right)) => left == right,
(Value::Map(left), Value::Map(right)) => left == right,
(Value::Mutable(left), Value::Mutable(right)) => { (Value::Mutable(left), Value::Mutable(right)) => {
let left = &*left.read().unwrap(); let left = &*left.read().unwrap();
let right = &*right.read().unwrap(); let right = &*right.read().unwrap();
@ -853,6 +946,15 @@ impl Serialize for Value {
Value::Function(function) => function.serialize(serializer), Value::Function(function) => function.serialize(serializer),
Value::Integer(integer) => serializer.serialize_i64(*integer), Value::Integer(integer) => serializer.serialize_i64(*integer),
Value::List(list) => list.serialize(serializer), Value::List(list) => list.serialize(serializer),
Value::Map(pairs) => {
let mut ser = serializer.serialize_map(Some(pairs.len()))?;
for (key, value) in pairs {
ser.serialize_entry(key, value)?;
}
ser.end()
}
Value::Range(range) => range.serialize(serializer), Value::Range(range) => range.serialize(serializer),
Value::RangeInclusive(inclusive) => inclusive.serialize(serializer), Value::RangeInclusive(inclusive) => inclusive.serialize(serializer),
Value::String(string) => serializer.serialize_str(string), Value::String(string) => serializer.serialize_str(string),
@ -1033,7 +1135,7 @@ impl<'de> Deserialize<'de> for Function {
return Err(de::Error::duplicate_field("body")); return Err(de::Error::duplicate_field("body"));
} }
body = Some(map.next_value().map(|ast| Arc::new(ast))?); body = Some(map.next_value().map(Arc::new)?);
} }
_ => { _ => {
return Err(de::Error::unknown_field(key, &["name", "type", "body"])); return Err(de::Error::unknown_field(key, &["name", "type", "body"]));
@ -1156,7 +1258,7 @@ impl Display for Struct {
} }
} }
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub enum Rangeable { pub enum Rangeable {
Byte(u8), Byte(u8),
Character(char), Character(char),
@ -1164,6 +1266,17 @@ pub enum Rangeable {
Integer(i64), Integer(i64),
} }
impl Rangeable {
fn r#type(&self) -> RangeableType {
match self {
Rangeable::Byte(_) => RangeableType::Byte,
Rangeable::Character(_) => RangeableType::Character,
Rangeable::Float(_) => RangeableType::Float,
Rangeable::Integer(_) => RangeableType::Integer,
}
}
}
impl Display for Rangeable { impl Display for Rangeable {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {

View File

@ -5,6 +5,7 @@
//! - `run_with_context` convenience function that takes a source code string and a context //! - `run_with_context` convenience function that takes a source code string and a context
//! - `Vm` struct that can be used to run an abstract syntax tree //! - `Vm` struct that can be used to run an abstract syntax tree
use std::{ use std::{
collections::HashMap,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@ -15,11 +16,11 @@ use crate::{
ast::{ ast::{
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, MapExpression, MathOperator, Node,
RangeExpression, Span, Statement, StructDefinition, OperatorExpression, RangeExpression, Span, Statement, StructDefinition, StructExpression,
}, },
parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, Identifier, ParseError, parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, FieldsStructType,
StructType, TupleType, Type, Value, ValueError, Identifier, ParseError, Struct, StructType, TupleType, Type, Value, ValueError,
}; };
/// Run the source code and return the result. /// Run the source code and return the result.
@ -129,7 +130,17 @@ impl Vm {
(name.inner.clone(), StructType::Tuple(TupleType { fields })) (name.inner.clone(), StructType::Tuple(TupleType { fields }))
} }
StructDefinition::Fields { name, fields } => todo!(), StructDefinition::Fields { name, fields } => {
let fields = fields
.into_iter()
.map(|(identifier, r#type)| (identifier.inner, r#type.inner))
.collect();
(
name.inner.clone(),
StructType::Fields(FieldsStructType { fields }),
)
}
}; };
self.context self.context
@ -202,7 +213,7 @@ impl Vm {
if let Some(value) = get_value { if let Some(value) = get_value {
Ok(Evaluation::Return(Some(value))) Ok(Evaluation::Return(Some(value)))
} else { } else {
Err(RuntimeError::UndefinedVariable { Err(RuntimeError::UndefinedValue {
identifier: identifier.inner, identifier: identifier.inner,
position: identifier.position, position: identifier.position,
}) })
@ -217,10 +228,99 @@ impl Vm {
} }
Expression::Literal(literal) => self.run_literal(*literal.inner), Expression::Literal(literal) => self.run_literal(*literal.inner),
Expression::Loop(loop_expression) => self.run_loop(*loop_expression.inner), Expression::Loop(loop_expression) => self.run_loop(*loop_expression.inner),
Expression::Map(map_expression) => self.run_map(*map_expression.inner, collect_garbage),
Expression::Operator(operator_expression) => { Expression::Operator(operator_expression) => {
self.run_operator(*operator_expression.inner, collect_garbage) self.run_operator(*operator_expression.inner, collect_garbage)
} }
Expression::Range(range_expression) => match *range_expression.inner { Expression::Range(range_expression) => {
self.run_range(*range_expression.inner, collect_garbage)
}
Expression::Struct(struct_expression) => {
self.run_struct(*struct_expression.inner, collect_garbage)
}
Expression::TupleAccess(_) => todo!(),
};
evaluation_result.map_err(|error| RuntimeError::Trace {
error: Box::new(error),
position,
})
}
fn run_struct(
&self,
struct_expression: StructExpression,
collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
match struct_expression {
StructExpression::Unit { name } => {
let position = name.position;
let r#type = self.context.get_type(&name.inner).ok_or_else(|| {
RuntimeError::UndefinedType {
identifier: name.inner.clone(),
position,
}
})?;
if let Type::Struct(StructType::Unit) = r#type {
Ok(Evaluation::Return(Some(Value::Struct(Struct::Unit {
name: name.inner,
}))))
} else {
Err(RuntimeError::ExpectedType {
expected: Type::Struct(StructType::Unit),
actual: r#type,
position,
})
}
}
StructExpression::Fields {
name,
fields: expressions,
} => {
let position = name.position;
let r#type = self.context.get_type(&name.inner).ok_or_else(|| {
RuntimeError::UndefinedType {
identifier: name.inner.clone(),
position,
}
})?;
if let Type::Struct(StructType::Fields(FieldsStructType { .. })) = r#type {
let mut values = HashMap::with_capacity(expressions.len());
for (identifier, expression) in expressions {
let expression_position = expression.position();
let value = self
.run_expression(expression, collect_garbage)?
.expect_value(expression_position)?;
values.insert(identifier.inner, value);
}
Ok(Evaluation::Return(Some(Value::Struct(Struct::Fields {
name: name.inner,
fields: values,
}))))
} else {
Err(RuntimeError::ExpectedType {
expected: Type::Struct(StructType::Fields(FieldsStructType {
fields: HashMap::new(),
})),
actual: r#type,
position,
})
}
}
}
}
fn run_range(
&self,
range: RangeExpression,
collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
match range {
RangeExpression::Exclusive { start, end } => { RangeExpression::Exclusive { start, end } => {
let start_position = start.position(); let start_position = start.position();
let start = self let start = self
@ -270,24 +370,37 @@ impl Vm {
(Value::Float(start), Value::Float(end)) => Ok(Evaluation::Return(Some( (Value::Float(start), Value::Float(end)) => Ok(Evaluation::Return(Some(
Value::float_range_inclusive(start, end), Value::float_range_inclusive(start, end),
))), ))),
(Value::Integer(start), Value::Integer(end)) => Ok(Evaluation::Return( (Value::Integer(start), Value::Integer(end)) => Ok(Evaluation::Return(Some(
Some(Value::integer_range_inclusive(start, end)), Value::integer_range_inclusive(start, end),
)), ))),
_ => Err(RuntimeError::InvalidRange { _ => Err(RuntimeError::InvalidRange {
start_position, start_position,
end_position, end_position,
}), }),
} }
} }
}, }
Expression::Struct(_) => todo!(), }
Expression::TupleAccess(_) => todo!(),
};
evaluation_result.map_err(|error| RuntimeError::Trace { fn run_map(
error: Box::new(error), &self,
position, map: MapExpression,
}) collect_garbage: bool,
) -> Result<Evaluation, RuntimeError> {
let MapExpression { pairs } = map;
let mut map = HashMap::new();
for (identifier, expression) in pairs {
let expression_position = expression.position();
let value = self
.run_expression(expression, collect_garbage)?
.expect_value(expression_position)?;
map.insert(identifier.inner, value);
}
Ok(Evaluation::Return(Some(Value::Map(map))))
} }
fn run_operator( fn run_operator(
@ -530,17 +643,16 @@ impl Vm {
.run_expression(index, collect_garbage)? .run_expression(index, collect_garbage)?
.expect_value(index_position)?; .expect_value(index_position)?;
let index = if let Some(index) = index_value.as_integer() { let get_index =
index as usize list_value
} else { .get_index(index_value)
return Err(RuntimeError::ExpectedInteger { .map_err(|error| RuntimeError::ValueError {
position: index_position, error,
}); left_position: list_position,
}; right_position: index_position,
})?;
let value_option = list_value.get_index(index); Ok(Evaluation::Return(get_index))
Ok(Evaluation::Return(value_option))
} }
fn run_call( fn run_call(
@ -797,10 +909,6 @@ pub enum RuntimeError {
error: BuiltInFunctionError, error: BuiltInFunctionError,
position: Span, position: Span,
}, },
CannotMutate {
value: Value,
position: Span,
},
ExpectedBoolean { ExpectedBoolean {
position: Span, position: Span,
}, },
@ -822,6 +930,11 @@ pub enum RuntimeError {
ExpectedMap { ExpectedMap {
position: Span, position: Span,
}, },
ExpectedType {
expected: Type,
actual: Type,
position: Span,
},
ExpectedFunction { ExpectedFunction {
actual: Value, actual: Value,
position: Span, position: Span,
@ -836,7 +949,11 @@ pub enum RuntimeError {
start_position: Span, start_position: Span,
end_position: Span, end_position: Span,
}, },
UndefinedVariable { UndefinedType {
identifier: Identifier,
position: Span,
},
UndefinedValue {
identifier: Identifier, identifier: Identifier,
position: Span, position: Span,
}, },
@ -859,23 +976,24 @@ impl RuntimeError {
.. ..
} => (left_position.0, right_position.1), } => (left_position.0, right_position.1),
Self::BuiltInFunctionError { position, .. } => *position, Self::BuiltInFunctionError { position, .. } => *position,
Self::CannotMutate { position, .. } => *position,
Self::ExpectedBoolean { position } => *position, Self::ExpectedBoolean { position } => *position,
Self::ExpectedFunction { position, .. } => *position,
Self::ExpectedIdentifier { position } => *position, Self::ExpectedIdentifier { position } => *position,
Self::ExpectedIntegerOrRange { position } => *position,
Self::ExpectedIdentifierOrString { position } => *position, Self::ExpectedIdentifierOrString { position } => *position,
Self::ExpectedInteger { position } => *position, Self::ExpectedInteger { position } => *position,
Self::ExpectedNumber { position } => *position, Self::ExpectedIntegerOrRange { position } => *position,
Self::ExpectedMap { position } => *position,
Self::ExpectedFunction { position, .. } => *position,
Self::ExpectedList { position } => *position, Self::ExpectedList { position } => *position,
Self::ExpectedMap { position } => *position,
Self::ExpectedNumber { position } => *position,
Self::ExpectedType { position, .. } => *position,
Self::ExpectedValue { position } => *position, Self::ExpectedValue { position } => *position,
Self::InvalidRange { Self::InvalidRange {
start_position, start_position,
end_position, end_position,
.. ..
} => (start_position.0, end_position.1), } => (start_position.0, end_position.1),
Self::UndefinedVariable { position, .. } => *position, Self::UndefinedType { position, .. } => *position,
Self::UndefinedValue { position, .. } => *position,
Self::UndefinedProperty { Self::UndefinedProperty {
property_position, .. property_position, ..
} => *property_position, } => *property_position,
@ -911,9 +1029,6 @@ impl Display for RuntimeError {
left_position, right_position, error left_position, right_position, error
) )
} }
Self::CannotMutate { value, .. } => {
write!(f, "Cannot mutate immutable value {}", value)
}
Self::BuiltInFunctionError { error, .. } => { Self::BuiltInFunctionError { error, .. } => {
write!(f, "{}", error) write!(f, "{}", error)
} }
@ -950,6 +1065,17 @@ impl Display for RuntimeError {
Self::ExpectedList { position } => { Self::ExpectedList { position } => {
write!(f, "Expected a list at position: {:?}", position) write!(f, "Expected a list at position: {:?}", position)
} }
Self::ExpectedType {
expected,
actual,
position,
} => {
write!(
f,
"Expected type {}, but got {} at position: {:?}",
expected, actual, position
)
}
Self::ExpectedMap { position } => { Self::ExpectedMap { position } => {
write!(f, "Expected a map at position: {:?}", position) write!(f, "Expected a map at position: {:?}", position)
} }
@ -973,7 +1099,7 @@ impl Display for RuntimeError {
start_position, end_position start_position, end_position
) )
} }
Self::UndefinedVariable { Self::UndefinedValue {
identifier, identifier,
position, position,
} => { } => {
@ -988,6 +1114,16 @@ impl Display for RuntimeError {
} => { } => {
write!(f, "Value {} does not have the property {}", value, property) write!(f, "Value {} does not have the property {}", value, property)
} }
Self::UndefinedType {
identifier,
position,
} => {
write!(
f,
"Undefined type {} at position: {:?}",
identifier, position
)
}
} }
} }
} }
@ -1001,10 +1137,30 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn async_block() { fn string_index() {
let input = "let x = 1; async { x += 1; x -= 1; } x"; let input = "'foo'[0]";
assert_eq!(run(input), Ok(Some(Value::Integer(1)))); assert_eq!(run(input), Ok(Some(Value::Character('f'))));
}
#[test]
fn map_expression() {
let input = "let x = map { foo = 42, bar = 4.2 }; x";
assert_eq!(
run(input),
Ok(Some(Value::map([
(Identifier::new("foo"), Value::Integer(42)),
(Identifier::new("bar"), Value::Float(4.2))
])))
);
}
#[test]
fn async_block() {
let input = "let mut x = 1; async { x += 1; x -= 1; } x";
assert_eq!(run(input), Ok(Some(Value::mutable(Value::Integer(1)))));
} }
#[test] #[test]
@ -1056,8 +1212,8 @@ mod tests {
#[test] #[test]
fn assign_unit_struct_variable() { fn assign_unit_struct_variable() {
let input = " let input = "
struct Foo struct Foo;
x = Foo let x = Foo;
x x
"; ";