fork of https://github.com/tree-sitter/tree-sitter-graph
at main 24 kB view raw
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}