Continue implementing the VM

This commit is contained in:
Jeff 2024-08-16 00:41:52 -04:00
parent b48b5d4369
commit 26348fb82e
3 changed files with 218 additions and 75 deletions

View File

@ -16,7 +16,7 @@ pub enum Expression {
FieldAccess(Node<Box<FieldAccess>>),
Grouped(Node<Box<Expression>>),
Identifier(Node<Identifier>),
If(Node<Box<If>>),
If(Node<Box<IfExpression>>),
List(Node<Box<ListExpression>>),
ListIndex(Node<Box<ListIndex>>),
Literal(Node<Box<LiteralExpression>>),
@ -197,7 +197,7 @@ impl Expression {
Self::ListIndex(Node::new(Box::new(list_index), position))
}
pub fn r#if(r#if: If, position: Span) -> Self {
pub fn r#if(r#if: IfExpression, position: Span) -> Self {
Self::If(Node::new(Box::new(r#if), position))
}
@ -543,7 +543,7 @@ impl Display for LogicOperator {
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum If {
pub enum IfExpression {
If {
condition: Expression,
if_block: Node<Block>,
@ -558,7 +558,7 @@ pub enum If {
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum ElseExpression {
Block(Node<Block>),
If(Box<If>),
If(Node<Box<IfExpression>>),
}
impl Display for ElseExpression {
@ -570,16 +570,16 @@ impl Display for ElseExpression {
}
}
impl Display for If {
impl Display for IfExpression {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
If::If {
IfExpression::If {
condition,
if_block,
} => {
write!(f, "if {} {}", condition, if_block)
}
If::IfElse {
IfExpression::IfElse {
condition,
if_block,
r#else,

View File

@ -774,7 +774,7 @@ impl<'src> Parser<'src> {
}
}
fn parse_if(&mut self) -> Result<If, ParseError> {
fn parse_if(&mut self) -> Result<IfExpression, ParseError> {
// Assume that the "if" token has already been consumed
self.mode = ParserMode::Condition;
@ -788,27 +788,30 @@ impl<'src> Parser<'src> {
if let Token::Else = self.current_token {
self.next_token()?;
let if_keyword_start = self.current_position.0;
if let Token::If = self.current_token {
self.next_token()?;
let else_if = self.parse_if()?;
let if_expression = self.parse_if()?;
let position = (if_keyword_start, self.current_position.1);
Ok(If::IfElse {
Ok(IfExpression::IfElse {
condition,
if_block,
r#else: ElseExpression::If(Box::new(else_if)),
r#else: ElseExpression::If(Node::new(Box::new(if_expression), position)),
})
} else {
let else_block = self.parse_block()?;
Ok(If::IfElse {
Ok(IfExpression::IfElse {
condition,
if_block,
r#else: ElseExpression::Block(else_block),
})
}
} else {
Ok(If::If {
Ok(IfExpression::If {
condition,
if_block,
})
@ -1383,7 +1386,7 @@ mod tests {
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::r#if(
If::If {
IfExpression::If {
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
if_block: Node::new(
Block::Sync(vec![Statement::Expression(Expression::identifier(
@ -1407,7 +1410,7 @@ mod tests {
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::r#if(
If::IfElse {
IfExpression::IfElse {
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
if_block: Node::new(
Block::Sync(vec![Statement::Expression(Expression::identifier(
@ -1438,7 +1441,7 @@ mod tests {
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::r#if(
If::IfElse {
IfExpression::IfElse {
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
if_block: Node::new(
Block::Sync(vec![Statement::Expression(Expression::identifier(
@ -1447,23 +1450,24 @@ mod tests {
))]),
(5, 10)
),
r#else: ElseExpression::If(Box::new(If::IfElse {
condition: Expression::identifier(Identifier::new("z"), (19, 20)),
if_block: Node::new(
Block::Sync(vec![Statement::Expression(Expression::identifier(
Identifier::new("a"),
(23, 24)
))]),
(21, 26)
),
r#else: ElseExpression::Block(Node::new(
Block::Sync(vec![Statement::Expression(Expression::identifier(
Identifier::new("b"),
(34, 35)
))]),
(32, 37)
)),
})),
r#else: ElseExpression::If(Node::new(
Box::new(IfExpression::IfElse {
condition: Expression::identifier(Identifier::new("z"), (19, 20)),
if_block: Node::new(
Block::Sync(vec![Statement::Expression(
Expression::identifier(Identifier::new("a"), (23, 24))
)]),
(21, 26)
),
r#else: ElseExpression::Block(Node::new(
Block::Sync(vec![Statement::Expression(
Expression::identifier(Identifier::new("b"), (34, 35))
)]),
(32, 37)
)),
}),
(16, 37)
)),
},
(0, 37)
))

View File

@ -12,9 +12,12 @@ use std::{
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use crate::{
abstract_tree::{AbstractSyntaxTree, Block, CallExpression, FieldAccess, Node, Statement},
abstract_tree::{
AbstractSyntaxTree, Block, CallExpression, ElseExpression, FieldAccess, IfExpression,
ListExpression, Node, Statement,
},
parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, Identifier, ParseError,
Span, Struct, StructType, Type, Value, ValueError,
Span, Value, ValueError,
};
/// Run the source code and return the result.
@ -104,7 +107,8 @@ impl Vm {
}
fn run_statement(&self, statement: Statement) -> Result<Option<Value>, VmError> {
match statement {
let position = statement.position();
let result = match statement {
Statement::Expression(expression) => self.run_expression(expression),
Statement::ExpressionNullified(expression) => {
self.run_expression(expression.inner)?;
@ -113,37 +117,18 @@ impl Vm {
}
Statement::Let(_) => todo!(),
Statement::StructDefinition(_) => todo!(),
}
};
result.map_err(|error| VmError::Trace {
error: Box::new(error),
position,
})
}
fn run_expression(&self, expression: Expression) -> Result<Option<Value>, VmError> {
match expression {
Expression::Block(Node { inner, position }) => match *inner {
Block::Async(statements) => {
let error_option = statements
.into_par_iter()
.find_map_any(|statement| self.run_statement(statement).err());
if let Some(error) = error_option {
Err(error)
} else {
Ok(None)
}
}
Block::Sync(statements) => {
let mut previous_value = None;
for statement in statements {
let position = statement.position();
previous_value = self.run_statement(statement)?;
self.context.collect_garbage(position.1);
}
Ok(previous_value)
}
},
let position = expression.position();
let result = match expression {
Expression::Block(Node { inner, .. }) => self.run_block(*inner),
Expression::Call(Node { inner, .. }) => {
let CallExpression { invoker, arguments } = *inner;
@ -195,10 +180,18 @@ impl Vm {
Ok(container_value.get_field(&field.inner))
}
Expression::Grouped(_) => todo!(),
Expression::Identifier(_) => todo!(),
Expression::If(_) => todo!(),
Expression::List(_) => todo!(),
Expression::Grouped(expression) => self.run_expression(*expression.inner),
Expression::Identifier(identifier) => {
let value_option = self.context.get_value(&identifier.inner);
if let Some(value) = value_option {
Ok(Some(value))
} else {
Err(VmError::UndefinedVariable { identifier })
}
}
Expression::If(if_expression) => self.run_if(*if_expression.inner),
Expression::List(list_expression) => self.run_list(*list_expression.inner),
Expression::ListIndex(_) => todo!(),
Expression::Literal(_) => todo!(),
Expression::Loop(_) => todo!(),
@ -206,6 +199,147 @@ impl Vm {
Expression::Range(_) => todo!(),
Expression::Struct(_) => todo!(),
Expression::TupleAccess(_) => todo!(),
};
result.map_err(|error| VmError::Trace {
error: Box::new(error),
position,
})
}
fn run_list(&self, list_expression: ListExpression) -> Result<Option<Value>, VmError> {
match list_expression {
ListExpression::AutoFill {
repeat_operand,
length_operand,
} => {
let position = length_operand.position();
let length = if let Some(value) = self.run_expression(length_operand)? {
if let Some(length) = value.as_integer() {
length
} else {
return Err(VmError::ExpectedInteger { position });
}
} else {
return Err(VmError::ExpectedValue { position });
};
let position = repeat_operand.position();
let value = if let Some(value) = self.run_expression(repeat_operand)? {
value
} else {
return Err(VmError::ExpectedValue { position });
};
Ok(Some(Value::list(vec![value; length as usize])))
}
ListExpression::Ordered(expressions) => {
let mut values = Vec::new();
for expression in expressions {
let position = expression.position();
if let Some(value) = self.run_expression(expression)? {
values.push(value);
} else {
return Err(VmError::ExpectedValue { position });
}
}
Ok(Some(Value::list(values)))
}
}
}
fn run_block(&self, block: Block) -> Result<Option<Value>, VmError> {
match block {
Block::Async(statements) => {
let error_option = statements
.into_par_iter()
.find_map_any(|statement| self.run_statement(statement).err());
if let Some(error) = error_option {
Err(error)
} else {
Ok(None)
}
}
Block::Sync(statements) => {
let mut previous_value = None;
for statement in statements {
let position = statement.position();
previous_value = self.run_statement(statement)?;
self.context.collect_garbage(position.1);
}
Ok(previous_value)
}
}
}
fn run_if(&self, if_expression: IfExpression) -> Result<Option<Value>, VmError> {
match if_expression {
IfExpression::If {
condition,
if_block,
} => {
let condition_position = condition.position();
let condition_value = if let Some(value) = self.run_expression(condition)? {
value
} else {
return Err(VmError::ExpectedValue {
position: condition_position,
});
};
if let Some(boolean) = condition_value.as_boolean() {
if boolean {
self.run_expression(Expression::block(if_block.inner, if_block.position))?;
}
} else {
return Err(VmError::ExpectedBoolean {
position: condition_position,
});
}
Ok(None)
}
IfExpression::IfElse {
condition,
if_block,
r#else,
} => {
let condition_position = condition.position();
let condition_value = if let Some(value) = self.run_expression(condition)? {
value
} else {
return Err(VmError::ExpectedValue {
position: condition_position,
});
};
if let Some(boolean) = condition_value.as_boolean() {
if boolean {
self.run_expression(Expression::block(if_block.inner, if_block.position))?;
}
} else {
return Err(VmError::ExpectedBoolean {
position: condition_position,
});
}
match r#else {
ElseExpression::If(if_expression) => {
self.run_expression(Expression::If(if_expression))
}
ElseExpression::Block(block) => {
self.run_expression(Expression::block(block.inner, block.position))
}
}
}
}
}
}
@ -213,6 +347,10 @@ impl Vm {
#[derive(Clone, Debug, PartialEq)]
pub enum VmError {
ParseError(ParseError),
Trace {
error: Box<VmError>,
position: Span,
},
ValueError {
error: ValueError,
position: Span,
@ -274,6 +412,7 @@ impl VmError {
pub fn position(&self) -> Span {
match self {
Self::ParseError(parse_error) => parse_error.position(),
Self::Trace { position, .. } => *position,
Self::ValueError { position, .. } => *position,
Self::CannotMutate { position, .. } => *position,
Self::BuiltInFunctionError { position, .. } => *position,
@ -305,6 +444,13 @@ impl Display for VmError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::ParseError(parse_error) => write!(f, "{}", parse_error),
Self::Trace { error, position } => {
write!(
f,
"Error during execution at position: {:?}\n{}",
position, error
)
}
Self::ValueError { error, .. } => write!(f, "{}", error),
Self::CannotMutate { value, .. } => {
write!(f, "Cannot mutate immutable value {}", value)
@ -492,13 +638,6 @@ mod tests {
assert_eq!(run(input), Ok(Some(Value::integer(42))));
}
#[test]
fn map_property_access_expression() {
let input = "{ foobar = 42 }.('foo' + 'bar')";
assert_eq!(run(input), Ok(Some(Value::integer(42))));
}
#[test]
fn list_index_range() {
let input = "[1, 2, 3, 4, 5][1..3]";