pub_just/
assignment_resolver.rs1use {super::*, CompileErrorKind::*};
2
3pub struct AssignmentResolver<'src: 'run, 'run> {
4 assignments: &'run Table<'src, Assignment<'src>>,
5 stack: Vec<&'src str>,
6 evaluated: BTreeSet<&'src str>,
7}
8
9impl<'src: 'run, 'run> AssignmentResolver<'src, 'run> {
10 pub fn resolve_assignments(
11 assignments: &'run Table<'src, Assignment<'src>>,
12 ) -> CompileResult<'src> {
13 let mut resolver = Self {
14 stack: Vec::new(),
15 evaluated: BTreeSet::new(),
16 assignments,
17 };
18
19 for name in assignments.keys() {
20 resolver.resolve_assignment(name)?;
21 }
22
23 Ok(())
24 }
25
26 fn resolve_assignment(&mut self, name: &'src str) -> CompileResult<'src> {
27 if self.evaluated.contains(name) {
28 return Ok(());
29 }
30
31 self.stack.push(name);
32
33 if let Some(assignment) = self.assignments.get(name) {
34 for variable in assignment.value.variables() {
35 let name = variable.lexeme();
36
37 if self.evaluated.contains(name) || constants().contains_key(name) {
38 continue;
39 }
40
41 if self.stack.contains(&name) {
42 self.stack.push(name);
43 return Err(
44 self.assignments[name]
45 .name
46 .error(CircularVariableDependency {
47 variable: name,
48 circle: self.stack.clone(),
49 }),
50 );
51 } else if self.assignments.contains_key(name) {
52 self.resolve_assignment(name)?;
53 } else {
54 return Err(variable.error(UndefinedVariable { variable: name }));
55 }
56 }
57 self.evaluated.insert(name);
58 } else {
59 let message = format!("attempted to resolve unknown assignment `{name}`");
60 let token = Token {
61 src: "",
62 offset: 0,
63 line: 0,
64 column: 0,
65 length: 0,
66 kind: TokenKind::Unspecified,
67 path: "".as_ref(),
68 };
69 return Err(CompileError::new(token, Internal { message }));
70 }
71
72 self.stack.pop();
73
74 Ok(())
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 analysis_error! {
83 name: circular_variable_dependency,
84 input: "a := b\nb := a",
85 offset: 0,
86 line: 0,
87 column: 0,
88 width: 1,
89 kind: CircularVariableDependency{variable: "a", circle: vec!["a", "b", "a"]},
90 }
91
92 analysis_error! {
93 name: self_variable_dependency,
94 input: "a := a",
95 offset: 0,
96 line: 0,
97 column: 0,
98 width: 1,
99 kind: CircularVariableDependency{variable: "a", circle: vec!["a", "a"]},
100 }
101
102 analysis_error! {
103 name: unknown_expression_variable,
104 input: "x := yy",
105 offset: 5,
106 line: 0,
107 column: 5,
108 width: 2,
109 kind: UndefinedVariable{variable: "yy"},
110 }
111
112 analysis_error! {
113 name: unknown_function_parameter,
114 input: "x := env_var(yy)",
115 offset: 13,
116 line: 0,
117 column: 13,
118 width: 2,
119 kind: UndefinedVariable{variable: "yy"},
120 }
121
122 analysis_error! {
123 name: unknown_function_parameter_binary_first,
124 input: "x := env_var_or_default(yy, 'foo')",
125 offset: 24,
126 line: 0,
127 column: 24,
128 width: 2,
129 kind: UndefinedVariable{variable: "yy"},
130 }
131
132 analysis_error! {
133 name: unknown_function_parameter_binary_second,
134 input: "x := env_var_or_default('foo', yy)",
135 offset: 31,
136 line: 0,
137 column: 31,
138 width: 2,
139 kind: UndefinedVariable{variable: "yy"},
140 }
141}