tree_sitter_graph/
functions.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
8//! Functions that can be called by graph DSL files
9
10use std::collections::HashMap;
11use std::sync::Arc;
12
13use crate::execution::error::ExecutionError;
14use crate::graph::Graph;
15use crate::graph::Value;
16use crate::Identifier;
17
18/// The implementation of a function that can be called from the graph DSL.
19///
20/// You have access to the graph, as it has been constructed up to the point of the function call,
21/// as well as the text content of the source file that's being processed.
22///
23/// Any other data that you need must be passed in as a parameter to the function.  You can use the
24/// [`Parameters`][] trait to consume those parameters and verify that you received the correct
25/// number and type of them.
26pub trait Function {
27    fn call(
28        &self,
29        graph: &mut Graph,
30        source: &str,
31        parameters: &mut dyn Parameters,
32    ) -> Result<Value, ExecutionError>;
33}
34
35/// A helper trait for consuming the parameters of a function.  You will typically use it as
36/// follows:
37///
38/// ```
39/// # use tree_sitter_graph::functions::Parameters;
40/// # use tree_sitter_graph::graph::Graph;
41/// # use tree_sitter_graph::graph::Value;
42/// # use tree_sitter_graph::ExecutionError;
43/// # fn main() -> Result<(), ExecutionError> {
44/// # let param_vec = vec![Value::String("test".to_string()), Value::Integer(42)];
45/// # let mut params = param_vec.into_iter();
46/// let first_param = params.param()?.into_string()?;
47/// let second_param = params.param()?.as_integer()?;
48/// // etc
49/// params.finish()?;
50/// # Ok(())
51/// # }
52/// ```
53pub trait Parameters {
54    /// Returns the next parameter, returning an error if you have exhausted all of the parameters
55    /// that were passed in.
56    fn param(&mut self) -> Result<Value, ExecutionError>;
57
58    /// Ensures that there are no more parameters to consume.
59    fn finish(&mut self) -> Result<(), ExecutionError>;
60}
61
62impl<I> Parameters for I
63where
64    I: Iterator<Item = Value>,
65{
66    fn param(&mut self) -> Result<Value, ExecutionError> {
67        let value = self
68            .next()
69            .ok_or(ExecutionError::InvalidParameters(format!(
70                "expected more parameters"
71            )))?;
72        Ok(value)
73    }
74
75    fn finish(&mut self) -> Result<(), ExecutionError> {
76        let value = self.next();
77        if value.is_some() {
78            return Err(ExecutionError::InvalidParameters(format!(
79                "unexpected extra parameter"
80            )));
81        }
82        Ok(())
83    }
84}
85
86/// A library of named functions.
87#[derive(Default)]
88pub struct Functions {
89    functions: HashMap<Identifier, Arc<dyn Function + Send + Sync>>,
90}
91
92impl Functions {
93    /// Creates a new, empty library of functions.
94    pub fn new() -> Functions {
95        Functions::default()
96    }
97
98    /// Returns the standard library of functions, as defined in the [language
99    /// reference][`crate::reference::functions`].
100    pub fn stdlib() -> Functions {
101        let mut functions = Functions::new();
102        // general functions
103        functions.add(Identifier::from("eq"), stdlib::Eq);
104        functions.add(Identifier::from("is-null"), stdlib::IsNull);
105        // tree functions
106        functions.add(
107            Identifier::from("named-child-index"),
108            stdlib::syntax::NamedChildIndex,
109        );
110        functions.add(Identifier::from("source-text"), stdlib::syntax::SourceText);
111        functions.add(Identifier::from("start-row"), stdlib::syntax::StartRow);
112        functions.add(
113            Identifier::from("start-column"),
114            stdlib::syntax::StartColumn,
115        );
116        functions.add(Identifier::from("end-row"), stdlib::syntax::EndRow);
117        functions.add(Identifier::from("end-column"), stdlib::syntax::EndColumn);
118        functions.add(Identifier::from("node-type"), stdlib::syntax::NodeType);
119        functions.add(
120            Identifier::from("named-child-count"),
121            stdlib::syntax::NamedChildCount,
122        );
123        // graph functions
124        functions.add(Identifier::from("node"), stdlib::graph::Node);
125        // boolean functions
126        functions.add(Identifier::from("not"), stdlib::bool::Not);
127        functions.add(Identifier::from("and"), stdlib::bool::And);
128        functions.add(Identifier::from("or"), stdlib::bool::Or);
129        // math functions
130        functions.add(Identifier::from("plus"), stdlib::math::Plus);
131        // string functions
132        functions.add(Identifier::from("format"), stdlib::string::Format);
133        functions.add(Identifier::from("replace"), stdlib::string::Replace);
134        // list functions
135        functions.add(Identifier::from("concat"), stdlib::list::Concat);
136        functions.add(Identifier::from("is-empty"), stdlib::list::IsEmpty);
137        functions.add(Identifier::from("join"), stdlib::list::Join);
138        functions.add(Identifier::from("length"), stdlib::list::Length);
139        functions
140    }
141
142    /// Adds a new function to this library.
143    pub fn add<F>(&mut self, name: Identifier, function: F)
144    where
145        F: Function + Send + Sync + 'static,
146    {
147        self.functions.insert(name, Arc::new(function));
148    }
149
150    /// Calls a named function, returning an error if there is no function with that name.
151    pub fn call(
152        &self,
153        name: &Identifier,
154        graph: &mut Graph,
155        source: &str,
156        parameters: &mut dyn Parameters,
157    ) -> Result<Value, ExecutionError> {
158        let function = self
159            .functions
160            .get(name)
161            .ok_or(ExecutionError::UndefinedFunction(format!("{}", name)))?;
162        function.call(graph, source, parameters)
163    }
164}
165
166/// Implementations of the [standard library functions][`crate::reference::functions`]
167pub mod stdlib {
168    use regex::Regex;
169
170    use crate::execution::error::ExecutionError;
171    use crate::graph::Graph;
172    use crate::graph::Value;
173
174    use super::Function;
175    use super::Parameters;
176
177    /// The implementation of the standard [`eq`][`crate::reference::functions#eq`] function.
178    pub struct Eq;
179
180    impl Function for Eq {
181        fn call(
182            &self,
183            _graph: &mut Graph,
184            _source: &str,
185            parameters: &mut dyn Parameters,
186        ) -> Result<Value, ExecutionError> {
187            let left = parameters.param()?;
188            let right = parameters.param()?;
189            parameters.finish()?;
190
191            match &left {
192                Value::Null => match right {
193                    Value::Null => return Ok(true.into()),
194                    _ => return Ok(false.into()),
195                },
196                Value::Boolean(left) => match &right {
197                    Value::Null => return Ok(false.into()),
198                    Value::Boolean(right) => return Ok((left == right).into()),
199                    _ => {}
200                },
201                Value::Integer(left) => match &right {
202                    Value::Null => return Ok(false.into()),
203                    Value::Integer(right) => return Ok((left == right).into()),
204                    _ => {}
205                },
206                Value::String(left) => match &right {
207                    Value::Null => return Ok(false.into()),
208                    Value::String(right) => return Ok((left == right).into()),
209                    _ => {}
210                },
211                Value::List(left) => match &right {
212                    Value::Null => return Ok(false.into()),
213                    Value::List(right) => return Ok((left == right).into()),
214                    _ => {}
215                },
216                Value::Set(left) => match &right {
217                    Value::Null => return Ok(false.into()),
218                    Value::Set(right) => return Ok((left == right).into()),
219                    _ => {}
220                },
221                Value::SyntaxNode(left) => match &right {
222                    Value::Null => return Ok(false.into()),
223                    Value::SyntaxNode(right) => return Ok((left == right).into()),
224                    _ => {}
225                },
226                Value::GraphNode(left) => match &right {
227                    Value::Null => return Ok(false.into()),
228                    Value::GraphNode(right) => return Ok((left == right).into()),
229                    _ => {}
230                },
231            };
232            Err(ExecutionError::FunctionFailed(
233                "eq".into(),
234                format!(
235                    "Cannot compare values of different types: {} and {}",
236                    left, right
237                ),
238            ))
239        }
240    }
241
242    /// The implementation of the standard [`is-null`][`crate::reference::functions#is-null`] function.
243    pub struct IsNull;
244
245    impl Function for IsNull {
246        fn call(
247            &self,
248            _graph: &mut Graph,
249            _source: &str,
250            parameters: &mut dyn Parameters,
251        ) -> Result<Value, ExecutionError> {
252            let parameter = parameters.param()?;
253            parameters.finish()?;
254            let result = if let Value::Null = parameter {
255                true
256            } else {
257                false
258            };
259            Ok(result.into())
260        }
261    }
262
263    pub mod syntax {
264        use super::*;
265
266        /// The implementation of the standard [`named-child-index`][`crate::reference::functions#named-child-index`]
267        /// function.
268        pub struct NamedChildIndex;
269
270        impl Function for NamedChildIndex {
271            fn call(
272                &self,
273                graph: &mut Graph,
274                _source: &str,
275                parameters: &mut dyn Parameters,
276            ) -> Result<Value, ExecutionError> {
277                let node = graph[parameters.param()?.into_syntax_node_ref()?];
278                parameters.finish()?;
279                let parent = match node.parent() {
280                    Some(parent) => parent,
281                    None => {
282                        return Err(ExecutionError::FunctionFailed(
283                            "named-child-index".into(),
284                            format!("Cannot call named-child-index on the root node"),
285                        ))
286                    }
287                };
288                let mut tree_cursor = parent.walk();
289                let index = parent
290                    .named_children(&mut tree_cursor)
291                    .position(|child| child == node)
292                    .ok_or(ExecutionError::FunctionFailed(
293                        "named-child-index".into(),
294                        format!("Called named-child-index on a non-named child"),
295                    ))?;
296                Ok(Value::Integer(index as u32))
297            }
298        }
299
300        /// The implementation of the standard [`source-text`][`crate::reference::functions#source-text`]
301        /// function.
302        pub struct SourceText;
303
304        impl Function for SourceText {
305            fn call(
306                &self,
307                graph: &mut Graph,
308                source: &str,
309                parameters: &mut dyn Parameters,
310            ) -> Result<Value, ExecutionError> {
311                let node = graph[parameters.param()?.into_syntax_node_ref()?];
312                parameters.finish()?;
313                Ok(Value::String(source[node.byte_range()].to_string()))
314            }
315        }
316
317        // The implementation of the standard [`start-row`][`crate::reference::functions#start-row`]
318        // function.
319        pub struct StartRow;
320
321        impl Function for StartRow {
322            fn call(
323                &self,
324                graph: &mut Graph,
325                _source: &str,
326                parameters: &mut dyn Parameters,
327            ) -> Result<Value, ExecutionError> {
328                let node = graph[parameters.param()?.into_syntax_node_ref()?];
329                parameters.finish()?;
330                Ok(Value::Integer(node.start_position().row as u32))
331            }
332        }
333
334        // The implementation of the standard
335        // [`start-column`][`crate::reference::functions#start-column`]
336        // function.
337        pub struct StartColumn;
338
339        impl Function for StartColumn {
340            fn call(
341                &self,
342                graph: &mut Graph,
343                _source: &str,
344                parameters: &mut dyn Parameters,
345            ) -> Result<Value, ExecutionError> {
346                let node = graph[parameters.param()?.into_syntax_node_ref()?];
347                parameters.finish()?;
348                Ok(Value::Integer(node.start_position().column as u32))
349            }
350        }
351
352        // The implementation of the standard [`end-row`][`crate::reference::functions#end-row`]
353        // function.
354        pub struct EndRow;
355
356        impl Function for EndRow {
357            fn call(
358                &self,
359                graph: &mut Graph,
360                _source: &str,
361                parameters: &mut dyn Parameters,
362            ) -> Result<Value, ExecutionError> {
363                let node = graph[parameters.param()?.into_syntax_node_ref()?];
364                parameters.finish()?;
365                Ok(Value::Integer(node.end_position().row as u32))
366            }
367        }
368
369        // The implementation of the standard [`end-column`][`crate::reference::functions#end-column`]
370        // function.
371        pub struct EndColumn;
372
373        impl Function for EndColumn {
374            fn call(
375                &self,
376                graph: &mut Graph,
377                _source: &str,
378                parameters: &mut dyn Parameters,
379            ) -> Result<Value, ExecutionError> {
380                let node = graph[parameters.param()?.into_syntax_node_ref()?];
381                parameters.finish()?;
382                Ok(Value::Integer(node.end_position().column as u32))
383            }
384        }
385
386        // The implementation of the standard [`node-type`][`crate::reference::functions#node-type`]
387        // function.
388        pub struct NodeType;
389
390        impl Function for NodeType {
391            fn call(
392                &self,
393                graph: &mut Graph,
394                _source: &str,
395                parameters: &mut dyn Parameters,
396            ) -> Result<Value, ExecutionError> {
397                let node = graph[parameters.param()?.into_syntax_node_ref()?];
398                parameters.finish()?;
399                Ok(Value::String(node.kind().to_string()))
400            }
401        }
402
403        // The implementation of the standard
404        // [`named-child-count`][`crate::reference::functions#named-child-count`] function.
405
406        pub struct NamedChildCount;
407
408        impl Function for NamedChildCount {
409            fn call(
410                &self,
411                graph: &mut Graph,
412                _source: &str,
413                parameters: &mut dyn Parameters,
414            ) -> Result<Value, ExecutionError> {
415                let node = graph[parameters.param()?.into_syntax_node_ref()?];
416                parameters.finish()?;
417                Ok(Value::Integer(node.named_child_count() as u32))
418            }
419        }
420    }
421
422    pub mod graph {
423        use super::*;
424
425        /// The implementation of the standard [`node`][`crate::reference::functions#node`] function.
426        pub struct Node;
427
428        impl Function for Node {
429            fn call(
430                &self,
431                graph: &mut Graph,
432                _source: &str,
433                parameters: &mut dyn Parameters,
434            ) -> Result<Value, ExecutionError> {
435                parameters.finish()?;
436                let node = graph.add_graph_node();
437                Ok(Value::GraphNode(node))
438            }
439        }
440    }
441
442    pub mod bool {
443        use super::*;
444
445        /// The implementation of the standard [`not`][`crate::reference::functions#not`] function.
446        pub struct Not;
447
448        impl Function for Not {
449            fn call(
450                &self,
451                _graph: &mut Graph,
452                _source: &str,
453                parameters: &mut dyn Parameters,
454            ) -> Result<Value, ExecutionError> {
455                let result = !parameters.param()?.as_boolean()?;
456                parameters.finish()?;
457                Ok(result.into())
458            }
459        }
460
461        /// The implementation of the standard [`and`][`crate::reference::functions#and`] function.
462        pub struct And;
463
464        impl Function for And {
465            fn call(
466                &self,
467                _graph: &mut Graph,
468                _source: &str,
469                parameters: &mut dyn Parameters,
470            ) -> Result<Value, ExecutionError> {
471                let mut result = true;
472                while let Ok(parameter) = parameters.param() {
473                    result &= parameter.as_boolean()?;
474                }
475                Ok(result.into())
476            }
477        }
478
479        /// The implementation of the standard [`or`][`crate::reference::functions#or`] function.
480        pub struct Or;
481
482        impl Function for Or {
483            fn call(
484                &self,
485                _graph: &mut Graph,
486                _source: &str,
487                parameters: &mut dyn Parameters,
488            ) -> Result<Value, ExecutionError> {
489                let mut result = false;
490                while let Ok(parameter) = parameters.param() {
491                    result |= parameter.as_boolean()?;
492                }
493                Ok(result.into())
494            }
495        }
496    }
497
498    pub mod math {
499        use super::*;
500
501        /// The implementation of the standard [`plus`][`crate::reference::functions#plus`] function.
502        pub struct Plus;
503
504        impl Function for Plus {
505            fn call(
506                &self,
507                _graph: &mut Graph,
508                _source: &str,
509                parameters: &mut dyn Parameters,
510            ) -> Result<Value, ExecutionError> {
511                let mut result = 0;
512                while let Ok(parameter) = parameters.param() {
513                    result += parameter.as_integer()?;
514                }
515                Ok(Value::Integer(result))
516            }
517        }
518    }
519
520    pub mod string {
521        use super::*;
522
523        /// The implementation of the standard [`format`][`crate::reference::functions#format`] function.
524        pub struct Format;
525
526        impl Function for Format {
527            fn call(
528                &self,
529                _graph: &mut Graph,
530                _source: &str,
531                parameters: &mut dyn Parameters,
532            ) -> Result<Value, ExecutionError> {
533                let format = parameters.param()?.into_string()?;
534                let mut result = String::new();
535                let mut it = format.chars().enumerate().into_iter();
536                while let Some((_, c)) = it.next() {
537                    match c {
538                        '{' => match it.next() {
539                            Some((_, '{')) => result.push('{'),
540                            Some((_, '}')) => {
541                                let value = parameters.param()?;
542                                result += &value.to_string();
543                            },
544                            Some((i, c)) => return Err(ExecutionError::FunctionFailed("format".into(), format!("Unexpected character `{}` after `{{` at position {} in format string `{}`. Expected `{{` or `}}`.", c, i + 1, format))),
545                            None => return Err(ExecutionError::FunctionFailed("format".into(), format!("Unexpected end of format string `{}` after `{{`. Expected `{{` or `}}`.", format))),
546                        },
547                        '}' => match it.next() {
548                            Some((_, '}')) => result.push('}'),
549                            Some((i, c)) => return Err(ExecutionError::FunctionFailed("format".into(), format!("Unexpected character `{}` after `}}` at position {} in format string `{}`. Expected `}}`.", c, i + 1, format))),
550                            None => return Err(ExecutionError::FunctionFailed("format".into(), format!("Unexpected end of format string `{}` after `{{. Expected `}}`.", format))),
551                        },
552                        c => result.push(c),
553                    }
554                }
555                parameters.finish()?;
556                Ok(result.into())
557            }
558        }
559
560        /// The implementation of the standard [`replace`][`crate::reference::functions#replace`] function.
561        pub struct Replace;
562
563        impl Function for Replace {
564            fn call(
565                &self,
566                _graph: &mut Graph,
567                _source: &str,
568                parameters: &mut dyn Parameters,
569            ) -> Result<Value, ExecutionError> {
570                let text = parameters.param()?.into_string()?;
571                let pattern = parameters.param()?.into_string()?;
572                let pattern = Regex::new(&pattern).map_err(|e| {
573                    ExecutionError::FunctionFailed("replace".into(), format!("{}", e))
574                })?;
575                let replacement = parameters.param()?.into_string()?;
576                parameters.finish()?;
577                Ok(Value::String(
578                    pattern.replace_all(&text, replacement.as_str()).to_string(),
579                ))
580            }
581        }
582    }
583
584    pub mod list {
585        use super::*;
586
587        /// The implementation of the standard [`concat`][`crate::reference::functions#concat`] function.
588        pub struct Concat;
589
590        impl Function for Concat {
591            fn call(
592                &self,
593                _graph: &mut Graph,
594                _source: &str,
595                parameters: &mut dyn Parameters,
596            ) -> Result<Value, ExecutionError> {
597                let mut result = Vec::new();
598                while let Ok(list) = parameters.param() {
599                    result.append(&mut list.into_list()?);
600                }
601                Ok(result.into())
602            }
603        }
604
605        /// The implementation of the standard [`is-empty`][`crate::reference::functions#is-empty`] function.
606        pub struct IsEmpty;
607
608        impl Function for IsEmpty {
609            fn call(
610                &self,
611                _graph: &mut Graph,
612                _source: &str,
613                parameters: &mut dyn Parameters,
614            ) -> Result<Value, ExecutionError> {
615                let list = parameters.param()?.into_list()?;
616                Ok(list.is_empty().into())
617            }
618        }
619
620        /// The implementation of the standard [`join`][`crate::reference::functions#join`] function.
621        pub struct Join;
622
623        impl Function for Join {
624            fn call(
625                &self,
626                _graph: &mut Graph,
627                _source: &str,
628                parameters: &mut dyn Parameters,
629            ) -> Result<Value, ExecutionError> {
630                let list = parameters.param()?.into_list()?;
631                let sep = match parameters.param() {
632                    Ok(sep) => sep.into_string()?,
633                    Err(_) => "".to_string(),
634                };
635                parameters.finish()?;
636                let result = list
637                    .into_iter()
638                    .map(|x| format!("{}", x))
639                    .collect::<Vec<_>>()
640                    .join(&sep);
641                Ok(result.into())
642            }
643        }
644
645        /// The implementation of the standard [`length`][`crate::reference::functions#length`] function.
646        pub struct Length;
647
648        impl Function for Length {
649            fn call(
650                &self,
651                _graph: &mut Graph,
652                _source: &str,
653                parameters: &mut dyn Parameters,
654            ) -> Result<Value, ExecutionError> {
655                let list = parameters.param()?.into_list()?;
656                Ok((list.len() as u32).into())
657            }
658        }
659    }
660}