tree_sitter_graph/execution/
strict.rs

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