Implement VM
This commit is contained in:
parent
26348fb82e
commit
bfb07047a5
@ -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,
|
||||
|
@ -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(),
|
||||
|
@ -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)),
|
||||
|
@ -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, "{{ ")?;
|
||||
|
||||
|
@ -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> {
|
||||
|
@ -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,146 +128,230 @@ 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;
|
||||
|
||||
let invoker_position = invoker.position();
|
||||
let invoker_value = if let Some(value) = self.run_expression(invoker)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: invoker_position,
|
||||
});
|
||||
};
|
||||
|
||||
let function = if let Some(function) = invoker_value.as_function() {
|
||||
function
|
||||
} else {
|
||||
return Err(VmError::ExpectedFunction {
|
||||
actual: invoker_value,
|
||||
position: invoker_position,
|
||||
});
|
||||
};
|
||||
|
||||
let mut value_arguments = Vec::new();
|
||||
|
||||
for argument in arguments {
|
||||
let position = argument.position();
|
||||
|
||||
if let Some(value) = self.run_expression(argument)? {
|
||||
value_arguments.push(value);
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue { position });
|
||||
}
|
||||
}
|
||||
|
||||
let context = Context::new();
|
||||
|
||||
function.call(None, Some(value_arguments), &context)
|
||||
}
|
||||
Expression::FieldAccess(Node { inner, .. }) => {
|
||||
let FieldAccess { container, field } = *inner;
|
||||
|
||||
let container_position = container.position();
|
||||
let container_value = if let Some(value) = self.run_expression(container)? {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: container_position,
|
||||
});
|
||||
};
|
||||
|
||||
Ok(container_value.get_field(&field.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) => {
|
||||
let value_option = self.context.get_value(&identifier.inner);
|
||||
|
||||
if let Some(value) = value_option {
|
||||
Ok(Some(value))
|
||||
} else {
|
||||
Err(VmError::UndefinedVariable { identifier })
|
||||
}
|
||||
}
|
||||
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(_) => todo!(),
|
||||
Expression::Literal(_) => todo!(),
|
||||
Expression::Loop(_) => todo!(),
|
||||
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!(),
|
||||
};
|
||||
|
||||
result.map_err(|error| VmError::Trace {
|
||||
evaluation_result.map_err(|error| VmError::Trace {
|
||||
error: Box::new(error),
|
||||
position,
|
||||
})
|
||||
}
|
||||
|
||||
fn run_list(&self, list_expression: ListExpression) -> Result<Option<Value>, VmError> {
|
||||
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)?.value() {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: invoker_position,
|
||||
});
|
||||
};
|
||||
|
||||
let function = if let Some(function) = invoker_value.as_function() {
|
||||
function
|
||||
} else {
|
||||
return Err(VmError::ExpectedFunction {
|
||||
actual: invoker_value,
|
||||
position: invoker_position,
|
||||
});
|
||||
};
|
||||
|
||||
let mut value_arguments = Vec::new();
|
||||
|
||||
for argument in arguments {
|
||||
let position = argument.position();
|
||||
|
||||
if let Some(value) = self.run_expression(argument)?.value() {
|
||||
value_arguments.push(value);
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue { position });
|
||||
}
|
||||
}
|
||||
|
||||
let context = Context::new();
|
||||
|
||||
function
|
||||
.call(None, Some(value_arguments), &context)
|
||||
.map(|value_option| Evaluation::Return(value_option))
|
||||
}
|
||||
|
||||
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)?.value() {
|
||||
value
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
position: container_position,
|
||||
});
|
||||
};
|
||||
|
||||
Ok(Evaluation::Return(container_value.get_field(&field.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(Evaluation::Return(Some(value)))
|
||||
} else {
|
||||
Err(VmError::UndefinedVariable { identifier })
|
||||
}
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
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,60 +362,44 @@ 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,
|
||||
});
|
||||
if boolean {
|
||||
self.run_expression(Expression::block(if_block.inner, if_block.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,
|
||||
});
|
||||
if boolean {
|
||||
self.run_expression(Expression::block(if_block.inner, if_block.position))?;
|
||||
}
|
||||
|
||||
match r#else {
|
||||
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user