Pass tests
This commit is contained in:
parent
4846b3f74d
commit
169c1a9e3f
@ -16,7 +16,8 @@ use crate::{
|
||||
LoopExpression, MapExpression, Node, OperatorExpression, RangeExpression, Span, Statement,
|
||||
StructDefinition, StructExpression, TupleAccessExpression,
|
||||
},
|
||||
parse, Context, ContextError, DustError, Expression, Identifier, StructType, Type,
|
||||
core_library, parse, Context, ContextError, DustError, Expression, Identifier, StructType,
|
||||
Type,
|
||||
};
|
||||
|
||||
/// Analyzes the abstract syntax tree for errors.
|
||||
@ -32,7 +33,7 @@ use crate::{
|
||||
/// ```
|
||||
pub fn analyze(source: &str) -> Result<(), DustError> {
|
||||
let abstract_tree = parse(source)?;
|
||||
let context = Context::new();
|
||||
let context = core_library().create_child();
|
||||
let analyzer = Analyzer::new(&abstract_tree, context);
|
||||
|
||||
analyzer
|
||||
@ -149,7 +150,7 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn analyze_expression(&'recovered self, expression: &Expression) -> Result<(), AnalysisError> {
|
||||
fn analyze_expression(&self, expression: &Expression) -> Result<(), AnalysisError> {
|
||||
match expression {
|
||||
Expression::Block(block_expression) => self.analyze_block(&block_expression.inner)?,
|
||||
Expression::Call(call_expression) => {
|
||||
@ -173,8 +174,15 @@ impl<'recovered, 'a: 'recovered> Analyzer<'a> {
|
||||
self.analyze_expression(expression.inner.as_ref())?;
|
||||
}
|
||||
Expression::Identifier(identifier) => {
|
||||
self.context
|
||||
let found = self
|
||||
.context
|
||||
.update_last_position(&identifier.inner, identifier.position)?;
|
||||
|
||||
if !found {
|
||||
return Err(AnalysisError::UndefinedVariable {
|
||||
identifier: identifier.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Expression::If(if_expression) => self.analyze_if(&if_expression.inner)?,
|
||||
Expression::List(list_expression) => match list_expression.inner.as_ref() {
|
||||
@ -573,7 +581,7 @@ mod tests {
|
||||
#[test]
|
||||
fn subtract_assign_wrong_type() {
|
||||
let source = "
|
||||
a = 1
|
||||
let mut a = 1;
|
||||
a -= 1.0
|
||||
";
|
||||
|
||||
@ -674,6 +682,14 @@ mod tests {
|
||||
fn undefined_variable() {
|
||||
let source = "foo";
|
||||
|
||||
assert_eq!(analyze(source), todo!());
|
||||
assert_eq!(
|
||||
analyze(source),
|
||||
Err(DustError::Analysis {
|
||||
analysis_error: AnalysisError::UndefinedVariable {
|
||||
identifier: Node::new(Identifier::new("foo"), (0, 3))
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ pub enum AstError {
|
||||
impl AstError {
|
||||
pub fn position(&self) -> Option<Span> {
|
||||
match self {
|
||||
AstError::ContextError(error) => None,
|
||||
AstError::ContextError(_) => None,
|
||||
AstError::ExpectedType { position } => Some(*position),
|
||||
AstError::ExpectedTupleType { position } => Some(*position),
|
||||
AstError::ExpectedNonEmptyList { position } => Some(*position),
|
||||
|
@ -47,7 +47,13 @@ impl Context {
|
||||
|
||||
/// Returns a boolean indicating whether the identifier is in the context.
|
||||
pub fn contains(&self, identifier: &Identifier) -> Result<bool, ContextError> {
|
||||
Ok(self.associations.read()?.contains_key(identifier))
|
||||
if self.associations.read()?.contains_key(identifier) {
|
||||
Ok(true)
|
||||
} else if let Some(parent) = &self.parent {
|
||||
parent.contains(identifier)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the full ContextData and Span if the context contains the given identifier.
|
||||
@ -224,7 +230,9 @@ impl Context {
|
||||
}
|
||||
|
||||
/// Updates an associated identifier's last known position, allowing it to live longer in the
|
||||
/// program. Returns a boolean indicating whether the identifier.
|
||||
/// program. Returns a boolean indicating whether the identifier was found. If the identifier is
|
||||
/// not found in the current context, the parent context is searched but parent context's
|
||||
/// position is not updated.
|
||||
pub fn update_last_position(
|
||||
&self,
|
||||
identifier: &Identifier,
|
||||
@ -236,6 +244,8 @@ impl Context {
|
||||
log::trace!("Updating {identifier}'s last position to {position:?}");
|
||||
|
||||
Ok(true)
|
||||
} else if let Some(parent) = &self.parent {
|
||||
parent.contains(identifier)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
|
@ -1462,8 +1462,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn while_loop() {
|
||||
env_logger::builder().is_test(true).try_init().ok();
|
||||
|
||||
let input = "let mut x = 0; while x < 5 { x += 1 } x";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::mutable_from(5))));
|
||||
|
Loading…
Reference in New Issue
Block a user