Pass VM test

This commit is contained in:
Jeff 2024-08-20 02:25:22 -04:00
parent e3d821a1c3
commit fab66a4877
7 changed files with 265 additions and 269 deletions

View File

@ -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, .. } => {

View File

@ -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,

View 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,
})
}
}

View File

@ -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>>;

View File

@ -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};

View File

@ -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;

View File

@ -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>),
}