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
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}