fork of https://github.com/tree-sitter/tree-sitter-graph
1// -*- coding: utf-8 -*-
2// ------------------------------------------------------------------------------------------------
3// Copyright © 2021, tree-sitter authors.
4// Licensed under either of Apache License, Version 2.0, or MIT license, at your option.
5// Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details.
6// ------------------------------------------------------------------------------------------------
7
8use std::collections::BTreeSet;
9use std::collections::HashMap;
10use std::collections::HashSet;
11use streaming_iterator::StreamingIterator;
12use tree_sitter::QueryCursor;
13use tree_sitter::QueryMatch;
14use tree_sitter::Tree;
15
16use crate::ast::AddEdgeAttribute;
17use crate::ast::AddGraphNodeAttribute;
18use crate::ast::Assign;
19use crate::ast::ExpressionStatement;
20use crate::ast::Attribute;
21use crate::ast::AttributeShorthand;
22use crate::ast::AttributeShorthands;
23use crate::ast::Call;
24use crate::ast::Capture;
25use crate::ast::Condition;
26use crate::ast::CreateEdge;
27use crate::ast::CreateGraphNode;
28use crate::ast::DeclareImmutable;
29use crate::ast::DeclareMutable;
30use crate::ast::Expression;
31use crate::ast::File;
32use crate::ast::ForIn;
33use crate::ast::If;
34use crate::ast::IntegerConstant;
35use crate::ast::ListComprehension;
36use crate::ast::ListLiteral;
37use crate::ast::Print;
38use crate::ast::RegexCapture;
39use crate::ast::Scan;
40use crate::ast::ScopedVariable;
41use crate::ast::SetComprehension;
42use crate::ast::SetLiteral;
43use crate::ast::Stanza;
44use crate::ast::Statement;
45use crate::ast::StringConstant;
46use crate::ast::UnscopedVariable;
47use crate::ast::Variable;
48use crate::execution::error::ExecutionError;
49use crate::execution::error::ResultWithExecutionError;
50use crate::execution::error::StatementContext;
51use crate::execution::CancellationFlag;
52use crate::execution::ExecutionConfig;
53use crate::graph::Graph;
54use crate::graph::SyntaxNodeID;
55use crate::graph::SyntaxNodeRef;
56use crate::graph::Value;
57use crate::variables::Globals;
58use crate::variables::MutVariables;
59use crate::variables::VariableMap;
60use crate::variables::Variables;
61use crate::Identifier;
62use crate::Location;
63
64impl File {
65 /// Executes this graph DSL file against a source file, saving the results into an existing
66 /// `Graph` instance. You must provide the parsed syntax tree (`tree`) as well as the source
67 /// text that it was parsed from (`source`). You also provide the set of functions and global
68 /// variables that are available during execution. This variant is useful when you need to
69 /// “pre-seed” the graph with some predefined nodes and/or edges before executing the DSL file.
70 pub(super) fn execute_strict_into<'a, 'tree>(
71 &self,
72 graph: &mut Graph<'tree>,
73 tree: &'tree Tree,
74 source: &'tree str,
75 config: &ExecutionConfig,
76 cancellation_flag: &dyn CancellationFlag,
77 ) -> Result<(), ExecutionError> {
78 let mut globals = Globals::nested(config.globals);
79 self.check_globals(&mut globals)?;
80 let mut config = ExecutionConfig {
81 functions: config.functions,
82 globals: &globals,
83 lazy: config.lazy,
84 location_attr: config.location_attr.clone(),
85 variable_name_attr: config.variable_name_attr.clone(),
86 match_node_attr: config.match_node_attr.clone(),
87 };
88
89 let mut locals = VariableMap::new();
90 let mut scoped = ScopedVariables::new();
91 let current_regex_captures = Vec::new();
92 let mut function_parameters = Vec::new();
93
94 self.try_visit_matches_strict(tree, source, |stanza, mat| {
95 stanza.execute(
96 source,
97 &mat,
98 graph,
99 &mut config,
100 &mut locals,
101 &mut scoped,
102 ¤t_regex_captures,
103 &mut function_parameters,
104 &self.inherited_variables,
105 &self.shorthands,
106 cancellation_flag,
107 )
108 })?;
109
110 Ok(())
111 }
112
113 pub(super) fn try_visit_matches_strict<'tree, E, F>(
114 &self,
115 tree: &'tree Tree,
116 source: &'tree str,
117 mut visit: F,
118 ) -> Result<(), E>
119 where
120 F: FnMut(&Stanza, &QueryMatch<'_, 'tree>) -> Result<(), E>,
121 {
122 for stanza in &self.stanzas {
123 stanza.try_visit_matches_strict(tree, source, |mat| visit(stanza, mat))?;
124 }
125 Ok(())
126 }
127}
128
129/// State that is threaded through the execution
130struct ExecutionContext<'a, 'c, 'g, 's, 'tree> {
131 source: &'tree str,
132 graph: &'a mut Graph<'tree>,
133 config: &'a ExecutionConfig<'c, 'g>,
134 locals: &'a mut dyn MutVariables<Value>,
135 scoped: &'a mut ScopedVariables<'s>,
136 current_regex_captures: &'a Vec<String>,
137 function_parameters: &'a mut Vec<Value>,
138 mat: &'a QueryMatch<'a, 'tree>,
139 full_match_stanza_capture_index: usize,
140 error_context: StatementContext,
141 inherited_variables: &'a HashSet<Identifier>,
142 shorthands: &'a AttributeShorthands,
143 cancellation_flag: &'a dyn CancellationFlag,
144}
145
146struct ScopedVariables<'a> {
147 scopes: HashMap<SyntaxNodeID, VariableMap<'a, Value>>,
148}
149
150impl<'a> ScopedVariables<'a> {
151 fn new() -> Self {
152 Self {
153 scopes: HashMap::new(),
154 }
155 }
156
157 fn get_mut(&mut self, scope: SyntaxNodeRef) -> &mut VariableMap<'a, Value> {
158 self.scopes.entry(scope.index).or_insert(VariableMap::new())
159 }
160
161 fn try_get(&self, index: SyntaxNodeID) -> Option<&VariableMap<'a, Value>> {
162 self.scopes.get(&index)
163 }
164}
165
166impl Stanza {
167 fn execute<'a, 'g, 'l, 's, 'tree>(
168 &self,
169 source: &'tree str,
170 mat: &QueryMatch<'_, 'tree>,
171 graph: &mut Graph<'tree>,
172 config: &ExecutionConfig<'_, 'g>,
173 locals: &mut VariableMap<'l, Value>,
174 scoped: &mut ScopedVariables<'s>,
175 current_regex_captures: &Vec<String>,
176 function_parameters: &mut Vec<Value>,
177 inherited_variables: &HashSet<Identifier>,
178 shorthands: &AttributeShorthands,
179 cancellation_flag: &dyn CancellationFlag,
180 ) -> Result<(), ExecutionError> {
181 locals.clear();
182 for statement in &self.statements {
183 let error_context = {
184 let node = mat
185 .nodes_for_capture_index(self.full_match_stanza_capture_index as u32)
186 .next()
187 .expect("missing full capture");
188 StatementContext::new(&statement, &self, &node)
189 };
190 let mut exec = ExecutionContext {
191 source,
192 graph,
193 config,
194 locals,
195 scoped,
196 current_regex_captures,
197 function_parameters,
198 mat: &mat,
199 full_match_stanza_capture_index: self.full_match_stanza_capture_index,
200 error_context,
201 inherited_variables,
202 shorthands,
203 cancellation_flag,
204 };
205 statement
206 .execute(&mut exec)
207 .with_context(|| exec.error_context.into())?;
208 }
209 Ok(())
210 }
211
212 pub(super) fn try_visit_matches_strict<'tree, E, F>(
213 &self,
214 tree: &'tree Tree,
215 source: &'tree str,
216 mut visit: F,
217 ) -> Result<(), E>
218 where
219 F: FnMut(&QueryMatch<'_, 'tree>) -> Result<(), E>,
220 {
221 let mut cursor = QueryCursor::new();
222 let mut matches = cursor.matches(&self.query, tree.root_node(), source.as_bytes());
223 while let Some(mat) = matches.next() {
224 visit(mat)?;
225 }
226 Ok(())
227 }
228}
229
230impl Statement {
231 pub fn location(&self) -> Location {
232 match self {
233 Statement::DeclareImmutable(s) => s.location,
234 Statement::DeclareMutable(s) => s.location,
235 Statement::Assign(s) => s.location,
236 Statement::Expr(s) => s.location,
237 Statement::CreateGraphNode(s) => s.location,
238 Statement::AddGraphNodeAttribute(s) => s.location,
239 Statement::CreateEdge(s) => s.location,
240 Statement::AddEdgeAttribute(s) => s.location,
241 Statement::Scan(s) => s.location,
242 Statement::Print(s) => s.location,
243 Statement::If(s) => s.location,
244 Statement::ForIn(s) => s.location,
245 }
246 }
247
248 fn execute(&self, exec: &mut ExecutionContext) -> Result<(), ExecutionError> {
249 exec.cancellation_flag.check("executing statement")?;
250 match self {
251 Statement::DeclareImmutable(statement) => statement.execute(exec),
252 Statement::DeclareMutable(statement) => statement.execute(exec),
253 Statement::Assign(statement) => statement.execute(exec),
254 Statement::Expr(statement) => statement.execute(exec),
255 Statement::CreateGraphNode(statement) => statement.execute(exec),
256 Statement::AddGraphNodeAttribute(statement) => statement.execute(exec),
257 Statement::CreateEdge(statement) => statement.execute(exec),
258 Statement::AddEdgeAttribute(statement) => statement.execute(exec),
259 Statement::Scan(statement) => statement.execute(exec),
260 Statement::Print(statement) => statement.execute(exec),
261 Statement::If(statement) => statement.execute(exec),
262 Statement::ForIn(statement) => statement.execute(exec),
263 }
264 }
265}
266
267impl DeclareImmutable {
268 fn execute(&self, exec: &mut ExecutionContext) -> Result<(), ExecutionError> {
269 let value = self.value.evaluate(exec)?;
270 self.variable.add(exec, value, false)
271 }
272}
273
274impl DeclareMutable {
275 fn execute(&self, exec: &mut ExecutionContext) -> Result<(), ExecutionError> {
276 let value = self.value.evaluate(exec)?;
277 self.variable.add(exec, value, true)
278 }
279}
280
281impl Assign {
282 fn execute(&self, exec: &mut ExecutionContext) -> Result<(), ExecutionError> {
283 let value = self.value.evaluate(exec)?;
284 self.variable.set(exec, value)
285 }
286}
287
288impl ExpressionStatement {
289 fn execute(&self, exec: &mut ExecutionContext) -> Result<(), ExecutionError> {
290 self.value.evaluate(exec).map(|_| ())
291 }
292}
293
294impl CreateGraphNode {
295 fn execute(&self, exec: &mut ExecutionContext) -> Result<(), ExecutionError> {
296 let graph_node = exec.graph.add_graph_node();
297 self.node
298 .add_debug_attrs(&mut exec.graph[graph_node].attributes, exec.config)?;
299 if let Some(match_node_attr) = &exec.config.match_node_attr {
300 let match_node = exec
301 .mat
302 .nodes_for_capture_index(exec.full_match_stanza_capture_index as u32)
303 .next()
304 .expect("missing capture for full match");
305 let syn_node = exec.graph.add_syntax_node(match_node);
306 exec.graph[graph_node]
307 .attributes
308 .add(match_node_attr.clone(), syn_node)
309 .map_err(|_| {
310 ExecutionError::DuplicateAttribute(format!(
311 " {} on graph node ({}) in {}",
312 match_node_attr, graph_node, self,
313 ))
314 })?;
315 }
316 let value = Value::GraphNode(graph_node);
317 self.node.add(exec, value, false)
318 }
319}
320
321impl AddGraphNodeAttribute {
322 fn execute(&self, exec: &mut ExecutionContext) -> Result<(), ExecutionError> {
323 let node = self.node.evaluate(exec)?.into_graph_node_ref()?;
324 let add_attribute = |exec: &mut ExecutionContext, name: Identifier, value: Value| {
325 exec.graph[node]
326 .attributes
327 .add(name.clone(), value)
328 .map_err(|_| {
329 ExecutionError::DuplicateAttribute(format!(
330 " {} on graph node ({}) in {}",
331 name, node, self,
332 ))
333 })
334 };
335 for attribute in &self.attributes {
336 attribute.execute(exec, &add_attribute)?;
337 }
338 Ok(())
339 }
340}
341
342impl CreateEdge {
343 fn execute(&self, exec: &mut ExecutionContext) -> Result<(), ExecutionError> {
344 let source = self.source.evaluate(exec)?.into_graph_node_ref()?;
345 let sink = self.sink.evaluate(exec)?.into_graph_node_ref()?;
346 let edge = match exec.graph[source].add_edge(sink) {
347 Ok(edge) | Err(edge) => edge,
348 };
349 self.add_debug_attrs(&mut edge.attributes, exec.config)?;
350 Ok(())
351 }
352}
353
354impl AddEdgeAttribute {
355 fn execute(&self, exec: &mut ExecutionContext) -> Result<(), ExecutionError> {
356 let source = self.source.evaluate(exec)?.into_graph_node_ref()?;
357 let sink = self.sink.evaluate(exec)?.into_graph_node_ref()?;
358 let add_attribute = |exec: &mut ExecutionContext, name: Identifier, value: Value| {
359 let edge = match exec.graph[source].get_edge_mut(sink) {
360 Some(edge) => Ok(edge),
361 None => Err(ExecutionError::UndefinedEdge(format!(
362 "({} -> {}) in {}",
363 source, sink, self,
364 ))),
365 }?;
366 edge.attributes.add(name.clone(), value).map_err(|_| {
367 ExecutionError::DuplicateAttribute(format!(
368 " {} on edge ({} -> {}) in {}",
369 name, source, sink, self,
370 ))
371 })
372 };
373 for attribute in &self.attributes {
374 attribute.execute(exec, &add_attribute)?;
375 }
376 Ok(())
377 }
378}
379
380impl Scan {
381 fn execute(&self, exec: &mut ExecutionContext) -> Result<(), ExecutionError> {
382 let match_string = self.value.evaluate(exec)?.into_string()?;
383
384 let mut i = 0;
385 let mut matches = Vec::new();
386 while i < match_string.len() {
387 exec.cancellation_flag.check("processing scan matches")?;
388 matches.clear();
389 for (index, arm) in self.arms.iter().enumerate() {
390 let captures = arm.regex.captures(&match_string[i..]);
391 if let Some(captures) = captures {
392 if captures
393 .get(0)
394 .expect("missing regex capture")
395 .range()
396 .is_empty()
397 {
398 return Err(ExecutionError::EmptyRegexCapture(format!(
399 "for regular expression /{}/",
400 arm.regex
401 )));
402 }
403 matches.push((captures, index));
404 }
405 }
406
407 if matches.is_empty() {
408 return Ok(());
409 }
410
411 matches.sort_by_key(|(captures, index)| {
412 let range = captures.get(0).expect("missing regex capture").range();
413 (range.start, *index)
414 });
415
416 let (regex_captures, block_index) = &matches[0];
417 let arm = &self.arms[*block_index];
418
419 let mut current_regex_captures = Vec::new();
420 for regex_capture in regex_captures.iter() {
421 current_regex_captures
422 .push(regex_capture.map(|m| m.as_str()).unwrap_or("").to_string());
423 }
424
425 let mut arm_locals = VariableMap::nested(exec.locals);
426 let mut arm_exec = ExecutionContext {
427 source: exec.source,
428 graph: exec.graph,
429 config: exec.config,
430 locals: &mut arm_locals,
431 scoped: exec.scoped,
432 current_regex_captures: ¤t_regex_captures,
433 function_parameters: exec.function_parameters,
434 mat: exec.mat,
435 full_match_stanza_capture_index: exec.full_match_stanza_capture_index,
436 error_context: exec.error_context.clone(),
437 inherited_variables: exec.inherited_variables,
438 shorthands: exec.shorthands,
439 cancellation_flag: exec.cancellation_flag,
440 };
441
442 for statement in &arm.statements {
443 arm_exec.error_context.update_statement(statement);
444 statement
445 .execute(&mut arm_exec)
446 .with_context(|| {
447 format!("matching {} with arm \"{}\"", match_string, arm.regex,).into()
448 })
449 .with_context(|| arm_exec.error_context.clone().into())?;
450 }
451
452 i += regex_captures
453 .get(0)
454 .expect("missing regex capture")
455 .range()
456 .end;
457 }
458
459 Ok(())
460 }
461}
462
463impl Print {
464 fn execute(&self, exec: &mut ExecutionContext) -> Result<(), ExecutionError> {
465 for value in &self.values {
466 if let Expression::StringConstant(expr) = value {
467 eprint!("{}", expr.value);
468 } else {
469 let value = value.evaluate(exec)?;
470 eprint!("{:?}", value);
471 }
472 }
473 eprintln!();
474 Ok(())
475 }
476}
477
478impl If {
479 fn execute(&self, exec: &mut ExecutionContext) -> Result<(), ExecutionError> {
480 for arm in &self.arms {
481 let mut result = true;
482 for condition in &arm.conditions {
483 result &= condition.test(exec)?;
484 }
485 if result {
486 let mut arm_locals = VariableMap::nested(exec.locals);
487 let mut arm_exec = ExecutionContext {
488 source: exec.source,
489 graph: exec.graph,
490 config: exec.config,
491 locals: &mut arm_locals,
492 scoped: exec.scoped,
493 current_regex_captures: exec.current_regex_captures,
494 function_parameters: exec.function_parameters,
495 mat: exec.mat,
496 full_match_stanza_capture_index: exec.full_match_stanza_capture_index,
497 error_context: exec.error_context.clone(),
498 inherited_variables: exec.inherited_variables,
499 shorthands: exec.shorthands,
500 cancellation_flag: exec.cancellation_flag,
501 };
502 for stmt in &arm.statements {
503 arm_exec.error_context.update_statement(stmt);
504 stmt.execute(&mut arm_exec)
505 .with_context(|| arm_exec.error_context.clone().into())?;
506 }
507 break;
508 }
509 }
510 Ok(())
511 }
512}
513
514impl Condition {
515 fn test(&self, exec: &mut ExecutionContext) -> Result<bool, ExecutionError> {
516 match self {
517 Condition::Some { value, .. } => Ok(!value.evaluate(exec)?.is_null()),
518 Condition::None { value, .. } => Ok(value.evaluate(exec)?.is_null()),
519 Condition::Bool { value, .. } => Ok(value.evaluate(exec)?.into_boolean()?),
520 }
521 }
522}
523
524impl ForIn {
525 fn execute(&self, exec: &mut ExecutionContext) -> Result<(), ExecutionError> {
526 let values = self.value.evaluate(exec)?.into_list()?;
527 let mut loop_locals = VariableMap::nested(exec.locals);
528 for value in values {
529 loop_locals.clear();
530 let mut loop_exec = ExecutionContext {
531 source: exec.source,
532 graph: exec.graph,
533 config: exec.config,
534 locals: &mut loop_locals,
535 scoped: exec.scoped,
536 current_regex_captures: exec.current_regex_captures,
537 function_parameters: exec.function_parameters,
538 mat: exec.mat,
539 full_match_stanza_capture_index: exec.full_match_stanza_capture_index,
540 error_context: exec.error_context.clone(),
541 inherited_variables: exec.inherited_variables,
542 shorthands: exec.shorthands,
543 cancellation_flag: exec.cancellation_flag,
544 };
545 self.variable.add(&mut loop_exec, value, false)?;
546 for stmt in &self.statements {
547 loop_exec.error_context.update_statement(stmt);
548 stmt.execute(&mut loop_exec)
549 .with_context(|| loop_exec.error_context.clone().into())?;
550 }
551 }
552 Ok(())
553 }
554}
555
556impl Expression {
557 fn evaluate(&self, exec: &mut ExecutionContext) -> Result<Value, ExecutionError> {
558 match self {
559 Expression::FalseLiteral => Ok(Value::Boolean(false)),
560 Expression::NullLiteral => Ok(Value::Null),
561 Expression::TrueLiteral => Ok(Value::Boolean(true)),
562 Expression::IntegerConstant(expr) => expr.evaluate(exec),
563 Expression::StringConstant(expr) => expr.evaluate(exec),
564 Expression::ListLiteral(expr) => expr.evaluate(exec),
565 Expression::SetLiteral(expr) => expr.evaluate(exec),
566 Expression::ListComprehension(expr) => expr.evaluate(exec),
567 Expression::SetComprehension(expr) => expr.evaluate(exec),
568 Expression::Capture(expr) => expr.evaluate(exec),
569 Expression::Variable(expr) => expr.evaluate(exec),
570 Expression::Call(expr) => expr.evaluate(exec),
571 Expression::RegexCapture(expr) => expr.evaluate(exec),
572 }
573 }
574}
575
576impl IntegerConstant {
577 fn evaluate(&self, _exec: &mut ExecutionContext) -> Result<Value, ExecutionError> {
578 Ok(Value::Integer(self.value))
579 }
580}
581
582impl StringConstant {
583 fn evaluate(&self, _exec: &mut ExecutionContext) -> Result<Value, ExecutionError> {
584 Ok(Value::String(self.value.clone()))
585 }
586}
587
588impl ListLiteral {
589 fn evaluate(&self, exec: &mut ExecutionContext) -> Result<Value, ExecutionError> {
590 let elements = self
591 .elements
592 .iter()
593 .map(|e| e.evaluate(exec))
594 .collect::<Result<_, _>>()?;
595 Ok(Value::List(elements))
596 }
597}
598
599impl ListComprehension {
600 fn evaluate(&self, exec: &mut ExecutionContext) -> Result<Value, ExecutionError> {
601 let values = self.value.evaluate(exec)?.into_list()?;
602 let mut elements = Vec::new();
603 let mut loop_locals = VariableMap::nested(exec.locals);
604 for value in values {
605 loop_locals.clear();
606 let mut loop_exec = ExecutionContext {
607 source: exec.source,
608 graph: exec.graph,
609 config: exec.config,
610 locals: &mut loop_locals,
611 scoped: exec.scoped,
612 current_regex_captures: exec.current_regex_captures,
613 function_parameters: exec.function_parameters,
614 mat: exec.mat,
615 full_match_stanza_capture_index: exec.full_match_stanza_capture_index,
616 error_context: exec.error_context.clone(),
617 inherited_variables: exec.inherited_variables,
618 shorthands: exec.shorthands,
619 cancellation_flag: exec.cancellation_flag,
620 };
621 self.variable.add(&mut loop_exec, value, false)?;
622 let element = self.element.evaluate(&mut loop_exec)?;
623 elements.push(element);
624 }
625 Ok(Value::List(elements))
626 }
627}
628
629impl SetLiteral {
630 fn evaluate(&self, exec: &mut ExecutionContext) -> Result<Value, ExecutionError> {
631 let elements = self
632 .elements
633 .iter()
634 .map(|e| e.evaluate(exec))
635 .collect::<Result<_, _>>()?;
636 Ok(Value::Set(elements))
637 }
638}
639
640impl SetComprehension {
641 fn evaluate(&self, exec: &mut ExecutionContext) -> Result<Value, ExecutionError> {
642 let values = self.value.evaluate(exec)?.into_list()?;
643 let mut elements = BTreeSet::new();
644 let mut loop_locals = VariableMap::nested(exec.locals);
645 for value in values {
646 loop_locals.clear();
647 let mut loop_exec = ExecutionContext {
648 source: exec.source,
649 graph: exec.graph,
650 config: exec.config,
651 locals: &mut loop_locals,
652 scoped: exec.scoped,
653 current_regex_captures: exec.current_regex_captures,
654 function_parameters: exec.function_parameters,
655 mat: exec.mat,
656 full_match_stanza_capture_index: exec.full_match_stanza_capture_index,
657 error_context: exec.error_context.clone(),
658 inherited_variables: exec.inherited_variables,
659 shorthands: exec.shorthands,
660 cancellation_flag: exec.cancellation_flag,
661 };
662 self.variable.add(&mut loop_exec, value, false)?;
663 let element = self.element.evaluate(&mut loop_exec)?;
664 elements.insert(element);
665 }
666 Ok(Value::Set(elements))
667 }
668}
669
670impl Capture {
671 fn evaluate(&self, exec: &mut ExecutionContext) -> Result<Value, ExecutionError> {
672 Ok(Value::from_nodes(
673 exec.graph,
674 exec.mat
675 .nodes_for_capture_index(self.stanza_capture_index as u32),
676 self.quantifier,
677 )
678 .into())
679 }
680}
681
682impl Call {
683 fn evaluate(&self, exec: &mut ExecutionContext) -> Result<Value, ExecutionError> {
684 for parameter in &self.parameters {
685 let parameter = parameter.evaluate(exec)?;
686 exec.function_parameters.push(parameter);
687 }
688 exec.config.functions.call(
689 &self.function,
690 exec.graph,
691 exec.source,
692 &mut exec
693 .function_parameters
694 .drain(exec.function_parameters.len() - self.parameters.len()..),
695 )
696 }
697}
698
699impl RegexCapture {
700 fn evaluate(&self, exec: &mut ExecutionContext) -> Result<Value, ExecutionError> {
701 let capture = exec
702 .current_regex_captures
703 .get(self.match_index)
704 .ok_or(ExecutionError::UndefinedRegexCapture(format!("{}", self)))?;
705 Ok(Value::String(capture.clone()))
706 }
707}
708
709impl Variable {
710 fn evaluate(&self, exec: &mut ExecutionContext) -> Result<Value, ExecutionError> {
711 let value = self.get(exec)?;
712 Ok(value.clone())
713 }
714}
715
716impl Variable {
717 fn get<'a>(&self, exec: &'a mut ExecutionContext) -> Result<&'a Value, ExecutionError> {
718 match self {
719 Variable::Scoped(variable) => variable.get(exec),
720 Variable::Unscoped(variable) => variable.get(exec),
721 }
722 }
723
724 fn add(
725 &self,
726 exec: &mut ExecutionContext,
727 value: Value,
728 mutable: bool,
729 ) -> Result<(), ExecutionError> {
730 match self {
731 Variable::Scoped(variable) => variable.add(exec, value, mutable),
732 Variable::Unscoped(variable) => variable.add(exec, value, mutable),
733 }
734 }
735
736 fn set(&self, exec: &mut ExecutionContext, value: Value) -> Result<(), ExecutionError> {
737 match self {
738 Variable::Scoped(variable) => variable.set(exec, value),
739 Variable::Unscoped(variable) => variable.set(exec, value),
740 }
741 }
742}
743
744impl ScopedVariable {
745 fn get<'a>(&self, exec: &'a mut ExecutionContext) -> Result<&'a Value, ExecutionError> {
746 let scope = self.scope.evaluate(exec)?;
747 let scope = match scope {
748 Value::SyntaxNode(scope) => scope,
749 _ => {
750 return Err(ExecutionError::InvalidVariableScope(format!(
751 "got {}",
752 scope
753 )))
754 }
755 };
756
757 // search this node
758 if let Some(value) = exec
759 .scoped
760 .try_get(scope.index)
761 .and_then(|v| v.get(&self.name))
762 {
763 return Ok(value);
764 }
765
766 // search parent nodes
767 if exec.inherited_variables.contains(&self.name) {
768 let mut parent = exec
769 .graph
770 .syntax_nodes
771 .get(&scope.index)
772 .and_then(|n| n.parent());
773 while let Some(scope) = parent {
774 if let Some(value) = exec
775 .scoped
776 .try_get(scope.id() as u32)
777 .and_then(|v| v.get(&self.name))
778 {
779 return Ok(value);
780 }
781 parent = scope.parent();
782 }
783 }
784
785 Err(ExecutionError::UndefinedVariable(format!(
786 "{} on node {}",
787 self, scope
788 )))
789 }
790
791 fn add(
792 &self,
793 exec: &mut ExecutionContext,
794 value: Value,
795 mutable: bool,
796 ) -> Result<(), ExecutionError> {
797 let scope = self.scope.evaluate(exec)?;
798 let scope = match scope {
799 Value::SyntaxNode(scope) => scope,
800 _ => {
801 return Err(ExecutionError::InvalidVariableScope(format!(
802 "got {}",
803 scope
804 )))
805 }
806 };
807 let variables = exec.scoped.get_mut(scope);
808 variables
809 .add(self.name.clone(), value, mutable)
810 .map_err(|_| ExecutionError::DuplicateVariable(format!("{}", self)))
811 }
812
813 fn set(&self, exec: &mut ExecutionContext, value: Value) -> Result<(), ExecutionError> {
814 let scope = self.scope.evaluate(exec)?;
815 let scope = match scope {
816 Value::SyntaxNode(scope) => scope,
817 _ => {
818 return Err(ExecutionError::InvalidVariableScope(format!(
819 "got {}",
820 scope,
821 )))
822 }
823 };
824 let variables = exec.scoped.get_mut(scope);
825 variables
826 .set(self.name.clone(), value)
827 .map_err(|_| ExecutionError::DuplicateVariable(format!("{}", self)))
828 }
829}
830
831impl UnscopedVariable {
832 fn get<'a>(&self, exec: &'a mut ExecutionContext) -> Result<&'a Value, ExecutionError> {
833 if let Some(value) = exec.config.globals.get(&self.name) {
834 Some(value)
835 } else {
836 exec.locals.get(&self.name)
837 }
838 .ok_or_else(|| ExecutionError::UndefinedVariable(format!("{}", self)))
839 }
840
841 fn add(
842 &self,
843 exec: &mut ExecutionContext,
844 value: Value,
845 mutable: bool,
846 ) -> Result<(), ExecutionError> {
847 if exec.config.globals.get(&self.name).is_some() {
848 return Err(ExecutionError::DuplicateVariable(format!(
849 " global {}",
850 self,
851 )));
852 }
853 exec.locals
854 .add(self.name.clone(), value, mutable)
855 .map_err(|_| ExecutionError::DuplicateVariable(format!(" local {}", self)))
856 }
857
858 fn set(&self, exec: &mut ExecutionContext, value: Value) -> Result<(), ExecutionError> {
859 if exec.config.globals.get(&self.name).is_some() {
860 return Err(ExecutionError::CannotAssignImmutableVariable(format!(
861 " global {}",
862 self,
863 )));
864 }
865 exec.locals.set(self.name.clone(), value).map_err(|_| {
866 if exec.locals.get(&self.name).is_some() {
867 ExecutionError::CannotAssignImmutableVariable(format!("{}", self))
868 } else {
869 ExecutionError::UndefinedVariable(format!("{}", self))
870 }
871 })
872 }
873}
874
875impl Attribute {
876 fn execute<F>(
877 &self,
878 exec: &mut ExecutionContext,
879 add_attribute: &F,
880 ) -> Result<(), ExecutionError>
881 where
882 F: Fn(&mut ExecutionContext, Identifier, Value) -> Result<(), ExecutionError>,
883 {
884 exec.cancellation_flag.check("executing attribute")?;
885 let value = self.value.evaluate(exec)?;
886 if let Some(shorthand) = exec.shorthands.get(&self.name) {
887 shorthand.execute(exec, add_attribute, value)
888 } else {
889 add_attribute(exec, self.name.clone(), value)
890 }
891 }
892}
893
894impl AttributeShorthand {
895 fn execute<F>(
896 &self,
897 exec: &mut ExecutionContext,
898 add_attribute: &F,
899 value: Value,
900 ) -> Result<(), ExecutionError>
901 where
902 F: Fn(&mut ExecutionContext, Identifier, Value) -> Result<(), ExecutionError>,
903 {
904 let mut shorthand_locals = VariableMap::new();
905 let mut shorthand_exec = ExecutionContext {
906 source: exec.source,
907 graph: exec.graph,
908 config: exec.config,
909 locals: &mut shorthand_locals,
910 scoped: exec.scoped,
911 current_regex_captures: exec.current_regex_captures,
912 function_parameters: exec.function_parameters,
913 mat: exec.mat,
914 full_match_stanza_capture_index: exec.full_match_stanza_capture_index,
915 error_context: exec.error_context.clone(),
916 inherited_variables: exec.inherited_variables,
917 shorthands: exec.shorthands,
918 cancellation_flag: exec.cancellation_flag,
919 };
920 self.variable.add(&mut shorthand_exec, value, false)?;
921 for attr in &self.attributes {
922 attr.execute(&mut shorthand_exec, add_attribute)?;
923 }
924 Ok(())
925 }
926}