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