1
0

Remimplement features

This commit is contained in:
Jeff 2024-08-20 00:15:19 -04:00
parent 0fd19a623d
commit e3d821a1c3
11 changed files with 797 additions and 472 deletions

1
Cargo.lock generated
View File

@ -165,6 +165,7 @@ version = "0.1.0"
dependencies = [
"clap",
"dust-lang",
"env_logger",
]
[[package]]

View File

@ -16,8 +16,7 @@ use crate::{
MapExpression, Node, OperatorExpression, RangeExpression, Span, Statement,
StructDefinition, StructExpression, TupleAccessExpression,
},
parse, Context, DustError, Expression, FieldsStructType, Identifier, StructType, TupleType,
Type,
parse, Context, DustError, Expression, Identifier, StructType, Type,
};
/// Analyzes the abstract syntax tree for errors.
@ -85,62 +84,44 @@ impl<'a> Analyzer<'a> {
self.analyze_expression(&expression_node.inner)?;
}
Statement::Let(let_statement) => match &let_statement.inner {
LetStatement::Let { identifier, value } => {
let type_option = value.return_type(self.context);
LetStatement::Let { identifier, value }
| LetStatement::LetMut { identifier, value } => {
self.analyze_expression(value)?;
if let Some(r#type) = type_option {
self.context.set_type(
let r#type = value.return_type(self.context);
if let Some(r#type) = r#type {
self.context.set_variable_type(
identifier.inner.clone(),
r#type,
identifier.position,
);
} else {
return Err(AnalysisError::ExpectedValue {
actual: statement.clone(),
return Err(AnalysisError::ExpectedValueFromExpression {
actual: value.clone(),
});
}
self.analyze_expression(value)?;
}
LetStatement::LetMut { identifier, value } => {
let type_option = value.return_type(self.context);
if let Some(r#type) = type_option {
self.context.set_type(
identifier.inner.clone(),
r#type,
identifier.position,
);
} else {
return Err(AnalysisError::ExpectedValue {
actual: statement.clone(),
});
}
self.analyze_expression(value)?;
}
LetStatement::LetType {
identifier,
r#type,
value,
} => todo!(),
LetStatement::LetMutType {
identifier,
r#type,
value,
} => todo!(),
LetStatement::LetType { .. } => todo!(),
LetStatement::LetMutType { .. } => todo!(),
},
Statement::StructDefinition(struct_definition) => {
let (name, struct_type) = match &struct_definition.inner {
StructDefinition::Unit { name } => {
(name.inner.clone(), Type::Struct(StructType::Unit))
}
StructDefinition::Unit { name } => (
name,
Type::Struct(StructType::Unit {
name: name.inner.clone(),
}),
),
StructDefinition::Tuple { name, items } => {
let fields = items.iter().map(|item| item.inner.clone()).collect();
(
name.inner.clone(),
Type::Struct(StructType::Tuple(TupleType { fields })),
name,
Type::Struct(StructType::Tuple {
name: name.inner.clone(),
fields,
}),
)
}
StructDefinition::Fields { name, fields } => {
@ -152,14 +133,16 @@ impl<'a> Analyzer<'a> {
.collect();
(
name.inner.clone(),
Type::Struct(StructType::Fields(FieldsStructType { fields })),
name,
Type::Struct(StructType::Fields {
name: name.inner.clone(),
fields,
}),
)
}
};
self.context
.set_type(name, struct_type, struct_definition.position);
todo!("Set constructor")
}
}
@ -179,24 +162,19 @@ impl<'a> Analyzer<'a> {
}
}
Expression::FieldAccess(field_access_expression) => {
let FieldAccessExpression { container, .. } =
let FieldAccessExpression { container, field } =
field_access_expression.inner.as_ref();
self.context
.update_last_position(&field.inner, field.position);
self.analyze_expression(container)?;
}
Expression::Grouped(expression) => {
self.analyze_expression(expression.inner.as_ref())?;
}
Expression::Identifier(identifier) => {
let found = self
.context
self.context
.update_last_position(&identifier.inner, identifier.position);
if !found {
return Err(AnalysisError::UndefinedVariable {
identifier: identifier.clone(),
});
}
}
Expression::If(if_expression) => self.analyze_if(&if_expression.inner)?,
Expression::List(list_expression) => match list_expression.inner.as_ref() {
@ -256,6 +234,31 @@ impl<'a> Analyzer<'a> {
} => {
self.analyze_expression(assignee)?;
self.analyze_expression(modifier)?;
let expected_type = assignee.return_type(self.context);
let actual_type = modifier.return_type(self.context);
if expected_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression {
actual: assignee.clone(),
});
}
if actual_type.is_none() {
return Err(AnalysisError::ExpectedValueFromExpression {
actual: modifier.clone(),
});
}
if let (Some(expected_type), Some(actual_type)) = (expected_type, actual_type) {
expected_type.check(&actual_type).map_err(|type_conflct| {
AnalysisError::TypeConflict {
actual_expression: modifier.clone(),
actual_type,
expected: expected_type,
}
})?;
}
}
OperatorExpression::ErrorPropagation(_) => todo!(),
OperatorExpression::Negation(expression) => {
@ -285,30 +288,14 @@ impl<'a> Analyzer<'a> {
},
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
StructExpression::Unit { name } => {
let found = self
.context
.update_last_position(&name.inner, name.position);
if !found {
return Err(AnalysisError::UndefinedType {
identifier: name.clone(),
});
}
todo!("Update constructor position");
}
StructExpression::Fields { name, fields } => {
let found = self
.context
.update_last_position(&name.inner, name.position);
todo!("Update constructor position");
if !found {
return Err(AnalysisError::UndefinedType {
identifier: name.clone(),
});
}
for (_, expression) in fields {
self.analyze_expression(expression)?;
}
// for (_, expression) in fields {
// self.analyze_expression(expression)?;
// }
}
},
Expression::TupleAccess(tuple_access) => {
@ -390,9 +377,12 @@ pub enum AnalysisError {
ExpectedMap {
actual: Statement,
},
ExpectedValue {
ExpectedValueFromStatement {
actual: Statement,
},
ExpectedValueFromExpression {
actual: Expression,
},
ExpectedValueArgumentCount {
expected: usize,
actual: usize,
@ -405,7 +395,7 @@ pub enum AnalysisError {
length: usize,
},
TypeConflict {
actual_statement: Statement,
actual_expression: Expression,
actual_type: Type,
expected: Type,
},
@ -436,12 +426,13 @@ impl AnalysisError {
AnalysisError::ExpectedIntegerOrRange { actual } => actual.position(),
AnalysisError::ExpectedList { actual } => actual.position(),
AnalysisError::ExpectedMap { actual } => actual.position(),
AnalysisError::ExpectedValue { actual } => actual.position(),
AnalysisError::ExpectedValueFromExpression { actual } => actual.position(),
AnalysisError::ExpectedValueFromStatement { actual } => actual.position(),
AnalysisError::ExpectedValueArgumentCount { position, .. } => *position,
AnalysisError::IndexOutOfBounds { index, .. } => index.position(),
AnalysisError::TypeConflict {
actual_statement, ..
} => actual_statement.position(),
actual_expression, ..
} => actual_expression.position(),
AnalysisError::UndefinedField { identifier, .. } => identifier.position(),
AnalysisError::UndefinedType { identifier } => identifier.position,
AnalysisError::UndefinedVariable { identifier } => identifier.position,
@ -470,8 +461,15 @@ impl Display for AnalysisError {
}
AnalysisError::ExpectedList { actual } => write!(f, "Expected list, found {}", actual),
AnalysisError::ExpectedMap { actual } => write!(f, "Expected map, found {}", actual),
AnalysisError::ExpectedValue { actual, .. } => {
write!(f, "Expected value, found {}", actual)
AnalysisError::ExpectedValueFromExpression { actual, .. } => {
write!(
f,
"Expected expression to produce a value, found {}",
actual
)
}
AnalysisError::ExpectedValueFromStatement { actual, .. } => {
write!(f, "Expected statement to produce a value, found {}", actual)
}
AnalysisError::ExpectedValueArgumentCount {
expected, actual, ..
@ -487,7 +485,7 @@ impl Display for AnalysisError {
index_value, list, length
),
AnalysisError::TypeConflict {
actual_statement,
actual_expression: actual_statement,
actual_type,
expected,
} => {
@ -521,18 +519,27 @@ impl Display for AnalysisError {
#[cfg(test)]
mod tests {
use crate::{Identifier, Value};
use super::*;
#[test]
fn add_assign_wrong_type() {
let source = "
a = 1
let mut a = 1;
a += 1.0
";
assert_eq!(analyze(source), todo!());
assert_eq!(
analyze(source),
Err(DustError::AnalysisError {
analysis_error: AnalysisError::TypeConflict {
actual_expression: Expression::literal(1.0, (45, 48)),
actual_type: Type::Float,
expected: Type::Integer,
},
source,
})
);
}
#[test]
@ -542,7 +549,17 @@ mod tests {
a -= 1.0
";
assert_eq!(analyze(source), todo!());
assert_eq!(
analyze(source),
Err(DustError::AnalysisError {
analysis_error: AnalysisError::TypeConflict {
actual_expression: Expression::literal(1.0, (45, 48)),
actual_type: Type::Float,
expected: Type::Integer,
},
source,
})
);
}
#[test]

View File

@ -6,9 +6,7 @@ use std::{
use serde::{Deserialize, Serialize};
use crate::{
Context, FieldsStructType, FunctionType, Identifier, RangeableType, StructType, TupleType, Type,
};
use crate::{Context, FunctionType, Identifier, RangeableType, StructType, Type};
use super::{Node, Span, Statement};
@ -268,17 +266,17 @@ 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)
Some(block_expression.inner.return_type(context)?)
}
Expression::Call(call_expression) => {
let CallExpression { invoker, .. } = call_expression.inner.as_ref();
let invoker_type = invoker.return_type(context)?;
let invoker_type = invoker.return_type(context);
if let Type::Function(FunctionType { return_type, .. }) = invoker_type {
if let Some(Type::Function(FunctionType { return_type, .. })) = invoker_type {
return_type.map(|r#type| *r#type)
} else if let Type::Struct(_) = invoker_type {
Some(invoker_type)
} else if let Some(Type::Struct(_)) = invoker_type {
invoker_type
} else {
None
}
@ -287,11 +285,9 @@ impl Expression {
let FieldAccessExpression { container, field } =
field_access_expression.inner.as_ref();
let container_type = container.return_type(context)?;
let container_type = container.return_type(context);
if let Type::Struct(StructType::Fields(FieldsStructType { fields, .. })) =
container_type
{
if let Some(Type::Struct(StructType::Fields { fields, .. })) = container_type {
fields
.into_iter()
.find(|(name, _)| name == &field.inner)
@ -301,12 +297,13 @@ impl Expression {
}
}
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() {
Expression::Identifier(identifier) => context.get_variable_type(&identifier.inner),
Expression::If(if_expression) => {
return 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)?;
@ -396,7 +393,7 @@ impl Expression {
})
}
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
StructExpression::Fields { fields, .. } => {
StructExpression::Fields { name, fields } => {
let mut types = HashMap::with_capacity(fields.len());
for (field, expression) in fields {
@ -405,17 +402,20 @@ impl Expression {
types.insert(field.inner.clone(), r#type);
}
Some(Type::Struct(StructType::Fields(FieldsStructType {
Some(Type::Struct(StructType::Fields {
name: name.inner.clone(),
fields: types,
})))
}))
}
StructExpression::Unit { .. } => Some(Type::Struct(StructType::Unit)),
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();
let tuple_value = tuple.return_type(context)?;
if let Type::Tuple(TupleType { fields }) = tuple_value {
if let Type::Tuple(fields) = tuple_value {
fields.get(index.inner).cloned()
} else {
None
@ -944,12 +944,13 @@ pub enum BlockExpression {
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)),
BlockExpression::Async(statements) | BlockExpression::Sync(statements) => {
if let Some(statement) = statements.last() {
statement.return_type(context)
} else {
None
}
}
}
}
}

View File

@ -19,17 +19,6 @@ 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(),
@ -38,6 +27,15 @@ impl Statement {
Statement::StructDefinition(definition) => definition.position,
}
}
pub fn return_type(&self, context: &Context) -> Option<Type> {
match self {
Statement::Expression(expression) => expression.return_type(context),
Statement::ExpressionNullified(expression) => None,
Statement::Let(_) => None,
Statement::StructDefinition(_) => None,
}
}
}
impl Display for Statement {

View File

@ -22,7 +22,7 @@ impl Context {
}
/// Creates a deep copy of another context.
pub fn with_variables_from(other: &Self) -> Self {
pub fn with_data_from(other: &Self) -> Self {
Self {
variables: Arc::new(RwLock::new(other.variables.read().unwrap().clone())),
}
@ -44,7 +44,7 @@ impl Context {
}
/// Returns the type of the variable with the given identifier.
pub fn get_type(&self, identifier: &Identifier) -> Option<Type> {
pub fn get_variable_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()),
@ -61,7 +61,7 @@ impl Context {
}
/// Returns the value of the variable with the given identifier.
pub fn get_value(&self, identifier: &Identifier) -> Option<Value> {
pub fn get_variable_value(&self, identifier: &Identifier) -> Option<Value> {
match self.variables.read().unwrap().get(identifier) {
Some((VariableData::Value(value), _)) => Some(value.clone()),
_ => None,
@ -69,7 +69,7 @@ impl Context {
}
/// Sets a variable to a type, with a position given for garbage collection.
pub fn set_type(&self, identifier: Identifier, r#type: Type, position: Span) {
pub fn set_variable_type(&self, identifier: Identifier, r#type: Type, position: Span) {
log::trace!("Setting {identifier} to type {type} at {position:?}");
self.variables
@ -79,7 +79,7 @@ impl Context {
}
/// Sets a variable to a value.
pub fn set_value(&self, identifier: Identifier, value: Value) {
pub fn set_variable_value(&self, identifier: Identifier, value: Value) {
log::trace!("Setting {identifier} to value {value}");
let mut variables = self.variables.write().unwrap();

View File

@ -314,21 +314,12 @@ impl<'src> Parser<'src> {
}
let expression = self.parse_expression(0)?;
let end = self.current_position.1;
let is_nullified = if let Token::Semicolon = self.current_token {
if let Token::Semicolon = self.current_token {
let position = (start_position.0, self.current_position.1);
self.next_token()?;
true
} else {
matches!(
expression,
Expression::Block(_) | Expression::Loop(_) | Expression::If(_)
)
};
if is_nullified {
let position = (start_position.0, end);
Ok(Statement::ExpressionNullified(Node::new(
expression, position,
)))
@ -446,10 +437,9 @@ impl<'src> Parser<'src> {
}
if let Token::LeftCurlyBrace = self.current_token {
let name = Node::new(identifier, start_position);
self.next_token()?;
let name = Node::new(identifier, start_position);
let mut fields = Vec::new();
loop {
@ -1274,16 +1264,12 @@ mod tests {
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree {
statements: [Statement::ExpressionNullified(Node::new(
Expression::block(
statements: [Statement::Expression(Expression::block(
BlockExpression::Async(vec![
Statement::ExpressionNullified(Node::new(
Expression::operator(
OperatorExpression::Assignment {
assignee: Expression::identifier(
Identifier::new("x"),
(8, 9)
),
assignee: Expression::identifier(Identifier::new("x"), (8, 9)),
value: Expression::literal(42, (12, 14)),
},
(8, 14)
@ -1292,18 +1278,13 @@ mod tests {
)),
Statement::Expression(Expression::operator(
OperatorExpression::Assignment {
assignee: Expression::identifier(
Identifier::new("y"),
(16, 17)
),
assignee: Expression::identifier(Identifier::new("y"), (16, 17)),
value: Expression::literal(4.0, (20, 23)),
},
(16, 23)
))
]),
(0, 25)
),
(0, 25)
))]
.into()
})
@ -1597,8 +1578,7 @@ mod tests {
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::ExpressionNullified(Node::new(
Expression::r#if(
Statement::Expression(Expression::r#if(
IfExpression::If {
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
if_block: Node::new(
@ -1609,8 +1589,6 @@ mod tests {
)
},
(0, 10)
),
(0, 10)
))
]))
);
@ -1623,8 +1601,7 @@ mod tests {
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::ExpressionNullified(Node::new(
Expression::r#if(
Statement::Expression(Expression::r#if(
IfExpression::IfElse {
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
if_block: Node::new(
@ -1641,8 +1618,6 @@ mod tests {
))
},
(0, 21)
),
(0, 21)
))
]))
);
@ -1655,8 +1630,7 @@ mod tests {
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::ExpressionNullified(Node::new(
Expression::r#if(
Statement::Expression(Expression::r#if(
IfExpression::IfElse {
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
if_block: Node::new(
@ -1667,10 +1641,7 @@ mod tests {
),
r#else: ElseExpression::If(Node::new(
Box::new(IfExpression::IfElse {
condition: Expression::identifier(
Identifier::new("z"),
(19, 20)
),
condition: Expression::identifier(Identifier::new("z"), (19, 20)),
if_block: Node::new(
BlockExpression::Sync(vec![Statement::Expression(
Expression::identifier(Identifier::new("a"), (23, 24))
@ -1688,8 +1659,6 @@ mod tests {
)),
},
(0, 37)
),
(0, 37)
))
]))
)
@ -1702,8 +1671,7 @@ mod tests {
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::ExpressionNullified(Node::new(
Expression::while_loop(
Statement::Expression(Expression::while_loop(
Expression::operator(
OperatorExpression::Comparison {
left: Expression::identifier(Identifier::new("x"), (6, 7)),
@ -1713,24 +1681,17 @@ mod tests {
(6, 12)
),
Node::new(
BlockExpression::Sync(vec![Statement::Expression(
Expression::operator(
BlockExpression::Sync(vec![Statement::Expression(Expression::operator(
OperatorExpression::CompoundAssignment {
assignee: Expression::identifier(
Identifier::new("x"),
(15, 16)
),
assignee: Expression::identifier(Identifier::new("x"), (15, 16)),
operator: Node::new(MathOperator::Add, (17, 19)),
modifier: Expression::literal(1, (20, 21)),
},
(15, 21)
)
)]),
))]),
(13, 23)
),
(0, 23)
),
(0, 23)
))
]))
)
@ -1781,8 +1742,7 @@ mod tests {
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::ExpressionNullified(Node::new(
Expression::block(
Statement::Expression(Expression::block(
BlockExpression::Sync(vec![Statement::Expression(Expression::operator(
OperatorExpression::Math {
left: Expression::literal(40, (2, 4)),
@ -1792,8 +1752,6 @@ mod tests {
(2, 8)
))]),
(0, 10)
),
(0, 10)
))
]))
)
@ -1806,8 +1764,7 @@ mod tests {
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::ExpressionNullified(Node::new(
Expression::block(
Statement::Expression(Expression::block(
BlockExpression::Sync(vec![
Statement::ExpressionNullified(Node::new(
Expression::assignment(
@ -1832,8 +1789,6 @@ mod tests {
))
]),
(0, 34)
),
(0, 34)
))
]))
)

View File

@ -17,7 +17,7 @@ use std::{
use serde::{Deserialize, Serialize};
use crate::Identifier;
use crate::{Enum, Identifier, Struct, Value};
/// Description of a kind of value.
///
@ -53,7 +53,7 @@ pub enum Type {
},
String,
Struct(StructType),
Tuple(TupleType),
Tuple(Vec<Type>),
}
impl Type {
@ -266,36 +266,8 @@ impl Display for Type {
Type::Number => write!(f, "num"),
Type::Range { r#type } => write!(f, "{type} range"),
Type::String => write!(f, "str"),
Type::Struct(struct_type) => match struct_type {
StructType::Unit => write!(f, "()"),
StructType::Tuple(TupleType { fields }) => {
write!(f, "(")?;
for (index, r#type) in fields.iter().enumerate() {
write!(f, "{type}")?;
if index != fields.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
StructType::Fields(FieldsStructType { fields }) => {
write!(f, "{{")?;
for (index, (name, r#type)) in fields.iter().enumerate() {
write!(f, "{name}: {type}")?;
if index != fields.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "}}")
}
},
Type::Tuple(TupleType { fields }) => {
Type::Struct(struct_type) => write!(f, "{struct_type}"),
Type::Tuple(fields) => {
write!(f, "(")?;
for (index, r#type) in fields.iter().enumerate() {
@ -439,88 +411,257 @@ impl Display for FunctionType {
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum StructType {
Unit,
Tuple(TupleType),
Fields(FieldsStructType),
Unit {
name: Identifier,
},
Tuple {
name: Identifier,
fields: Vec<Type>,
},
Fields {
name: Identifier,
fields: HashMap<Identifier, Type>,
},
}
impl StructType {
pub fn name(&self) -> &Identifier {
match self {
StructType::Unit { name } => name,
StructType::Tuple { name, .. } => name,
StructType::Fields { name, .. } => name,
}
}
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)
}
}
impl Display for StructType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
StructType::Unit => write!(f, "()"),
StructType::Tuple(tuple) => write!(f, "{tuple}"),
StructType::Fields(fields) => write!(f, "{fields}"),
}
}
}
StructType::Unit { name } => write!(f, "{name}"),
StructType::Tuple { name, fields } => {
write!(f, "{name}(")?;
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct TupleType {
pub fields: Vec<Type>,
}
impl Display for TupleType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "(")?;
for (index, field) in self.fields.iter().enumerate() {
for (index, field) in fields.iter().enumerate() {
write!(f, "{field}")?;
if index != self.fields.len() - 1 {
if index != fields.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
}
StructType::Fields { name, fields } => {
write!(f, "{name} {{")?;
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct FieldsStructType {
pub fields: HashMap<Identifier, Type>,
}
impl Display for FieldsStructType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{{ ")?;
for (index, (identifier, r#type)) in self.fields.iter().enumerate() {
for (index, (identifier, r#type)) in fields.iter().enumerate() {
write!(f, "{identifier}: {type}")?;
if index != self.fields.len() - 1 {
if index != fields.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, " }}")
write!(f, "}}")
}
}
}
}
impl PartialOrd for FieldsStructType {
impl PartialOrd for StructType {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for FieldsStructType {
impl Ord for StructType {
fn cmp(&self, other: &Self) -> Ordering {
self.fields.iter().cmp(other.fields.iter())
match (self, other) {
(StructType::Unit { name: left_name }, StructType::Unit { name: right_name }) => {
left_name.cmp(right_name)
}
(StructType::Unit { .. }, _) => Ordering::Greater,
(
StructType::Tuple {
name: left_name,
fields: left_fields,
},
StructType::Tuple {
name: right_name,
fields: right_fields,
},
) => {
let name_cmp = left_name.cmp(right_name);
if name_cmp == Ordering::Equal {
left_fields.cmp(right_fields)
} else {
name_cmp
}
}
(StructType::Tuple { .. }, _) => Ordering::Greater,
(
StructType::Fields {
name: left_name,
fields: left_fields,
},
StructType::Fields {
name: right_name,
fields: right_fields,
},
) => {
let name_cmp = left_name.cmp(right_name);
if name_cmp == Ordering::Equal {
let len_cmp = left_fields.len().cmp(&right_fields.len());
if len_cmp == Ordering::Equal {
left_fields.iter().cmp(right_fields.iter())
} else {
len_cmp
}
} else {
name_cmp
}
}
(StructType::Fields { .. }, _) => Ordering::Greater,
}
}
}
#[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 {
name: Identifier,
variants: Vec<StructType>,
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;
write!(f, "enum {name} {{")?;
write!(f, "enum {name} {{ ")?;
for (index, variant) in variants.iter().enumerate() {
write!(f, "{variant}")?;
@ -530,7 +671,7 @@ impl Display for EnumType {
}
}
write!(f, "}}")
write!(f, " }}")
}
}

View File

@ -16,8 +16,8 @@ use serde::{
};
use crate::{
AbstractSyntaxTree, Context, EnumType, FieldsStructType, FunctionType, Identifier,
RangeableType, RuntimeError, StructType, TupleType, Type, Vm,
AbstractSyntaxTree, Context, EnumType, FunctionType, Identifier, RangeableType, RuntimeError,
StructType, Type, Vm,
};
/// Dust value representation
@ -57,7 +57,7 @@ pub enum Value {
Boolean(bool),
Byte(u8),
Character(char),
Enum { name: Identifier, r#type: EnumType },
Enum(Enum),
Float(f64),
Function(Function),
Integer(i64),
@ -80,6 +80,10 @@ impl Value {
Value::Mutable(Arc::new(RwLock::new(value)))
}
pub fn mutable_from<T: Into<Value>>(into_value: T) -> Value {
Value::Mutable(Arc::new(RwLock::new(into_value.into())))
}
pub fn byte_range(start: u8, end: u8) -> Value {
Value::Range(Rangeable::Byte(start)..Rangeable::Byte(end))
}
@ -188,7 +192,7 @@ impl Value {
Value::Boolean(_) => Type::Boolean,
Value::Byte(_) => Type::Byte,
Value::Character(_) => Type::Character,
Value::Enum { r#type, .. } => Type::Enum(r#type.clone()),
Value::Enum(Enum { r#type, .. }) => Type::Enum(r#type.clone()),
Value::Float(_) => Type::Float,
Value::Function(function) => Type::Function(function.r#type.clone()),
Value::Integer(_) => Type::Integer,
@ -221,25 +225,31 @@ impl Value {
}
Value::String(_) => Type::String,
Value::Struct(r#struct) => match r#struct {
Struct::Unit { .. } => Type::Struct(StructType::Unit),
Struct::Tuple { fields, .. } => {
Struct::Unit { name } => Type::Struct(StructType::Unit { name: name.clone() }),
Struct::Tuple { name, fields } => {
let types = fields.iter().map(|field| field.r#type()).collect();
Type::Struct(StructType::Tuple(TupleType { fields: types }))
Type::Struct(StructType::Tuple {
name: name.clone(),
fields: types,
})
}
Struct::Fields { fields, .. } => {
Struct::Fields { name, fields } => {
let types = fields
.iter()
.map(|(identifier, value)| (identifier.clone(), value.r#type()))
.collect();
Type::Struct(StructType::Fields(FieldsStructType { fields: types }))
Type::Struct(StructType::Fields {
name: name.clone(),
fields: types,
})
}
},
Value::Tuple(values) => {
let fields = values.iter().map(|value| value.r#type()).collect();
Type::Tuple(TupleType { fields })
Type::Tuple(fields)
}
}
}
@ -248,6 +258,7 @@ impl Value {
match self {
Value::Mutable(inner) => inner.read().unwrap().get_field(field),
Value::Struct(Struct::Fields { fields, .. }) => fields.get(field).cloned(),
Value::Map(pairs) => pairs.get(field).cloned(),
_ => None,
}
}
@ -762,6 +773,54 @@ impl Value {
}
}
impl From<bool> for Value {
fn from(value: bool) -> Self {
Value::Boolean(value)
}
}
impl From<u8> for Value {
fn from(value: u8) -> Self {
Value::Byte(value)
}
}
impl From<char> for Value {
fn from(value: char) -> Self {
Value::Character(value)
}
}
impl From<f64> for Value {
fn from(value: f64) -> Self {
Value::Float(value)
}
}
impl From<i32> for Value {
fn from(value: i32) -> Self {
Value::Integer(value as i64)
}
}
impl From<i64> for Value {
fn from(value: i64) -> Self {
Value::Integer(value)
}
}
impl From<String> for Value {
fn from(value: String) -> Self {
Value::String(value)
}
}
impl From<&str> for Value {
fn from(value: &str) -> Self {
Value::String(value.to_string())
}
}
impl Display for Value {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
@ -773,7 +832,7 @@ impl Display for Value {
Value::Boolean(boolean) => write!(f, "{boolean}"),
Value::Byte(byte) => write!(f, "{byte}"),
Value::Character(character) => write!(f, "{character}"),
Value::Enum { name, r#type } => write!(f, "{name}::{type}"),
Value::Enum(r#enum) => write!(f, "{enum}"),
Value::Float(float) => write!(f, "{float}"),
Value::Function(function) => write!(f, "{function}"),
Value::Integer(integer) => write!(f, "{integer}"),
@ -813,7 +872,7 @@ impl Display for Value {
write!(f, "{start}..={end}")
}
Value::String(string) => write!(f, "{string}"),
Value::Struct(structure) => write!(f, "{structure}"),
Value::Struct(r#struct) => write!(f, "{struct}"),
Value::Tuple(fields) => {
write!(f, "(")?;
@ -934,14 +993,7 @@ impl Serialize for Value {
Value::Boolean(boolean) => serializer.serialize_bool(*boolean),
Value::Byte(byte) => serializer.serialize_u8(*byte),
Value::Character(character) => serializer.serialize_char(*character),
Value::Enum { name, r#type } => {
let mut ser = serializer.serialize_struct_variant("Value", 4, "Enum", 2)?;
ser.serialize_field("name", name)?;
ser.serialize_field("type", r#type)?;
ser.end()
}
Value::Enum(r#emum) => r#emum.serialize(serializer),
Value::Float(float) => serializer.serialize_f64(*float),
Value::Function(function) => function.serialize(serializer),
Value::Integer(integer) => serializer.serialize_i64(*integer),
@ -1021,13 +1073,13 @@ impl Function {
value_arguments: Option<Vec<Value>>,
context: &Context,
) -> Result<Option<Value>, RuntimeError> {
let new_context = Context::with_variables_from(context);
let new_context = Context::with_data_from(context);
if let (Some(value_parameters), Some(value_arguments)) =
(&self.r#type.value_parameters, value_arguments)
{
for ((identifier, _), value) in value_parameters.iter().zip(value_arguments) {
new_context.set_value(identifier.clone(), value);
new_context.set_variable_value(identifier.clone(), value);
}
}
@ -1226,9 +1278,9 @@ impl Ord for Struct {
impl Display for Struct {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Struct::Unit { .. } => write!(f, "()"),
Struct::Tuple { fields, .. } => {
write!(f, "(")?;
Struct::Unit { name } => write!(f, "{name}"),
Struct::Tuple { name, fields } => {
write!(f, "{name}(")?;
for (index, field) in fields.iter().enumerate() {
if index > 0 {
@ -1240,8 +1292,8 @@ impl Display for Struct {
write!(f, ")")
}
Struct::Fields { fields, .. } => {
write!(f, "{{ ")?;
Struct::Fields { name, fields } => {
write!(f, "{name} {{ ")?;
for (index, (identifier, value)) in fields.iter().enumerate() {
if index > 0 {
@ -1310,6 +1362,57 @@ impl Ord for Rangeable {
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Enum {
pub r#type: EnumType,
pub name: Identifier,
pub variant_data: Struct,
}
impl Display for Enum {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let Enum {
name, variant_data, ..
} = self;
match &variant_data {
Struct::Unit { name: variant_name } => write!(f, "{name}::{variant_name}"),
Struct::Tuple {
name: variant_name,
fields,
} => {
write!(f, "{name}::{variant_name}(")?;
for (index, field) in fields.iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}
write!(f, "{}", field)?;
}
write!(f, ")")
}
Struct::Fields {
name: variant_name,
fields,
} => {
write!(f, "{name}::{variant_name} {{ ")?;
for (index, (identifier, value)) in fields.iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}
write!(f, "{}: {}", identifier, value)?;
}
write!(f, " }}")
}
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum ValueError {
CannotAdd(Value, Value),

View File

@ -21,8 +21,9 @@ use crate::{
OperatorExpression, PrimitiveValueExpression, RangeExpression, RawStringExpression, Span,
Statement, StructDefinition, StructExpression,
},
parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, FieldsStructType,
Identifier, ParseError, Struct, StructType, TupleType, Type, Value, ValueError,
parse, Analyzer, BuiltInFunctionError, Constructor, Context, DustError, Enum, EnumType,
Expression, Identifier, ParseError, Struct, StructType, TupleConstructor, Type, Value,
ValueError,
};
/// Run the source code and return the result.
@ -126,11 +127,19 @@ impl Vm {
}
Statement::StructDefinition(struct_definition) => {
let (name, struct_type) = match struct_definition.inner {
StructDefinition::Unit { name } => (name.inner.clone(), StructType::Unit),
StructDefinition::Unit { name } => {
(name.inner.clone(), StructType::Unit { name: name.inner })
}
StructDefinition::Tuple { name, items } => {
let fields = items.into_iter().map(|item| item.inner).collect();
(name.inner.clone(), StructType::Tuple(TupleType { fields }))
(
name.inner.clone(),
StructType::Tuple {
name: name.inner,
fields,
},
)
}
StructDefinition::Fields { name, fields } => {
let fields = fields
@ -140,23 +149,25 @@ impl Vm {
(
name.inner.clone(),
StructType::Fields(FieldsStructType { fields }),
StructType::Fields {
name: name.inner,
fields,
},
)
}
};
self.context
.set_type(name, Type::Struct(struct_type), struct_definition.position);
todo!("Set constructor");
Ok(None)
}
};
if collect_garbage {
self.context.collect_garbage(position);
// self.context.collect_garbage(position);
}
result.map_err(|error| RuntimeError::Trace {
result.map_err(|error| RuntimeError::Statement {
error: Box::new(error),
position,
})
@ -174,7 +185,7 @@ impl Vm {
.run_expression(value, collect_garbage)?
.expect_value(value_position)?;
self.context.set_value(identifier.inner, value);
self.context.set_variable_value(identifier.inner, value);
Ok(())
}
@ -185,7 +196,8 @@ impl Vm {
.expect_value(value_position)?
.into_mutable();
self.context.set_value(identifier.inner, mutable_value);
self.context
.set_variable_value(identifier.inner, mutable_value);
Ok(())
}
@ -210,7 +222,7 @@ impl Vm {
self.run_expression(*expression.inner, collect_garbage)
}
Expression::Identifier(identifier) => {
let get_value = self.context.get_value(&identifier.inner);
let get_value = self.context.get_variable_value(&identifier.inner);
if let Some(value) = get_value {
Ok(Evaluation::Return(Some(value)))
@ -243,7 +255,7 @@ impl Vm {
Expression::TupleAccess(_) => todo!(),
};
evaluation_result.map_err(|error| RuntimeError::Trace {
evaluation_result.map_err(|error| RuntimeError::Expression {
error: Box::new(error),
position,
})
@ -257,20 +269,20 @@ impl Vm {
match struct_expression {
StructExpression::Unit { name } => {
let position = name.position;
let r#type = self.context.get_type(&name.inner).ok_or_else(|| {
let r#type = self.context.get_variable_type(&name.inner).ok_or_else(|| {
RuntimeError::UndefinedType {
identifier: name.inner.clone(),
position,
}
})?;
if let Type::Struct(StructType::Unit) = r#type {
if let Type::Struct(StructType::Unit { name }) = r#type {
Ok(Evaluation::Return(Some(Value::Struct(Struct::Unit {
name: name.inner,
name,
}))))
} else {
Err(RuntimeError::ExpectedType {
expected: Type::Struct(StructType::Unit),
expected: Type::Struct(StructType::Unit { name: name.inner }),
actual: r#type,
position,
})
@ -281,14 +293,14 @@ impl Vm {
fields: expressions,
} => {
let position = name.position;
let r#type = self.context.get_type(&name.inner).ok_or_else(|| {
let r#type = self.context.get_variable_type(&name.inner).ok_or_else(|| {
RuntimeError::UndefinedType {
identifier: name.inner.clone(),
position,
}
})?;
if let Type::Struct(StructType::Fields(FieldsStructType { .. })) = r#type {
if let Type::Struct(StructType::Fields { name, .. }) = r#type {
let mut values = HashMap::with_capacity(expressions.len());
for (identifier, expression) in expressions {
@ -301,14 +313,15 @@ impl Vm {
}
Ok(Evaluation::Return(Some(Value::Struct(Struct::Fields {
name: name.inner,
name,
fields: values,
}))))
} else {
Err(RuntimeError::ExpectedType {
expected: Type::Struct(StructType::Fields(FieldsStructType {
fields: HashMap::new(),
})),
expected: Type::Struct(StructType::Fields {
name: name.inner,
fields: Default::default(),
}),
actual: r#type,
position,
})
@ -609,11 +622,7 @@ impl Vm {
Ok(Evaluation::Return(None))
}
LoopExpression::For {
identifier,
iterator,
block,
} => todo!(),
LoopExpression::For { .. } => todo!(),
}
}
@ -668,8 +677,47 @@ impl Vm {
let CallExpression { invoker, arguments } = call_expression;
let invoker_position = invoker.position();
let invoker_value =
if let Some(value) = self.run_expression(invoker, collect_garbage)?.value() {
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());
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
} else {
return Err(RuntimeError::ExpectedValue {
@ -814,7 +862,7 @@ impl Vm {
previous_value = self.run_statement(statement, collect_garbage)?;
if collect_garbage {
self.context.collect_garbage(position);
// self.context.collect_garbage(position);
}
}
@ -864,7 +912,7 @@ impl Vm {
match r#else {
ElseExpression::If(if_expression) => {
self.run_expression(Expression::If(if_expression), collect_garbage)
self.run_if(*if_expression.inner, collect_garbage)
}
ElseExpression::Block(block) => self.run_block(block.inner, collect_garbage),
}
@ -875,14 +923,15 @@ impl Vm {
enum Evaluation {
Break,
Constructor(Type),
Return(Option<Value>),
}
impl Evaluation {
pub fn value(self) -> Option<Value> {
match self {
Evaluation::Break => None,
Evaluation::Return(value_option) => value_option,
_ => None,
}
}
@ -898,7 +947,11 @@ impl Evaluation {
#[derive(Clone, Debug, PartialEq)]
pub enum RuntimeError {
ParseError(ParseError),
Trace {
Expression {
error: Box<RuntimeError>,
position: Span,
},
Statement {
error: Box<RuntimeError>,
position: Span,
},
@ -914,9 +967,17 @@ pub enum RuntimeError {
error: BuiltInFunctionError,
position: Span,
},
EnumVariantNotFound {
identifier: Identifier,
position: Span,
},
ExpectedBoolean {
position: Span,
},
ExpectedConstructor {
actual: Type,
position: Span,
},
ExpectedIdentifier {
position: Span,
},
@ -974,14 +1035,17 @@ impl RuntimeError {
pub fn position(&self) -> Span {
match self {
Self::ParseError(parse_error) => parse_error.position(),
Self::Trace { position, .. } => *position,
Self::Expression { position, .. } => *position,
Self::Statement { position, .. } => *position,
Self::ValueError {
left_position,
right_position,
..
} => (left_position.0, right_position.1),
Self::BuiltInFunctionError { position, .. } => *position,
Self::EnumVariantNotFound { position, .. } => *position,
Self::ExpectedBoolean { position } => *position,
Self::ExpectedConstructor { position, .. } => *position,
Self::ExpectedFunction { position, .. } => *position,
Self::ExpectedIdentifier { position } => *position,
Self::ExpectedIdentifierOrString { position } => *position,
@ -1016,10 +1080,17 @@ impl Display for RuntimeError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::ParseError(parse_error) => write!(f, "{}", parse_error),
Self::Trace { error, position } => {
Self::Expression { error, position } => {
write!(
f,
"Error during execution at position: {:?}\n{}",
"Error while running expression at {:?}: {}",
position, error
)
}
Self::Statement { error, position } => {
write!(
f,
"Error while running statement at {:?}: {}",
position, error
)
}
@ -1037,9 +1108,26 @@ impl Display for RuntimeError {
Self::BuiltInFunctionError { error, .. } => {
write!(f, "{}", error)
}
Self::EnumVariantNotFound {
identifier,
position,
} => {
write!(
f,
"Enum variant not found: {} at position: {:?}",
identifier, position
)
}
Self::ExpectedBoolean { position } => {
write!(f, "Expected a boolean at position: {:?}", position)
}
Self::ExpectedConstructor { actual, position } => {
write!(
f,
"Expected a constructor, but got {} at position: {:?}",
actual, position
)
}
Self::ExpectedFunction { actual, position } => {
write!(
f,
@ -1110,7 +1198,7 @@ impl Display for RuntimeError {
} => {
write!(
f,
"Undefined variable {} at position: {:?}",
"Undefined value {} at position: {:?}",
identifier, position
)
}
@ -1187,8 +1275,8 @@ mod tests {
#[test]
fn assign_tuple_struct_variable() {
let input = "
struct Foo(int)
x = Foo(42)
struct Foo(int);
let x = Foo(42);
x
";
@ -1203,7 +1291,7 @@ mod tests {
#[test]
fn define_and_instantiate_tuple_struct() {
let input = "struct Foo(int) Foo(42)";
let input = "struct Foo(int); Foo(42)";
assert_eq!(
run(input),
@ -1232,7 +1320,7 @@ mod tests {
#[test]
fn define_and_instantiate_unit_struct() {
let input = "struct Foo Foo";
let input = "struct Foo; Foo";
assert_eq!(
run(input),
@ -1271,6 +1359,8 @@ 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))));
@ -1292,7 +1382,7 @@ mod tests {
#[test]
fn map_property_access() {
let input = "{ a = 42 }.a";
let input = "map { a = 42 }.a";
assert_eq!(run(input), Ok(Some(Value::Integer(42))));
}
@ -1343,21 +1433,21 @@ mod tests {
fn while_loop() {
let input = "let mut x = 0; while x < 5 { x += 1 } x";
assert_eq!(run(input), Ok(Some(Value::Integer(5))));
assert_eq!(run(input), Ok(Some(Value::mutable_from(5))));
}
#[test]
fn subtract_assign() {
let input = "let mut x = 1; x -= 1; x";
assert_eq!(run(input), Ok(Some(Value::mutable(Value::Integer(0)))));
assert_eq!(run(input), Ok(Some(Value::mutable_from(0))));
}
#[test]
fn add_assign() {
let input = "let mut x = 1; x += 1; x";
assert_eq!(run(input), Ok(Some(Value::mutable(Value::Integer(2)))));
assert_eq!(run(input), Ok(Some(Value::mutable_from(2))));
}
#[test]

View File

@ -10,3 +10,4 @@ repository.workspace = true
[dependencies]
clap = { version = "4.5.14", features = ["derive"] }
dust-lang = { path = "../dust-lang" }
env_logger = "0.11.5"

View File

@ -8,21 +8,39 @@ struct Cli {
#[arg(short, long)]
command: Option<String>,
#[arg(short, long)]
parse: bool,
path: Option<String>,
}
fn main() {
env_logger::init();
let args = Cli::parse();
if let Some(command) = &args.command {
if args.parse {
parse_and_display_errors(command);
} else {
run_and_display_errors(command);
}
} else if let Some(path) = &args.path {
let source = read_to_string(path).expect("Failed to read file");
run_and_display_errors(&source)
if args.parse {
parse_and_display_errors(&source);
} else {
panic!("No command or path provided");
};
run_and_display_errors(&source);
}
}
}
fn parse_and_display_errors(source: &str) {
match dust_lang::parse(source) {
Ok(ast) => println!("{:#?}", ast),
Err(error) => eprintln!("{}", error.report()),
}
}
fn run_and_display_errors(source: &str) {