Add new analyzer and vm tests

This commit is contained in:
Jeff 2024-08-11 22:02:17 -04:00
parent f2c0786bfb
commit 78228ce8d6
3 changed files with 78 additions and 17 deletions

View File

@ -220,7 +220,6 @@ impl<'a> Analyzer<'a> {
} else { } else {
return Err(AnalyzerError::ExpectedBoolean { return Err(AnalyzerError::ExpectedBoolean {
actual: condition.as_ref().clone(), actual: condition.as_ref().clone(),
position: condition.position,
}); });
} }
@ -238,7 +237,6 @@ impl<'a> Analyzer<'a> {
} else { } else {
return Err(AnalyzerError::ExpectedBoolean { return Err(AnalyzerError::ExpectedBoolean {
actual: condition.as_ref().clone(), actual: condition.as_ref().clone(),
position: condition.position,
}); });
} }
@ -257,7 +255,6 @@ impl<'a> Analyzer<'a> {
} else { } else {
return Err(AnalyzerError::ExpectedBoolean { return Err(AnalyzerError::ExpectedBoolean {
actual: condition.as_ref().clone(), actual: condition.as_ref().clone(),
position: condition.position,
}); });
} }
@ -271,7 +268,6 @@ impl<'a> Analyzer<'a> {
} else { } else {
return Err(AnalyzerError::ExpectedBoolean { return Err(AnalyzerError::ExpectedBoolean {
actual: condition.clone(), actual: condition.clone(),
position: condition.position,
}); });
} }
@ -291,7 +287,6 @@ impl<'a> Analyzer<'a> {
} else { } else {
return Err(AnalyzerError::ExpectedBoolean { return Err(AnalyzerError::ExpectedBoolean {
actual: condition.as_ref().clone(), actual: condition.as_ref().clone(),
position: condition.position,
}); });
} }
@ -305,7 +300,6 @@ impl<'a> Analyzer<'a> {
} else { } else {
return Err(AnalyzerError::ExpectedBoolean { return Err(AnalyzerError::ExpectedBoolean {
actual: condition.clone(), actual: condition.clone(),
position: condition.position,
}); });
} }
@ -328,13 +322,20 @@ impl<'a> Analyzer<'a> {
self.analyze_node(node)?; self.analyze_node(node)?;
} }
Statement::PropertyAccess(left, right) => { Statement::PropertyAccess(left, right) => {
self.analyze_node(left)?;
if let Statement::Identifier(_) = right.inner {
// Do not expect a value for property accessors
} else {
self.analyze_node(right)?;
}
if let Some(Type::List { .. }) = left.inner.expected_type(self.context) { if let Some(Type::List { .. }) = left.inner.expected_type(self.context) {
if let Some(Type::Integer) = right.inner.expected_type(self.context) { if let Some(Type::Integer) = right.inner.expected_type(self.context) {
// Allow indexing lists with integers // Allow indexing lists with integers
} else { } else {
return Err(AnalyzerError::ExpectedInteger { return Err(AnalyzerError::ExpectedInteger {
actual: right.as_ref().clone(), actual: right.as_ref().clone(),
position: right.position,
}); });
} }
} }
@ -350,9 +351,6 @@ impl<'a> Analyzer<'a> {
}); });
} }
} }
self.analyze_node(left)?;
self.analyze_node(right)?;
} }
Statement::While { condition, body } => { Statement::While { condition, body } => {
self.analyze_node(condition)?; self.analyze_node(condition)?;
@ -362,7 +360,6 @@ impl<'a> Analyzer<'a> {
} else { } else {
return Err(AnalyzerError::ExpectedBoolean { return Err(AnalyzerError::ExpectedBoolean {
actual: condition.as_ref().clone(), actual: condition.as_ref().clone(),
position: condition.position,
}); });
} }
} }
@ -376,18 +373,15 @@ impl<'a> Analyzer<'a> {
pub enum AnalyzerError { pub enum AnalyzerError {
ExpectedBoolean { ExpectedBoolean {
actual: Node<Statement>, actual: Node<Statement>,
position: Span,
}, },
ExpectedIdentifier { ExpectedIdentifier {
actual: Node<Statement>, actual: Node<Statement>,
position: Span,
}, },
ExpectedIdentifierOrString { ExpectedIdentifierOrString {
actual: Node<Statement>, actual: Node<Statement>,
}, },
ExpectedInteger { ExpectedInteger {
actual: Node<Statement>, actual: Node<Statement>,
position: Span,
}, },
ExpectedValue { ExpectedValue {
actual: Node<Statement>, actual: Node<Statement>,
@ -416,10 +410,10 @@ pub enum AnalyzerError {
impl AnalyzerError { impl AnalyzerError {
pub fn position(&self) -> Span { pub fn position(&self) -> Span {
match self { match self {
AnalyzerError::ExpectedBoolean { position, .. } => *position, AnalyzerError::ExpectedBoolean { actual, .. } => actual.position,
AnalyzerError::ExpectedIdentifier { position, .. } => *position, AnalyzerError::ExpectedIdentifier { actual, .. } => actual.position,
AnalyzerError::ExpectedIdentifierOrString { actual } => actual.position, AnalyzerError::ExpectedIdentifierOrString { actual } => actual.position,
AnalyzerError::ExpectedInteger { position, .. } => *position, AnalyzerError::ExpectedInteger { actual, .. } => actual.position,
AnalyzerError::ExpectedValue { actual } => actual.position, AnalyzerError::ExpectedValue { actual } => actual.position,
AnalyzerError::ExpectedValueArgumentCount { position, .. } => *position, AnalyzerError::ExpectedValueArgumentCount { position, .. } => *position,
AnalyzerError::TypeConflict { AnalyzerError::TypeConflict {
@ -485,6 +479,36 @@ mod tests {
use super::*; use super::*;
#[test]
fn malformed_list_index() {
let source = "[1, 2, 3].foo";
assert_eq!(
analyze(source),
Err(DustError::AnalyzerError {
analyzer_error: AnalyzerError::ExpectedInteger {
actual: Node::new(Statement::Identifier(Identifier::new("foo")), (10, 13)),
},
source
})
);
}
#[test]
fn malformed_property_access() {
let source = "{ x = 1 }.0";
assert_eq!(
analyze(source),
Err(DustError::AnalyzerError {
analyzer_error: AnalyzerError::ExpectedIdentifierOrString {
actual: Node::new(Statement::Constant(Value::integer(0)), (10, 11)),
},
source
})
);
}
#[test] #[test]
fn length_no_arguments() { fn length_no_arguments() {
let source = "length()"; let source = "length()";

View File

@ -121,6 +121,14 @@ impl Value {
} }
} }
pub fn as_map(&self) -> Option<&BTreeMap<Identifier, Value>> {
if let ValueInner::Map(map) = self.inner().as_ref() {
Some(map)
} else {
None
}
}
pub fn as_integer(&self) -> Option<i64> { pub fn as_integer(&self) -> Option<i64> {
if let ValueInner::Integer(integer) = self.inner().as_ref() { if let ValueInner::Integer(integer) = self.inner().as_ref() {
Some(*integer) Some(*integer)

View File

@ -463,6 +463,14 @@ impl Vm {
} }
} }
if let (Some(map), Statement::Identifier(identifier)) =
(left_value.as_map(), &right.inner)
{
let value = map.get(identifier).cloned();
return Ok(value);
}
Err(VmError::ExpectedIdentifierOrInteger { Err(VmError::ExpectedIdentifierOrInteger {
position: right_span, position: right_span,
}) })
@ -623,6 +631,27 @@ impl Display for VmError {
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn list_index() {
let input = "[1, 42, 3].1";
assert_eq!(run(input), Ok(Some(Value::integer(42))));
}
#[test]
fn map_property_access() {
let input = "{ a = 42 }.a";
assert_eq!(run(input), Ok(Some(Value::integer(42))));
}
#[test]
fn built_in_function_dot_notation() {
let input = "42.to_string()";
assert_eq!(run(input), Ok(Some(Value::string("42"))));
}
#[test] #[test]
fn to_string() { fn to_string() {
let input = "to_string(42)"; let input = "to_string(42)";