kotoba_jsonnet/eval/
context.rs1use crate::error::{JsonnetError, Result};
4use crate::value::JsonnetValue;
5use std::collections::HashMap;
6
7#[derive(Debug, Clone)]
9pub struct Scope {
10 variables: HashMap<String, JsonnetValue>,
11}
12
13impl Scope {
14 pub fn new() -> Self {
15 Scope {
16 variables: HashMap::new(),
17 }
18 }
19
20 pub fn get(&self, name: &str) -> Option<&JsonnetValue> {
21 self.variables.get(name)
22 }
23
24 pub fn set(&mut self, name: String, value: JsonnetValue) {
25 self.variables.insert(name, value);
26 }
27
28 pub fn contains(&self, name: &str) -> bool {
29 self.variables.contains_key(name)
30 }
31
32 pub fn variables(&self) -> &HashMap<String, JsonnetValue> {
33 &self.variables
34 }
35}
36
37#[derive(Debug)]
39pub struct Context {
40 global_scope: Scope,
42 local_scopes: Vec<Scope>,
44 depth: usize,
46 max_depth: usize,
48}
49
50impl Context {
51 pub fn new() -> Self {
52 Context {
53 global_scope: Scope::new(),
54 local_scopes: Vec::new(),
55 depth: 0,
56 max_depth: 100, }
58 }
59
60 pub fn with_max_depth(max_depth: usize) -> Self {
61 Context {
62 global_scope: Scope::new(),
63 local_scopes: Vec::new(),
64 depth: 0,
65 max_depth,
66 }
67 }
68
69 pub fn depth(&self) -> usize {
71 self.depth
72 }
73
74 pub fn check_depth(&self) -> Result<()> {
76 if self.depth >= self.max_depth {
77 return Err(JsonnetError::runtime_error(
78 format!("Maximum evaluation depth ({}) exceeded", self.max_depth)
79 ));
80 }
81 Ok(())
82 }
83
84 pub fn push_depth(&mut self) -> Result<()> {
86 self.depth += 1;
87 self.check_depth()
88 }
89
90 pub fn pop_depth(&mut self) {
92 if self.depth > 0 {
93 self.depth -= 1;
94 }
95 }
96
97 pub fn get_variable(&self, name: &str) -> Option<&JsonnetValue> {
99 for scope in self.local_scopes.iter().rev() {
101 if let Some(value) = scope.get(name) {
102 return Some(value);
103 }
104 }
105 self.global_scope.get(name)
107 }
108
109 pub fn set_variable(&mut self, name: String, value: JsonnetValue) {
111 if let Some(scope) = self.local_scopes.last_mut() {
112 scope.set(name, value);
113 } else {
114 self.global_scope.set(name, value);
115 }
116 }
117
118 pub fn set_global(&mut self, name: String, value: JsonnetValue) {
120 self.global_scope.set(name, value);
121 }
122
123 pub fn has_variable(&self, name: &str) -> bool {
125 for scope in self.local_scopes.iter().rev() {
127 if scope.contains(name) {
128 return true;
129 }
130 }
131 self.global_scope.contains(name)
133 }
134
135 pub fn push_scope(&mut self) {
137 self.local_scopes.push(Scope::new());
138 }
139
140 pub fn pop_scope(&mut self) -> Option<Scope> {
142 self.local_scopes.pop()
143 }
144
145 pub fn current_scope(&mut self) -> Option<&mut Scope> {
147 self.local_scopes.last_mut()
148 }
149
150 pub fn global_scope(&self) -> &Scope {
152 &self.global_scope
153 }
154
155 pub fn global_scope_mut(&mut self) -> &mut Scope {
157 &mut self.global_scope
158 }
159
160 pub fn all_variables(&self) -> HashMap<String, &JsonnetValue> {
162 let mut result = HashMap::new();
163
164 for (name, value) in self.global_scope.variables() {
166 result.insert(name.clone(), value);
167 }
168
169 for scope in &self.local_scopes {
171 for (name, value) in scope.variables() {
172 result.insert(name.clone(), value);
173 }
174 }
175
176 result
177 }
178
179 pub fn fork(&self) -> Self {
181 Context {
182 global_scope: self.global_scope.clone(),
183 local_scopes: Vec::new(),
184 depth: 0,
185 max_depth: self.max_depth,
186 }
187 }
188
189 pub fn merge_locals_to_global(&mut self) {
191 for scope in &self.local_scopes {
192 for (name, value) in scope.variables() {
193 self.global_scope.set(name.clone(), value.clone());
194 }
195 }
196 self.local_scopes.clear();
197 }
198}
199
200impl Default for Context {
201 fn default() -> Self {
202 Self::new()
203 }
204}