Add new analyzer and vm tests
This commit is contained in:
parent
f2c0786bfb
commit
78228ce8d6
@ -220,7 +220,6 @@ impl<'a> Analyzer<'a> {
|
||||
} else {
|
||||
return Err(AnalyzerError::ExpectedBoolean {
|
||||
actual: condition.as_ref().clone(),
|
||||
position: condition.position,
|
||||
});
|
||||
}
|
||||
|
||||
@ -238,7 +237,6 @@ impl<'a> Analyzer<'a> {
|
||||
} else {
|
||||
return Err(AnalyzerError::ExpectedBoolean {
|
||||
actual: condition.as_ref().clone(),
|
||||
position: condition.position,
|
||||
});
|
||||
}
|
||||
|
||||
@ -257,7 +255,6 @@ impl<'a> Analyzer<'a> {
|
||||
} else {
|
||||
return Err(AnalyzerError::ExpectedBoolean {
|
||||
actual: condition.as_ref().clone(),
|
||||
position: condition.position,
|
||||
});
|
||||
}
|
||||
|
||||
@ -271,7 +268,6 @@ impl<'a> Analyzer<'a> {
|
||||
} else {
|
||||
return Err(AnalyzerError::ExpectedBoolean {
|
||||
actual: condition.clone(),
|
||||
position: condition.position,
|
||||
});
|
||||
}
|
||||
|
||||
@ -291,7 +287,6 @@ impl<'a> Analyzer<'a> {
|
||||
} else {
|
||||
return Err(AnalyzerError::ExpectedBoolean {
|
||||
actual: condition.as_ref().clone(),
|
||||
position: condition.position,
|
||||
});
|
||||
}
|
||||
|
||||
@ -305,7 +300,6 @@ impl<'a> Analyzer<'a> {
|
||||
} else {
|
||||
return Err(AnalyzerError::ExpectedBoolean {
|
||||
actual: condition.clone(),
|
||||
position: condition.position,
|
||||
});
|
||||
}
|
||||
|
||||
@ -328,13 +322,20 @@ impl<'a> Analyzer<'a> {
|
||||
self.analyze_node(node)?;
|
||||
}
|
||||
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::Integer) = right.inner.expected_type(self.context) {
|
||||
// Allow indexing lists with integers
|
||||
} else {
|
||||
return Err(AnalyzerError::ExpectedInteger {
|
||||
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 } => {
|
||||
self.analyze_node(condition)?;
|
||||
@ -362,7 +360,6 @@ impl<'a> Analyzer<'a> {
|
||||
} else {
|
||||
return Err(AnalyzerError::ExpectedBoolean {
|
||||
actual: condition.as_ref().clone(),
|
||||
position: condition.position,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -376,18 +373,15 @@ impl<'a> Analyzer<'a> {
|
||||
pub enum AnalyzerError {
|
||||
ExpectedBoolean {
|
||||
actual: Node<Statement>,
|
||||
position: Span,
|
||||
},
|
||||
ExpectedIdentifier {
|
||||
actual: Node<Statement>,
|
||||
position: Span,
|
||||
},
|
||||
ExpectedIdentifierOrString {
|
||||
actual: Node<Statement>,
|
||||
},
|
||||
ExpectedInteger {
|
||||
actual: Node<Statement>,
|
||||
position: Span,
|
||||
},
|
||||
ExpectedValue {
|
||||
actual: Node<Statement>,
|
||||
@ -416,10 +410,10 @@ pub enum AnalyzerError {
|
||||
impl AnalyzerError {
|
||||
pub fn position(&self) -> Span {
|
||||
match self {
|
||||
AnalyzerError::ExpectedBoolean { position, .. } => *position,
|
||||
AnalyzerError::ExpectedIdentifier { position, .. } => *position,
|
||||
AnalyzerError::ExpectedBoolean { actual, .. } => actual.position,
|
||||
AnalyzerError::ExpectedIdentifier { actual, .. } => actual.position,
|
||||
AnalyzerError::ExpectedIdentifierOrString { actual } => actual.position,
|
||||
AnalyzerError::ExpectedInteger { position, .. } => *position,
|
||||
AnalyzerError::ExpectedInteger { actual, .. } => actual.position,
|
||||
AnalyzerError::ExpectedValue { actual } => actual.position,
|
||||
AnalyzerError::ExpectedValueArgumentCount { position, .. } => *position,
|
||||
AnalyzerError::TypeConflict {
|
||||
@ -485,6 +479,36 @@ mod tests {
|
||||
|
||||
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]
|
||||
fn length_no_arguments() {
|
||||
let source = "length()";
|
||||
|
@ -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> {
|
||||
if let ValueInner::Integer(integer) = self.inner().as_ref() {
|
||||
Some(*integer)
|
||||
|
@ -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 {
|
||||
position: right_span,
|
||||
})
|
||||
@ -623,6 +631,27 @@ impl Display for VmError {
|
||||
mod tests {
|
||||
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]
|
||||
fn to_string() {
|
||||
let input = "to_string(42)";
|
||||
|
Loading…
Reference in New Issue
Block a user