diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index b5ea5b1..4eb0ea0 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -160,7 +160,9 @@ impl<'a> Analyzer<'a> { } } Statement::Identifier(identifier) => { - if !self.context.contains(identifier) { + let exists = self.context.add_allowed_use(identifier); + + if !exists { return Err(AnalyzerError::UndefinedVariable { identifier: node.clone(), }); @@ -241,11 +243,6 @@ pub enum AnalyzerError { actual: Node, position: Span, }, - ExpectedSameType { - left: Node, - right: Node, - position: Span, - }, ExpectedString { actual: Node, position: (usize, usize), @@ -278,7 +275,6 @@ impl AnalyzerError { AnalyzerError::ExpectedInteger { position, .. } => *position, AnalyzerError::ExpectedIntegerOrFloat { position, .. } => *position, AnalyzerError::ExpectedIntegerFloatOrString { position, .. } => *position, - AnalyzerError::ExpectedSameType { position, .. } => *position, AnalyzerError::ExpectedString { position, .. } => *position, AnalyzerError::UndefinedVariable { identifier } => identifier.position, AnalyzerError::UnexpectedIdentifier { position, .. } => *position, @@ -313,9 +309,6 @@ impl Display for AnalyzerError { AnalyzerError::ExpectedIntegerFloatOrString { actual, .. } => { write!(f, "Expected integer, float, or string, found {}", actual) } - AnalyzerError::ExpectedSameType { left, right, .. } => { - write!(f, "Expected same type, found {} and {}", left, right) - } AnalyzerError::ExpectedString { actual, .. } => { write!(f, "Expected string, found {}", actual) } @@ -341,6 +334,31 @@ mod tests { use super::*; + #[test] + fn math_requires_same_types() { + let abstract_tree = AbstractSyntaxTree { + nodes: [Node::new( + Statement::BinaryOperation { + left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))), + operator: Node::new(BinaryOperator::Add, (1, 2)), + right: Box::new(Node::new(Statement::Constant(Value::float(1.0)), (3, 4))), + }, + (0, 2), + )] + .into(), + }; + let mut context = Context::new(); + let mut analyzer = Analyzer::new(&abstract_tree, &mut context); + + assert_eq!( + analyzer.analyze(), + Err(AnalyzerError::ExpectedInteger { + actual: Node::new(Statement::Constant(Value::float(1.0)), (3, 4)), + position: (3, 4) + }) + ) + } + #[test] fn float_plus_integer() { let abstract_tree = AbstractSyntaxTree { diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index cd19f3a..e473ab5 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -31,9 +31,13 @@ impl Context { } } - pub fn get_value(&self, identifier: &Identifier) -> Option<&Value> { - match self.variables.get(identifier) { - Some((VariableData::Value(value), _)) => Some(value), + pub fn use_value(&mut self, identifier: &Identifier) -> Option<&Value> { + match self.variables.get_mut(identifier) { + Some((VariableData::Value(value), usage_data)) => { + usage_data.used += 1; + + Some(value) + } _ => None, } } @@ -63,6 +67,16 @@ impl Context { self.variables .retain(|_, (_, usage_data)| usage_data.used < usage_data.allowed_uses); } + + pub fn add_allowed_use(&mut self, identifier: &Identifier) -> bool { + if let Some((_, usage_data)) = self.variables.get_mut(identifier) { + usage_data.allowed_uses += 1; + + true + } else { + false + } + } } impl Default for Context { diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 65577f5..2de4b9d 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -90,7 +90,7 @@ impl Vm { position: right_position, }); }; - let left_value = context.get_value(&identifier).ok_or_else(|| { + let left_value = context.use_value(&identifier).ok_or_else(|| { VmError::UndefinedVariable { identifier: Node::new( Statement::Identifier(identifier.clone()), @@ -236,7 +236,7 @@ impl Vm { Ok(function.clone().call(None, value_parameters, context)?) } Statement::Identifier(identifier) => { - if let Some(value) = context.get_value(&identifier) { + if let Some(value) = context.use_value(&identifier) { Ok(Some(value.clone())) } else { Err(VmError::UndefinedVariable { diff --git a/dust_examples/fizzbuzz.ds b/dust_examples/fizzbuzz.ds index 2fd54c0..e44083a 100644 --- a/dust_examples/fizzbuzz.ds +++ b/dust_examples/fizzbuzz.ds @@ -1,14 +1,12 @@ -use std.io - count = 1 while count <= 15 { divides_by_3 = count % 3 == 0 divides_by_5 = count % 5 == 0 - output = if divides_by_3 && divides_by_5 { + output = if divides_by_3 && divides_by_5 { 'fizzbuzz' - } else if divides_by_3 { + } else if divides_by_3 { 'fizz' } else if divides_by_5 { 'buzz' @@ -16,8 +14,7 @@ while count <= 15 { count as str } - io.write_line(output) - + write_line(output) + count += 1 } -