diff options
Diffstat (limited to 'src/eval.rs')
-rw-r--r-- | src/eval.rs | 55 |
1 files changed, 48 insertions, 7 deletions
diff --git a/src/eval.rs b/src/eval.rs index 859979d..e13cec3 100644 --- a/src/eval.rs +++ b/src/eval.rs | |||
@@ -39,6 +39,7 @@ pub enum Value { | |||
39 | String(String), | 39 | String(String), |
40 | Boolean(bool), | 40 | Boolean(bool), |
41 | Node, | 41 | Node, |
42 | FieldAccess(Vec<String>), | ||
42 | } | 43 | } |
43 | 44 | ||
44 | impl Value { | 45 | impl Value { |
@@ -49,6 +50,7 @@ impl Value { | |||
49 | Self::String(_) => ast::Type::String, | 50 | Self::String(_) => ast::Type::String, |
50 | Self::Boolean(_) => ast::Type::Boolean, | 51 | Self::Boolean(_) => ast::Type::Boolean, |
51 | Self::Node => ast::Type::Node, | 52 | Self::Node => ast::Type::Node, |
53 | Self::FieldAccess(_) => ast::Type::Node, | ||
52 | } | 54 | } |
53 | } | 55 | } |
54 | 56 | ||
@@ -241,6 +243,7 @@ impl fmt::Display for Value { | |||
241 | Self::String(s) => write!(f, "{s}"), | 243 | Self::String(s) => write!(f, "{s}"), |
242 | Self::Boolean(b) => write!(f, "{b}"), | 244 | Self::Boolean(b) => write!(f, "{b}"), |
243 | Self::Node => write!(f, "<node>"), | 245 | Self::Node => write!(f, "<node>"), |
246 | Self::FieldAccess(items) => write!(f, "<node>.{}", items.join(".")), | ||
244 | } | 247 | } |
245 | } | 248 | } |
246 | } | 249 | } |
@@ -317,7 +320,7 @@ pub enum Error { | |||
317 | CurrentNodeNotPresent, | 320 | CurrentNodeNotPresent, |
318 | } | 321 | } |
319 | 322 | ||
320 | type Result = std::result::Result<Value, Error>; | 323 | pub type Result = std::result::Result<Value, Error>; |
321 | 324 | ||
322 | pub struct Context<'a> { | 325 | pub struct Context<'a> { |
323 | variables: HashMap<ast::Identifier, Variable>, | 326 | variables: HashMap<ast::Identifier, Variable>, |
@@ -385,6 +388,7 @@ impl<'a> Context<'a> { | |||
385 | ast::Expr::IfExpr(if_expr) => self.eval_if(if_expr), | 388 | ast::Expr::IfExpr(if_expr) => self.eval_if(if_expr), |
386 | ast::Expr::Block(block) => self.eval_block(block), | 389 | ast::Expr::Block(block) => self.eval_block(block), |
387 | ast::Expr::Node => Ok(Value::Node), | 390 | ast::Expr::Node => Ok(Value::Node), |
391 | ast::Expr::FieldAccess(items) => Ok(Value::FieldAccess(items.to_owned())), | ||
388 | } | 392 | } |
389 | } | 393 | } |
390 | 394 | ||
@@ -544,12 +548,33 @@ impl<'a> Context<'a> { | |||
544 | } | 548 | } |
545 | Ok(Value::Unit) | 549 | Ok(Value::Unit) |
546 | } | 550 | } |
547 | ("text", [arg]) if self.eval_expr(arg)? == Value::Node => { | 551 | ("text", [arg]) => { |
548 | let node = self | 552 | let node = match self.eval_expr(arg)? { |
549 | .cursor | 553 | Value::Node => self |
550 | .as_ref() | 554 | .cursor |
551 | .ok_or(Error::CurrentNodeNotPresent)? | 555 | .as_ref() |
552 | .node(); | 556 | .ok_or(Error::CurrentNodeNotPresent)? |
557 | .node(), | ||
558 | Value::FieldAccess(fields) => { | ||
559 | let mut node = self | ||
560 | .cursor | ||
561 | .as_ref() | ||
562 | .ok_or(Error::CurrentNodeNotPresent)? | ||
563 | .node(); | ||
564 | for field in &fields { | ||
565 | node = node | ||
566 | .child_by_field_name(field.as_bytes()) | ||
567 | .ok_or_else(|| Error::FailedLookup(field.to_owned()))?; | ||
568 | } | ||
569 | node | ||
570 | } | ||
571 | v => { | ||
572 | return Err(Error::TypeMismatch { | ||
573 | expected: ast::Type::Node, | ||
574 | got: v.ty(), | ||
575 | }) | ||
576 | } | ||
577 | }; | ||
553 | let text = node | 578 | let text = node |
554 | .utf8_text(self.input_src.as_ref().unwrap().as_bytes()) | 579 | .utf8_text(self.input_src.as_ref().unwrap().as_bytes()) |
555 | .unwrap(); | 580 | .unwrap(); |
@@ -629,6 +654,22 @@ impl<'a> Context<'a> { | |||
629 | } | 654 | } |
630 | } | 655 | } |
631 | 656 | ||
657 | pub fn evaluate(file: &str, program: &str, language: tree_sitter::Language) -> Result { | ||
658 | let mut parser = tree_sitter::Parser::new(); | ||
659 | let _ = parser.set_language(language); | ||
660 | |||
661 | let tree = parser.parse(file, None).unwrap(); | ||
662 | let cursor = tree.walk(); | ||
663 | |||
664 | let program = ast::Program::new().from_str(program).unwrap(); | ||
665 | let mut ctx = Context::new(tree_sitter_md::language()) | ||
666 | .with_input(file.to_owned()) | ||
667 | .with_cursor(cursor) | ||
668 | .with_program(program)?; | ||
669 | |||
670 | ctx.eval() | ||
671 | } | ||
672 | |||
632 | #[cfg(test)] | 673 | #[cfg(test)] |
633 | mod test { | 674 | mod test { |
634 | use super::*; | 675 | use super::*; |