2019-04-11 15:23:14 -07:00
|
|
|
use crate::common::*;
|
2017-11-16 23:30:08 -08:00
|
|
|
|
2017-11-17 17:28:06 -08:00
|
|
|
use CompilationErrorKind::*;
|
|
|
|
|
2019-09-21 15:35:03 -07:00
|
|
|
pub(crate) struct AssignmentResolver<'a: 'b, 'b> {
|
2019-04-11 15:23:14 -07:00
|
|
|
assignments: &'b BTreeMap<&'a str, Expression<'a>>,
|
|
|
|
assignment_tokens: &'b BTreeMap<&'a str, Token<'a>>,
|
2018-12-08 14:29:41 -08:00
|
|
|
stack: Vec<&'a str>,
|
2019-04-11 15:23:14 -07:00
|
|
|
seen: BTreeSet<&'a str>,
|
|
|
|
evaluated: BTreeSet<&'a str>,
|
2017-11-16 23:30:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a: 'b, 'b> AssignmentResolver<'a, 'b> {
|
2019-09-21 15:35:03 -07:00
|
|
|
pub(crate) fn resolve_assignments(
|
2019-04-11 15:23:14 -07:00
|
|
|
assignments: &BTreeMap<&'a str, Expression<'a>>,
|
|
|
|
assignment_tokens: &BTreeMap<&'a str, Token<'a>>,
|
2017-11-18 01:18:04 -08:00
|
|
|
) -> CompilationResult<'a, ()> {
|
|
|
|
let mut resolver = AssignmentResolver {
|
2018-12-08 14:29:41 -08:00
|
|
|
stack: empty(),
|
|
|
|
seen: empty(),
|
2018-03-05 13:21:35 -08:00
|
|
|
evaluated: empty(),
|
|
|
|
assignments,
|
|
|
|
assignment_tokens,
|
2017-11-18 01:18:04 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
for name in assignments.keys() {
|
|
|
|
resolver.resolve_assignment(name)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2017-11-17 17:28:06 -08:00
|
|
|
fn resolve_assignment(&mut self, name: &'a str) -> CompilationResult<'a, ()> {
|
2017-11-16 23:30:08 -08:00
|
|
|
if self.evaluated.contains(name) {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
self.seen.insert(name);
|
|
|
|
self.stack.push(name);
|
|
|
|
|
|
|
|
if let Some(expression) = self.assignments.get(name) {
|
|
|
|
self.resolve_expression(expression)?;
|
|
|
|
self.evaluated.insert(name);
|
|
|
|
} else {
|
|
|
|
let message = format!("attempted to resolve unknown assignment `{}`", name);
|
|
|
|
return Err(CompilationError {
|
2018-12-08 14:29:41 -08:00
|
|
|
text: "",
|
2019-04-15 22:40:02 -07:00
|
|
|
offset: 0,
|
2018-12-08 14:29:41 -08:00
|
|
|
line: 0,
|
2017-11-16 23:30:08 -08:00
|
|
|
column: 0,
|
2019-04-15 22:40:02 -07:00
|
|
|
width: 0,
|
2018-12-08 14:29:41 -08:00
|
|
|
kind: Internal { message },
|
2017-11-16 23:30:08 -08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2018-12-08 14:29:41 -08:00
|
|
|
fn resolve_expression(&mut self, expression: &Expression<'a>) -> CompilationResult<'a, ()> {
|
2019-04-11 23:58:08 -07:00
|
|
|
match expression {
|
2018-12-08 14:29:41 -08:00
|
|
|
Expression::Variable { name, ref token } => {
|
2017-11-16 23:30:08 -08:00
|
|
|
if self.evaluated.contains(name) {
|
|
|
|
return Ok(());
|
|
|
|
} else if self.seen.contains(name) {
|
|
|
|
let token = &self.assignment_tokens[name];
|
|
|
|
self.stack.push(name);
|
2017-11-17 17:28:06 -08:00
|
|
|
return Err(token.error(CircularVariableDependency {
|
2017-11-16 23:30:08 -08:00
|
|
|
variable: name,
|
2018-12-08 14:29:41 -08:00
|
|
|
circle: self.stack.clone(),
|
2017-11-16 23:30:08 -08:00
|
|
|
}));
|
|
|
|
} else if self.assignments.contains_key(name) {
|
|
|
|
self.resolve_assignment(name)?;
|
|
|
|
} else {
|
2018-12-08 14:29:41 -08:00
|
|
|
return Err(token.error(UndefinedVariable { variable: name }));
|
2017-11-16 23:30:08 -08:00
|
|
|
}
|
|
|
|
}
|
2018-12-08 14:29:41 -08:00
|
|
|
Expression::Call {
|
|
|
|
ref token,
|
|
|
|
ref arguments,
|
|
|
|
..
|
2019-04-19 02:40:25 -07:00
|
|
|
} => Function::resolve(token, arguments.len())?,
|
2018-12-08 14:29:41 -08:00
|
|
|
Expression::Concatination { ref lhs, ref rhs } => {
|
2017-11-16 23:30:08 -08:00
|
|
|
self.resolve_expression(lhs)?;
|
|
|
|
self.resolve_expression(rhs)?;
|
|
|
|
}
|
2018-12-08 14:29:41 -08:00
|
|
|
Expression::String { .. } | Expression::Backtick { .. } => {}
|
2019-04-11 23:58:08 -07:00
|
|
|
Expression::Group { expression } => self.resolve_expression(expression)?,
|
2017-11-16 23:30:08 -08:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
|
2019-04-19 02:17:43 -07:00
|
|
|
error_test! {
|
2017-11-18 01:44:59 -08:00
|
|
|
name: circular_variable_dependency,
|
|
|
|
input: "a = b\nb = a",
|
2019-04-15 22:40:02 -07:00
|
|
|
offset: 0,
|
2017-11-18 01:44:59 -08:00
|
|
|
line: 0,
|
|
|
|
column: 0,
|
2019-04-15 22:40:02 -07:00
|
|
|
width: 1,
|
2017-11-18 01:44:59 -08:00
|
|
|
kind: CircularVariableDependency{variable: "a", circle: vec!["a", "b", "a"]},
|
2017-11-17 17:28:06 -08:00
|
|
|
}
|
2017-11-16 23:30:08 -08:00
|
|
|
|
2019-04-19 02:17:43 -07:00
|
|
|
error_test! {
|
2017-11-18 01:44:59 -08:00
|
|
|
name: self_variable_dependency,
|
|
|
|
input: "a = a",
|
2019-04-15 22:40:02 -07:00
|
|
|
offset: 0,
|
2017-11-18 01:44:59 -08:00
|
|
|
line: 0,
|
|
|
|
column: 0,
|
2019-04-15 22:40:02 -07:00
|
|
|
width: 1,
|
2017-11-18 01:44:59 -08:00
|
|
|
kind: CircularVariableDependency{variable: "a", circle: vec!["a", "a"]},
|
|
|
|
}
|
|
|
|
|
2019-04-19 02:17:43 -07:00
|
|
|
error_test! {
|
2017-11-18 01:44:59 -08:00
|
|
|
name: unknown_expression_variable,
|
|
|
|
input: "x = yy",
|
2019-04-15 22:40:02 -07:00
|
|
|
offset: 4,
|
2017-11-18 01:44:59 -08:00
|
|
|
line: 0,
|
|
|
|
column: 4,
|
2019-04-15 22:40:02 -07:00
|
|
|
width: 2,
|
2017-11-18 01:44:59 -08:00
|
|
|
kind: UndefinedVariable{variable: "yy"},
|
2017-11-17 17:28:06 -08:00
|
|
|
}
|
2017-12-02 05:37:10 -08:00
|
|
|
|
2019-04-19 02:17:43 -07:00
|
|
|
error_test! {
|
2017-12-02 05:37:10 -08:00
|
|
|
name: unknown_function,
|
|
|
|
input: "a = foo()",
|
2019-04-15 22:40:02 -07:00
|
|
|
offset: 4,
|
2017-12-02 05:37:10 -08:00
|
|
|
line: 0,
|
|
|
|
column: 4,
|
2019-04-15 22:40:02 -07:00
|
|
|
width: 3,
|
2017-12-02 05:37:10 -08:00
|
|
|
kind: UnknownFunction{function: "foo"},
|
|
|
|
}
|
|
|
|
|
2017-11-16 23:30:08 -08:00
|
|
|
}
|