Fix parsing bug
This commit is contained in:
parent
f2e5b8d499
commit
e643ebe114
@ -17,8 +17,8 @@ use crate::{
|
||||
PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition,
|
||||
StructExpression, TupleAccessExpression,
|
||||
},
|
||||
parse, ContextError, DustError, Expression, Identifier, RangeableType, StructType, Type,
|
||||
TypeConflict, TypeEvaluation,
|
||||
parse, Context, ContextData, ContextError, DustError, Expression, Identifier, RangeableType,
|
||||
StructType, Type, TypeConflict, TypeEvaluation,
|
||||
};
|
||||
|
||||
/// Analyzes the abstract syntax tree for errors.
|
||||
@ -36,7 +36,7 @@ pub fn analyze(source: &str) -> Result<(), DustError> {
|
||||
let abstract_tree = parse(source)?;
|
||||
let mut analyzer = Analyzer::new(&abstract_tree);
|
||||
|
||||
analyzer.analyze();
|
||||
analyzer.analyze()?;
|
||||
|
||||
if analyzer.errors.is_empty() {
|
||||
Ok(())
|
||||
@ -71,19 +71,23 @@ impl<'a> Analyzer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn analyze(&mut self) {
|
||||
pub fn analyze(&mut self) -> Result<(), ContextError> {
|
||||
for statement in &self.abstract_tree.statements {
|
||||
self.analyze_statement(statement);
|
||||
}
|
||||
self.analyze_statement(statement, &self.abstract_tree.context)?;
|
||||
}
|
||||
|
||||
fn analyze_statement(&mut self, statement: &Statement) {
|
||||
match statement {
|
||||
Statement::Expression(expression) => {
|
||||
self.analyze_expression(expression, statement.position())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn analyze_statement(
|
||||
&mut self,
|
||||
statement: &Statement,
|
||||
context: &Context,
|
||||
) -> Result<(), ContextError> {
|
||||
match statement {
|
||||
Statement::Expression(expression) => self.analyze_expression(expression, context)?,
|
||||
Statement::ExpressionNullified(expression_node) => {
|
||||
self.analyze_expression(&expression_node.inner, statement.position());
|
||||
self.analyze_expression(&expression_node.inner, context)?;
|
||||
}
|
||||
Statement::Let(let_statement) => match &let_statement.inner {
|
||||
LetStatement::Let { identifier, value }
|
||||
@ -92,42 +96,25 @@ impl<'a> Analyzer<'a> {
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
Ok(TypeEvaluation::Constructor(StructType::Unit { name })) => {
|
||||
let set_type = self.abstract_tree.context.set_variable_type(
|
||||
self.abstract_tree.context.set_variable_type(
|
||||
identifier.inner.clone(),
|
||||
Type::Struct(StructType::Unit { name }),
|
||||
statement.position(),
|
||||
);
|
||||
)?;
|
||||
|
||||
if let Err(context_error) = set_type {
|
||||
self.errors.push(AnalysisError::ContextError {
|
||||
error: context_error,
|
||||
position: identifier.position,
|
||||
});
|
||||
}
|
||||
self.analyze_expression(value, context)?;
|
||||
|
||||
self.analyze_expression(value, statement.position());
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
Ok(evaluation) => evaluation.r#type(),
|
||||
};
|
||||
|
||||
if let Some(r#type) = r#type {
|
||||
let set_type = self.abstract_tree.context.set_variable_type(
|
||||
identifier.inner.clone(),
|
||||
r#type.clone(),
|
||||
statement.position(),
|
||||
);
|
||||
|
||||
if let Err(context_error) = set_type {
|
||||
self.errors.push(AnalysisError::ContextError {
|
||||
error: context_error,
|
||||
position: identifier.position,
|
||||
});
|
||||
}
|
||||
self.abstract_tree
|
||||
.context
|
||||
.set_variable_type(identifier.inner.clone(), r#type.clone())?;
|
||||
} else {
|
||||
self.errors
|
||||
.push(AnalysisError::LetExpectedValueFromStatement {
|
||||
@ -135,13 +122,13 @@ impl<'a> Analyzer<'a> {
|
||||
});
|
||||
}
|
||||
|
||||
self.analyze_expression(value, statement.position());
|
||||
self.analyze_expression(value, context)?;
|
||||
}
|
||||
LetStatement::LetType { .. } => todo!(),
|
||||
LetStatement::LetMutType { .. } => todo!(),
|
||||
},
|
||||
Statement::StructDefinition(struct_definition) => {
|
||||
let set_constructor_type = match &struct_definition.inner {
|
||||
match &struct_definition.inner {
|
||||
StructDefinition::Unit { name } => {
|
||||
self.abstract_tree.context.set_constructor_type(
|
||||
name.inner.clone(),
|
||||
@ -149,7 +136,7 @@ impl<'a> Analyzer<'a> {
|
||||
name: name.inner.clone(),
|
||||
},
|
||||
statement.position(),
|
||||
)
|
||||
)?;
|
||||
}
|
||||
StructDefinition::Tuple { name, items } => {
|
||||
let fields = items.iter().map(|item| item.inner.clone()).collect();
|
||||
@ -161,7 +148,7 @@ impl<'a> Analyzer<'a> {
|
||||
fields,
|
||||
},
|
||||
statement.position(),
|
||||
)
|
||||
)?;
|
||||
}
|
||||
StructDefinition::Fields { name, fields } => {
|
||||
let fields = fields
|
||||
@ -178,32 +165,33 @@ impl<'a> Analyzer<'a> {
|
||||
fields,
|
||||
},
|
||||
statement.position(),
|
||||
)
|
||||
)?;
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(context_error) = set_constructor_type {
|
||||
self.errors.push(AnalysisError::ContextError {
|
||||
error: context_error,
|
||||
position: struct_definition.position,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn analyze_expression(&mut self, expression: &Expression, statement_position: Span) {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn analyze_expression(
|
||||
&mut self,
|
||||
expression: &Expression,
|
||||
context: &Context,
|
||||
) -> Result<(), ContextError> {
|
||||
match expression {
|
||||
Expression::Block(block_expression) => self.analyze_block(&block_expression.inner),
|
||||
Expression::Block(block_expression) => {
|
||||
self.analyze_block(&block_expression.inner, context)?;
|
||||
}
|
||||
Expression::Break(break_node) => {
|
||||
if let Some(expression) = &break_node.inner {
|
||||
self.analyze_expression(expression, statement_position);
|
||||
self.analyze_expression(expression, context)?;
|
||||
}
|
||||
}
|
||||
Expression::Call(call_expression) => {
|
||||
let CallExpression { invoker, arguments } = call_expression.inner.as_ref();
|
||||
|
||||
self.analyze_expression(invoker, statement_position);
|
||||
self.analyze_expression(invoker, context)?;
|
||||
|
||||
let invoker_evaluation = match invoker.type_evaluation(&self.abstract_tree.context)
|
||||
{
|
||||
@ -211,7 +199,7 @@ impl<'a> Analyzer<'a> {
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
@ -225,7 +213,7 @@ impl<'a> Analyzer<'a> {
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
@ -241,7 +229,7 @@ impl<'a> Analyzer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let invoked_type = if let Some(r#type) = invoker_evaluation.r#type() {
|
||||
@ -252,7 +240,7 @@ impl<'a> Analyzer<'a> {
|
||||
expression: invoker.clone(),
|
||||
});
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
};
|
||||
let function_type = if let Type::Function(function_type) = invoked_type {
|
||||
function_type
|
||||
@ -262,7 +250,7 @@ impl<'a> Analyzer<'a> {
|
||||
actual_expression: invoker.clone(),
|
||||
});
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let value_parameters =
|
||||
@ -277,11 +265,11 @@ impl<'a> Analyzer<'a> {
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
for ((_, expected_type), argument) in value_parameters.iter().zip(arguments) {
|
||||
self.analyze_expression(argument, statement_position);
|
||||
self.analyze_expression(argument, context)?;
|
||||
|
||||
let argument_evaluation =
|
||||
match argument.type_evaluation(&self.abstract_tree.context) {
|
||||
@ -313,11 +301,11 @@ impl<'a> Analyzer<'a> {
|
||||
}
|
||||
|
||||
for argument in arguments {
|
||||
self.analyze_expression(argument, statement_position);
|
||||
self.analyze_expression(argument, context)?;
|
||||
}
|
||||
}
|
||||
Expression::Dereference(expression) => {
|
||||
self.analyze_expression(&expression.inner, statement_position);
|
||||
self.analyze_expression(&expression.inner, context)?;
|
||||
}
|
||||
Expression::FieldAccess(field_access_expression) => {
|
||||
let FieldAccessExpression { container, field } =
|
||||
@ -328,7 +316,7 @@ impl<'a> Analyzer<'a> {
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let container_type = match evaluation.r#type() {
|
||||
@ -339,7 +327,7 @@ impl<'a> Analyzer<'a> {
|
||||
expression: container.clone(),
|
||||
});
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
@ -350,59 +338,47 @@ impl<'a> Analyzer<'a> {
|
||||
});
|
||||
}
|
||||
|
||||
self.analyze_expression(container, statement_position);
|
||||
self.analyze_expression(container, context)?;
|
||||
}
|
||||
Expression::Grouped(expression) => {
|
||||
self.analyze_expression(expression.inner.as_ref(), statement_position);
|
||||
self.analyze_expression(expression.inner.as_ref(), context)?;
|
||||
}
|
||||
Expression::Identifier(identifier) => {
|
||||
let find_identifier = self
|
||||
.abstract_tree
|
||||
.context
|
||||
.update_last_position(&identifier.inner, statement_position);
|
||||
let context_data = context.get_data(&identifier.inner)?;
|
||||
|
||||
if let Ok(false) = find_identifier {
|
||||
if let Some(ContextData::Reserved) | None = context_data {
|
||||
self.errors.push(AnalysisError::UndefinedVariable {
|
||||
identifier: identifier.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
if let Err(context_error) = find_identifier {
|
||||
self.errors.push(AnalysisError::ContextError {
|
||||
error: context_error,
|
||||
position: identifier.position,
|
||||
});
|
||||
}
|
||||
}
|
||||
Expression::If(if_expression) => {
|
||||
self.analyze_if(&if_expression.inner, statement_position)
|
||||
}
|
||||
Expression::If(if_expression) => self.analyze_if(&if_expression.inner, context)?,
|
||||
Expression::List(list_expression) => match list_expression.inner.as_ref() {
|
||||
ListExpression::AutoFill {
|
||||
repeat_operand,
|
||||
length_operand,
|
||||
} => {
|
||||
self.analyze_expression(repeat_operand, statement_position);
|
||||
self.analyze_expression(length_operand, statement_position);
|
||||
self.analyze_expression(repeat_operand, context)?;
|
||||
self.analyze_expression(length_operand, context)?;
|
||||
}
|
||||
ListExpression::Ordered(expressions) => {
|
||||
for expression in expressions {
|
||||
self.analyze_expression(expression, statement_position);
|
||||
self.analyze_expression(expression, context)?;
|
||||
}
|
||||
}
|
||||
},
|
||||
Expression::ListIndex(list_index_expression) => {
|
||||
let ListIndexExpression { list, index } = list_index_expression.inner.as_ref();
|
||||
|
||||
self.analyze_expression(list, statement_position);
|
||||
self.analyze_expression(index, statement_position);
|
||||
self.analyze_expression(list, context)?;
|
||||
self.analyze_expression(index, context)?;
|
||||
|
||||
let list_type_evaluation = match list.type_evaluation(&self.abstract_tree.context) {
|
||||
Ok(evaluation) => evaluation,
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let list_type = match list_type_evaluation.r#type() {
|
||||
@ -413,7 +389,7 @@ impl<'a> Analyzer<'a> {
|
||||
expression: list.clone(),
|
||||
});
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let index_type_evaluation = match index.type_evaluation(&self.abstract_tree.context)
|
||||
@ -422,7 +398,7 @@ impl<'a> Analyzer<'a> {
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let index_type = match index_type_evaluation.r#type() {
|
||||
@ -433,7 +409,7 @@ impl<'a> Analyzer<'a> {
|
||||
expression: list.clone(),
|
||||
});
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let literal_type = if let Expression::Literal(Node { inner, .. }) = index {
|
||||
@ -510,39 +486,39 @@ impl<'a> Analyzer<'a> {
|
||||
// Literals don't need to be analyzed
|
||||
}
|
||||
Expression::Loop(loop_expression) => match loop_expression.inner.as_ref() {
|
||||
LoopExpression::Infinite { block } => self.analyze_block(&block.inner),
|
||||
LoopExpression::Infinite { block } => self.analyze_block(&block.inner, context)?,
|
||||
LoopExpression::While { condition, block } => {
|
||||
self.analyze_expression(condition, statement_position);
|
||||
self.analyze_block(&block.inner);
|
||||
self.analyze_expression(condition, context)?;
|
||||
self.analyze_block(&block.inner, context)?;
|
||||
}
|
||||
LoopExpression::For {
|
||||
iterator, block, ..
|
||||
} => {
|
||||
self.analyze_expression(iterator, statement_position);
|
||||
self.analyze_block(&block.inner);
|
||||
self.analyze_expression(iterator, context)?;
|
||||
self.analyze_block(&block.inner, context)?;
|
||||
}
|
||||
},
|
||||
Expression::Map(map_expression) => {
|
||||
let MapExpression { pairs } = map_expression.inner.as_ref();
|
||||
|
||||
for (_, expression) in pairs {
|
||||
self.analyze_expression(expression, statement_position);
|
||||
self.analyze_expression(expression, context)?;
|
||||
}
|
||||
}
|
||||
Expression::Operator(operator_expression) => match operator_expression.inner.as_ref() {
|
||||
OperatorExpression::Assignment { assignee, value } => {
|
||||
self.analyze_expression(assignee, statement_position);
|
||||
self.analyze_expression(value, statement_position);
|
||||
self.analyze_expression(assignee, context)?;
|
||||
self.analyze_expression(value, context)?;
|
||||
}
|
||||
OperatorExpression::Comparison { left, right, .. } => {
|
||||
self.analyze_expression(left, statement_position);
|
||||
self.analyze_expression(right, statement_position);
|
||||
self.analyze_expression(left, context)?;
|
||||
self.analyze_expression(right, context)?;
|
||||
}
|
||||
OperatorExpression::CompoundAssignment {
|
||||
assignee, modifier, ..
|
||||
} => {
|
||||
self.analyze_expression(assignee, statement_position);
|
||||
self.analyze_expression(modifier, statement_position);
|
||||
self.analyze_expression(assignee, context)?;
|
||||
self.analyze_expression(modifier, context)?;
|
||||
|
||||
let assignee_type_evaluation =
|
||||
match assignee.type_evaluation(&self.abstract_tree.context) {
|
||||
@ -550,7 +526,7 @@ impl<'a> Analyzer<'a> {
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let modifier_type_evaluation =
|
||||
@ -559,7 +535,7 @@ impl<'a> Analyzer<'a> {
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
@ -577,21 +553,21 @@ impl<'a> Analyzer<'a> {
|
||||
.push(AnalysisError::ExpectedValueFromExpression {
|
||||
expression: modifier.clone(),
|
||||
});
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
(None, _) => {
|
||||
self.errors
|
||||
.push(AnalysisError::ExpectedValueFromExpression {
|
||||
expression: assignee.clone(),
|
||||
});
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
(_, None) => {
|
||||
self.errors
|
||||
.push(AnalysisError::ExpectedValueFromExpression {
|
||||
expression: modifier.clone(),
|
||||
});
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
@ -605,14 +581,14 @@ impl<'a> Analyzer<'a> {
|
||||
}
|
||||
OperatorExpression::ErrorPropagation(_) => todo!(),
|
||||
OperatorExpression::Negation(expression) => {
|
||||
self.analyze_expression(expression, statement_position);
|
||||
self.analyze_expression(expression, context)?;
|
||||
}
|
||||
OperatorExpression::Not(expression) => {
|
||||
self.analyze_expression(expression, statement_position);
|
||||
self.analyze_expression(expression, context)?;
|
||||
}
|
||||
OperatorExpression::Math { left, right, .. } => {
|
||||
self.analyze_expression(left, statement_position);
|
||||
self.analyze_expression(right, statement_position);
|
||||
self.analyze_expression(left, context)?;
|
||||
self.analyze_expression(right, context)?;
|
||||
|
||||
let left_type_evaluation =
|
||||
match left.type_evaluation(&self.abstract_tree.context) {
|
||||
@ -620,7 +596,7 @@ impl<'a> Analyzer<'a> {
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let right_type_evaluation =
|
||||
@ -629,7 +605,7 @@ impl<'a> Analyzer<'a> {
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
@ -647,21 +623,21 @@ impl<'a> Analyzer<'a> {
|
||||
.push(AnalysisError::ExpectedValueFromExpression {
|
||||
expression: right.clone(),
|
||||
});
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
(None, _) => {
|
||||
self.errors
|
||||
.push(AnalysisError::ExpectedValueFromExpression {
|
||||
expression: left.clone(),
|
||||
});
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
(_, None) => {
|
||||
self.errors
|
||||
.push(AnalysisError::ExpectedValueFromExpression {
|
||||
expression: right.clone(),
|
||||
});
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
@ -709,8 +685,8 @@ impl<'a> Analyzer<'a> {
|
||||
}
|
||||
}
|
||||
OperatorExpression::Logic { left, right, .. } => {
|
||||
self.analyze_expression(left, statement_position);
|
||||
self.analyze_expression(right, statement_position);
|
||||
self.analyze_expression(left, context)?;
|
||||
self.analyze_expression(right, context)?;
|
||||
|
||||
let left_type_evaluation =
|
||||
match left.type_evaluation(&self.abstract_tree.context) {
|
||||
@ -718,7 +694,7 @@ impl<'a> Analyzer<'a> {
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let right_type_evaluation =
|
||||
@ -727,7 +703,7 @@ impl<'a> Analyzer<'a> {
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
@ -745,21 +721,21 @@ impl<'a> Analyzer<'a> {
|
||||
.push(AnalysisError::ExpectedValueFromExpression {
|
||||
expression: right.clone(),
|
||||
});
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
(None, _) => {
|
||||
self.errors
|
||||
.push(AnalysisError::ExpectedValueFromExpression {
|
||||
expression: left.clone(),
|
||||
});
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
(_, None) => {
|
||||
self.errors
|
||||
.push(AnalysisError::ExpectedValueFromExpression {
|
||||
expression: right.clone(),
|
||||
});
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
@ -774,32 +750,18 @@ impl<'a> Analyzer<'a> {
|
||||
},
|
||||
Expression::Range(range_expression) => match range_expression.inner.as_ref() {
|
||||
RangeExpression::Exclusive { start, end } => {
|
||||
self.analyze_expression(start, statement_position);
|
||||
self.analyze_expression(end, statement_position);
|
||||
self.analyze_expression(start, context)?;
|
||||
self.analyze_expression(end, context)?;
|
||||
}
|
||||
RangeExpression::Inclusive { start, end } => {
|
||||
self.analyze_expression(start, statement_position);
|
||||
self.analyze_expression(end, statement_position);
|
||||
self.analyze_expression(start, context)?;
|
||||
self.analyze_expression(end, context)?;
|
||||
}
|
||||
},
|
||||
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
|
||||
StructExpression::Fields { name, fields } => {
|
||||
let update_position = self
|
||||
.abstract_tree
|
||||
.context
|
||||
.update_last_position(&name.inner, statement_position);
|
||||
|
||||
if let Err(error) = update_position {
|
||||
self.errors.push(AnalysisError::ContextError {
|
||||
error,
|
||||
position: name.position,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
StructExpression::Fields { fields, .. } => {
|
||||
for (_, expression) in fields {
|
||||
self.analyze_expression(expression, statement_position);
|
||||
self.analyze_expression(expression, context)?;
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -810,7 +772,7 @@ impl<'a> Analyzer<'a> {
|
||||
Ok(evaluation) => evaluation,
|
||||
Err(ast_error) => {
|
||||
self.errors.push(AnalysisError::AstError(ast_error));
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
@ -821,7 +783,7 @@ impl<'a> Analyzer<'a> {
|
||||
.push(AnalysisError::ExpectedValueFromExpression {
|
||||
expression: tuple.clone(),
|
||||
});
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
@ -845,64 +807,69 @@ impl<'a> Analyzer<'a> {
|
||||
});
|
||||
}
|
||||
|
||||
self.analyze_expression(tuple, statement_position);
|
||||
}
|
||||
self.analyze_expression(tuple, context)?;
|
||||
}
|
||||
}
|
||||
|
||||
fn analyze_block(&mut self, block_expression: &BlockExpression) {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn analyze_block(
|
||||
&mut self,
|
||||
block_expression: &BlockExpression,
|
||||
_context: &Context,
|
||||
) -> Result<(), ContextError> {
|
||||
let ast = match block_expression {
|
||||
BlockExpression::Async(ast) => ast,
|
||||
BlockExpression::Sync(ast) => ast,
|
||||
};
|
||||
|
||||
ast.context
|
||||
.assign_parent(self.abstract_tree.context.clone());
|
||||
|
||||
let mut analyzer = Analyzer::new(ast);
|
||||
|
||||
analyzer.analyze();
|
||||
|
||||
self.errors.append(&mut analyzer.errors);
|
||||
for statement in &ast.statements {
|
||||
self.analyze_statement(statement, &ast.context)?;
|
||||
}
|
||||
|
||||
fn analyze_if(&mut self, if_expression: &IfExpression, statement_position: Span) {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn analyze_if(
|
||||
&mut self,
|
||||
if_expression: &IfExpression,
|
||||
context: &Context,
|
||||
) -> Result<(), ContextError> {
|
||||
match if_expression {
|
||||
IfExpression::If {
|
||||
condition,
|
||||
if_block,
|
||||
} => {
|
||||
self.analyze_expression(condition, statement_position);
|
||||
self.analyze_block(&if_block.inner);
|
||||
self.analyze_expression(condition, context)?;
|
||||
self.analyze_block(&if_block.inner, context)?;
|
||||
}
|
||||
IfExpression::IfElse {
|
||||
condition,
|
||||
if_block,
|
||||
r#else,
|
||||
} => {
|
||||
self.analyze_expression(condition, statement_position);
|
||||
self.analyze_block(&if_block.inner);
|
||||
self.analyze_expression(condition, context)?;
|
||||
self.analyze_block(&if_block.inner, context)?;
|
||||
|
||||
match r#else {
|
||||
ElseExpression::Block(block_expression) => {
|
||||
self.analyze_block(&block_expression.inner);
|
||||
self.analyze_block(&block_expression.inner, context)?;
|
||||
}
|
||||
ElseExpression::If(if_expression) => {
|
||||
self.analyze_if(&if_expression.inner, statement_position);
|
||||
self.analyze_if(&if_expression.inner, context)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum AnalysisError {
|
||||
AstError(AstError),
|
||||
ContextError {
|
||||
error: ContextError,
|
||||
position: Span,
|
||||
},
|
||||
ExpectedFunction {
|
||||
actual: Type,
|
||||
actual_expression: Expression,
|
||||
@ -978,8 +945,8 @@ pub enum AnalysisError {
|
||||
}
|
||||
|
||||
impl From<AstError> for AnalysisError {
|
||||
fn from(v: AstError) -> Self {
|
||||
Self::AstError(v)
|
||||
fn from(error: AstError) -> Self {
|
||||
Self::AstError(error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -987,7 +954,6 @@ impl AnalysisError {
|
||||
pub fn position(&self) -> Span {
|
||||
match self {
|
||||
AnalysisError::AstError(ast_error) => ast_error.position(),
|
||||
AnalysisError::ContextError { position, .. } => *position,
|
||||
AnalysisError::ExpectedFunction {
|
||||
actual_expression, ..
|
||||
} => actual_expression.position(),
|
||||
@ -1024,7 +990,6 @@ impl Display for AnalysisError {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
AnalysisError::AstError(ast_error) => write!(f, "{}", ast_error),
|
||||
AnalysisError::ContextError { error, .. } => write!(f, "{}", error),
|
||||
AnalysisError::ExpectedFunction {
|
||||
actual,
|
||||
actual_expression,
|
||||
|
@ -156,20 +156,13 @@ impl Context {
|
||||
&self,
|
||||
identifier: Identifier,
|
||||
r#type: Type,
|
||||
position: Span,
|
||||
) -> Result<(), ContextError> {
|
||||
log::trace!("Setting {identifier} to type {type} at {position:?}");
|
||||
log::trace!("Setting {identifier} to type {type}.");
|
||||
|
||||
let mut associations = self.associations.write()?;
|
||||
let last_position = associations
|
||||
.get(&identifier)
|
||||
.map(|(_, last_position)| {
|
||||
if last_position.1 > position.1 {
|
||||
*last_position
|
||||
} else {
|
||||
position
|
||||
}
|
||||
})
|
||||
.map(|(_, last_position)| *last_position)
|
||||
.unwrap_or_default();
|
||||
|
||||
associations.insert(
|
||||
@ -283,18 +276,34 @@ impl Context {
|
||||
identifier: &Identifier,
|
||||
position: Span,
|
||||
) -> Result<bool, ContextError> {
|
||||
if let Some((_, last_position)) = self.associations.write()?.get_mut(identifier) {
|
||||
*last_position = position;
|
||||
let mut associations = self.associations.write()?;
|
||||
|
||||
if let Some((_, last_position)) = associations.get_mut(identifier) {
|
||||
if position.1 > last_position.1 {
|
||||
log::trace!("Updating {identifier}'s last position to {position:?}");
|
||||
|
||||
*last_position = position;
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
} else if let Some(parent) = self.parent.read().unwrap().as_ref() {
|
||||
parent.contains(identifier)
|
||||
} else {
|
||||
let ancestor_contains = if let Some(parent) = self.parent.read().unwrap().as_ref() {
|
||||
parent.contains(identifier)?
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if ancestor_contains {
|
||||
Ok(true)
|
||||
} else {
|
||||
log::trace!("Reserving {identifier} at {position:?}");
|
||||
|
||||
associations.insert(identifier.clone(), (ContextData::Reserved, position));
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Recovers the context from a poisoned state by recovering data from an error.
|
||||
///
|
||||
@ -327,6 +336,7 @@ pub enum ContextData {
|
||||
ConstructorType(StructType),
|
||||
VariableValue(Value),
|
||||
VariableType(Type),
|
||||
Reserved,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -2,12 +2,13 @@
|
||||
use annotate_snippets::{Level, Renderer, Snippet};
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::{ast::Span, AnalysisError, LexError, ParseError, RuntimeError};
|
||||
use crate::{ast::Span, AnalysisError, ContextError, LexError, ParseError, RuntimeError};
|
||||
|
||||
/// An error that occurred during the execution of the Dust language and its
|
||||
/// corresponding source code.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum DustError<'src> {
|
||||
ContextError(ContextError),
|
||||
Runtime {
|
||||
runtime_error: RuntimeError,
|
||||
source: &'src str,
|
||||
@ -26,6 +27,12 @@ pub enum DustError<'src> {
|
||||
},
|
||||
}
|
||||
|
||||
impl<'src> From<ContextError> for DustError<'src> {
|
||||
fn from(error: ContextError) -> Self {
|
||||
Self::ContextError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'src> DustError<'src> {
|
||||
pub fn runtime(runtime_error: RuntimeError, source: &'src str) -> Self {
|
||||
DustError::Runtime {
|
||||
@ -54,6 +61,7 @@ impl<'src> DustError<'src> {
|
||||
|
||||
pub fn title(&self) -> &'static str {
|
||||
match self {
|
||||
DustError::ContextError(_) => "Context error",
|
||||
DustError::Runtime { .. } => "Runtime error",
|
||||
DustError::Analysis { .. } => "Analysis error",
|
||||
DustError::Parse { .. } => "Parse error",
|
||||
@ -63,6 +71,7 @@ impl<'src> DustError<'src> {
|
||||
|
||||
pub fn source(&self) -> &'src str {
|
||||
match self {
|
||||
DustError::ContextError(_) => "",
|
||||
DustError::Runtime { source, .. } => source,
|
||||
DustError::Analysis { source, .. } => source,
|
||||
DustError::Parse { source, .. } => source,
|
||||
@ -72,6 +81,7 @@ impl<'src> DustError<'src> {
|
||||
|
||||
pub fn error_data(&self) -> Vec<(&'static str, Span, String)> {
|
||||
match self {
|
||||
DustError::ContextError(_) => vec![],
|
||||
DustError::Runtime { runtime_error, .. } => vec![(
|
||||
"Runtime error",
|
||||
runtime_error.position(),
|
||||
@ -114,6 +124,7 @@ impl<'src> DustError<'src> {
|
||||
impl Display for DustError<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
DustError::ContextError(context_error) => write!(f, "{context_error}"),
|
||||
DustError::Runtime { runtime_error, .. } => write!(f, "{runtime_error}"),
|
||||
DustError::Analysis {
|
||||
analysis_errors, ..
|
||||
|
@ -11,8 +11,8 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ast::*, core_library, Context, DustError, Identifier, LexError, Lexer, Token, TokenKind,
|
||||
TokenOwned, Type,
|
||||
ast::*, core_library, Context, ContextError, DustError, Identifier, LexError, Lexer, Token,
|
||||
TokenKind, TokenOwned, Type,
|
||||
};
|
||||
|
||||
/// Parses the input into an abstract syntax tree.
|
||||
@ -40,34 +40,27 @@ use crate::{
|
||||
pub fn parse(source: &str) -> Result<AbstractSyntaxTree, DustError> {
|
||||
let mut tree = AbstractSyntaxTree::new();
|
||||
|
||||
parse_into(source, &mut tree)?;
|
||||
tree.context.assign_parent(core_library().clone());
|
||||
|
||||
Ok(tree)
|
||||
}
|
||||
|
||||
pub fn parse_into<'src>(
|
||||
source: &'src str,
|
||||
tree: &mut AbstractSyntaxTree,
|
||||
) -> Result<(), DustError<'src>> {
|
||||
let lexer = Lexer::new(source);
|
||||
let mut parser = Parser::new(lexer);
|
||||
|
||||
loop {
|
||||
let node = parser
|
||||
.parse_statement()
|
||||
let statement = parser
|
||||
.parse_statement(&tree.context)
|
||||
.map_err(|parse_error| DustError::Parse {
|
||||
parse_error,
|
||||
source,
|
||||
})?;
|
||||
|
||||
tree.statements.push_back(node);
|
||||
tree.statements.push_back(statement);
|
||||
|
||||
if let Token::Eof = parser.current_token {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(tree)
|
||||
}
|
||||
|
||||
/// Low-level tool for parsing the input a statement at a time.
|
||||
@ -99,7 +92,6 @@ pub struct Parser<'src> {
|
||||
current_token: Token<'src>,
|
||||
current_position: Span,
|
||||
mode: ParserMode,
|
||||
context: Context,
|
||||
}
|
||||
|
||||
impl<'src> Parser<'src> {
|
||||
@ -111,7 +103,6 @@ impl<'src> Parser<'src> {
|
||||
current_token,
|
||||
current_position,
|
||||
mode: ParserMode::Normal,
|
||||
context: core_library().create_child(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +110,7 @@ impl<'src> Parser<'src> {
|
||||
matches!(self.current_token, Token::Eof)
|
||||
}
|
||||
|
||||
pub fn parse_statement(&mut self) -> Result<Statement, ParseError> {
|
||||
pub fn parse_statement(&mut self, context: &Context) -> Result<Statement, ParseError> {
|
||||
let start_position = self.current_position;
|
||||
|
||||
if let Token::Let = self.current_token {
|
||||
@ -135,7 +126,7 @@ impl<'src> Parser<'src> {
|
||||
false
|
||||
};
|
||||
|
||||
let identifier = self.parse_identifier()?;
|
||||
let identifier = self.parse_identifier(context)?;
|
||||
|
||||
if let Token::Equal = self.current_token {
|
||||
self.next_token()?;
|
||||
@ -147,7 +138,7 @@ impl<'src> Parser<'src> {
|
||||
});
|
||||
}
|
||||
|
||||
let value = self.parse_expression(0)?;
|
||||
let value = self.parse_expression(0, context)?;
|
||||
|
||||
let end = if let Token::Semicolon = self.current_token {
|
||||
let end = self.current_position.1;
|
||||
@ -174,7 +165,7 @@ impl<'src> Parser<'src> {
|
||||
self.next_token()?;
|
||||
|
||||
let name = if let Token::Identifier(_) = self.current_token {
|
||||
self.parse_identifier()?
|
||||
self.parse_identifier(context)?
|
||||
} else {
|
||||
return Err(ParseError::ExpectedToken {
|
||||
expected: TokenKind::Identifier,
|
||||
@ -203,10 +194,6 @@ impl<'src> Parser<'src> {
|
||||
if let Token::RightParenthesis = self.current_token {
|
||||
self.next_token()?;
|
||||
|
||||
if let Token::Semicolon = self.current_token {
|
||||
self.next_token()?;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -223,6 +210,10 @@ impl<'src> Parser<'src> {
|
||||
|
||||
let position = (start_position.0, self.current_position.1);
|
||||
|
||||
if let Token::Semicolon = self.current_token {
|
||||
self.next_token()?;
|
||||
}
|
||||
|
||||
return if types.is_empty() {
|
||||
Ok(Statement::struct_definition(
|
||||
StructDefinition::Unit { name },
|
||||
@ -245,14 +236,10 @@ impl<'src> Parser<'src> {
|
||||
if let Token::RightCurlyBrace = self.current_token {
|
||||
self.next_token()?;
|
||||
|
||||
if let Token::Semicolon = self.current_token {
|
||||
self.next_token()?;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
let field_name = self.parse_identifier()?;
|
||||
let field_name = self.parse_identifier(context)?;
|
||||
|
||||
if let Token::Colon = self.current_token {
|
||||
self.next_token()?;
|
||||
@ -277,6 +264,10 @@ impl<'src> Parser<'src> {
|
||||
|
||||
let position = (start_position.0, self.current_position.1);
|
||||
|
||||
if let Token::Semicolon = self.current_token {
|
||||
self.next_token()?;
|
||||
}
|
||||
|
||||
return if fields.is_empty() {
|
||||
Ok(Statement::struct_definition(
|
||||
StructDefinition::Unit { name },
|
||||
@ -301,7 +292,7 @@ impl<'src> Parser<'src> {
|
||||
});
|
||||
}
|
||||
|
||||
let expression = self.parse_expression(0)?;
|
||||
let expression = self.parse_expression(0, context)?;
|
||||
|
||||
if let Token::Semicolon = self.current_token {
|
||||
let position = (start_position.0, self.current_position.1);
|
||||
@ -325,19 +316,23 @@ impl<'src> Parser<'src> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_expression(&mut self, mut precedence: u8) -> Result<Expression, ParseError> {
|
||||
fn parse_expression(
|
||||
&mut self,
|
||||
mut precedence: u8,
|
||||
context: &Context,
|
||||
) -> Result<Expression, ParseError> {
|
||||
// Parse a statement starting from the current node.
|
||||
let mut left = if self.current_token.is_prefix() {
|
||||
self.parse_prefix()?
|
||||
self.parse_prefix(context)?
|
||||
} else {
|
||||
self.parse_primary()?
|
||||
self.parse_primary(context)?
|
||||
};
|
||||
|
||||
// While the current token has a higher precedence than the given precedence
|
||||
while precedence < self.current_token.precedence() {
|
||||
// Give precedence to postfix operations
|
||||
left = if self.current_token.is_postfix() {
|
||||
let statement = self.parse_postfix(left)?;
|
||||
let statement = self.parse_postfix(left, context)?;
|
||||
|
||||
precedence = self.current_token.precedence();
|
||||
|
||||
@ -345,14 +340,14 @@ impl<'src> Parser<'src> {
|
||||
statement
|
||||
} else {
|
||||
// Replace the left-hand side with the infix operation
|
||||
self.parse_infix(left)?
|
||||
self.parse_infix(left, context)?
|
||||
};
|
||||
}
|
||||
|
||||
Ok(left)
|
||||
}
|
||||
|
||||
fn parse_prefix(&mut self) -> Result<Expression, ParseError> {
|
||||
fn parse_prefix(&mut self, context: &Context) -> Result<Expression, ParseError> {
|
||||
log::trace!("Parsing {} as prefix operator", self.current_token);
|
||||
|
||||
let operator_start = self.current_position.0;
|
||||
@ -361,7 +356,7 @@ impl<'src> Parser<'src> {
|
||||
Token::Bang => {
|
||||
self.next_token()?;
|
||||
|
||||
let operand = self.parse_expression(0)?;
|
||||
let operand = self.parse_expression(0, context)?;
|
||||
let position = (operator_start, self.current_position.1);
|
||||
|
||||
Ok(Expression::not(operand, position))
|
||||
@ -369,7 +364,7 @@ impl<'src> Parser<'src> {
|
||||
Token::Minus => {
|
||||
self.next_token()?;
|
||||
|
||||
let operand = self.parse_expression(0)?;
|
||||
let operand = self.parse_expression(0, context)?;
|
||||
let position = (operator_start, self.current_position.1);
|
||||
|
||||
Ok(Expression::negation(operand, position))
|
||||
@ -377,7 +372,7 @@ impl<'src> Parser<'src> {
|
||||
Token::Star => {
|
||||
self.next_token()?;
|
||||
|
||||
let operand = self.parse_expression(0)?;
|
||||
let operand = self.parse_expression(0, context)?;
|
||||
let position = (operator_start, self.current_position.1);
|
||||
|
||||
Ok(Expression::dereference(operand, position))
|
||||
@ -390,14 +385,14 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_primary(&mut self) -> Result<Expression, ParseError> {
|
||||
fn parse_primary(&mut self, context: &Context) -> Result<Expression, ParseError> {
|
||||
log::trace!("Parsing {} as primary", self.current_token);
|
||||
|
||||
let start_position = self.current_position;
|
||||
|
||||
match self.current_token {
|
||||
Token::Async => {
|
||||
let block = self.parse_block()?;
|
||||
let block = self.parse_block(context)?;
|
||||
let position = (start_position.0, block.position.1);
|
||||
|
||||
Ok(Expression::block(block.inner, position))
|
||||
@ -422,7 +417,7 @@ impl<'src> Parser<'src> {
|
||||
// Do not consume the semicolon, allowing it to nullify the expression
|
||||
|
||||
(None, break_end)
|
||||
} else if let Ok(expression) = self.parse_expression(0) {
|
||||
} else if let Ok(expression) = self.parse_expression(0, context) {
|
||||
let end = expression.position().1;
|
||||
|
||||
(Some(expression), end)
|
||||
@ -460,13 +455,15 @@ impl<'src> Parser<'src> {
|
||||
let identifier = Identifier::new(text);
|
||||
|
||||
if let ParserMode::Condition = self.mode {
|
||||
context.update_last_position(&identifier, start_position)?;
|
||||
|
||||
return Ok(Expression::identifier(identifier, start_position));
|
||||
}
|
||||
|
||||
if let Token::LeftCurlyBrace = self.current_token {
|
||||
self.next_token()?;
|
||||
|
||||
let name = Node::new(identifier, start_position);
|
||||
let name = Node::new(identifier.clone(), start_position);
|
||||
let mut fields = Vec::new();
|
||||
|
||||
loop {
|
||||
@ -476,7 +473,7 @@ impl<'src> Parser<'src> {
|
||||
break;
|
||||
}
|
||||
|
||||
let field_name = self.parse_identifier()?;
|
||||
let field_name = self.parse_identifier(context)?;
|
||||
|
||||
if let Token::Colon = self.current_token {
|
||||
self.next_token()?;
|
||||
@ -488,7 +485,7 @@ impl<'src> Parser<'src> {
|
||||
});
|
||||
}
|
||||
|
||||
let field_value = self.parse_expression(0)?;
|
||||
let field_value = self.parse_expression(0, context)?;
|
||||
|
||||
fields.push((field_name, field_value));
|
||||
|
||||
@ -499,12 +496,16 @@ impl<'src> Parser<'src> {
|
||||
|
||||
let position = (start_position.0, self.current_position.1);
|
||||
|
||||
context.update_last_position(&identifier, position)?;
|
||||
|
||||
return Ok(Expression::r#struct(
|
||||
StructExpression::Fields { name, fields },
|
||||
position,
|
||||
));
|
||||
}
|
||||
|
||||
context.update_last_position(&identifier, start_position)?;
|
||||
|
||||
Ok(Expression::identifier(identifier, start_position))
|
||||
}
|
||||
Token::Integer(text) => {
|
||||
@ -520,7 +521,7 @@ impl<'src> Parser<'src> {
|
||||
Token::If => {
|
||||
self.next_token()?;
|
||||
|
||||
let r#if = self.parse_if()?;
|
||||
let r#if = self.parse_if(context)?;
|
||||
let position = (start_position.0, self.current_position.1);
|
||||
|
||||
Ok(Expression::r#if(r#if, position))
|
||||
@ -531,14 +532,14 @@ impl<'src> Parser<'src> {
|
||||
Ok(Expression::literal(text.to_string(), start_position))
|
||||
}
|
||||
Token::LeftCurlyBrace => {
|
||||
let block_node = self.parse_block()?;
|
||||
let block_node = self.parse_block(context)?;
|
||||
|
||||
Ok(Expression::block(block_node.inner, block_node.position))
|
||||
}
|
||||
Token::LeftParenthesis => {
|
||||
self.next_token()?;
|
||||
|
||||
let node = self.parse_expression(0)?;
|
||||
let node = self.parse_expression(0, context)?;
|
||||
|
||||
if let Token::RightParenthesis = self.current_token {
|
||||
let position = (start_position.0, self.current_position.1);
|
||||
@ -565,12 +566,12 @@ impl<'src> Parser<'src> {
|
||||
return Ok(Expression::list(Vec::new(), position));
|
||||
}
|
||||
|
||||
let first_expression = self.parse_expression(0)?;
|
||||
let first_expression = self.parse_expression(0, context)?;
|
||||
|
||||
if let Token::Semicolon = self.current_token {
|
||||
self.next_token()?;
|
||||
|
||||
let repeat_operand = self.parse_expression(0)?;
|
||||
let repeat_operand = self.parse_expression(0, context)?;
|
||||
|
||||
if let Token::RightSquareBrace = self.current_token {
|
||||
let position = (start_position.0, self.current_position.1);
|
||||
@ -608,7 +609,7 @@ impl<'src> Parser<'src> {
|
||||
continue;
|
||||
}
|
||||
|
||||
let expression = self.parse_expression(0)?;
|
||||
let expression = self.parse_expression(0, context)?;
|
||||
|
||||
expressions.push(expression);
|
||||
}
|
||||
@ -616,7 +617,7 @@ impl<'src> Parser<'src> {
|
||||
Token::Loop => {
|
||||
self.next_token()?;
|
||||
|
||||
let block = self.parse_block()?;
|
||||
let block = self.parse_block(context)?;
|
||||
let position = (start_position.0, block.position.1);
|
||||
|
||||
Ok(Expression::infinite_loop(block, position))
|
||||
@ -645,7 +646,7 @@ impl<'src> Parser<'src> {
|
||||
return Ok(Expression::map(fields, position));
|
||||
}
|
||||
|
||||
let field_name = self.parse_identifier()?;
|
||||
let field_name = self.parse_identifier(context)?;
|
||||
|
||||
if let Token::Equal = self.current_token {
|
||||
self.next_token()?;
|
||||
@ -657,7 +658,7 @@ impl<'src> Parser<'src> {
|
||||
});
|
||||
}
|
||||
|
||||
let field_value = self.parse_expression(0)?;
|
||||
let field_value = self.parse_expression(0, context)?;
|
||||
|
||||
fields.push((field_name, field_value));
|
||||
|
||||
@ -669,8 +670,8 @@ impl<'src> Parser<'src> {
|
||||
Token::While => {
|
||||
self.next_token()?;
|
||||
|
||||
let condition = self.parse_expression(0)?;
|
||||
let block = self.parse_block()?;
|
||||
let condition = self.parse_expression(0, context)?;
|
||||
let block = self.parse_block(context)?;
|
||||
let position = (start_position.0, block.position.1);
|
||||
|
||||
Ok(Expression::while_loop(condition, block, position))
|
||||
@ -695,7 +696,11 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_infix(&mut self, left: Expression) -> Result<Expression, ParseError> {
|
||||
fn parse_infix(
|
||||
&mut self,
|
||||
left: Expression,
|
||||
context: &Context,
|
||||
) -> Result<Expression, ParseError> {
|
||||
log::trace!("Parsing {} as infix operator", self.current_token);
|
||||
|
||||
let operator_precedence = self.current_token.precedence()
|
||||
@ -709,7 +714,7 @@ impl<'src> Parser<'src> {
|
||||
if let Token::Equal = &self.current_token {
|
||||
self.next_token()?;
|
||||
|
||||
let value = self.parse_expression(operator_precedence)?;
|
||||
let value = self.parse_expression(operator_precedence, context)?;
|
||||
let position = (left_start, value.position().1);
|
||||
|
||||
return Ok(Expression::assignment(left, value, position));
|
||||
@ -725,7 +730,7 @@ impl<'src> Parser<'src> {
|
||||
|
||||
self.next_token()?;
|
||||
|
||||
let value = self.parse_expression(operator_precedence)?;
|
||||
let value = self.parse_expression(operator_precedence, context)?;
|
||||
let position = (left_start, value.position().1);
|
||||
|
||||
return Ok(Expression::operator(
|
||||
@ -741,7 +746,7 @@ impl<'src> Parser<'src> {
|
||||
if let Token::DoubleDot = &self.current_token {
|
||||
self.next_token()?;
|
||||
|
||||
let end = self.parse_expression(operator_precedence)?;
|
||||
let end = self.parse_expression(operator_precedence, context)?;
|
||||
let position = (left_start, end.position().1);
|
||||
|
||||
return Ok(Expression::exclusive_range(left, end, position));
|
||||
@ -761,7 +766,7 @@ impl<'src> Parser<'src> {
|
||||
|
||||
self.next_token()?;
|
||||
|
||||
let right = self.parse_expression(operator_precedence)?;
|
||||
let right = self.parse_expression(operator_precedence, context)?;
|
||||
let position = (left_start, right.position().1);
|
||||
|
||||
return Ok(Expression::operator(
|
||||
@ -798,7 +803,7 @@ impl<'src> Parser<'src> {
|
||||
|
||||
self.next_token()?;
|
||||
|
||||
let right = self.parse_expression(operator_precedence)?;
|
||||
let right = self.parse_expression(operator_precedence, context)?;
|
||||
let position = (left_start, right.position().1);
|
||||
|
||||
return Ok(Expression::operator(
|
||||
@ -824,7 +829,7 @@ impl<'src> Parser<'src> {
|
||||
|
||||
self.next_token()?;
|
||||
|
||||
let right = self.parse_expression(operator_precedence)?;
|
||||
let right = self.parse_expression(operator_precedence, context)?;
|
||||
let position = (left_start, right.position().1);
|
||||
|
||||
Ok(Expression::operator(
|
||||
@ -837,7 +842,11 @@ impl<'src> Parser<'src> {
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_postfix(&mut self, left: Expression) -> Result<Expression, ParseError> {
|
||||
fn parse_postfix(
|
||||
&mut self,
|
||||
left: Expression,
|
||||
context: &Context,
|
||||
) -> Result<Expression, ParseError> {
|
||||
log::trace!("Parsing {} as postfix operator", self.current_token);
|
||||
|
||||
let expression = match &self.current_token {
|
||||
@ -856,7 +865,7 @@ impl<'src> Parser<'src> {
|
||||
|
||||
Expression::tuple_access(left, index_node, position)
|
||||
} else {
|
||||
let field = self.parse_identifier()?;
|
||||
let field = self.parse_identifier(context)?;
|
||||
let position = (left.position().0, field.position.1);
|
||||
|
||||
Expression::field_access(left, field, position)
|
||||
@ -868,7 +877,7 @@ impl<'src> Parser<'src> {
|
||||
let mut arguments = Vec::new();
|
||||
|
||||
while self.current_token != Token::RightParenthesis {
|
||||
let argument = self.parse_expression(0)?;
|
||||
let argument = self.parse_expression(0, context)?;
|
||||
|
||||
arguments.push(argument);
|
||||
|
||||
@ -879,16 +888,16 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
}
|
||||
|
||||
self.next_token()?;
|
||||
|
||||
let position = (left.position().0, self.current_position.1);
|
||||
|
||||
self.next_token()?;
|
||||
|
||||
Expression::call(left, arguments, position)
|
||||
}
|
||||
Token::LeftSquareBrace => {
|
||||
self.next_token()?;
|
||||
|
||||
let index = self.parse_expression(0)?;
|
||||
let index = self.parse_expression(0, context)?;
|
||||
|
||||
let operator_end = if let Token::RightSquareBrace = self.current_token {
|
||||
let end = self.current_position.1;
|
||||
@ -922,22 +931,22 @@ impl<'src> Parser<'src> {
|
||||
};
|
||||
|
||||
if self.current_token.is_postfix() {
|
||||
self.parse_postfix(expression)
|
||||
self.parse_postfix(expression, context)
|
||||
} else {
|
||||
Ok(expression)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_if(&mut self) -> Result<IfExpression, ParseError> {
|
||||
fn parse_if(&mut self, context: &Context) -> Result<IfExpression, ParseError> {
|
||||
// Assume that the "if" token has already been consumed
|
||||
|
||||
self.mode = ParserMode::Condition;
|
||||
|
||||
let condition = self.parse_expression(0)?;
|
||||
let condition = self.parse_expression(0, context)?;
|
||||
|
||||
self.mode = ParserMode::Normal;
|
||||
|
||||
let if_block = self.parse_block()?;
|
||||
let if_block = self.parse_block(context)?;
|
||||
|
||||
if let Token::Else = self.current_token {
|
||||
self.next_token()?;
|
||||
@ -947,7 +956,7 @@ impl<'src> Parser<'src> {
|
||||
if let Token::If = self.current_token {
|
||||
self.next_token()?;
|
||||
|
||||
let if_expression = self.parse_if()?;
|
||||
let if_expression = self.parse_if(context)?;
|
||||
let position = (if_keyword_start, self.current_position.1);
|
||||
|
||||
Ok(IfExpression::IfElse {
|
||||
@ -956,7 +965,7 @@ impl<'src> Parser<'src> {
|
||||
r#else: ElseExpression::If(Node::new(Box::new(if_expression), position)),
|
||||
})
|
||||
} else {
|
||||
let else_block = self.parse_block()?;
|
||||
let else_block = self.parse_block(context)?;
|
||||
|
||||
Ok(IfExpression::IfElse {
|
||||
condition,
|
||||
@ -972,13 +981,16 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_identifier(&mut self) -> Result<Node<Identifier>, ParseError> {
|
||||
fn parse_identifier(&mut self, context: &Context) -> Result<Node<Identifier>, ParseError> {
|
||||
if let Token::Identifier(text) = self.current_token {
|
||||
let position = self.current_position;
|
||||
let identifier = Identifier::new(text);
|
||||
|
||||
self.next_token()?;
|
||||
|
||||
Ok(Node::new(Identifier::new(text), position))
|
||||
context.update_last_position(&identifier, position)?;
|
||||
|
||||
Ok(Node::new(identifier, position))
|
||||
} else {
|
||||
Err(ParseError::ExpectedToken {
|
||||
expected: TokenKind::Identifier,
|
||||
@ -988,7 +1000,7 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_block(&mut self) -> Result<Node<BlockExpression>, ParseError> {
|
||||
fn parse_block(&mut self, context: &Context) -> Result<Node<BlockExpression>, ParseError> {
|
||||
let left_start = self.current_position.0;
|
||||
let is_async = if let Token::Async = self.current_token {
|
||||
self.next_token()?;
|
||||
@ -1008,7 +1020,10 @@ impl<'src> Parser<'src> {
|
||||
});
|
||||
}
|
||||
|
||||
let mut statements = VecDeque::new();
|
||||
let mut ast = AbstractSyntaxTree {
|
||||
statements: VecDeque::new(),
|
||||
context: context.create_child(),
|
||||
};
|
||||
|
||||
loop {
|
||||
if let Token::RightCurlyBrace = self.current_token {
|
||||
@ -1016,11 +1031,6 @@ impl<'src> Parser<'src> {
|
||||
|
||||
self.next_token()?;
|
||||
|
||||
let ast = AbstractSyntaxTree {
|
||||
statements,
|
||||
context: self.context.create_child(),
|
||||
};
|
||||
|
||||
return if is_async {
|
||||
Ok(Node::new(BlockExpression::Async(ast), position))
|
||||
} else {
|
||||
@ -1028,9 +1038,9 @@ impl<'src> Parser<'src> {
|
||||
};
|
||||
}
|
||||
|
||||
let statement = self.parse_statement()?;
|
||||
let statement = self.parse_statement(&ast.context)?;
|
||||
|
||||
statements.push_back(statement);
|
||||
ast.statements.push_back(statement);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1063,6 +1073,7 @@ pub enum ParserMode {
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum ParseError {
|
||||
ContextError(ContextError),
|
||||
Boolean {
|
||||
error: ParseBoolError,
|
||||
position: Span,
|
||||
@ -1105,6 +1116,12 @@ pub enum ParseError {
|
||||
},
|
||||
}
|
||||
|
||||
impl From<ContextError> for ParseError {
|
||||
fn from(error: ContextError) -> Self {
|
||||
Self::ContextError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LexError> for ParseError {
|
||||
fn from(v: LexError) -> Self {
|
||||
Self::Lex(v)
|
||||
@ -1115,6 +1132,7 @@ impl ParseError {
|
||||
pub fn position(&self) -> Span {
|
||||
match self {
|
||||
ParseError::Boolean { position, .. } => *position,
|
||||
ParseError::ContextError { .. } => (0, 0),
|
||||
ParseError::ExpectedAssignment { actual } => actual.position(),
|
||||
ParseError::ExpectedExpression { actual } => actual.position(),
|
||||
ParseError::ExpectedIdentifierNode { actual } => actual.position(),
|
||||
@ -1133,6 +1151,7 @@ impl Display for ParseError {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Boolean { error, .. } => write!(f, "{}", error),
|
||||
Self::ContextError(error) => write!(f, "{}", error),
|
||||
Self::ExpectedAssignment { .. } => write!(f, "Expected assignment"),
|
||||
Self::ExpectedExpression { .. } => write!(f, "Expected expression"),
|
||||
Self::ExpectedIdentifierNode { actual } => {
|
||||
@ -1398,7 +1417,7 @@ mod tests {
|
||||
Expression::literal(42, (4, 6)),
|
||||
Expression::literal("bar".to_string(), (8, 13)),
|
||||
],
|
||||
(0, 15)
|
||||
(0, 14)
|
||||
),
|
||||
Node::new(0, (15, 16)),
|
||||
(0, 16)
|
||||
|
@ -40,7 +40,7 @@ pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
||||
let abstract_syntax_tree = parse(source)?;
|
||||
let mut analyzer = Analyzer::new(&abstract_syntax_tree);
|
||||
|
||||
analyzer.analyze();
|
||||
analyzer.analyze()?;
|
||||
|
||||
if !analyzer.errors.is_empty() {
|
||||
return Err(DustError::Analysis {
|
||||
@ -58,11 +58,7 @@ pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
||||
|
||||
/// Dust virtual machine.
|
||||
///
|
||||
/// **Warning**: Do not run an AbstractSyntaxTree that has not been analyzed *with the same
|
||||
/// context*. Use the `run` or `run_with_context` functions to make sure the program is analyzed
|
||||
/// before running it.
|
||||
///
|
||||
/// See the `run_with_context` function for an example of how to use the Analyzer and the VM.
|
||||
/// See the `run` function for an example of how to parse, analyze and run code.
|
||||
pub struct Vm;
|
||||
|
||||
impl Vm {
|
||||
@ -70,7 +66,11 @@ impl Vm {
|
||||
let mut previous_evaluation = Evaluation::Return(None);
|
||||
|
||||
while let Some(statement) = tree.statements.pop_front() {
|
||||
let statement_end = statement.position().1;
|
||||
|
||||
previous_evaluation = self.run_statement(statement, &tree.context, true)?;
|
||||
|
||||
tree.context.collect_garbage(statement_end).unwrap();
|
||||
}
|
||||
|
||||
match previous_evaluation {
|
||||
@ -193,12 +193,6 @@ impl Vm {
|
||||
}
|
||||
};
|
||||
|
||||
if collect_garbage {
|
||||
context
|
||||
.collect_garbage(position.1)
|
||||
.map_err(|error| RuntimeError::ContextError { error, position })?;
|
||||
}
|
||||
|
||||
result.map_err(|error| RuntimeError::Statement {
|
||||
error: Box::new(error),
|
||||
position,
|
||||
@ -1020,7 +1014,7 @@ impl Vm {
|
||||
fn run_block(
|
||||
&self,
|
||||
block: BlockExpression,
|
||||
context: &Context,
|
||||
_context: &Context,
|
||||
collect_garbage: bool,
|
||||
) -> Result<Evaluation, RuntimeError> {
|
||||
match block {
|
||||
@ -1424,7 +1418,7 @@ impl Display for RuntimeError {
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{AnalysisError, Struct};
|
||||
use crate::Struct;
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -1480,50 +1474,6 @@ mod tests {
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(42))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_scope_captures_parent() {
|
||||
let source = "let x = 42; { x }";
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(42))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_scope_does_not_capture_child() {
|
||||
let source = "{ let x = 42; } x";
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Err(DustError::analysis(
|
||||
[AnalysisError::UndefinedVariable {
|
||||
identifier: Node::new(Identifier::new("x"), (16, 17))
|
||||
}],
|
||||
source
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_scope_does_not_capture_sibling() {
|
||||
let source = "{ let x = 42; } { x }";
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Err(DustError::analysis(
|
||||
[AnalysisError::UndefinedVariable {
|
||||
identifier: Node::new(Identifier::new("x"), (18, 19))
|
||||
}],
|
||||
source
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_scope_does_not_pollute_parent() {
|
||||
let source = "let x = 42; { let x = \"foo\"; let x = \"bar\"; } x";
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(42))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn character() {
|
||||
let input = "'a'";
|
||||
|
45
dust-lang/tests/scopes.rs
Normal file
45
dust-lang/tests/scopes.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn block_scope_captures_parent() {
|
||||
let source = "let x = 42; { x }";
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(42))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_scope_does_not_capture_child() {
|
||||
let source = "{ let x = 42; } x";
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Err(DustError::analysis(
|
||||
[AnalysisError::UndefinedVariable {
|
||||
identifier: Node::new(Identifier::new("x"), (16, 17))
|
||||
}],
|
||||
source
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_scope_does_not_capture_sibling() {
|
||||
let source = "{ let x = 42; } { x }";
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Err(DustError::analysis(
|
||||
[AnalysisError::UndefinedVariable {
|
||||
identifier: Node::new(Identifier::new("x"), (18, 19))
|
||||
}],
|
||||
source
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_scope_does_not_pollute_parent() {
|
||||
let source = "let x = 42; { let x = \"foo\"; let x = \"bar\"; } x";
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(42))));
|
||||
}
|
Loading…
Reference in New Issue
Block a user