Pass VM test
This commit is contained in:
parent
fab66a4877
commit
d5c2ae92c9
@ -31,7 +31,7 @@ impl Statement {
|
|||||||
pub fn return_type(&self, context: &Context) -> Option<Type> {
|
pub fn return_type(&self, context: &Context) -> Option<Type> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Expression(expression) => expression.return_type(context),
|
Statement::Expression(expression) => expression.return_type(context),
|
||||||
Statement::ExpressionNullified(expression) => None,
|
Statement::ExpressionNullified(_) => None,
|
||||||
Statement::Let(_) => None,
|
Statement::Let(_) => None,
|
||||||
Statement::StructDefinition(_) => None,
|
Statement::StructDefinition(_) => None,
|
||||||
}
|
}
|
||||||
@ -42,9 +42,37 @@ impl Display for Statement {
|
|||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Statement::Expression(expression) => write!(f, "{}", expression),
|
Statement::Expression(expression) => write!(f, "{}", expression),
|
||||||
Statement::ExpressionNullified(expression) => write!(f, "{}", expression),
|
Statement::ExpressionNullified(expression) => write!(f, "{};", expression),
|
||||||
Statement::Let(r#let) => write!(f, "{}", r#let),
|
Statement::Let(r#let) => write!(f, "{};", r#let),
|
||||||
Statement::StructDefinition(definition) => write!(f, "{}", definition),
|
Statement::StructDefinition(struct_definition) => match &struct_definition.inner {
|
||||||
|
StructDefinition::Unit { name } => write!(f, "struct {};", name),
|
||||||
|
StructDefinition::Tuple { name, items } => {
|
||||||
|
write!(f, "struct {name} {{ ")?;
|
||||||
|
|
||||||
|
for (index, item) in items.iter().enumerate() {
|
||||||
|
write!(f, "{}: {}", item, index)?;
|
||||||
|
|
||||||
|
if index < items.len() - 1 {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, " }}")
|
||||||
|
}
|
||||||
|
StructDefinition::Fields { name, fields } => {
|
||||||
|
write!(f, "struct {name} {{ ")?;
|
||||||
|
|
||||||
|
for (index, (field, r#type)) in fields.iter().enumerate() {
|
||||||
|
write!(f, "{}: {}", field, r#type)?;
|
||||||
|
|
||||||
|
if index < fields.len() - 1 {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, " }}")
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fmt::{self, Display, Formatter},
|
||||||
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -11,6 +14,16 @@ pub enum Constructor {
|
|||||||
Fields(FieldsConstructor),
|
Fields(FieldsConstructor),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Constructor {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Constructor::Unit(unit) => write!(f, "{}", unit.name),
|
||||||
|
Constructor::Tuple(tuple) => write!(f, "{}", tuple.name),
|
||||||
|
Constructor::Fields(fields) => write!(f, "{}", fields.name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct UnitConstructor {
|
pub struct UnitConstructor {
|
||||||
pub name: Identifier,
|
pub name: Identifier,
|
||||||
|
@ -108,7 +108,7 @@ impl Context {
|
|||||||
|
|
||||||
/// Associates a constructor with an identifier.
|
/// Associates a constructor with an identifier.
|
||||||
pub fn set_constructor(&self, identifier: Identifier, constructor: Constructor) {
|
pub fn set_constructor(&self, identifier: Identifier, constructor: Constructor) {
|
||||||
log::trace!("Setting {identifier} to constructor {constructor:?}");
|
log::trace!("Setting {identifier} to constructor {constructor}");
|
||||||
|
|
||||||
let mut variables = self.variables.write().unwrap();
|
let mut variables = self.variables.write().unwrap();
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ impl Context {
|
|||||||
struct_type: StructType,
|
struct_type: StructType,
|
||||||
position: Span,
|
position: Span,
|
||||||
) {
|
) {
|
||||||
log::trace!("Setting {identifier} to constructor of type {struct_type:?}");
|
log::trace!("Setting {identifier} to constructor of type {struct_type}");
|
||||||
|
|
||||||
let mut variables = self.variables.write().unwrap();
|
let mut variables = self.variables.write().unwrap();
|
||||||
|
|
||||||
|
@ -13,14 +13,13 @@ use std::{
|
|||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
rc::Weak,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constructor::{FieldsConstructor, TupleConstructor, UnitConstructor},
|
constructor::{FieldsConstructor, TupleConstructor, UnitConstructor},
|
||||||
Constructor, Enum, Identifier, Struct, Value,
|
Constructor, Identifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Description of a kind of value.
|
/// Description of a kind of value.
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
primitive,
|
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -21,8 +20,8 @@ use crate::{
|
|||||||
OperatorExpression, PrimitiveValueExpression, RangeExpression, RawStringExpression, Span,
|
OperatorExpression, PrimitiveValueExpression, RangeExpression, RawStringExpression, Span,
|
||||||
Statement, StructDefinition, StructExpression,
|
Statement, StructDefinition, StructExpression,
|
||||||
},
|
},
|
||||||
parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData, DustError, Enum,
|
parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData, DustError,
|
||||||
EnumType, Expression, Identifier, ParseError, Struct, StructType, Type, Value, ValueError,
|
Expression, Identifier, ParseError, Struct, StructType, Type, Value, ValueError,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Run the source code and return the result.
|
/// Run the source code and return the result.
|
||||||
@ -109,6 +108,8 @@ impl Vm {
|
|||||||
statement: Statement,
|
statement: Statement,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Option<Value>, RuntimeError> {
|
) -> Result<Option<Value>, RuntimeError> {
|
||||||
|
log::debug!("Running statement: {}", statement);
|
||||||
|
|
||||||
let position = statement.position();
|
let position = statement.position();
|
||||||
let result = match statement {
|
let result = match statement {
|
||||||
Statement::Expression(expression) => self
|
Statement::Expression(expression) => self
|
||||||
@ -211,6 +212,8 @@ impl Vm {
|
|||||||
expression: Expression,
|
expression: Expression,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
|
log::debug!("Running expression: {}", expression);
|
||||||
|
|
||||||
let position = expression.position();
|
let position = expression.position();
|
||||||
let evaluation_result = match expression {
|
let evaluation_result = match expression {
|
||||||
Expression::Block(Node { inner, .. }) => self.run_block(*inner, collect_garbage),
|
Expression::Block(Node { inner, .. }) => self.run_block(*inner, collect_garbage),
|
||||||
@ -222,13 +225,19 @@ impl Vm {
|
|||||||
self.run_expression(*expression.inner, collect_garbage)
|
self.run_expression(*expression.inner, collect_garbage)
|
||||||
}
|
}
|
||||||
Expression::Identifier(identifier) => {
|
Expression::Identifier(identifier) => {
|
||||||
|
log::debug!("Running identifier: {}", identifier.inner);
|
||||||
|
|
||||||
let get_data = self.context.get_data(&identifier.inner);
|
let get_data = self.context.get_data(&identifier.inner);
|
||||||
|
|
||||||
if let Some(ContextData::VariableValue(value)) = get_data {
|
if let Some(ContextData::VariableValue(value)) = get_data {
|
||||||
return Ok(Evaluation::Return(Some(value.clone())));
|
return Ok(Evaluation::Return(Some(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ContextData::Constructor(constructor)) = get_data {
|
if let Some(ContextData::Constructor(constructor)) = get_data {
|
||||||
|
if let Constructor::Unit(unit_constructor) = constructor {
|
||||||
|
return Ok(Evaluation::Return(Some(unit_constructor.construct())));
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(Evaluation::Constructor(constructor));
|
return Ok(Evaluation::Constructor(constructor));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,6 +279,8 @@ impl Vm {
|
|||||||
struct_expression: StructExpression,
|
struct_expression: StructExpression,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
|
log::debug!("Running struct expression: {struct_expression}");
|
||||||
|
|
||||||
match struct_expression {
|
match struct_expression {
|
||||||
StructExpression::Unit { name } => {
|
StructExpression::Unit { name } => {
|
||||||
let position = name.position;
|
let position = name.position;
|
||||||
@ -678,14 +689,19 @@ impl Vm {
|
|||||||
call_expression: CallExpression,
|
call_expression: CallExpression,
|
||||||
collect_garbage: bool,
|
collect_garbage: bool,
|
||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
|
log::debug!("Running call expression: {call_expression}");
|
||||||
|
|
||||||
let CallExpression { invoker, arguments } = call_expression;
|
let CallExpression { invoker, arguments } = call_expression;
|
||||||
|
|
||||||
let invoker_position = invoker.position();
|
let invoker_position = invoker.position();
|
||||||
let run_invoker = self.run_expression(invoker, collect_garbage)?;
|
let run_invoker = self.run_expression(invoker, collect_garbage)?;
|
||||||
|
|
||||||
match run_invoker {
|
match run_invoker {
|
||||||
Evaluation::Constructor(constructor) => {
|
Evaluation::Constructor(constructor) => match constructor {
|
||||||
if let Constructor::Tuple(tuple_constructor) = constructor {
|
Constructor::Unit(unit_constructor) => {
|
||||||
|
Ok(Evaluation::Return(Some(unit_constructor.construct())))
|
||||||
|
}
|
||||||
|
Constructor::Tuple(tuple_constructor) => {
|
||||||
let mut fields = Vec::new();
|
let mut fields = Vec::new();
|
||||||
|
|
||||||
for argument in arguments {
|
for argument in arguments {
|
||||||
@ -701,9 +717,12 @@ impl Vm {
|
|||||||
|
|
||||||
let tuple = tuple_constructor.construct(fields);
|
let tuple = tuple_constructor.construct(fields);
|
||||||
|
|
||||||
return Ok(Evaluation::Return(Some(tuple)));
|
Ok(Evaluation::Return(Some(tuple)))
|
||||||
}
|
}
|
||||||
|
Constructor::Fields(_) => {
|
||||||
|
todo!("Return an error")
|
||||||
}
|
}
|
||||||
|
},
|
||||||
Evaluation::Return(Some(value)) => {
|
Evaluation::Return(Some(value)) => {
|
||||||
let function = if let Value::Function(function) = value {
|
let function = if let Value::Function(function) = value {
|
||||||
function
|
function
|
||||||
@ -718,26 +737,23 @@ impl Vm {
|
|||||||
|
|
||||||
for argument in arguments {
|
for argument in arguments {
|
||||||
let position = argument.position();
|
let position = argument.position();
|
||||||
|
let value = self
|
||||||
|
.run_expression(argument, collect_garbage)?
|
||||||
|
.expect_value(position)?;
|
||||||
|
|
||||||
if let Some(value) = self.run_expression(argument, collect_garbage)?.value() {
|
|
||||||
value_arguments.push(value);
|
value_arguments.push(value);
|
||||||
} else {
|
|
||||||
return Err(RuntimeError::ExpectedValue { position });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let context = Context::new();
|
let context = Context::new();
|
||||||
|
|
||||||
return function
|
function
|
||||||
.call(None, Some(value_arguments), &context)
|
.call(None, Some(value_arguments), &context)
|
||||||
.map(Evaluation::Return);
|
.map(Evaluation::Return)
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => Err(RuntimeError::ExpectedValueOrConstructor {
|
||||||
}
|
|
||||||
|
|
||||||
Err(RuntimeError::ExpectedValue {
|
|
||||||
position: invoker_position,
|
position: invoker_position,
|
||||||
})
|
}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_field_access(
|
fn run_field_access(
|
||||||
@ -998,6 +1014,9 @@ pub enum RuntimeError {
|
|||||||
ExpectedValue {
|
ExpectedValue {
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
|
ExpectedValueOrConstructor {
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
InvalidRange {
|
InvalidRange {
|
||||||
start_position: Span,
|
start_position: Span,
|
||||||
end_position: Span,
|
end_position: Span,
|
||||||
@ -1050,6 +1069,7 @@ impl RuntimeError {
|
|||||||
} => (start_position.0, end_position.1),
|
} => (start_position.0, end_position.1),
|
||||||
Self::UndefinedType { position, .. } => *position,
|
Self::UndefinedType { position, .. } => *position,
|
||||||
Self::UndefinedValue { position, .. } => *position,
|
Self::UndefinedValue { position, .. } => *position,
|
||||||
|
Self::ExpectedValueOrConstructor { position } => *position,
|
||||||
Self::UndefinedProperty {
|
Self::UndefinedProperty {
|
||||||
property_position, ..
|
property_position, ..
|
||||||
} => *property_position,
|
} => *property_position,
|
||||||
@ -1169,6 +1189,13 @@ impl Display for RuntimeError {
|
|||||||
Self::ExpectedValue { position } => {
|
Self::ExpectedValue { position } => {
|
||||||
write!(f, "Expected a value at position: {:?}", position)
|
write!(f, "Expected a value at position: {:?}", position)
|
||||||
}
|
}
|
||||||
|
Self::ExpectedValueOrConstructor { position } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Expected a value or constructor at position: {:?}",
|
||||||
|
position
|
||||||
|
)
|
||||||
|
}
|
||||||
Self::InvalidRange {
|
Self::InvalidRange {
|
||||||
start_position,
|
start_position,
|
||||||
end_position,
|
end_position,
|
||||||
@ -1291,6 +1318,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assign_unit_struct_variable() {
|
fn assign_unit_struct_variable() {
|
||||||
|
env_logger::builder().is_test(true).try_init().unwrap();
|
||||||
|
|
||||||
let input = "
|
let input = "
|
||||||
struct Foo;
|
struct Foo;
|
||||||
let x = Foo;
|
let x = Foo;
|
||||||
|
Loading…
Reference in New Issue
Block a user