Pass VM tests
This commit is contained in:
parent
d5c2ae92c9
commit
c0ab5a84a2
@ -289,10 +289,6 @@ impl<'a> Analyzer<'a> {
|
||||
}
|
||||
},
|
||||
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
|
||||
StructExpression::Unit { name } => {
|
||||
self.context
|
||||
.update_last_position(&name.inner, name.position);
|
||||
}
|
||||
StructExpression::Fields { name, fields } => {
|
||||
self.context
|
||||
.update_last_position(&name.inner, name.position);
|
||||
|
@ -407,9 +407,6 @@ impl Expression {
|
||||
fields: types,
|
||||
}))
|
||||
}
|
||||
StructExpression::Unit { name } => Some(Type::Struct(StructType::Unit {
|
||||
name: name.inner.clone(),
|
||||
})),
|
||||
},
|
||||
Expression::TupleAccess(tuple_access_expression) => {
|
||||
let TupleAccessExpression { tuple, index } = tuple_access_expression.inner.as_ref();
|
||||
@ -647,15 +644,6 @@ impl Ord for PrimitiveValueExpression {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct RawStringExpression(pub String);
|
||||
|
||||
impl Display for RawStringExpression {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for LiteralExpression {
|
||||
fn from(value: i64) -> Self {
|
||||
LiteralExpression::Primitive(PrimitiveValueExpression::Integer(value))
|
||||
@ -664,13 +652,13 @@ impl From<i64> for LiteralExpression {
|
||||
|
||||
impl From<String> for LiteralExpression {
|
||||
fn from(value: String) -> Self {
|
||||
LiteralExpression::String(RawStringExpression(value))
|
||||
LiteralExpression::String(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for LiteralExpression {
|
||||
fn from(value: &str) -> Self {
|
||||
LiteralExpression::String(RawStringExpression(value.to_string()))
|
||||
LiteralExpression::String(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@ -695,7 +683,7 @@ impl From<char> for LiteralExpression {
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum LiteralExpression {
|
||||
Primitive(PrimitiveValueExpression),
|
||||
String(RawStringExpression),
|
||||
String(String),
|
||||
}
|
||||
|
||||
impl Display for LiteralExpression {
|
||||
@ -1022,10 +1010,8 @@ impl Display for LoopExpression {
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum StructExpression {
|
||||
// The tuple struct expression is omitted because it is redundant with call expression
|
||||
Unit {
|
||||
name: Node<Identifier>,
|
||||
},
|
||||
// The unit struct is omitted because it is redundant with a plain identifier
|
||||
// The tuple struct is omitted because it is redundant with the call expression
|
||||
Fields {
|
||||
name: Node<Identifier>,
|
||||
fields: Vec<(Node<Identifier>, Expression)>,
|
||||
@ -1035,7 +1021,6 @@ pub enum StructExpression {
|
||||
impl Display for StructExpression {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
StructExpression::Unit { name } => write!(f, "{}", name),
|
||||
StructExpression::Fields { name, fields } => {
|
||||
write!(f, "{} {{", name)?;
|
||||
|
||||
|
@ -17,9 +17,10 @@ use crate::{
|
||||
AbstractSyntaxTree, BlockExpression, CallExpression, ComparisonOperator, ElseExpression,
|
||||
FieldAccessExpression, IfExpression, LetStatement, ListExpression, ListIndexExpression,
|
||||
LiteralExpression, LogicOperator, LoopExpression, MapExpression, MathOperator, Node,
|
||||
OperatorExpression, PrimitiveValueExpression, RangeExpression, RawStringExpression, Span,
|
||||
Statement, StructDefinition, StructExpression,
|
||||
OperatorExpression, PrimitiveValueExpression, RangeExpression, Span, Statement,
|
||||
StructDefinition, StructExpression,
|
||||
},
|
||||
constructor::FieldsConstructor,
|
||||
parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData, DustError,
|
||||
Expression, Identifier, ParseError, Struct, StructType, Type, Value, ValueError,
|
||||
};
|
||||
@ -281,67 +282,32 @@ impl Vm {
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
log::debug!("Running struct expression: {struct_expression}");
|
||||
|
||||
match struct_expression {
|
||||
StructExpression::Unit { name } => {
|
||||
let position = name.position;
|
||||
let r#type = self.context.get_type(&name.inner).ok_or_else(|| {
|
||||
RuntimeError::UndefinedType {
|
||||
identifier: name.inner.clone(),
|
||||
position,
|
||||
}
|
||||
})?;
|
||||
let StructExpression::Fields { name, fields } = struct_expression;
|
||||
|
||||
if let Type::Struct(StructType::Unit { name }) = r#type {
|
||||
Ok(Evaluation::Return(Some(Value::Struct(Struct::Unit {
|
||||
name,
|
||||
}))))
|
||||
} else {
|
||||
Err(RuntimeError::ExpectedType {
|
||||
expected: Type::Struct(StructType::Unit { name: name.inner }),
|
||||
actual: r#type,
|
||||
position,
|
||||
})
|
||||
}
|
||||
}
|
||||
StructExpression::Fields {
|
||||
name,
|
||||
fields: expressions,
|
||||
} => {
|
||||
let position = name.position;
|
||||
let r#type = self.context.get_type(&name.inner).ok_or_else(|| {
|
||||
RuntimeError::UndefinedType {
|
||||
identifier: name.inner.clone(),
|
||||
position,
|
||||
}
|
||||
})?;
|
||||
|
||||
if let Type::Struct(StructType::Fields { name, .. }) = r#type {
|
||||
let mut values = HashMap::with_capacity(expressions.len());
|
||||
|
||||
for (identifier, expression) in expressions {
|
||||
let expression_position = expression.position();
|
||||
let value = self
|
||||
.run_expression(expression, collect_garbage)?
|
||||
.expect_value(expression_position)?;
|
||||
|
||||
values.insert(identifier.inner, value);
|
||||
}
|
||||
|
||||
Ok(Evaluation::Return(Some(Value::Struct(Struct::Fields {
|
||||
name,
|
||||
fields: values,
|
||||
}))))
|
||||
} else {
|
||||
Err(RuntimeError::ExpectedType {
|
||||
expected: Type::Struct(StructType::Fields {
|
||||
name: name.inner,
|
||||
fields: Default::default(),
|
||||
}),
|
||||
actual: r#type,
|
||||
position,
|
||||
})
|
||||
let position = name.position;
|
||||
let constructor = self.context.get_constructor(&name.inner);
|
||||
|
||||
if let Some(constructor) = constructor {
|
||||
if let Constructor::Fields(fields_constructor) = constructor {
|
||||
let mut arguments = HashMap::with_capacity(fields.len());
|
||||
|
||||
for (identifier, expression) in fields {
|
||||
let position = expression.position();
|
||||
let value = self
|
||||
.run_expression(expression, collect_garbage)?
|
||||
.expect_value(position)?;
|
||||
|
||||
arguments.insert(identifier.inner, value);
|
||||
}
|
||||
|
||||
Ok(Evaluation::Return(Some(
|
||||
fields_constructor.construct(arguments),
|
||||
)))
|
||||
} else {
|
||||
Err(RuntimeError::ExpectedFieldsConstructor { position })
|
||||
}
|
||||
} else {
|
||||
Err(RuntimeError::ExpectedConstructor { position })
|
||||
}
|
||||
}
|
||||
|
||||
@ -643,7 +609,7 @@ impl Vm {
|
||||
|
||||
fn run_literal(&self, literal: LiteralExpression) -> Result<Evaluation, RuntimeError> {
|
||||
let value = match literal {
|
||||
LiteralExpression::String(RawStringExpression(string)) => Value::String(string),
|
||||
LiteralExpression::String(string) => Value::String(string),
|
||||
LiteralExpression::Primitive(primitive_expression) => match primitive_expression {
|
||||
PrimitiveValueExpression::Boolean(boolean) => Value::Boolean(boolean),
|
||||
PrimitiveValueExpression::Character(character) => Value::Character(character),
|
||||
@ -978,7 +944,9 @@ pub enum RuntimeError {
|
||||
position: Span,
|
||||
},
|
||||
ExpectedConstructor {
|
||||
actual: Type,
|
||||
position: Span,
|
||||
},
|
||||
ExpectedFieldsConstructor {
|
||||
position: Span,
|
||||
},
|
||||
ExpectedIdentifier {
|
||||
@ -1052,6 +1020,7 @@ impl RuntimeError {
|
||||
Self::EnumVariantNotFound { position, .. } => *position,
|
||||
Self::ExpectedBoolean { position } => *position,
|
||||
Self::ExpectedConstructor { position, .. } => *position,
|
||||
Self::ExpectedFieldsConstructor { position } => *position,
|
||||
Self::ExpectedFunction { position, .. } => *position,
|
||||
Self::ExpectedIdentifier { position } => *position,
|
||||
Self::ExpectedIdentifierOrString { position } => *position,
|
||||
@ -1128,11 +1097,14 @@ impl Display for RuntimeError {
|
||||
Self::ExpectedBoolean { position } => {
|
||||
write!(f, "Expected a boolean at position: {:?}", position)
|
||||
}
|
||||
Self::ExpectedConstructor { actual, position } => {
|
||||
Self::ExpectedConstructor { position } => {
|
||||
write!(f, "Expected a constructor at position: {:?}", position)
|
||||
}
|
||||
Self::ExpectedFieldsConstructor { position } => {
|
||||
write!(
|
||||
f,
|
||||
"Expected a constructor, but got {} at position: {:?}",
|
||||
actual, position
|
||||
"Expected a fields constructor at position: {:?}",
|
||||
position
|
||||
)
|
||||
}
|
||||
Self::ExpectedFunction { actual, position } => {
|
||||
@ -1318,8 +1290,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn assign_unit_struct_variable() {
|
||||
env_logger::builder().is_test(true).try_init().unwrap();
|
||||
|
||||
let input = "
|
||||
struct Foo;
|
||||
let x = Foo;
|
||||
@ -1375,8 +1345,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn negate_expression() {
|
||||
env_logger::builder().is_test(true).try_init().unwrap();
|
||||
|
||||
let input = "let x = -42; -x";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(42))));
|
||||
|
Loading…
Reference in New Issue
Block a user