Implement VM

This commit is contained in:
Jeff 2024-08-16 05:14:00 -04:00
parent 26348fb82e
commit bfb07047a5
6 changed files with 443 additions and 228 deletions

View File

@ -5,22 +5,22 @@ use std::{
use serde::{Deserialize, Serialize};
use crate::{Identifier, Span, Value};
use crate::{Context, Identifier, Span, StructType, Type, Value};
use super::{Node, Statement};
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Expression {
Block(Node<Box<Block>>),
Block(Node<Box<BlockExpression>>),
Call(Node<Box<CallExpression>>),
FieldAccess(Node<Box<FieldAccess>>),
FieldAccess(Node<Box<FieldAccessExpression>>),
Grouped(Node<Box<Expression>>),
Identifier(Node<Identifier>),
If(Node<Box<IfExpression>>),
List(Node<Box<ListExpression>>),
ListIndex(Node<Box<ListIndex>>),
ListIndex(Node<Box<ListIndexExpression>>),
Literal(Node<Box<LiteralExpression>>),
Loop(Node<Box<Loop>>),
Loop(Node<Box<LoopExpression>>),
Operator(Node<Box<OperatorExpression>>),
Range(Node<Box<Range>>),
Struct(Node<Box<StructExpression>>),
@ -45,7 +45,7 @@ impl Expression {
pub fn field_access(container: Expression, field: Node<Identifier>, position: Span) -> Self {
Self::FieldAccess(Node::new(
Box::new(FieldAccess { container, field }),
Box::new(FieldAccessExpression { container, field }),
position,
))
}
@ -146,13 +146,16 @@ impl Expression {
))
}
pub fn infinite_loop(block: Node<Block>, position: Span) -> Self {
Self::Loop(Node::new(Box::new(Loop::Infinite { block }), position))
pub fn infinite_loop(block: Node<BlockExpression>, position: Span) -> Self {
Self::Loop(Node::new(
Box::new(LoopExpression::Infinite { block }),
position,
))
}
pub fn while_loop(condition: Expression, block: Node<Block>, position: Span) -> Self {
pub fn while_loop(condition: Expression, block: Node<BlockExpression>, position: Span) -> Self {
Self::Loop(Node::new(
Box::new(Loop::While { condition, block }),
Box::new(LoopExpression::While { condition, block }),
position,
))
}
@ -160,11 +163,11 @@ impl Expression {
pub fn for_loop(
identifier: Node<Identifier>,
iterator: Expression,
block: Node<Block>,
block: Node<BlockExpression>,
position: Span,
) -> Self {
Self::Loop(Node::new(
Box::new(Loop::For {
Box::new(LoopExpression::For {
identifier,
iterator,
block,
@ -173,7 +176,7 @@ impl Expression {
))
}
pub fn block(block: Block, position: Span) -> Self {
pub fn block(block: BlockExpression, position: Span) -> Self {
Self::Block(Node::new(Box::new(block), position))
}
@ -193,7 +196,7 @@ impl Expression {
Self::List(Node::new(Box::new(list_expression), position))
}
pub fn list_index(list_index: ListIndex, position: Span) -> Self {
pub fn list_index(list_index: ListIndexExpression, position: Span) -> Self {
Self::ListIndex(Node::new(Box::new(list_index), position))
}
@ -213,6 +216,127 @@ impl Expression {
}
}
pub fn return_type(&self, context: &Context) -> Option<Type> {
match self {
Expression::Block(block_expression) => {
block_expression.inner.as_ref().return_type(context)
}
Expression::Call(call_expression) => {
let CallExpression { invoker, .. } = call_expression.inner.as_ref();
let invoker_type = invoker.return_type(context)?;
if let Type::Function { return_type, .. } = invoker_type {
return_type.map(|r#type| *r#type)
} else if let Type::Struct(_) = invoker_type {
Some(invoker_type)
} else {
None
}
}
Expression::FieldAccess(field_access_expression) => {
let FieldAccessExpression { container, field } =
field_access_expression.inner.as_ref();
let container_type = container.return_type(context)?;
if let Type::Struct(StructType::Fields { fields, .. }) = container_type {
fields
.into_iter()
.find(|(name, _)| name == &field.inner)
.map(|(_, r#type)| r#type)
} else {
None
}
}
Expression::Grouped(expression) => expression.inner.return_type(context),
Expression::Identifier(identifier) => context.get_type(&identifier.inner),
Expression::If(if_expression) => match if_expression.inner.as_ref() {
IfExpression::If { .. } => None,
IfExpression::IfElse { if_block, .. } => if_block.inner.return_type(context),
},
Expression::List(list_expression) => match list_expression.inner.as_ref() {
ListExpression::AutoFill { repeat_operand, .. } => {
let item_type = repeat_operand.return_type(context)?;
Some(Type::ListOf {
item_type: Box::new(item_type),
})
}
ListExpression::Ordered(expressions) => {
if expressions.is_empty() {
return Some(Type::EmptyList);
}
let item_type = expressions.last().unwrap().return_type(context)?;
let length = expressions.len();
Some(Type::List {
item_type: Box::new(item_type),
length,
})
}
},
Expression::ListIndex(list_index_expression) => {
let ListIndexExpression { list, .. } = list_index_expression.inner.as_ref();
let list_type = list.return_type(context)?;
if let Type::List { item_type, .. } = list_type {
Some(*item_type)
} else {
None
}
}
Expression::Literal(literal_expression) => match literal_expression.inner.as_ref() {
LiteralExpression::Boolean(_) => Some(Type::Boolean),
LiteralExpression::Float(_) => Some(Type::Float),
LiteralExpression::Integer(_) => Some(Type::Integer),
LiteralExpression::String(_) => Some(Type::String),
LiteralExpression::Value(value) => Some(value.r#type()),
},
Expression::Loop(loop_expression) => match loop_expression.inner.as_ref() {
LoopExpression::For { block, .. } => block.inner.return_type(context),
LoopExpression::Infinite { .. } => None,
LoopExpression::While { block, .. } => block.inner.return_type(context),
},
Expression::Operator(operator_expression) => match operator_expression.inner.as_ref() {
OperatorExpression::Assignment { .. } => None,
OperatorExpression::Comparison { .. } => Some(Type::Boolean),
OperatorExpression::CompoundAssignment { .. } => None,
OperatorExpression::ErrorPropagation(expression) => expression.return_type(context),
OperatorExpression::Negation(expression) => expression.return_type(context),
OperatorExpression::Not(_) => Some(Type::Boolean),
OperatorExpression::Math { left, .. } => left.return_type(context),
OperatorExpression::Logic { .. } => Some(Type::Boolean),
},
Expression::Range(_) => Some(Type::Range),
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
StructExpression::Fields { name, fields } => {
let mut field_types = Vec::with_capacity(fields.len());
for (name, expression) in fields {
let r#type = expression.return_type(context)?;
field_types.push((name.inner.clone(), r#type));
}
Some(Type::Struct(StructType::Fields {
name: name.inner.clone(),
fields: field_types,
}))
}
StructExpression::Unit { name } => Some(Type::Struct(StructType::Unit {
name: name.inner.clone(),
})),
},
Expression::TupleAccess(tuple_access_expression) => {
todo!()
}
}
}
pub fn position(&self) -> Span {
match self {
Expression::Block(block) => block.position,
@ -279,12 +403,12 @@ impl Display for Range {
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct ListIndex {
pub struct ListIndexExpression {
pub list: Expression,
pub index: Expression,
}
impl Display for ListIndex {
impl Display for ListIndexExpression {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}[{}]", self.list, self.index)
}
@ -313,12 +437,12 @@ impl Display for CallExpression {
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct FieldAccess {
pub struct FieldAccessExpression {
pub container: Expression,
pub field: Node<Identifier>,
}
impl Display for FieldAccess {
impl Display for FieldAccessExpression {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}.{}", self.container, self.field)
}
@ -546,18 +670,18 @@ impl Display for LogicOperator {
pub enum IfExpression {
If {
condition: Expression,
if_block: Node<Block>,
if_block: Node<BlockExpression>,
},
IfElse {
condition: Expression,
if_block: Node<Block>,
if_block: Node<BlockExpression>,
r#else: ElseExpression,
},
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum ElseExpression {
Block(Node<Block>),
Block(Node<BlockExpression>),
If(Node<Box<IfExpression>>),
}
@ -591,15 +715,28 @@ impl Display for IfExpression {
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Block {
pub enum BlockExpression {
Async(Vec<Statement>),
Sync(Vec<Statement>),
}
impl Display for Block {
impl BlockExpression {
fn return_type(&self, context: &Context) -> Option<Type> {
match self {
BlockExpression::Async(statements) => statements
.last()
.and_then(|statement| statement.return_type(context)),
BlockExpression::Sync(statements) => statements
.last()
.and_then(|statement| statement.return_type(context)),
}
}
}
impl Display for BlockExpression {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Block::Async(statements) => {
BlockExpression::Async(statements) => {
writeln!(f, "async {{ ")?;
for (i, statement) in statements.iter().enumerate() {
@ -612,7 +749,7 @@ impl Display for Block {
write!(f, " }}")
}
Block::Sync(statements) => {
BlockExpression::Sync(statements) => {
writeln!(f, "{{ ")?;
for (i, statement) in statements.iter().enumerate() {
@ -630,27 +767,29 @@ impl Display for Block {
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Loop {
pub enum LoopExpression {
Infinite {
block: Node<Block>,
block: Node<BlockExpression>,
},
While {
condition: Expression,
block: Node<Block>,
block: Node<BlockExpression>,
},
For {
identifier: Node<Identifier>,
iterator: Expression,
block: Node<Block>,
block: Node<BlockExpression>,
},
}
impl Display for Loop {
impl Display for LoopExpression {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Loop::Infinite { block } => write!(f, "loop {}", block),
Loop::While { condition, block } => write!(f, "while {} {}", condition, block),
Loop::For {
LoopExpression::Infinite { block } => write!(f, "loop {}", block),
LoopExpression::While { condition, block } => {
write!(f, "while {} {}", condition, block)
}
LoopExpression::For {
identifier,
iterator,
block,

View File

@ -10,7 +10,7 @@ use std::{
use serde::{Deserialize, Serialize};
use crate::{Identifier, Span, Type};
use crate::{Context, Identifier, Span, Type};
/// In-memory representation of a Dust program.
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
@ -69,6 +69,17 @@ impl Statement {
Statement::StructDefinition(Node::new(struct_definition, position))
}
pub fn return_type(&self, context: &Context) -> Option<Type> {
match self {
Statement::Expression(expression) => expression.return_type(context),
Statement::ExpressionNullified(expression_node) => {
expression_node.inner.return_type(context)
}
Statement::Let(_) => None,
Statement::StructDefinition(_) => None,
}
}
pub fn position(&self) -> Span {
match self {
Statement::Expression(expression) => expression.position(),

View File

@ -757,7 +757,7 @@ impl<'src> Parser<'src> {
let position = (left.position().0, operator_end);
Expression::list_index(ListIndex { list: left, index }, position)
Expression::list_index(ListIndexExpression { list: left, index }, position)
}
_ => {
return Err(ParseError::UnexpectedToken {
@ -834,7 +834,7 @@ impl<'src> Parser<'src> {
}
}
fn parse_block(&mut self) -> Result<Node<Block>, ParseError> {
fn parse_block(&mut self) -> Result<Node<BlockExpression>, ParseError> {
let left_start = self.current_position.0;
let is_async = if let Token::Async = self.current_token {
self.next_token()?;
@ -863,9 +863,9 @@ impl<'src> Parser<'src> {
self.next_token()?;
return if is_async {
Ok(Node::new(Block::Async(statements), position))
Ok(Node::new(BlockExpression::Async(statements), position))
} else {
Ok(Node::new(Block::Sync(statements), position))
Ok(Node::new(BlockExpression::Sync(statements), position))
};
}
@ -1041,7 +1041,7 @@ mod tests {
parse(source),
Ok(AbstractSyntaxTree {
statements: [Statement::Expression(Expression::block(
Block::Async(vec![
BlockExpression::Async(vec![
Statement::ExpressionNullified(Node::new(
Expression::operator(
OperatorExpression::Assignment {
@ -1230,9 +1230,9 @@ mod tests {
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::list_index(
ListIndex {
ListIndexExpression {
list: Expression::list_index(
ListIndex {
ListIndexExpression {
list: Expression::list(
ListExpression::Ordered(vec![
Expression::literal(LiteralExpression::Integer(1), (1, 2)),
@ -1389,10 +1389,9 @@ mod tests {
IfExpression::If {
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
if_block: Node::new(
Block::Sync(vec![Statement::Expression(Expression::identifier(
Identifier::new("y"),
(7, 8)
))]),
BlockExpression::Sync(vec![Statement::Expression(
Expression::identifier(Identifier::new("y"), (7, 8))
)]),
(5, 10)
)
},
@ -1413,17 +1412,15 @@ mod tests {
IfExpression::IfElse {
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
if_block: Node::new(
Block::Sync(vec![Statement::Expression(Expression::identifier(
Identifier::new("y"),
(7, 8)
))]),
BlockExpression::Sync(vec![Statement::Expression(
Expression::identifier(Identifier::new("y"), (7, 8))
)]),
(5, 10)
),
r#else: ElseExpression::Block(Node::new(
Block::Sync(vec![Statement::Expression(Expression::identifier(
Identifier::new("z"),
(18, 19)
))]),
BlockExpression::Sync(vec![Statement::Expression(
Expression::identifier(Identifier::new("z"), (18, 19))
)]),
(16, 21)
))
},
@ -1444,23 +1441,22 @@ mod tests {
IfExpression::IfElse {
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
if_block: Node::new(
Block::Sync(vec![Statement::Expression(Expression::identifier(
Identifier::new("y"),
(7, 8)
))]),
BlockExpression::Sync(vec![Statement::Expression(
Expression::identifier(Identifier::new("y"), (7, 8))
)]),
(5, 10)
),
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(
BlockExpression::Sync(vec![Statement::Expression(
Expression::identifier(Identifier::new("a"), (23, 24))
)]),
(21, 26)
),
r#else: ElseExpression::Block(Node::new(
Block::Sync(vec![Statement::Expression(
BlockExpression::Sync(vec![Statement::Expression(
Expression::identifier(Identifier::new("b"), (34, 35))
)]),
(32, 37)
@ -1492,7 +1488,7 @@ mod tests {
(6, 12)
),
Node::new(
Block::Sync(vec![Statement::Expression(Expression::operator(
BlockExpression::Sync(vec![Statement::Expression(Expression::operator(
OperatorExpression::CompoundAssignment {
assignee: Expression::identifier(Identifier::new("x"), (15, 16)),
operator: Node::new(MathOperator::Add, (17, 19)),
@ -1557,7 +1553,7 @@ mod tests {
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::block(
Block::Sync(vec![Statement::Expression(Expression::operator(
BlockExpression::Sync(vec![Statement::Expression(Expression::operator(
OperatorExpression::Math {
left: Expression::literal(LiteralExpression::Integer(40), (2, 4)),
operator: Node::new(MathOperator::Add, (5, 6)),
@ -1579,7 +1575,7 @@ mod tests {
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::block(
Block::Sync(vec![
BlockExpression::Sync(vec![
Statement::ExpressionNullified(Node::new(
Expression::operator(
OperatorExpression::Assignment {
@ -1844,7 +1840,7 @@ mod tests {
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::list_index(
ListIndex {
ListIndexExpression {
list: Expression::list(
ListExpression::Ordered(vec![
Expression::literal(LiteralExpression::Integer(1), (1, 2)),

View File

@ -31,6 +31,7 @@ pub struct TypeConflict {
pub enum Type {
Any,
Boolean,
EmptyList,
Enum {
name: Identifier,
type_parameters: Option<Vec<Type>>,
@ -251,6 +252,7 @@ impl Display for Type {
match self {
Type::Any => write!(f, "any"),
Type::Boolean => write!(f, "bool"),
Type::EmptyList => write!(f, "[]"),
Type::Enum { variants, .. } => {
write!(f, "enum ")?;
@ -282,7 +284,7 @@ impl Display for Type {
}
Type::Integer => write!(f, "int"),
Type::List { item_type, length } => write!(f, "[{item_type}; {length}]"),
Type::ListOf { item_type } => write!(f, "list_of({item_type})"),
Type::ListOf { item_type } => write!(f, "[{item_type}]"),
Type::Map(map) => {
write!(f, "{{ ")?;

View File

@ -241,17 +241,17 @@ impl Value {
}
pub fn get_field(&self, field: &Identifier) -> Option<Value> {
return match self {
match self {
Value::Immutable(inner) => inner.get_field(field),
Value::Mutable(inner) => inner.read().unwrap().get_field(field),
};
}
}
pub fn get_index(&self, index: usize) -> Option<Value> {
return match self {
match self {
Value::Immutable(inner) => inner.get_index(index),
Value::Mutable(inner) => inner.read().unwrap().get_index(index),
};
}
}
pub fn add(&self, other: &Value) -> Result<Value, ValueError> {

View File

@ -5,19 +5,20 @@
//! - `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
use std::{
collections::BTreeMap,
fmt::{self, Display, Formatter},
sync::{Arc, Mutex},
};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
use crate::{
abstract_tree::{
AbstractSyntaxTree, Block, CallExpression, ElseExpression, FieldAccess, IfExpression,
ListExpression, Node, Statement,
AbstractSyntaxTree, BlockExpression, CallExpression, ElseExpression, FieldAccessExpression,
IfExpression, ListExpression, ListIndexExpression, LiteralExpression, LoopExpression, Node,
OperatorExpression, Statement,
},
parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, Identifier, ParseError,
Span, Value, ValueError,
Span, Type, Value, ValueError,
};
/// Run the source code and return the result.
@ -109,7 +110,9 @@ impl Vm {
fn run_statement(&self, statement: Statement) -> Result<Option<Value>, VmError> {
let position = statement.position();
let result = match statement {
Statement::Expression(expression) => self.run_expression(expression),
Statement::Expression(expression) => self
.run_expression(expression)
.map(|evaluation| evaluation.value()),
Statement::ExpressionNullified(expression) => {
self.run_expression(expression.inner)?;
@ -125,15 +128,113 @@ impl Vm {
})
}
fn run_expression(&self, expression: Expression) -> Result<Option<Value>, VmError> {
fn run_expression(&self, expression: Expression) -> Result<Evaluation, VmError> {
let position = expression.position();
let result = match expression {
let evaluation_result = match expression {
Expression::Block(Node { inner, .. }) => self.run_block(*inner),
Expression::Call(Node { inner, .. }) => {
let CallExpression { invoker, arguments } = *inner;
Expression::Call(call) => self.run_call(*call.inner),
Expression::FieldAccess(field_access) => self.run_field_access(*field_access.inner),
Expression::Grouped(expression) => self.run_expression(*expression.inner),
Expression::Identifier(identifier) => self.run_identifier(identifier.inner),
Expression::If(if_expression) => self.run_if(*if_expression.inner),
Expression::List(list_expression) => self.run_list(*list_expression.inner),
Expression::ListIndex(list_index) => self.run_list_index(*list_index.inner),
Expression::Literal(literal) => self.run_literal(*literal.inner),
Expression::Loop(loop_expression) => self.run_loop(*loop_expression.inner),
Expression::Operator(_) => todo!(),
Expression::Range(_) => todo!(),
Expression::Struct(_) => todo!(),
Expression::TupleAccess(_) => todo!(),
};
evaluation_result.map_err(|error| VmError::Trace {
error: Box::new(error),
position,
})
}
fn run_operator(&self, operator: OperatorExpression) -> Result<Evaluation, VmError> {
match operator {
OperatorExpression::Assignment { assignee, value } => todo!(),
OperatorExpression::Comparison {
left,
operator,
right,
} => todo!(),
OperatorExpression::CompoundAssignment {
assignee,
operator,
modifier,
} => todo!(),
OperatorExpression::ErrorPropagation(_) => todo!(),
OperatorExpression::Negation(_) => todo!(),
OperatorExpression::Not(_) => todo!(),
OperatorExpression::Math {
left,
operator,
right,
} => todo!(),
OperatorExpression::Logic {
left,
operator,
right,
} => todo!(),
}
}
fn run_loop(&self, loop_expression: LoopExpression) -> Result<Evaluation, VmError> {
match loop_expression {
LoopExpression::Infinite { block } => loop {
self.run_expression(Expression::block(block.inner.clone(), block.position))?;
},
LoopExpression::While { condition, block } => todo!(),
LoopExpression::For {
identifier,
iterator,
block,
} => todo!(),
}
}
fn run_literal(&self, literal: LiteralExpression) -> Result<Evaluation, VmError> {
let value = match literal {
LiteralExpression::Boolean(boolean) => Value::boolean(boolean),
LiteralExpression::Float(float) => Value::float(float),
LiteralExpression::Integer(integer) => Value::integer(integer),
LiteralExpression::String(string) => Value::string(string),
LiteralExpression::Value(value) => value,
};
Ok(Evaluation::Return(Some(value)))
}
fn run_list_index(&self, list_index: ListIndexExpression) -> Result<Evaluation, VmError> {
let ListIndexExpression { list, index } = list_index;
let list_position = list.position();
let list_value = self.run_expression(list)?.expect_value(list_position)?;
let index_position = index.position();
let index_value = self.run_expression(index)?.expect_value(index_position)?;
let index = if let Some(index) = index_value.as_integer() {
index as usize
} else {
return Err(VmError::ExpectedInteger {
position: index_position,
});
};
let value_option = list_value.get_index(index);
Ok(Evaluation::Return(value_option))
}
fn run_call(&self, call_expression: CallExpression) -> Result<Evaluation, VmError> {
let CallExpression { invoker, arguments } = call_expression;
let invoker_position = invoker.position();
let invoker_value = if let Some(value) = self.run_expression(invoker)? {
let invoker_value = if let Some(value) = self.run_expression(invoker)?.value() {
value
} else {
return Err(VmError::ExpectedValue {
@ -155,7 +256,7 @@ impl Vm {
for argument in arguments {
let position = argument.position();
if let Some(value) = self.run_expression(argument)? {
if let Some(value) = self.run_expression(argument)?.value() {
value_arguments.push(value);
} else {
return Err(VmError::ExpectedValue { position });
@ -164,13 +265,16 @@ impl Vm {
let context = Context::new();
function.call(None, Some(value_arguments), &context)
function
.call(None, Some(value_arguments), &context)
.map(|value_option| Evaluation::Return(value_option))
}
Expression::FieldAccess(Node { inner, .. }) => {
let FieldAccess { container, field } = *inner;
fn run_field_access(&self, field_access: FieldAccessExpression) -> Result<Evaluation, VmError> {
let FieldAccessExpression { container, field } = field_access;
let container_position = container.position();
let container_value = if let Some(value) = self.run_expression(container)? {
let container_value = if let Some(value) = self.run_expression(container)?.value() {
value
} else {
return Err(VmError::ExpectedValue {
@ -178,93 +282,76 @@ impl Vm {
});
};
Ok(container_value.get_field(&field.inner))
Ok(Evaluation::Return(container_value.get_field(&field.inner)))
}
Expression::Grouped(expression) => self.run_expression(*expression.inner),
Expression::Identifier(identifier) => {
let value_option = self.context.get_value(&identifier.inner);
fn run_identifier(&self, identifier: Identifier) -> Result<Evaluation, VmError> {
let value_option = self.context.get_value(&identifier);
if let Some(value) = value_option {
Ok(Some(value))
Ok(Evaluation::Return(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!(),
Expression::Operator(_) => todo!(),
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> {
fn run_list(&self, list_expression: ListExpression) -> Result<Evaluation, 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 length = self
.run_expression(length_operand)?
.expect_value(position)?
.as_integer()
.ok_or(VmError::ExpectedInteger { position })?;
let position = repeat_operand.position();
let value = if let Some(value) = self.run_expression(repeat_operand)? {
value
} else {
return Err(VmError::ExpectedValue { position });
};
let value = self
.run_expression(repeat_operand)?
.expect_value(position)?;
Ok(Some(Value::list(vec![value; length as usize])))
Ok(Evaluation::Return(Some(Value::list(vec![
value;
length as usize
]))))
}
ListExpression::Ordered(expressions) => {
let mut values = Vec::new();
for expression in expressions {
let position = expression.position();
let value = self.run_expression(expression)?.expect_value(position)?;
if let Some(value) = self.run_expression(expression)? {
values.push(value);
} else {
return Err(VmError::ExpectedValue { position });
}
}
Ok(Some(Value::list(values)))
Ok(Evaluation::Return(Some(Value::list(values))))
}
}
}
fn run_block(&self, block: Block) -> Result<Option<Value>, VmError> {
fn run_block(&self, block: BlockExpression) -> Result<Evaluation, VmError> {
match block {
Block::Async(statements) => {
BlockExpression::Async(statements) => {
let expected_return = statements.last().unwrap().expected_type();
let final_result = Arc::new(Mutex::new(None));
let error_option = statements
.into_par_iter()
.enumerate()
.find_map_any(|statement| self.run_statement(statement).err());
if let Some(error) = error_option {
Err(error)
} else {
Ok(None)
Ok(Evaluation::Return(None))
}
}
Block::Sync(statements) => {
BlockExpression::Sync(statements) => {
let mut previous_value = None;
for statement in statements {
@ -275,61 +362,45 @@ impl Vm {
self.context.collect_garbage(position.1);
}
Ok(previous_value)
Ok(Evaluation::Return(previous_value))
}
}
}
fn run_if(&self, if_expression: IfExpression) -> Result<Option<Value>, VmError> {
fn run_if(&self, if_expression: IfExpression) -> Result<Evaluation, 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,
});
};
let position = condition.position();
let boolean = self
.run_expression(condition)?
.expect_value(position)?
.as_boolean()
.ok_or(VmError::ExpectedBoolean { 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)
Ok(Evaluation::Return(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,
});
};
let position = condition.position();
let boolean = self
.run_expression(condition)?
.expect_value(position)?
.as_boolean()
.ok_or(VmError::ExpectedBoolean { 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) => {
@ -344,6 +415,28 @@ impl Vm {
}
}
enum Evaluation {
Break,
Return(Option<Value>),
}
impl Evaluation {
pub fn value(self) -> Option<Value> {
match self {
Evaluation::Break => None,
Evaluation::Return(value_option) => value_option,
}
}
pub fn expect_value(self, position: Span) -> Result<Value, VmError> {
if let Evaluation::Return(Some(value)) = self {
Ok(value)
} else {
Err(VmError::ExpectedValue { position })
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum VmError {
ParseError(ParseError),
@ -398,7 +491,7 @@ pub enum VmError {
position: Span,
},
UndefinedVariable {
identifier: Node<Identifier>,
identifier: Identifier,
},
UndefinedProperty {
value: Value,
@ -408,32 +501,6 @@ pub enum VmError {
},
}
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,
Self::ExpectedBoolean { position } => *position,
Self::ExpectedIdentifier { position } => *position,
Self::ExpectedIdentifierOrString { position } => *position,
Self::ExpectedIntegerOrRange { position } => *position,
Self::ExpectedInteger { position } => *position,
Self::ExpectedFunction { position, .. } => *position,
Self::ExpectedList { position } => *position,
Self::ExpectedMap { position } => *position,
Self::ExpectedNumber { position } => *position,
Self::ExpectedValue { position } => *position,
Self::UndefinedVariable { identifier } => identifier.position,
Self::UndefinedProperty {
property_position, ..
} => *property_position,
}
}
}
impl From<ParseError> for VmError {
fn from(error: ParseError) -> Self {
Self::ParseError(error)