Pass VM test
This commit is contained in:
parent
e3d821a1c3
commit
fab66a4877
@ -86,8 +86,6 @@ impl<'a> Analyzer<'a> {
|
||||
Statement::Let(let_statement) => match &let_statement.inner {
|
||||
LetStatement::Let { identifier, value }
|
||||
| LetStatement::LetMut { identifier, value } => {
|
||||
self.analyze_expression(value)?;
|
||||
|
||||
let r#type = value.return_type(self.context);
|
||||
|
||||
if let Some(r#type) = r#type {
|
||||
@ -98,31 +96,35 @@ impl<'a> Analyzer<'a> {
|
||||
);
|
||||
} else {
|
||||
return Err(AnalysisError::ExpectedValueFromExpression {
|
||||
actual: value.clone(),
|
||||
expression: value.clone(),
|
||||
found_type: r#type,
|
||||
});
|
||||
}
|
||||
|
||||
self.analyze_expression(value)?;
|
||||
}
|
||||
LetStatement::LetType { .. } => todo!(),
|
||||
LetStatement::LetMutType { .. } => todo!(),
|
||||
},
|
||||
Statement::StructDefinition(struct_definition) => {
|
||||
let (name, struct_type) = match &struct_definition.inner {
|
||||
StructDefinition::Unit { name } => (
|
||||
name,
|
||||
Type::Struct(StructType::Unit {
|
||||
Statement::StructDefinition(struct_definition) => match &struct_definition.inner {
|
||||
StructDefinition::Unit { name } => self.context.set_constructor_type(
|
||||
name.inner.clone(),
|
||||
StructType::Unit {
|
||||
name: name.inner.clone(),
|
||||
}),
|
||||
},
|
||||
name.position,
|
||||
),
|
||||
StructDefinition::Tuple { name, items } => {
|
||||
let fields = items.iter().map(|item| item.inner.clone()).collect();
|
||||
|
||||
(
|
||||
name,
|
||||
Type::Struct(StructType::Tuple {
|
||||
self.context.set_constructor_type(
|
||||
name.inner.clone(),
|
||||
StructType::Tuple {
|
||||
name: name.inner.clone(),
|
||||
fields,
|
||||
}),
|
||||
)
|
||||
},
|
||||
name.position,
|
||||
);
|
||||
}
|
||||
StructDefinition::Fields { name, fields } => {
|
||||
let fields = fields
|
||||
@ -132,18 +134,16 @@ impl<'a> Analyzer<'a> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
(
|
||||
name,
|
||||
Type::Struct(StructType::Fields {
|
||||
self.context.set_constructor_type(
|
||||
name.inner.clone(),
|
||||
StructType::Fields {
|
||||
name: name.inner.clone(),
|
||||
fields,
|
||||
}),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
todo!("Set constructor")
|
||||
},
|
||||
name.position,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -240,18 +240,20 @@ impl<'a> Analyzer<'a> {
|
||||
|
||||
if expected_type.is_none() {
|
||||
return Err(AnalysisError::ExpectedValueFromExpression {
|
||||
actual: assignee.clone(),
|
||||
expression: assignee.clone(),
|
||||
found_type: expected_type,
|
||||
});
|
||||
}
|
||||
|
||||
if actual_type.is_none() {
|
||||
return Err(AnalysisError::ExpectedValueFromExpression {
|
||||
actual: modifier.clone(),
|
||||
expression: modifier.clone(),
|
||||
found_type: actual_type,
|
||||
});
|
||||
}
|
||||
|
||||
if let (Some(expected_type), Some(actual_type)) = (expected_type, actual_type) {
|
||||
expected_type.check(&actual_type).map_err(|type_conflct| {
|
||||
expected_type.check(&actual_type).map_err(|_| {
|
||||
AnalysisError::TypeConflict {
|
||||
actual_expression: modifier.clone(),
|
||||
actual_type,
|
||||
@ -288,14 +290,16 @@ impl<'a> Analyzer<'a> {
|
||||
},
|
||||
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
|
||||
StructExpression::Unit { name } => {
|
||||
todo!("Update constructor position");
|
||||
self.context
|
||||
.update_last_position(&name.inner, name.position);
|
||||
}
|
||||
StructExpression::Fields { name, fields } => {
|
||||
todo!("Update constructor position");
|
||||
self.context
|
||||
.update_last_position(&name.inner, name.position);
|
||||
|
||||
// for (_, expression) in fields {
|
||||
// self.analyze_expression(expression)?;
|
||||
// }
|
||||
for (_, expression) in fields {
|
||||
self.analyze_expression(expression)?;
|
||||
}
|
||||
}
|
||||
},
|
||||
Expression::TupleAccess(tuple_access) => {
|
||||
@ -381,7 +385,8 @@ pub enum AnalysisError {
|
||||
actual: Statement,
|
||||
},
|
||||
ExpectedValueFromExpression {
|
||||
actual: Expression,
|
||||
expression: Expression,
|
||||
found_type: Option<Type>,
|
||||
},
|
||||
ExpectedValueArgumentCount {
|
||||
expected: usize,
|
||||
@ -426,7 +431,7 @@ impl AnalysisError {
|
||||
AnalysisError::ExpectedIntegerOrRange { actual } => actual.position(),
|
||||
AnalysisError::ExpectedList { actual } => actual.position(),
|
||||
AnalysisError::ExpectedMap { actual } => actual.position(),
|
||||
AnalysisError::ExpectedValueFromExpression { actual } => actual.position(),
|
||||
AnalysisError::ExpectedValueFromExpression { expression, .. } => expression.position(),
|
||||
AnalysisError::ExpectedValueFromStatement { actual } => actual.position(),
|
||||
AnalysisError::ExpectedValueArgumentCount { position, .. } => *position,
|
||||
AnalysisError::IndexOutOfBounds { index, .. } => index.position(),
|
||||
@ -461,11 +466,14 @@ impl Display for AnalysisError {
|
||||
}
|
||||
AnalysisError::ExpectedList { actual } => write!(f, "Expected list, found {}", actual),
|
||||
AnalysisError::ExpectedMap { actual } => write!(f, "Expected map, found {}", actual),
|
||||
AnalysisError::ExpectedValueFromExpression { actual, .. } => {
|
||||
AnalysisError::ExpectedValueFromExpression {
|
||||
expression,
|
||||
found_type,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"Expected expression to produce a value, found {}",
|
||||
actual
|
||||
"Expected {} to produce a value, found {:?}",
|
||||
expression, found_type
|
||||
)
|
||||
}
|
||||
AnalysisError::ExpectedValueFromStatement { actual, .. } => {
|
||||
|
@ -297,7 +297,7 @@ impl Expression {
|
||||
}
|
||||
}
|
||||
Expression::Grouped(expression) => expression.inner.return_type(context),
|
||||
Expression::Identifier(identifier) => context.get_variable_type(&identifier.inner),
|
||||
Expression::Identifier(identifier) => context.get_type(&identifier.inner),
|
||||
Expression::If(if_expression) => {
|
||||
return match if_expression.inner.as_ref() {
|
||||
IfExpression::If { .. } => None,
|
||||
|
51
dust-lang/src/constructor.rs
Normal file
51
dust-lang/src/constructor.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Identifier, Struct, Value};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Constructor {
|
||||
Unit(UnitConstructor),
|
||||
Tuple(TupleConstructor),
|
||||
Fields(FieldsConstructor),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct UnitConstructor {
|
||||
pub name: Identifier,
|
||||
}
|
||||
|
||||
impl UnitConstructor {
|
||||
pub fn construct(self) -> Value {
|
||||
Value::Struct(Struct::Unit { name: self.name })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct TupleConstructor {
|
||||
pub name: Identifier,
|
||||
}
|
||||
|
||||
impl TupleConstructor {
|
||||
pub fn construct(self, fields: Vec<Value>) -> Value {
|
||||
Value::Struct(Struct::Tuple {
|
||||
name: self.name,
|
||||
fields,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct FieldsConstructor {
|
||||
pub name: Identifier,
|
||||
}
|
||||
|
||||
impl FieldsConstructor {
|
||||
pub fn construct(self, fields: HashMap<Identifier, Value>) -> Value {
|
||||
Value::Struct(Struct::Fields {
|
||||
name: self.name,
|
||||
fields,
|
||||
})
|
||||
}
|
||||
}
|
@ -4,9 +4,9 @@ use std::{
|
||||
sync::{Arc, PoisonError as StdPoisonError, RwLock, RwLockWriteGuard},
|
||||
};
|
||||
|
||||
use crate::{ast::Span, Identifier, Type, Value};
|
||||
use crate::{ast::Span, Constructor, Identifier, StructType, Type, Value};
|
||||
|
||||
pub type Variables = HashMap<Identifier, (VariableData, Span)>;
|
||||
pub type Variables = HashMap<Identifier, (ContextData, Span)>;
|
||||
|
||||
/// Garbage-collecting context for variables.
|
||||
#[derive(Debug, Clone)]
|
||||
@ -39,21 +39,24 @@ impl Context {
|
||||
}
|
||||
|
||||
/// Returns the full VariableData and Span if the context contains the given identifier.
|
||||
pub fn get(&self, identifier: &Identifier) -> Option<(VariableData, Span)> {
|
||||
pub fn get(&self, identifier: &Identifier) -> Option<(ContextData, Span)> {
|
||||
self.variables.read().unwrap().get(identifier).cloned()
|
||||
}
|
||||
|
||||
/// Returns the type of the variable with the given identifier.
|
||||
pub fn get_variable_type(&self, identifier: &Identifier) -> Option<Type> {
|
||||
pub fn get_type(&self, identifier: &Identifier) -> Option<Type> {
|
||||
match self.variables.read().unwrap().get(identifier) {
|
||||
Some((VariableData::Type(r#type), _)) => Some(r#type.clone()),
|
||||
Some((VariableData::Value(value), _)) => Some(value.r#type()),
|
||||
Some((ContextData::VariableType(r#type), _)) => Some(r#type.clone()),
|
||||
Some((ContextData::VariableValue(value), _)) => Some(value.r#type()),
|
||||
Some((ContextData::ConstructorType(struct_type), _)) => {
|
||||
Some(Type::Struct(struct_type.clone()))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the VariableData of the variable with the given identifier.
|
||||
pub fn get_variable_data(&self, identifier: &Identifier) -> Option<VariableData> {
|
||||
pub fn get_data(&self, identifier: &Identifier) -> Option<ContextData> {
|
||||
match self.variables.read().unwrap().get(identifier) {
|
||||
Some((variable_data, _)) => Some(variable_data.clone()),
|
||||
_ => None,
|
||||
@ -63,7 +66,15 @@ impl Context {
|
||||
/// Returns the value of the variable with the given identifier.
|
||||
pub fn get_variable_value(&self, identifier: &Identifier) -> Option<Value> {
|
||||
match self.variables.read().unwrap().get(identifier) {
|
||||
Some((VariableData::Value(value), _)) => Some(value.clone()),
|
||||
Some((ContextData::VariableValue(value), _)) => Some(value.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the constructor associated with the given identifier.
|
||||
pub fn get_constructor(&self, identifier: &Identifier) -> Option<Constructor> {
|
||||
match self.variables.read().unwrap().get(identifier) {
|
||||
Some((ContextData::Constructor(constructor), _)) => Some(constructor.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -75,7 +86,7 @@ impl Context {
|
||||
self.variables
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(identifier, (VariableData::Type(r#type), position));
|
||||
.insert(identifier, (ContextData::VariableType(r#type), position));
|
||||
}
|
||||
|
||||
/// Sets a variable to a value.
|
||||
@ -89,7 +100,44 @@ impl Context {
|
||||
.map(|(_, last_position)| *last_position)
|
||||
.unwrap_or_default();
|
||||
|
||||
variables.insert(identifier, (VariableData::Value(value), last_position));
|
||||
variables.insert(
|
||||
identifier,
|
||||
(ContextData::VariableValue(value), last_position),
|
||||
);
|
||||
}
|
||||
|
||||
/// Associates a constructor with an identifier.
|
||||
pub fn set_constructor(&self, identifier: Identifier, constructor: Constructor) {
|
||||
log::trace!("Setting {identifier} to constructor {constructor:?}");
|
||||
|
||||
let mut variables = self.variables.write().unwrap();
|
||||
|
||||
let last_position = variables
|
||||
.get(&identifier)
|
||||
.map(|(_, last_position)| *last_position)
|
||||
.unwrap_or_default();
|
||||
|
||||
variables.insert(
|
||||
identifier,
|
||||
(ContextData::Constructor(constructor), last_position),
|
||||
);
|
||||
}
|
||||
|
||||
/// Associates a constructor type with an identifier.
|
||||
pub fn set_constructor_type(
|
||||
&self,
|
||||
identifier: Identifier,
|
||||
struct_type: StructType,
|
||||
position: Span,
|
||||
) {
|
||||
log::trace!("Setting {identifier} to constructor of type {struct_type:?}");
|
||||
|
||||
let mut variables = self.variables.write().unwrap();
|
||||
|
||||
variables.insert(
|
||||
identifier,
|
||||
(ContextData::ConstructorType(struct_type), position),
|
||||
);
|
||||
}
|
||||
|
||||
/// Collects garbage up to the given position, removing all variables with lesser positions.
|
||||
@ -149,9 +197,11 @@ impl Default for Context {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum VariableData {
|
||||
Value(Value),
|
||||
Type(Type),
|
||||
pub enum ContextData {
|
||||
Constructor(Constructor),
|
||||
ConstructorType(StructType),
|
||||
VariableValue(Value),
|
||||
VariableType(Type),
|
||||
}
|
||||
|
||||
pub type ContextPoisonError<'err> = StdPoisonError<RwLockWriteGuard<'err, Variables>>;
|
||||
|
@ -18,6 +18,7 @@
|
||||
pub mod analyzer;
|
||||
pub mod ast;
|
||||
pub mod built_in_function;
|
||||
pub mod constructor;
|
||||
pub mod context;
|
||||
pub mod dust_error;
|
||||
pub mod identifier;
|
||||
@ -31,7 +32,8 @@ pub mod vm;
|
||||
pub use analyzer::{analyze, AnalysisError, Analyzer};
|
||||
pub use ast::{AbstractSyntaxTree, Expression, Statement};
|
||||
pub use built_in_function::{BuiltInFunction, BuiltInFunctionError};
|
||||
pub use context::{Context, VariableData};
|
||||
pub use constructor::Constructor;
|
||||
pub use context::{Context, ContextData};
|
||||
pub use dust_error::DustError;
|
||||
pub use identifier::Identifier;
|
||||
pub use lexer::{lex, LexError, Lexer};
|
||||
|
@ -13,11 +13,15 @@ use std::{
|
||||
cmp::Ordering,
|
||||
collections::HashMap,
|
||||
fmt::{self, Display, Formatter},
|
||||
rc::Weak,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Enum, Identifier, Struct, Value};
|
||||
use crate::{
|
||||
constructor::{FieldsConstructor, TupleConstructor, UnitConstructor},
|
||||
Constructor, Enum, Identifier, Struct, Value,
|
||||
};
|
||||
|
||||
/// Description of a kind of value.
|
||||
///
|
||||
@ -59,12 +63,14 @@ pub enum Type {
|
||||
impl Type {
|
||||
/// Returns a concrete type, either the type itself or the concrete type of a generic type.
|
||||
pub fn concrete_type(&self) -> &Type {
|
||||
match self {
|
||||
Type::Generic {
|
||||
if let Type::Generic {
|
||||
concrete_type: Some(concrete_type),
|
||||
..
|
||||
} => concrete_type.concrete_type(),
|
||||
_ => self,
|
||||
} = self
|
||||
{
|
||||
concrete_type.concrete_type()
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@ -435,20 +441,16 @@ impl StructType {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn constructor(&self) -> Option<Constructor> {
|
||||
let constructor = match self {
|
||||
StructType::Unit { name } => Constructor::Unit { name: name.clone() },
|
||||
StructType::Tuple { name, fields } => Constructor::Tuple(TupleConstructor {
|
||||
name: name.clone(),
|
||||
tuple_arguments: Vec::with_capacity(fields.len()),
|
||||
}),
|
||||
StructType::Fields { name, fields } => Constructor::Fields {
|
||||
name: name.clone(),
|
||||
field_arguments: HashMap::with_capacity(fields.len()),
|
||||
},
|
||||
};
|
||||
|
||||
Some(constructor)
|
||||
pub fn constructor(&self) -> Constructor {
|
||||
match self {
|
||||
StructType::Unit { name } => Constructor::Unit(UnitConstructor { name: name.clone() }),
|
||||
StructType::Tuple { name, .. } => {
|
||||
Constructor::Tuple(TupleConstructor { name: name.clone() })
|
||||
}
|
||||
StructType::Fields { name, .. } => {
|
||||
Constructor::Fields(FieldsConstructor { name: name.clone() })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -547,116 +549,12 @@ impl Ord for StructType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Constructor {
|
||||
Unit {
|
||||
name: Identifier,
|
||||
},
|
||||
Tuple(TupleConstructor),
|
||||
Fields {
|
||||
name: Identifier,
|
||||
field_arguments: HashMap<Identifier, Value>,
|
||||
},
|
||||
Enum {
|
||||
name: Identifier,
|
||||
r#type: EnumType,
|
||||
variant_constructor: Box<Constructor>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Constructor {
|
||||
pub fn construct(self) -> Value {
|
||||
match self {
|
||||
Constructor::Unit { name } => Value::Struct(Struct::Unit { name }),
|
||||
Constructor::Tuple(tuple_constructor) => tuple_constructor.construct(),
|
||||
Constructor::Fields {
|
||||
name,
|
||||
field_arguments,
|
||||
} => Value::Struct(Struct::Fields {
|
||||
name,
|
||||
fields: field_arguments,
|
||||
}),
|
||||
Constructor::Enum {
|
||||
name,
|
||||
r#type,
|
||||
variant_constructor,
|
||||
} => Value::Enum(Enum {
|
||||
name,
|
||||
r#type,
|
||||
variant_data: Self::make_struct(*variant_constructor),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_struct(this: Self) -> Struct {
|
||||
match this {
|
||||
Constructor::Unit { name } => Struct::Unit { name },
|
||||
Constructor::Tuple(TupleConstructor {
|
||||
name,
|
||||
tuple_arguments,
|
||||
}) => Struct::Tuple {
|
||||
name,
|
||||
fields: tuple_arguments,
|
||||
},
|
||||
Constructor::Fields {
|
||||
name,
|
||||
field_arguments,
|
||||
} => Struct::Fields {
|
||||
name,
|
||||
fields: field_arguments,
|
||||
},
|
||||
Constructor::Enum {
|
||||
variant_constructor,
|
||||
..
|
||||
} => Self::make_struct(*variant_constructor),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct TupleConstructor {
|
||||
pub name: Identifier,
|
||||
pub tuple_arguments: Vec<Value>,
|
||||
}
|
||||
|
||||
impl TupleConstructor {
|
||||
pub fn push_argument(&mut self, value: Value) {
|
||||
self.tuple_arguments.push(value);
|
||||
}
|
||||
|
||||
pub fn construct(self) -> Value {
|
||||
Value::Struct(Struct::Tuple {
|
||||
name: self.name,
|
||||
fields: self.tuple_arguments,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct EnumType {
|
||||
pub name: Identifier,
|
||||
pub variants: Vec<StructType>,
|
||||
}
|
||||
|
||||
impl EnumType {
|
||||
pub fn constructor(&self) -> Option<Constructor> {
|
||||
let get_variant_constructor = self
|
||||
.variants
|
||||
.iter()
|
||||
.find_map(|struct_type| struct_type.constructor());
|
||||
|
||||
if let Some(variant_constructor) = get_variant_constructor {
|
||||
Some(Constructor::Enum {
|
||||
name: self.name.clone(),
|
||||
r#type: self.clone(),
|
||||
variant_constructor: Box::new(variant_constructor),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for EnumType {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
let EnumType { name, variants } = self;
|
||||
|
@ -21,9 +21,8 @@ use crate::{
|
||||
OperatorExpression, PrimitiveValueExpression, RangeExpression, RawStringExpression, Span,
|
||||
Statement, StructDefinition, StructExpression,
|
||||
},
|
||||
parse, Analyzer, BuiltInFunctionError, Constructor, Context, DustError, Enum, EnumType,
|
||||
Expression, Identifier, ParseError, Struct, StructType, TupleConstructor, Type, Value,
|
||||
ValueError,
|
||||
parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData, DustError, Enum,
|
||||
EnumType, Expression, Identifier, ParseError, Struct, StructType, Type, Value, ValueError,
|
||||
};
|
||||
|
||||
/// Run the source code and return the result.
|
||||
@ -156,8 +155,9 @@ impl Vm {
|
||||
)
|
||||
}
|
||||
};
|
||||
let constructor = struct_type.constructor();
|
||||
|
||||
todo!("Set constructor");
|
||||
self.context.set_constructor(name, constructor);
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
@ -222,17 +222,21 @@ impl Vm {
|
||||
self.run_expression(*expression.inner, collect_garbage)
|
||||
}
|
||||
Expression::Identifier(identifier) => {
|
||||
let get_value = self.context.get_variable_value(&identifier.inner);
|
||||
let get_data = self.context.get_data(&identifier.inner);
|
||||
|
||||
if let Some(ContextData::VariableValue(value)) = get_data {
|
||||
return Ok(Evaluation::Return(Some(value.clone())));
|
||||
}
|
||||
|
||||
if let Some(ContextData::Constructor(constructor)) = get_data {
|
||||
return Ok(Evaluation::Constructor(constructor));
|
||||
}
|
||||
|
||||
if let Some(value) = get_value {
|
||||
Ok(Evaluation::Return(Some(value)))
|
||||
} else {
|
||||
Err(RuntimeError::UndefinedValue {
|
||||
identifier: identifier.inner,
|
||||
position: identifier.position,
|
||||
position,
|
||||
})
|
||||
}
|
||||
}
|
||||
Expression::If(if_expression) => self.run_if(*if_expression.inner, collect_garbage),
|
||||
Expression::List(list_expression) => {
|
||||
self.run_list(*list_expression.inner, collect_garbage)
|
||||
@ -269,7 +273,7 @@ impl Vm {
|
||||
match struct_expression {
|
||||
StructExpression::Unit { name } => {
|
||||
let position = name.position;
|
||||
let r#type = self.context.get_variable_type(&name.inner).ok_or_else(|| {
|
||||
let r#type = self.context.get_type(&name.inner).ok_or_else(|| {
|
||||
RuntimeError::UndefinedType {
|
||||
identifier: name.inner.clone(),
|
||||
position,
|
||||
@ -293,7 +297,7 @@ impl Vm {
|
||||
fields: expressions,
|
||||
} => {
|
||||
let position = name.position;
|
||||
let r#type = self.context.get_variable_type(&name.inner).ok_or_else(|| {
|
||||
let r#type = self.context.get_type(&name.inner).ok_or_else(|| {
|
||||
RuntimeError::UndefinedType {
|
||||
identifier: name.inner.clone(),
|
||||
position,
|
||||
@ -679,57 +683,33 @@ impl Vm {
|
||||
let invoker_position = invoker.position();
|
||||
let run_invoker = self.run_expression(invoker, collect_garbage)?;
|
||||
|
||||
if let Evaluation::Constructor(Type::Struct(StructType::Tuple { name, fields })) =
|
||||
&run_invoker
|
||||
{
|
||||
let struct_type = fields
|
||||
.iter()
|
||||
.find(|r#type| {
|
||||
if let Type::Struct(struct_type) = r#type {
|
||||
struct_type.name() == name
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.ok_or(RuntimeError::EnumVariantNotFound {
|
||||
identifier: name.clone(),
|
||||
position: invoker_position,
|
||||
})?;
|
||||
|
||||
if let Type::Struct(StructType::Tuple { name, fields }) = struct_type {
|
||||
let mut values = Vec::with_capacity(arguments.len());
|
||||
match run_invoker {
|
||||
Evaluation::Constructor(constructor) => {
|
||||
if let Constructor::Tuple(tuple_constructor) = constructor {
|
||||
let mut fields = Vec::new();
|
||||
|
||||
for argument in arguments {
|
||||
let position = argument.position();
|
||||
let value = self
|
||||
.run_expression(argument, collect_garbage)?
|
||||
.expect_value(position)?;
|
||||
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
let r#struct = Struct::Tuple {
|
||||
name: name.clone(),
|
||||
fields: values,
|
||||
};
|
||||
|
||||
return Ok(Evaluation::Return(Some(Value::Struct(r#struct))));
|
||||
}
|
||||
}
|
||||
|
||||
let invoker_value = if let Some(value) = run_invoker.value() {
|
||||
value
|
||||
if let Some(value) = self.run_expression(argument, collect_garbage)?.value()
|
||||
{
|
||||
fields.push(value);
|
||||
} else {
|
||||
return Err(RuntimeError::ExpectedValue {
|
||||
position: invoker_position,
|
||||
});
|
||||
};
|
||||
return Err(RuntimeError::ExpectedValue { position });
|
||||
}
|
||||
}
|
||||
|
||||
let function = if let Value::Function(function) = invoker_value {
|
||||
let tuple = tuple_constructor.construct(fields);
|
||||
|
||||
return Ok(Evaluation::Return(Some(tuple)));
|
||||
}
|
||||
}
|
||||
Evaluation::Return(Some(value)) => {
|
||||
let function = if let Value::Function(function) = value {
|
||||
function
|
||||
} else {
|
||||
return Err(RuntimeError::ExpectedFunction {
|
||||
actual: invoker_value,
|
||||
actual: value.to_owned(),
|
||||
position: invoker_position,
|
||||
});
|
||||
};
|
||||
@ -748,9 +728,16 @@ impl Vm {
|
||||
|
||||
let context = Context::new();
|
||||
|
||||
function
|
||||
return function
|
||||
.call(None, Some(value_arguments), &context)
|
||||
.map(Evaluation::Return)
|
||||
.map(Evaluation::Return);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Err(RuntimeError::ExpectedValue {
|
||||
position: invoker_position,
|
||||
})
|
||||
}
|
||||
|
||||
fn run_field_access(
|
||||
@ -923,7 +910,7 @@ impl Vm {
|
||||
|
||||
enum Evaluation {
|
||||
Break,
|
||||
Constructor(Type),
|
||||
Constructor(Constructor),
|
||||
Return(Option<Value>),
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user