Remimplement features
This commit is contained in:
parent
0fd19a623d
commit
e3d821a1c3
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -165,6 +165,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"dust-lang",
|
"dust-lang",
|
||||||
|
"env_logger",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -16,8 +16,7 @@ use crate::{
|
|||||||
MapExpression, Node, OperatorExpression, RangeExpression, Span, Statement,
|
MapExpression, Node, OperatorExpression, RangeExpression, Span, Statement,
|
||||||
StructDefinition, StructExpression, TupleAccessExpression,
|
StructDefinition, StructExpression, TupleAccessExpression,
|
||||||
},
|
},
|
||||||
parse, Context, DustError, Expression, FieldsStructType, Identifier, StructType, TupleType,
|
parse, Context, DustError, Expression, Identifier, StructType, Type,
|
||||||
Type,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Analyzes the abstract syntax tree for errors.
|
/// Analyzes the abstract syntax tree for errors.
|
||||||
@ -85,62 +84,44 @@ impl<'a> Analyzer<'a> {
|
|||||||
self.analyze_expression(&expression_node.inner)?;
|
self.analyze_expression(&expression_node.inner)?;
|
||||||
}
|
}
|
||||||
Statement::Let(let_statement) => match &let_statement.inner {
|
Statement::Let(let_statement) => match &let_statement.inner {
|
||||||
LetStatement::Let { identifier, value } => {
|
LetStatement::Let { identifier, value }
|
||||||
let type_option = value.return_type(self.context);
|
| LetStatement::LetMut { identifier, value } => {
|
||||||
|
self.analyze_expression(value)?;
|
||||||
|
|
||||||
if let Some(r#type) = type_option {
|
let r#type = value.return_type(self.context);
|
||||||
self.context.set_type(
|
|
||||||
|
if let Some(r#type) = r#type {
|
||||||
|
self.context.set_variable_type(
|
||||||
identifier.inner.clone(),
|
identifier.inner.clone(),
|
||||||
r#type,
|
r#type,
|
||||||
identifier.position,
|
identifier.position,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Err(AnalysisError::ExpectedValue {
|
return Err(AnalysisError::ExpectedValueFromExpression {
|
||||||
actual: statement.clone(),
|
actual: value.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.analyze_expression(value)?;
|
|
||||||
}
|
}
|
||||||
LetStatement::LetMut { identifier, value } => {
|
LetStatement::LetType { .. } => todo!(),
|
||||||
let type_option = value.return_type(self.context);
|
LetStatement::LetMutType { .. } => todo!(),
|
||||||
|
|
||||||
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!(),
|
|
||||||
},
|
},
|
||||||
Statement::StructDefinition(struct_definition) => {
|
Statement::StructDefinition(struct_definition) => {
|
||||||
let (name, struct_type) = match &struct_definition.inner {
|
let (name, struct_type) = match &struct_definition.inner {
|
||||||
StructDefinition::Unit { name } => {
|
StructDefinition::Unit { name } => (
|
||||||
(name.inner.clone(), Type::Struct(StructType::Unit))
|
name,
|
||||||
}
|
Type::Struct(StructType::Unit {
|
||||||
|
name: name.inner.clone(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
StructDefinition::Tuple { name, items } => {
|
StructDefinition::Tuple { name, items } => {
|
||||||
let fields = items.iter().map(|item| item.inner.clone()).collect();
|
let fields = items.iter().map(|item| item.inner.clone()).collect();
|
||||||
|
|
||||||
(
|
(
|
||||||
name.inner.clone(),
|
name,
|
||||||
Type::Struct(StructType::Tuple(TupleType { fields })),
|
Type::Struct(StructType::Tuple {
|
||||||
|
name: name.inner.clone(),
|
||||||
|
fields,
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
StructDefinition::Fields { name, fields } => {
|
StructDefinition::Fields { name, fields } => {
|
||||||
@ -152,14 +133,16 @@ impl<'a> Analyzer<'a> {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
(
|
(
|
||||||
name.inner.clone(),
|
name,
|
||||||
Type::Struct(StructType::Fields(FieldsStructType { fields })),
|
Type::Struct(StructType::Fields {
|
||||||
|
name: name.inner.clone(),
|
||||||
|
fields,
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.context
|
todo!("Set constructor")
|
||||||
.set_type(name, struct_type, struct_definition.position);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,24 +162,19 @@ impl<'a> Analyzer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::FieldAccess(field_access_expression) => {
|
Expression::FieldAccess(field_access_expression) => {
|
||||||
let FieldAccessExpression { container, .. } =
|
let FieldAccessExpression { container, field } =
|
||||||
field_access_expression.inner.as_ref();
|
field_access_expression.inner.as_ref();
|
||||||
|
|
||||||
|
self.context
|
||||||
|
.update_last_position(&field.inner, field.position);
|
||||||
self.analyze_expression(container)?;
|
self.analyze_expression(container)?;
|
||||||
}
|
}
|
||||||
Expression::Grouped(expression) => {
|
Expression::Grouped(expression) => {
|
||||||
self.analyze_expression(expression.inner.as_ref())?;
|
self.analyze_expression(expression.inner.as_ref())?;
|
||||||
}
|
}
|
||||||
Expression::Identifier(identifier) => {
|
Expression::Identifier(identifier) => {
|
||||||
let found = self
|
self.context
|
||||||
.context
|
|
||||||
.update_last_position(&identifier.inner, identifier.position);
|
.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::If(if_expression) => self.analyze_if(&if_expression.inner)?,
|
||||||
Expression::List(list_expression) => match list_expression.inner.as_ref() {
|
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(assignee)?;
|
||||||
self.analyze_expression(modifier)?;
|
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::ErrorPropagation(_) => todo!(),
|
||||||
OperatorExpression::Negation(expression) => {
|
OperatorExpression::Negation(expression) => {
|
||||||
@ -285,30 +288,14 @@ impl<'a> Analyzer<'a> {
|
|||||||
},
|
},
|
||||||
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
|
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
|
||||||
StructExpression::Unit { name } => {
|
StructExpression::Unit { name } => {
|
||||||
let found = self
|
todo!("Update constructor position");
|
||||||
.context
|
|
||||||
.update_last_position(&name.inner, name.position);
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
return Err(AnalysisError::UndefinedType {
|
|
||||||
identifier: name.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
StructExpression::Fields { name, fields } => {
|
StructExpression::Fields { name, fields } => {
|
||||||
let found = self
|
todo!("Update constructor position");
|
||||||
.context
|
|
||||||
.update_last_position(&name.inner, name.position);
|
|
||||||
|
|
||||||
if !found {
|
// for (_, expression) in fields {
|
||||||
return Err(AnalysisError::UndefinedType {
|
// self.analyze_expression(expression)?;
|
||||||
identifier: name.clone(),
|
// }
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (_, expression) in fields {
|
|
||||||
self.analyze_expression(expression)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Expression::TupleAccess(tuple_access) => {
|
Expression::TupleAccess(tuple_access) => {
|
||||||
@ -390,9 +377,12 @@ pub enum AnalysisError {
|
|||||||
ExpectedMap {
|
ExpectedMap {
|
||||||
actual: Statement,
|
actual: Statement,
|
||||||
},
|
},
|
||||||
ExpectedValue {
|
ExpectedValueFromStatement {
|
||||||
actual: Statement,
|
actual: Statement,
|
||||||
},
|
},
|
||||||
|
ExpectedValueFromExpression {
|
||||||
|
actual: Expression,
|
||||||
|
},
|
||||||
ExpectedValueArgumentCount {
|
ExpectedValueArgumentCount {
|
||||||
expected: usize,
|
expected: usize,
|
||||||
actual: usize,
|
actual: usize,
|
||||||
@ -405,7 +395,7 @@ pub enum AnalysisError {
|
|||||||
length: usize,
|
length: usize,
|
||||||
},
|
},
|
||||||
TypeConflict {
|
TypeConflict {
|
||||||
actual_statement: Statement,
|
actual_expression: Expression,
|
||||||
actual_type: Type,
|
actual_type: Type,
|
||||||
expected: Type,
|
expected: Type,
|
||||||
},
|
},
|
||||||
@ -436,12 +426,13 @@ impl AnalysisError {
|
|||||||
AnalysisError::ExpectedIntegerOrRange { actual } => actual.position(),
|
AnalysisError::ExpectedIntegerOrRange { actual } => actual.position(),
|
||||||
AnalysisError::ExpectedList { actual } => actual.position(),
|
AnalysisError::ExpectedList { actual } => actual.position(),
|
||||||
AnalysisError::ExpectedMap { 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::ExpectedValueArgumentCount { position, .. } => *position,
|
||||||
AnalysisError::IndexOutOfBounds { index, .. } => index.position(),
|
AnalysisError::IndexOutOfBounds { index, .. } => index.position(),
|
||||||
AnalysisError::TypeConflict {
|
AnalysisError::TypeConflict {
|
||||||
actual_statement, ..
|
actual_expression, ..
|
||||||
} => actual_statement.position(),
|
} => actual_expression.position(),
|
||||||
AnalysisError::UndefinedField { identifier, .. } => identifier.position(),
|
AnalysisError::UndefinedField { identifier, .. } => identifier.position(),
|
||||||
AnalysisError::UndefinedType { identifier } => identifier.position,
|
AnalysisError::UndefinedType { identifier } => identifier.position,
|
||||||
AnalysisError::UndefinedVariable { 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::ExpectedList { actual } => write!(f, "Expected list, found {}", actual),
|
||||||
AnalysisError::ExpectedMap { actual } => write!(f, "Expected map, found {}", actual),
|
AnalysisError::ExpectedMap { actual } => write!(f, "Expected map, found {}", actual),
|
||||||
AnalysisError::ExpectedValue { actual, .. } => {
|
AnalysisError::ExpectedValueFromExpression { actual, .. } => {
|
||||||
write!(f, "Expected value, found {}", 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 {
|
AnalysisError::ExpectedValueArgumentCount {
|
||||||
expected, actual, ..
|
expected, actual, ..
|
||||||
@ -487,7 +485,7 @@ impl Display for AnalysisError {
|
|||||||
index_value, list, length
|
index_value, list, length
|
||||||
),
|
),
|
||||||
AnalysisError::TypeConflict {
|
AnalysisError::TypeConflict {
|
||||||
actual_statement,
|
actual_expression: actual_statement,
|
||||||
actual_type,
|
actual_type,
|
||||||
expected,
|
expected,
|
||||||
} => {
|
} => {
|
||||||
@ -521,18 +519,27 @@ impl Display for AnalysisError {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{Identifier, Value};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_assign_wrong_type() {
|
fn add_assign_wrong_type() {
|
||||||
let source = "
|
let source = "
|
||||||
a = 1
|
let mut a = 1;
|
||||||
a += 1.0
|
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]
|
#[test]
|
||||||
@ -542,7 +549,17 @@ mod tests {
|
|||||||
a -= 1.0
|
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]
|
#[test]
|
||||||
|
@ -6,9 +6,7 @@ use std::{
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{Context, FunctionType, Identifier, RangeableType, StructType, Type};
|
||||||
Context, FieldsStructType, FunctionType, Identifier, RangeableType, StructType, TupleType, Type,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{Node, Span, Statement};
|
use super::{Node, Span, Statement};
|
||||||
|
|
||||||
@ -268,17 +266,17 @@ impl Expression {
|
|||||||
pub fn return_type(&self, context: &Context) -> Option<Type> {
|
pub fn return_type(&self, context: &Context) -> Option<Type> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Block(block_expression) => {
|
Expression::Block(block_expression) => {
|
||||||
block_expression.inner.as_ref().return_type(context)
|
Some(block_expression.inner.return_type(context)?)
|
||||||
}
|
}
|
||||||
Expression::Call(call_expression) => {
|
Expression::Call(call_expression) => {
|
||||||
let CallExpression { invoker, .. } = call_expression.inner.as_ref();
|
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)
|
return_type.map(|r#type| *r#type)
|
||||||
} else if let Type::Struct(_) = invoker_type {
|
} else if let Some(Type::Struct(_)) = invoker_type {
|
||||||
Some(invoker_type)
|
invoker_type
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -287,11 +285,9 @@ impl Expression {
|
|||||||
let FieldAccessExpression { container, field } =
|
let FieldAccessExpression { container, field } =
|
||||||
field_access_expression.inner.as_ref();
|
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, .. })) =
|
if let Some(Type::Struct(StructType::Fields { fields, .. })) = container_type {
|
||||||
container_type
|
|
||||||
{
|
|
||||||
fields
|
fields
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find(|(name, _)| name == &field.inner)
|
.find(|(name, _)| name == &field.inner)
|
||||||
@ -301,12 +297,13 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Grouped(expression) => expression.inner.return_type(context),
|
Expression::Grouped(expression) => expression.inner.return_type(context),
|
||||||
Expression::Identifier(identifier) => context.get_type(&identifier.inner),
|
Expression::Identifier(identifier) => context.get_variable_type(&identifier.inner),
|
||||||
Expression::If(if_expression) => match if_expression.inner.as_ref() {
|
Expression::If(if_expression) => {
|
||||||
|
return match if_expression.inner.as_ref() {
|
||||||
IfExpression::If { .. } => None,
|
IfExpression::If { .. } => None,
|
||||||
IfExpression::IfElse { if_block, .. } => if_block.inner.return_type(context),
|
IfExpression::IfElse { if_block, .. } => if_block.inner.return_type(context),
|
||||||
},
|
}
|
||||||
|
}
|
||||||
Expression::List(list_expression) => match list_expression.inner.as_ref() {
|
Expression::List(list_expression) => match list_expression.inner.as_ref() {
|
||||||
ListExpression::AutoFill { repeat_operand, .. } => {
|
ListExpression::AutoFill { repeat_operand, .. } => {
|
||||||
let item_type = repeat_operand.return_type(context)?;
|
let item_type = repeat_operand.return_type(context)?;
|
||||||
@ -396,7 +393,7 @@ impl Expression {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
|
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());
|
let mut types = HashMap::with_capacity(fields.len());
|
||||||
|
|
||||||
for (field, expression) in fields {
|
for (field, expression) in fields {
|
||||||
@ -405,17 +402,20 @@ impl Expression {
|
|||||||
types.insert(field.inner.clone(), r#type);
|
types.insert(field.inner.clone(), r#type);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Type::Struct(StructType::Fields(FieldsStructType {
|
Some(Type::Struct(StructType::Fields {
|
||||||
|
name: name.inner.clone(),
|
||||||
fields: types,
|
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) => {
|
Expression::TupleAccess(tuple_access_expression) => {
|
||||||
let TupleAccessExpression { tuple, index } = tuple_access_expression.inner.as_ref();
|
let TupleAccessExpression { tuple, index } = tuple_access_expression.inner.as_ref();
|
||||||
let tuple_value = tuple.return_type(context)?;
|
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()
|
fields.get(index.inner).cloned()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -944,12 +944,13 @@ pub enum BlockExpression {
|
|||||||
impl BlockExpression {
|
impl BlockExpression {
|
||||||
fn return_type(&self, context: &Context) -> Option<Type> {
|
fn return_type(&self, context: &Context) -> Option<Type> {
|
||||||
match self {
|
match self {
|
||||||
BlockExpression::Async(statements) => statements
|
BlockExpression::Async(statements) | BlockExpression::Sync(statements) => {
|
||||||
.last()
|
if let Some(statement) = statements.last() {
|
||||||
.and_then(|statement| statement.return_type(context)),
|
statement.return_type(context)
|
||||||
BlockExpression::Sync(statements) => statements
|
} else {
|
||||||
.last()
|
None
|
||||||
.and_then(|statement| statement.return_type(context)),
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,17 +19,6 @@ impl Statement {
|
|||||||
Statement::StructDefinition(Node::new(struct_definition, position))
|
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 {
|
pub fn position(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
Statement::Expression(expression) => expression.position(),
|
Statement::Expression(expression) => expression.position(),
|
||||||
@ -38,6 +27,15 @@ impl Statement {
|
|||||||
Statement::StructDefinition(definition) => definition.position,
|
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 {
|
impl Display for Statement {
|
||||||
|
@ -22,7 +22,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a deep copy of another 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 {
|
Self {
|
||||||
variables: Arc::new(RwLock::new(other.variables.read().unwrap().clone())),
|
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.
|
/// 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) {
|
match self.variables.read().unwrap().get(identifier) {
|
||||||
Some((VariableData::Type(r#type), _)) => Some(r#type.clone()),
|
Some((VariableData::Type(r#type), _)) => Some(r#type.clone()),
|
||||||
Some((VariableData::Value(value), _)) => Some(value.r#type()),
|
Some((VariableData::Value(value), _)) => Some(value.r#type()),
|
||||||
@ -61,7 +61,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the value of the variable with the given identifier.
|
/// 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) {
|
match self.variables.read().unwrap().get(identifier) {
|
||||||
Some((VariableData::Value(value), _)) => Some(value.clone()),
|
Some((VariableData::Value(value), _)) => Some(value.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -69,7 +69,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a variable to a type, with a position given for garbage collection.
|
/// 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:?}");
|
log::trace!("Setting {identifier} to type {type} at {position:?}");
|
||||||
|
|
||||||
self.variables
|
self.variables
|
||||||
@ -79,7 +79,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a variable to a value.
|
/// 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}");
|
log::trace!("Setting {identifier} to value {value}");
|
||||||
|
|
||||||
let mut variables = self.variables.write().unwrap();
|
let mut variables = self.variables.write().unwrap();
|
||||||
|
@ -314,21 +314,12 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let expression = self.parse_expression(0)?;
|
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()?;
|
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(
|
Ok(Statement::ExpressionNullified(Node::new(
|
||||||
expression, position,
|
expression, position,
|
||||||
)))
|
)))
|
||||||
@ -446,10 +437,9 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Token::LeftCurlyBrace = self.current_token {
|
if let Token::LeftCurlyBrace = self.current_token {
|
||||||
let name = Node::new(identifier, start_position);
|
|
||||||
|
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
|
let name = Node::new(identifier, start_position);
|
||||||
let mut fields = Vec::new();
|
let mut fields = Vec::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -1274,16 +1264,12 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
Ok(AbstractSyntaxTree {
|
Ok(AbstractSyntaxTree {
|
||||||
statements: [Statement::ExpressionNullified(Node::new(
|
statements: [Statement::Expression(Expression::block(
|
||||||
Expression::block(
|
|
||||||
BlockExpression::Async(vec![
|
BlockExpression::Async(vec![
|
||||||
Statement::ExpressionNullified(Node::new(
|
Statement::ExpressionNullified(Node::new(
|
||||||
Expression::operator(
|
Expression::operator(
|
||||||
OperatorExpression::Assignment {
|
OperatorExpression::Assignment {
|
||||||
assignee: Expression::identifier(
|
assignee: Expression::identifier(Identifier::new("x"), (8, 9)),
|
||||||
Identifier::new("x"),
|
|
||||||
(8, 9)
|
|
||||||
),
|
|
||||||
value: Expression::literal(42, (12, 14)),
|
value: Expression::literal(42, (12, 14)),
|
||||||
},
|
},
|
||||||
(8, 14)
|
(8, 14)
|
||||||
@ -1292,18 +1278,13 @@ mod tests {
|
|||||||
)),
|
)),
|
||||||
Statement::Expression(Expression::operator(
|
Statement::Expression(Expression::operator(
|
||||||
OperatorExpression::Assignment {
|
OperatorExpression::Assignment {
|
||||||
assignee: Expression::identifier(
|
assignee: Expression::identifier(Identifier::new("y"), (16, 17)),
|
||||||
Identifier::new("y"),
|
|
||||||
(16, 17)
|
|
||||||
),
|
|
||||||
value: Expression::literal(4.0, (20, 23)),
|
value: Expression::literal(4.0, (20, 23)),
|
||||||
},
|
},
|
||||||
(16, 23)
|
(16, 23)
|
||||||
))
|
))
|
||||||
]),
|
]),
|
||||||
(0, 25)
|
(0, 25)
|
||||||
),
|
|
||||||
(0, 25)
|
|
||||||
))]
|
))]
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
@ -1597,8 +1578,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
Ok(AbstractSyntaxTree::with_statements([
|
Ok(AbstractSyntaxTree::with_statements([
|
||||||
Statement::ExpressionNullified(Node::new(
|
Statement::Expression(Expression::r#if(
|
||||||
Expression::r#if(
|
|
||||||
IfExpression::If {
|
IfExpression::If {
|
||||||
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
|
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
|
||||||
if_block: Node::new(
|
if_block: Node::new(
|
||||||
@ -1609,8 +1589,6 @@ mod tests {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
(0, 10)
|
(0, 10)
|
||||||
),
|
|
||||||
(0, 10)
|
|
||||||
))
|
))
|
||||||
]))
|
]))
|
||||||
);
|
);
|
||||||
@ -1623,8 +1601,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
Ok(AbstractSyntaxTree::with_statements([
|
Ok(AbstractSyntaxTree::with_statements([
|
||||||
Statement::ExpressionNullified(Node::new(
|
Statement::Expression(Expression::r#if(
|
||||||
Expression::r#if(
|
|
||||||
IfExpression::IfElse {
|
IfExpression::IfElse {
|
||||||
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
|
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
|
||||||
if_block: Node::new(
|
if_block: Node::new(
|
||||||
@ -1641,8 +1618,6 @@ mod tests {
|
|||||||
))
|
))
|
||||||
},
|
},
|
||||||
(0, 21)
|
(0, 21)
|
||||||
),
|
|
||||||
(0, 21)
|
|
||||||
))
|
))
|
||||||
]))
|
]))
|
||||||
);
|
);
|
||||||
@ -1655,8 +1630,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
Ok(AbstractSyntaxTree::with_statements([
|
Ok(AbstractSyntaxTree::with_statements([
|
||||||
Statement::ExpressionNullified(Node::new(
|
Statement::Expression(Expression::r#if(
|
||||||
Expression::r#if(
|
|
||||||
IfExpression::IfElse {
|
IfExpression::IfElse {
|
||||||
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
|
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
|
||||||
if_block: Node::new(
|
if_block: Node::new(
|
||||||
@ -1667,10 +1641,7 @@ mod tests {
|
|||||||
),
|
),
|
||||||
r#else: ElseExpression::If(Node::new(
|
r#else: ElseExpression::If(Node::new(
|
||||||
Box::new(IfExpression::IfElse {
|
Box::new(IfExpression::IfElse {
|
||||||
condition: Expression::identifier(
|
condition: Expression::identifier(Identifier::new("z"), (19, 20)),
|
||||||
Identifier::new("z"),
|
|
||||||
(19, 20)
|
|
||||||
),
|
|
||||||
if_block: Node::new(
|
if_block: Node::new(
|
||||||
BlockExpression::Sync(vec![Statement::Expression(
|
BlockExpression::Sync(vec![Statement::Expression(
|
||||||
Expression::identifier(Identifier::new("a"), (23, 24))
|
Expression::identifier(Identifier::new("a"), (23, 24))
|
||||||
@ -1688,8 +1659,6 @@ mod tests {
|
|||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
(0, 37)
|
(0, 37)
|
||||||
),
|
|
||||||
(0, 37)
|
|
||||||
))
|
))
|
||||||
]))
|
]))
|
||||||
)
|
)
|
||||||
@ -1702,8 +1671,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
Ok(AbstractSyntaxTree::with_statements([
|
Ok(AbstractSyntaxTree::with_statements([
|
||||||
Statement::ExpressionNullified(Node::new(
|
Statement::Expression(Expression::while_loop(
|
||||||
Expression::while_loop(
|
|
||||||
Expression::operator(
|
Expression::operator(
|
||||||
OperatorExpression::Comparison {
|
OperatorExpression::Comparison {
|
||||||
left: Expression::identifier(Identifier::new("x"), (6, 7)),
|
left: Expression::identifier(Identifier::new("x"), (6, 7)),
|
||||||
@ -1713,24 +1681,17 @@ mod tests {
|
|||||||
(6, 12)
|
(6, 12)
|
||||||
),
|
),
|
||||||
Node::new(
|
Node::new(
|
||||||
BlockExpression::Sync(vec![Statement::Expression(
|
BlockExpression::Sync(vec![Statement::Expression(Expression::operator(
|
||||||
Expression::operator(
|
|
||||||
OperatorExpression::CompoundAssignment {
|
OperatorExpression::CompoundAssignment {
|
||||||
assignee: Expression::identifier(
|
assignee: Expression::identifier(Identifier::new("x"), (15, 16)),
|
||||||
Identifier::new("x"),
|
|
||||||
(15, 16)
|
|
||||||
),
|
|
||||||
operator: Node::new(MathOperator::Add, (17, 19)),
|
operator: Node::new(MathOperator::Add, (17, 19)),
|
||||||
modifier: Expression::literal(1, (20, 21)),
|
modifier: Expression::literal(1, (20, 21)),
|
||||||
},
|
},
|
||||||
(15, 21)
|
(15, 21)
|
||||||
)
|
))]),
|
||||||
)]),
|
|
||||||
(13, 23)
|
(13, 23)
|
||||||
),
|
),
|
||||||
(0, 23)
|
(0, 23)
|
||||||
),
|
|
||||||
(0, 23)
|
|
||||||
))
|
))
|
||||||
]))
|
]))
|
||||||
)
|
)
|
||||||
@ -1781,8 +1742,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
Ok(AbstractSyntaxTree::with_statements([
|
Ok(AbstractSyntaxTree::with_statements([
|
||||||
Statement::ExpressionNullified(Node::new(
|
Statement::Expression(Expression::block(
|
||||||
Expression::block(
|
|
||||||
BlockExpression::Sync(vec![Statement::Expression(Expression::operator(
|
BlockExpression::Sync(vec![Statement::Expression(Expression::operator(
|
||||||
OperatorExpression::Math {
|
OperatorExpression::Math {
|
||||||
left: Expression::literal(40, (2, 4)),
|
left: Expression::literal(40, (2, 4)),
|
||||||
@ -1792,8 +1752,6 @@ mod tests {
|
|||||||
(2, 8)
|
(2, 8)
|
||||||
))]),
|
))]),
|
||||||
(0, 10)
|
(0, 10)
|
||||||
),
|
|
||||||
(0, 10)
|
|
||||||
))
|
))
|
||||||
]))
|
]))
|
||||||
)
|
)
|
||||||
@ -1806,8 +1764,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
Ok(AbstractSyntaxTree::with_statements([
|
Ok(AbstractSyntaxTree::with_statements([
|
||||||
Statement::ExpressionNullified(Node::new(
|
Statement::Expression(Expression::block(
|
||||||
Expression::block(
|
|
||||||
BlockExpression::Sync(vec![
|
BlockExpression::Sync(vec![
|
||||||
Statement::ExpressionNullified(Node::new(
|
Statement::ExpressionNullified(Node::new(
|
||||||
Expression::assignment(
|
Expression::assignment(
|
||||||
@ -1832,8 +1789,6 @@ mod tests {
|
|||||||
))
|
))
|
||||||
]),
|
]),
|
||||||
(0, 34)
|
(0, 34)
|
||||||
),
|
|
||||||
(0, 34)
|
|
||||||
))
|
))
|
||||||
]))
|
]))
|
||||||
)
|
)
|
||||||
|
@ -17,7 +17,7 @@ use std::{
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::Identifier;
|
use crate::{Enum, Identifier, Struct, Value};
|
||||||
|
|
||||||
/// Description of a kind of value.
|
/// Description of a kind of value.
|
||||||
///
|
///
|
||||||
@ -53,7 +53,7 @@ pub enum Type {
|
|||||||
},
|
},
|
||||||
String,
|
String,
|
||||||
Struct(StructType),
|
Struct(StructType),
|
||||||
Tuple(TupleType),
|
Tuple(Vec<Type>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Type {
|
impl Type {
|
||||||
@ -266,36 +266,8 @@ impl Display for Type {
|
|||||||
Type::Number => write!(f, "num"),
|
Type::Number => write!(f, "num"),
|
||||||
Type::Range { r#type } => write!(f, "{type} range"),
|
Type::Range { r#type } => write!(f, "{type} range"),
|
||||||
Type::String => write!(f, "str"),
|
Type::String => write!(f, "str"),
|
||||||
Type::Struct(struct_type) => match struct_type {
|
Type::Struct(struct_type) => write!(f, "{struct_type}"),
|
||||||
StructType::Unit => write!(f, "()"),
|
Type::Tuple(fields) => {
|
||||||
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 }) => {
|
|
||||||
write!(f, "(")?;
|
write!(f, "(")?;
|
||||||
|
|
||||||
for (index, r#type) in fields.iter().enumerate() {
|
for (index, r#type) in fields.iter().enumerate() {
|
||||||
@ -439,57 +411,71 @@ impl Display for FunctionType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum StructType {
|
pub enum StructType {
|
||||||
Unit,
|
Unit {
|
||||||
Tuple(TupleType),
|
name: Identifier,
|
||||||
Fields(FieldsStructType),
|
},
|
||||||
|
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 {
|
impl Display for StructType {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
StructType::Unit => write!(f, "()"),
|
StructType::Unit { name } => write!(f, "{name}"),
|
||||||
StructType::Tuple(tuple) => write!(f, "{tuple}"),
|
StructType::Tuple { name, fields } => {
|
||||||
StructType::Fields(fields) => write!(f, "{fields}"),
|
write!(f, "{name}(")?;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
for (index, field) in fields.iter().enumerate() {
|
||||||
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() {
|
|
||||||
write!(f, "{field}")?;
|
write!(f, "{field}")?;
|
||||||
|
|
||||||
if index != self.fields.len() - 1 {
|
if index != fields.len() - 1 {
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
}
|
StructType::Fields { name, fields } => {
|
||||||
|
write!(f, "{name} {{")?;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
for (index, (identifier, r#type)) in fields.iter().enumerate() {
|
||||||
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() {
|
|
||||||
write!(f, "{identifier}: {type}")?;
|
write!(f, "{identifier}: {type}")?;
|
||||||
|
|
||||||
if index != self.fields.len() - 1 {
|
if index != fields.len() - 1 {
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -497,23 +483,178 @@ impl Display for FieldsStructType {
|
|||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialOrd for FieldsStructType {
|
impl PartialOrd for StructType {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
Some(self.cmp(other))
|
Some(self.cmp(other))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for FieldsStructType {
|
impl Ord for StructType {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
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)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct EnumType {
|
pub struct EnumType {
|
||||||
name: Identifier,
|
pub name: Identifier,
|
||||||
variants: Vec<StructType>,
|
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 {
|
impl Display for EnumType {
|
||||||
|
@ -16,8 +16,8 @@ use serde::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AbstractSyntaxTree, Context, EnumType, FieldsStructType, FunctionType, Identifier,
|
AbstractSyntaxTree, Context, EnumType, FunctionType, Identifier, RangeableType, RuntimeError,
|
||||||
RangeableType, RuntimeError, StructType, TupleType, Type, Vm,
|
StructType, Type, Vm,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Dust value representation
|
/// Dust value representation
|
||||||
@ -57,7 +57,7 @@ pub enum Value {
|
|||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Byte(u8),
|
Byte(u8),
|
||||||
Character(char),
|
Character(char),
|
||||||
Enum { name: Identifier, r#type: EnumType },
|
Enum(Enum),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Function(Function),
|
Function(Function),
|
||||||
Integer(i64),
|
Integer(i64),
|
||||||
@ -80,6 +80,10 @@ impl Value {
|
|||||||
Value::Mutable(Arc::new(RwLock::new(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 {
|
pub fn byte_range(start: u8, end: u8) -> Value {
|
||||||
Value::Range(Rangeable::Byte(start)..Rangeable::Byte(end))
|
Value::Range(Rangeable::Byte(start)..Rangeable::Byte(end))
|
||||||
}
|
}
|
||||||
@ -188,7 +192,7 @@ impl Value {
|
|||||||
Value::Boolean(_) => Type::Boolean,
|
Value::Boolean(_) => Type::Boolean,
|
||||||
Value::Byte(_) => Type::Byte,
|
Value::Byte(_) => Type::Byte,
|
||||||
Value::Character(_) => Type::Character,
|
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::Float(_) => Type::Float,
|
||||||
Value::Function(function) => Type::Function(function.r#type.clone()),
|
Value::Function(function) => Type::Function(function.r#type.clone()),
|
||||||
Value::Integer(_) => Type::Integer,
|
Value::Integer(_) => Type::Integer,
|
||||||
@ -221,25 +225,31 @@ impl Value {
|
|||||||
}
|
}
|
||||||
Value::String(_) => Type::String,
|
Value::String(_) => Type::String,
|
||||||
Value::Struct(r#struct) => match r#struct {
|
Value::Struct(r#struct) => match r#struct {
|
||||||
Struct::Unit { .. } => Type::Struct(StructType::Unit),
|
Struct::Unit { name } => Type::Struct(StructType::Unit { name: name.clone() }),
|
||||||
Struct::Tuple { fields, .. } => {
|
Struct::Tuple { name, fields } => {
|
||||||
let types = fields.iter().map(|field| field.r#type()).collect();
|
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
|
let types = fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(identifier, value)| (identifier.clone(), value.r#type()))
|
.map(|(identifier, value)| (identifier.clone(), value.r#type()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Type::Struct(StructType::Fields(FieldsStructType { fields: types }))
|
Type::Struct(StructType::Fields {
|
||||||
|
name: name.clone(),
|
||||||
|
fields: types,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Value::Tuple(values) => {
|
Value::Tuple(values) => {
|
||||||
let fields = values.iter().map(|value| value.r#type()).collect();
|
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 {
|
match self {
|
||||||
Value::Mutable(inner) => inner.read().unwrap().get_field(field),
|
Value::Mutable(inner) => inner.read().unwrap().get_field(field),
|
||||||
Value::Struct(Struct::Fields { fields, .. }) => fields.get(field).cloned(),
|
Value::Struct(Struct::Fields { fields, .. }) => fields.get(field).cloned(),
|
||||||
|
Value::Map(pairs) => pairs.get(field).cloned(),
|
||||||
_ => None,
|
_ => 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 {
|
impl Display for Value {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@ -773,7 +832,7 @@ impl Display for Value {
|
|||||||
Value::Boolean(boolean) => write!(f, "{boolean}"),
|
Value::Boolean(boolean) => write!(f, "{boolean}"),
|
||||||
Value::Byte(byte) => write!(f, "{byte}"),
|
Value::Byte(byte) => write!(f, "{byte}"),
|
||||||
Value::Character(character) => write!(f, "{character}"),
|
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::Float(float) => write!(f, "{float}"),
|
||||||
Value::Function(function) => write!(f, "{function}"),
|
Value::Function(function) => write!(f, "{function}"),
|
||||||
Value::Integer(integer) => write!(f, "{integer}"),
|
Value::Integer(integer) => write!(f, "{integer}"),
|
||||||
@ -813,7 +872,7 @@ impl Display for Value {
|
|||||||
write!(f, "{start}..={end}")
|
write!(f, "{start}..={end}")
|
||||||
}
|
}
|
||||||
Value::String(string) => write!(f, "{string}"),
|
Value::String(string) => write!(f, "{string}"),
|
||||||
Value::Struct(structure) => write!(f, "{structure}"),
|
Value::Struct(r#struct) => write!(f, "{struct}"),
|
||||||
Value::Tuple(fields) => {
|
Value::Tuple(fields) => {
|
||||||
write!(f, "(")?;
|
write!(f, "(")?;
|
||||||
|
|
||||||
@ -934,14 +993,7 @@ impl Serialize for Value {
|
|||||||
Value::Boolean(boolean) => serializer.serialize_bool(*boolean),
|
Value::Boolean(boolean) => serializer.serialize_bool(*boolean),
|
||||||
Value::Byte(byte) => serializer.serialize_u8(*byte),
|
Value::Byte(byte) => serializer.serialize_u8(*byte),
|
||||||
Value::Character(character) => serializer.serialize_char(*character),
|
Value::Character(character) => serializer.serialize_char(*character),
|
||||||
Value::Enum { name, r#type } => {
|
Value::Enum(r#emum) => r#emum.serialize(serializer),
|
||||||
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::Float(float) => serializer.serialize_f64(*float),
|
Value::Float(float) => serializer.serialize_f64(*float),
|
||||||
Value::Function(function) => function.serialize(serializer),
|
Value::Function(function) => function.serialize(serializer),
|
||||||
Value::Integer(integer) => serializer.serialize_i64(*integer),
|
Value::Integer(integer) => serializer.serialize_i64(*integer),
|
||||||
@ -1021,13 +1073,13 @@ impl Function {
|
|||||||
value_arguments: Option<Vec<Value>>,
|
value_arguments: Option<Vec<Value>>,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
) -> Result<Option<Value>, RuntimeError> {
|
) -> 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)) =
|
if let (Some(value_parameters), Some(value_arguments)) =
|
||||||
(&self.r#type.value_parameters, value_arguments)
|
(&self.r#type.value_parameters, value_arguments)
|
||||||
{
|
{
|
||||||
for ((identifier, _), value) in value_parameters.iter().zip(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 {
|
impl Display for Struct {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Struct::Unit { .. } => write!(f, "()"),
|
Struct::Unit { name } => write!(f, "{name}"),
|
||||||
Struct::Tuple { fields, .. } => {
|
Struct::Tuple { name, fields } => {
|
||||||
write!(f, "(")?;
|
write!(f, "{name}(")?;
|
||||||
|
|
||||||
for (index, field) in fields.iter().enumerate() {
|
for (index, field) in fields.iter().enumerate() {
|
||||||
if index > 0 {
|
if index > 0 {
|
||||||
@ -1240,8 +1292,8 @@ impl Display for Struct {
|
|||||||
|
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
Struct::Fields { fields, .. } => {
|
Struct::Fields { name, fields } => {
|
||||||
write!(f, "{{ ")?;
|
write!(f, "{name} {{ ")?;
|
||||||
|
|
||||||
for (index, (identifier, value)) in fields.iter().enumerate() {
|
for (index, (identifier, value)) in fields.iter().enumerate() {
|
||||||
if index > 0 {
|
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)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum ValueError {
|
pub enum ValueError {
|
||||||
CannotAdd(Value, Value),
|
CannotAdd(Value, Value),
|
||||||
|
@ -21,8 +21,9 @@ use crate::{
|
|||||||
OperatorExpression, PrimitiveValueExpression, RangeExpression, RawStringExpression, Span,
|
OperatorExpression, PrimitiveValueExpression, RangeExpression, RawStringExpression, Span,
|
||||||
Statement, StructDefinition, StructExpression,
|
Statement, StructDefinition, StructExpression,
|
||||||
},
|
},
|
||||||
parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, FieldsStructType,
|
parse, Analyzer, BuiltInFunctionError, Constructor, Context, DustError, Enum, EnumType,
|
||||||
Identifier, ParseError, Struct, StructType, TupleType, Type, Value, ValueError,
|
Expression, Identifier, ParseError, Struct, StructType, TupleConstructor, Type, Value,
|
||||||
|
ValueError,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Run the source code and return the result.
|
/// Run the source code and return the result.
|
||||||
@ -126,11 +127,19 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
Statement::StructDefinition(struct_definition) => {
|
Statement::StructDefinition(struct_definition) => {
|
||||||
let (name, struct_type) = match struct_definition.inner {
|
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 } => {
|
StructDefinition::Tuple { name, items } => {
|
||||||
let fields = items.into_iter().map(|item| item.inner).collect();
|
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 } => {
|
StructDefinition::Fields { name, fields } => {
|
||||||
let fields = fields
|
let fields = fields
|
||||||
@ -140,23 +149,25 @@ impl Vm {
|
|||||||
|
|
||||||
(
|
(
|
||||||
name.inner.clone(),
|
name.inner.clone(),
|
||||||
StructType::Fields(FieldsStructType { fields }),
|
StructType::Fields {
|
||||||
|
name: name.inner,
|
||||||
|
fields,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.context
|
todo!("Set constructor");
|
||||||
.set_type(name, Type::Struct(struct_type), struct_definition.position);
|
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if collect_garbage {
|
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),
|
error: Box::new(error),
|
||||||
position,
|
position,
|
||||||
})
|
})
|
||||||
@ -174,7 +185,7 @@ impl Vm {
|
|||||||
.run_expression(value, collect_garbage)?
|
.run_expression(value, collect_garbage)?
|
||||||
.expect_value(value_position)?;
|
.expect_value(value_position)?;
|
||||||
|
|
||||||
self.context.set_value(identifier.inner, value);
|
self.context.set_variable_value(identifier.inner, value);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -185,7 +196,8 @@ impl Vm {
|
|||||||
.expect_value(value_position)?
|
.expect_value(value_position)?
|
||||||
.into_mutable();
|
.into_mutable();
|
||||||
|
|
||||||
self.context.set_value(identifier.inner, mutable_value);
|
self.context
|
||||||
|
.set_variable_value(identifier.inner, mutable_value);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -210,7 +222,7 @@ impl Vm {
|
|||||||
self.run_expression(*expression.inner, collect_garbage)
|
self.run_expression(*expression.inner, collect_garbage)
|
||||||
}
|
}
|
||||||
Expression::Identifier(identifier) => {
|
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 {
|
if let Some(value) = get_value {
|
||||||
Ok(Evaluation::Return(Some(value)))
|
Ok(Evaluation::Return(Some(value)))
|
||||||
@ -243,7 +255,7 @@ impl Vm {
|
|||||||
Expression::TupleAccess(_) => todo!(),
|
Expression::TupleAccess(_) => todo!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
evaluation_result.map_err(|error| RuntimeError::Trace {
|
evaluation_result.map_err(|error| RuntimeError::Expression {
|
||||||
error: Box::new(error),
|
error: Box::new(error),
|
||||||
position,
|
position,
|
||||||
})
|
})
|
||||||
@ -257,20 +269,20 @@ impl Vm {
|
|||||||
match struct_expression {
|
match struct_expression {
|
||||||
StructExpression::Unit { name } => {
|
StructExpression::Unit { name } => {
|
||||||
let position = name.position;
|
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 {
|
RuntimeError::UndefinedType {
|
||||||
identifier: name.inner.clone(),
|
identifier: name.inner.clone(),
|
||||||
position,
|
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 {
|
Ok(Evaluation::Return(Some(Value::Struct(Struct::Unit {
|
||||||
name: name.inner,
|
name,
|
||||||
}))))
|
}))))
|
||||||
} else {
|
} else {
|
||||||
Err(RuntimeError::ExpectedType {
|
Err(RuntimeError::ExpectedType {
|
||||||
expected: Type::Struct(StructType::Unit),
|
expected: Type::Struct(StructType::Unit { name: name.inner }),
|
||||||
actual: r#type,
|
actual: r#type,
|
||||||
position,
|
position,
|
||||||
})
|
})
|
||||||
@ -281,14 +293,14 @@ impl Vm {
|
|||||||
fields: expressions,
|
fields: expressions,
|
||||||
} => {
|
} => {
|
||||||
let position = name.position;
|
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 {
|
RuntimeError::UndefinedType {
|
||||||
identifier: name.inner.clone(),
|
identifier: name.inner.clone(),
|
||||||
position,
|
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());
|
let mut values = HashMap::with_capacity(expressions.len());
|
||||||
|
|
||||||
for (identifier, expression) in expressions {
|
for (identifier, expression) in expressions {
|
||||||
@ -301,14 +313,15 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(Evaluation::Return(Some(Value::Struct(Struct::Fields {
|
Ok(Evaluation::Return(Some(Value::Struct(Struct::Fields {
|
||||||
name: name.inner,
|
name,
|
||||||
fields: values,
|
fields: values,
|
||||||
}))))
|
}))))
|
||||||
} else {
|
} else {
|
||||||
Err(RuntimeError::ExpectedType {
|
Err(RuntimeError::ExpectedType {
|
||||||
expected: Type::Struct(StructType::Fields(FieldsStructType {
|
expected: Type::Struct(StructType::Fields {
|
||||||
fields: HashMap::new(),
|
name: name.inner,
|
||||||
})),
|
fields: Default::default(),
|
||||||
|
}),
|
||||||
actual: r#type,
|
actual: r#type,
|
||||||
position,
|
position,
|
||||||
})
|
})
|
||||||
@ -609,11 +622,7 @@ impl Vm {
|
|||||||
|
|
||||||
Ok(Evaluation::Return(None))
|
Ok(Evaluation::Return(None))
|
||||||
}
|
}
|
||||||
LoopExpression::For {
|
LoopExpression::For { .. } => todo!(),
|
||||||
identifier,
|
|
||||||
iterator,
|
|
||||||
block,
|
|
||||||
} => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -668,8 +677,47 @@ impl Vm {
|
|||||||
let CallExpression { invoker, arguments } = call_expression;
|
let CallExpression { invoker, arguments } = call_expression;
|
||||||
|
|
||||||
let invoker_position = invoker.position();
|
let invoker_position = invoker.position();
|
||||||
let invoker_value =
|
let run_invoker = self.run_expression(invoker, collect_garbage)?;
|
||||||
if let Some(value) = self.run_expression(invoker, collect_garbage)?.value() {
|
|
||||||
|
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
|
value
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ExpectedValue {
|
return Err(RuntimeError::ExpectedValue {
|
||||||
@ -814,7 +862,7 @@ impl Vm {
|
|||||||
previous_value = self.run_statement(statement, collect_garbage)?;
|
previous_value = self.run_statement(statement, collect_garbage)?;
|
||||||
|
|
||||||
if collect_garbage {
|
if collect_garbage {
|
||||||
self.context.collect_garbage(position);
|
// self.context.collect_garbage(position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -864,7 +912,7 @@ impl Vm {
|
|||||||
|
|
||||||
match r#else {
|
match r#else {
|
||||||
ElseExpression::If(if_expression) => {
|
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),
|
ElseExpression::Block(block) => self.run_block(block.inner, collect_garbage),
|
||||||
}
|
}
|
||||||
@ -875,14 +923,15 @@ impl Vm {
|
|||||||
|
|
||||||
enum Evaluation {
|
enum Evaluation {
|
||||||
Break,
|
Break,
|
||||||
|
Constructor(Type),
|
||||||
Return(Option<Value>),
|
Return(Option<Value>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluation {
|
impl Evaluation {
|
||||||
pub fn value(self) -> Option<Value> {
|
pub fn value(self) -> Option<Value> {
|
||||||
match self {
|
match self {
|
||||||
Evaluation::Break => None,
|
|
||||||
Evaluation::Return(value_option) => value_option,
|
Evaluation::Return(value_option) => value_option,
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -898,7 +947,11 @@ impl Evaluation {
|
|||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum RuntimeError {
|
pub enum RuntimeError {
|
||||||
ParseError(ParseError),
|
ParseError(ParseError),
|
||||||
Trace {
|
Expression {
|
||||||
|
error: Box<RuntimeError>,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
|
Statement {
|
||||||
error: Box<RuntimeError>,
|
error: Box<RuntimeError>,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
@ -914,9 +967,17 @@ pub enum RuntimeError {
|
|||||||
error: BuiltInFunctionError,
|
error: BuiltInFunctionError,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
|
EnumVariantNotFound {
|
||||||
|
identifier: Identifier,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
ExpectedBoolean {
|
ExpectedBoolean {
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
|
ExpectedConstructor {
|
||||||
|
actual: Type,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
ExpectedIdentifier {
|
ExpectedIdentifier {
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
@ -974,14 +1035,17 @@ impl RuntimeError {
|
|||||||
pub fn position(&self) -> Span {
|
pub fn position(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
Self::ParseError(parse_error) => parse_error.position(),
|
Self::ParseError(parse_error) => parse_error.position(),
|
||||||
Self::Trace { position, .. } => *position,
|
Self::Expression { position, .. } => *position,
|
||||||
|
Self::Statement { position, .. } => *position,
|
||||||
Self::ValueError {
|
Self::ValueError {
|
||||||
left_position,
|
left_position,
|
||||||
right_position,
|
right_position,
|
||||||
..
|
..
|
||||||
} => (left_position.0, right_position.1),
|
} => (left_position.0, right_position.1),
|
||||||
Self::BuiltInFunctionError { position, .. } => *position,
|
Self::BuiltInFunctionError { position, .. } => *position,
|
||||||
|
Self::EnumVariantNotFound { position, .. } => *position,
|
||||||
Self::ExpectedBoolean { position } => *position,
|
Self::ExpectedBoolean { position } => *position,
|
||||||
|
Self::ExpectedConstructor { position, .. } => *position,
|
||||||
Self::ExpectedFunction { position, .. } => *position,
|
Self::ExpectedFunction { position, .. } => *position,
|
||||||
Self::ExpectedIdentifier { position } => *position,
|
Self::ExpectedIdentifier { position } => *position,
|
||||||
Self::ExpectedIdentifierOrString { position } => *position,
|
Self::ExpectedIdentifierOrString { position } => *position,
|
||||||
@ -1016,10 +1080,17 @@ impl Display for RuntimeError {
|
|||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::ParseError(parse_error) => write!(f, "{}", parse_error),
|
Self::ParseError(parse_error) => write!(f, "{}", parse_error),
|
||||||
Self::Trace { error, position } => {
|
Self::Expression { error, position } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
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
|
position, error
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1037,9 +1108,26 @@ impl Display for RuntimeError {
|
|||||||
Self::BuiltInFunctionError { error, .. } => {
|
Self::BuiltInFunctionError { error, .. } => {
|
||||||
write!(f, "{}", error)
|
write!(f, "{}", error)
|
||||||
}
|
}
|
||||||
|
Self::EnumVariantNotFound {
|
||||||
|
identifier,
|
||||||
|
position,
|
||||||
|
} => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Enum variant not found: {} at position: {:?}",
|
||||||
|
identifier, position
|
||||||
|
)
|
||||||
|
}
|
||||||
Self::ExpectedBoolean { position } => {
|
Self::ExpectedBoolean { position } => {
|
||||||
write!(f, "Expected a boolean at position: {:?}", 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 } => {
|
Self::ExpectedFunction { actual, position } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -1110,7 +1198,7 @@ impl Display for RuntimeError {
|
|||||||
} => {
|
} => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Undefined variable {} at position: {:?}",
|
"Undefined value {} at position: {:?}",
|
||||||
identifier, position
|
identifier, position
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1187,8 +1275,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn assign_tuple_struct_variable() {
|
fn assign_tuple_struct_variable() {
|
||||||
let input = "
|
let input = "
|
||||||
struct Foo(int)
|
struct Foo(int);
|
||||||
x = Foo(42)
|
let x = Foo(42);
|
||||||
x
|
x
|
||||||
";
|
";
|
||||||
|
|
||||||
@ -1203,7 +1291,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn define_and_instantiate_tuple_struct() {
|
fn define_and_instantiate_tuple_struct() {
|
||||||
let input = "struct Foo(int) Foo(42)";
|
let input = "struct Foo(int); Foo(42)";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
run(input),
|
run(input),
|
||||||
@ -1232,7 +1320,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn define_and_instantiate_unit_struct() {
|
fn define_and_instantiate_unit_struct() {
|
||||||
let input = "struct Foo Foo";
|
let input = "struct Foo; Foo";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
run(input),
|
run(input),
|
||||||
@ -1271,6 +1359,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn negate_expression() {
|
fn negate_expression() {
|
||||||
|
env_logger::builder().is_test(true).try_init().unwrap();
|
||||||
|
|
||||||
let input = "let x = -42; -x";
|
let input = "let x = -42; -x";
|
||||||
|
|
||||||
assert_eq!(run(input), Ok(Some(Value::Integer(42))));
|
assert_eq!(run(input), Ok(Some(Value::Integer(42))));
|
||||||
@ -1292,7 +1382,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn map_property_access() {
|
fn map_property_access() {
|
||||||
let input = "{ a = 42 }.a";
|
let input = "map { a = 42 }.a";
|
||||||
|
|
||||||
assert_eq!(run(input), Ok(Some(Value::Integer(42))));
|
assert_eq!(run(input), Ok(Some(Value::Integer(42))));
|
||||||
}
|
}
|
||||||
@ -1343,21 +1433,21 @@ mod tests {
|
|||||||
fn while_loop() {
|
fn while_loop() {
|
||||||
let input = "let mut x = 0; while x < 5 { x += 1 } x";
|
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]
|
#[test]
|
||||||
fn subtract_assign() {
|
fn subtract_assign() {
|
||||||
let input = "let mut x = 1; x -= 1; x";
|
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]
|
#[test]
|
||||||
fn add_assign() {
|
fn add_assign() {
|
||||||
let input = "let mut x = 1; x += 1; x";
|
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]
|
#[test]
|
||||||
|
@ -10,3 +10,4 @@ repository.workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.5.14", features = ["derive"] }
|
clap = { version = "4.5.14", features = ["derive"] }
|
||||||
dust-lang = { path = "../dust-lang" }
|
dust-lang = { path = "../dust-lang" }
|
||||||
|
env_logger = "0.11.5"
|
||||||
|
@ -8,21 +8,39 @@ struct Cli {
|
|||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
command: Option<String>,
|
command: Option<String>,
|
||||||
|
|
||||||
|
#[arg(short, long)]
|
||||||
|
parse: bool,
|
||||||
|
|
||||||
path: Option<String>,
|
path: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
let args = Cli::parse();
|
let args = Cli::parse();
|
||||||
|
|
||||||
if let Some(command) = &args.command {
|
if let Some(command) = &args.command {
|
||||||
|
if args.parse {
|
||||||
|
parse_and_display_errors(command);
|
||||||
|
} else {
|
||||||
run_and_display_errors(command);
|
run_and_display_errors(command);
|
||||||
|
}
|
||||||
} else if let Some(path) = &args.path {
|
} else if let Some(path) = &args.path {
|
||||||
let source = read_to_string(path).expect("Failed to read file");
|
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 {
|
} 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) {
|
fn run_and_display_errors(source: &str) {
|
||||||
|
Loading…
Reference in New Issue
Block a user