Extend VM, abstract tree and parser
This commit is contained in:
parent
fa67a568d9
commit
0b64afccb1
@ -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)?;
|
||||||
|
@ -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,
|
||||||
|
@ -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";
|
||||||
|
@ -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)
|
||||||
))
|
))
|
||||||
]))
|
]))
|
||||||
);
|
);
|
||||||
|
@ -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,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
";
|
";
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user