tree-based source processing language
1//! tree walking interpreter for tbsp
2
3use crate::{ast, Wrap};
4use std::{collections::HashMap, fmt};
5
6#[derive(Debug, PartialEq, Eq, Clone)]
7pub struct Variable {
8 pub ty: ast::Type,
9 pub name: ast::Identifier,
10 pub value: Value,
11}
12
13impl Variable {
14 fn value(&self) -> &Value {
15 &self.value
16 }
17
18 pub(crate) fn ty(&self) -> &ast::Type {
19 &self.ty
20 }
21
22 fn assign(&mut self, value: Value) -> Result {
23 if self.ty() == &value.ty() {
24 self.value = value;
25 Ok(self.value.clone())
26 } else {
27 Err(Error::TypeMismatch {
28 expected: self.ty().clone(),
29 got: value.ty(),
30 })
31 }
32 }
33
34 pub(crate) fn mutate(&mut self, f: impl FnOnce(&mut Self) -> Result) -> Result {
35 f(self)
36 }
37}
38
39#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
40pub enum Value {
41 Unit,
42 Integer(i128),
43 String(String),
44 Boolean(bool),
45 Node(NodeId),
46 List(Vec<Value>),
47}
48
49type NodeId = usize;
50
51impl Value {
52 pub(crate) fn ty(&self) -> ast::Type {
53 match self {
54 Self::Unit => ast::Type::Unit,
55 Self::Integer(_) => ast::Type::Integer,
56 Self::String(_) => ast::Type::String,
57 Self::Boolean(_) => ast::Type::Boolean,
58 Self::Node(_) => ast::Type::Node,
59 Self::List(_) => ast::Type::List,
60 }
61 }
62
63 fn default(ty: ast::Type) -> Self {
64 match ty {
65 ast::Type::Unit => Self::Unit,
66 ast::Type::Integer => Self::default_int(),
67 ast::Type::String => Self::default_string(),
68 ast::Type::Boolean => Self::default_bool(),
69 ast::Type::Node => unreachable!(),
70 ast::Type::List => Self::default_list(),
71 }
72 }
73
74 fn default_int() -> Self {
75 Self::Integer(0)
76 }
77
78 fn default_bool() -> Self {
79 Self::Boolean(false)
80 }
81
82 fn default_string() -> Self {
83 Self::String(String::default())
84 }
85
86 fn default_list() -> Self {
87 Self::List(Vec::new())
88 }
89
90 fn as_boolean(&self) -> std::result::Result<bool, Error> {
91 match self {
92 Self::Boolean(b) => Ok(*b),
93 v => Err(Error::TypeMismatch {
94 expected: ast::Type::Boolean,
95 got: v.ty(),
96 }),
97 }
98 }
99
100 pub(crate) fn as_str(&self) -> std::result::Result<&str, Error> {
101 match self {
102 Self::String(s) => Ok(s.as_str()),
103 v => Err(Error::TypeMismatch {
104 expected: ast::Type::String,
105 got: v.ty(),
106 }),
107 }
108 }
109
110 pub(crate) fn as_int(&self) -> std::result::Result<i128, Error> {
111 match self {
112 Self::Integer(i) => Ok(*i),
113 v => Err(Error::TypeMismatch {
114 expected: ast::Type::Integer,
115 got: v.ty(),
116 }),
117 }
118 }
119
120 pub(crate) fn as_node(&self) -> std::result::Result<NodeId, Error> {
121 match self {
122 Self::Node(id) => Ok(*id),
123 v => Err(Error::TypeMismatch {
124 expected: ast::Type::Node,
125 got: v.ty(),
126 }),
127 }
128 }
129
130 pub(crate) fn as_list(&self) -> std::result::Result<Vec<Value>, Error> {
131 match self {
132 Self::List(values) => Ok(values.clone()),
133 v => Err(Error::TypeMismatch {
134 expected: ast::Type::List,
135 got: v.ty(),
136 }),
137 }
138 }
139
140 fn add(&self, other: &Self) -> Result {
141 match (self, other) {
142 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Integer(*s + *o)),
143 (Self::String(s), Self::String(o)) => Ok(Self::String(format!("{s}{o}"))),
144 (Self::List(l), o) => Ok(Self::List(l.iter().cloned().chain([o.clone()]).collect())),
145 _ => Err(Error::UndefinedBinOp(
146 ast::BinOp::Arith(ast::ArithOp::Add),
147 self.ty(),
148 other.ty(),
149 )),
150 }
151 }
152
153 fn sub(&self, other: &Self) -> Result {
154 match (self, other) {
155 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Integer(*s - *o)),
156 (Self::String(s), Self::String(o)) => {
157 Ok(Self::String(s.strip_suffix(o).unwrap_or(s).to_owned()))
158 }
159 _ => Err(Error::UndefinedBinOp(
160 ast::BinOp::Arith(ast::ArithOp::Sub),
161 self.ty(),
162 other.ty(),
163 )),
164 }
165 }
166
167 fn mul(&self, other: &Self) -> Result {
168 match (self, other) {
169 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Integer(*s * *o)),
170 (Self::Integer(s), Self::String(o)) => Ok(Self::String(o.repeat(*s as usize))),
171 (Self::String(_), Self::Integer(_)) => other.mul(self),
172 _ => Err(Error::UndefinedBinOp(
173 ast::BinOp::Arith(ast::ArithOp::Mul),
174 self.ty(),
175 other.ty(),
176 )),
177 }
178 }
179
180 fn div(&self, other: &Self) -> Result {
181 match (self, other) {
182 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Integer(*s / *o)),
183 _ => Err(Error::UndefinedBinOp(
184 ast::BinOp::Arith(ast::ArithOp::Div),
185 self.ty(),
186 other.ty(),
187 )),
188 }
189 }
190
191 fn mod_(&self, other: &Self) -> Result {
192 match (self, other) {
193 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Integer(*s % *o)),
194 _ => Err(Error::UndefinedBinOp(
195 ast::BinOp::Arith(ast::ArithOp::Mod),
196 self.ty(),
197 other.ty(),
198 )),
199 }
200 }
201
202 fn equals(&self, other: &Self) -> Result {
203 match (self, other) {
204 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Boolean(s == o)),
205 (Self::String(s), Self::String(o)) => Ok(Self::Boolean(s == o)),
206 (Self::Boolean(s), Self::Boolean(o)) => Ok(Self::Boolean(s == o)),
207 _ => Err(Error::UndefinedBinOp(
208 ast::BinOp::Cmp(ast::CmpOp::Eq),
209 self.ty(),
210 other.ty(),
211 )),
212 }
213 }
214
215 fn greater_than(&self, other: &Self) -> Result {
216 match (self, other) {
217 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Boolean(s > o)),
218 (Self::String(s), Self::String(o)) => Ok(Self::Boolean(s.cmp(o).is_gt())),
219 _ => Err(Error::UndefinedBinOp(
220 ast::BinOp::Cmp(ast::CmpOp::Gt),
221 self.ty(),
222 other.ty(),
223 )),
224 }
225 }
226
227 fn less_than(&self, other: &Self) -> Result {
228 match (self, other) {
229 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Boolean(s < o)),
230 (Self::String(s), Self::String(o)) => Ok(Self::Boolean(s.cmp(o).is_lt())),
231 _ => Err(Error::UndefinedBinOp(
232 ast::BinOp::Cmp(ast::CmpOp::Lt),
233 self.ty(),
234 other.ty(),
235 )),
236 }
237 }
238
239 fn greater_than_equals(&self, other: &Self) -> Result {
240 match (self, other) {
241 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Boolean(s >= o)),
242 (Self::String(s), Self::String(o)) => Ok(Self::Boolean(s.cmp(o).is_ge())),
243 (Self::Boolean(s), Self::Boolean(o)) => Ok(Self::Boolean(s == o)),
244 _ => Err(Error::UndefinedBinOp(
245 ast::BinOp::Cmp(ast::CmpOp::Gte),
246 self.ty(),
247 other.ty(),
248 )),
249 }
250 }
251
252 fn less_than_equals(&self, other: &Self) -> Result {
253 match (self, other) {
254 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Boolean(s <= o)),
255 (Self::String(s), Self::String(o)) => Ok(Self::Boolean(s.cmp(o).is_le())),
256 (Self::Boolean(s), Self::Boolean(o)) => Ok(Self::Boolean(s == o)),
257 _ => Err(Error::UndefinedBinOp(
258 ast::BinOp::Cmp(ast::CmpOp::Lte),
259 self.ty(),
260 other.ty(),
261 )),
262 }
263 }
264
265 fn not(&self) -> Result {
266 match self {
267 Self::Boolean(s) => Ok(Self::Boolean(!s)),
268 _ => Err(Error::UndefinedUnaryOp(ast::UnaryOp::Not, self.ty())),
269 }
270 }
271
272 fn and(&self, other: &Self) -> Result {
273 match (self, other) {
274 (Self::Boolean(s), Self::Boolean(o)) => Ok(Self::Boolean(*s && *o)),
275 _ => Err(Error::UndefinedBinOp(
276 ast::BinOp::Logic(ast::LogicOp::And),
277 self.ty(),
278 other.ty(),
279 )),
280 }
281 }
282
283 fn or(&self, other: &Self) -> Result {
284 match (self, other) {
285 (Self::Boolean(s), Self::Boolean(o)) => Ok(Self::Boolean(*s || *o)),
286 _ => Err(Error::UndefinedBinOp(
287 ast::BinOp::Logic(ast::LogicOp::Or),
288 self.ty(),
289 other.ty(),
290 )),
291 }
292 }
293}
294
295impl fmt::Display for Value {
296 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297 match self {
298 Self::Unit => write!(f, "()"),
299 Self::Integer(i) => write!(f, "{i}"),
300 Self::String(s) => write!(f, "{s}"),
301 Self::Boolean(b) => write!(f, "{b}"),
302 Self::Node(id) => write!(f, "<node #{id}>"),
303 Self::List(items) => {
304 write!(f, "[")?;
305 let mut iterable = items.iter().peekable();
306 while let Some(item) = iterable.next() {
307 if iterable.peek().is_none() {
308 write!(f, "{item}")?;
309 } else {
310 write!(f, "{item}, ")?;
311 }
312 }
313 write!(f, "]")
314 }
315 }
316 }
317}
318
319impl From<bool> for Value {
320 fn from(value: bool) -> Self {
321 Self::Boolean(value)
322 }
323}
324
325impl From<i128> for Value {
326 fn from(value: i128) -> Self {
327 Self::Integer(value)
328 }
329}
330
331impl From<usize> for Value {
332 fn from(value: usize) -> Self {
333 (value as i128).into()
334 }
335}
336
337impl From<&str> for Value {
338 fn from(value: &str) -> Self {
339 Self::String(value.to_owned())
340 }
341}
342
343impl From<Vec<Value>> for Value {
344 fn from(value: Vec<Value>) -> Self {
345 Self::List(value)
346 }
347}
348
349#[derive(Debug, PartialEq, Eq)]
350pub enum Error {
351 FailedLookup(ast::Identifier),
352 TypeMismatch {
353 expected: ast::Type,
354 got: ast::Type,
355 },
356 UndefinedBinOp(ast::BinOp, ast::Type, ast::Type),
357 UndefinedUnaryOp(ast::UnaryOp, ast::Type),
358 AlreadyBound(ast::Identifier),
359 MalformedExpr(String),
360 InvalidNodeKind(String),
361 NoParentNode(tree_sitter::Node<'static>),
362 IncorrectArgFormat {
363 wanted: usize,
364 got: usize,
365 },
366 InvalidStringSlice {
367 length: usize,
368 start: i128,
369 end: i128,
370 },
371 ArrayOutOfBounds {
372 idx: i128,
373 len: usize,
374 },
375 // current node is only set in visitors, not in BEGIN or END blocks
376 CurrentNodeNotPresent,
377}
378
379pub type Result = std::result::Result<Value, Error>;
380
381pub struct Context {
382 variables: HashMap<ast::Identifier, Variable>,
383 language: tree_sitter::Language,
384 program: ast::Program,
385 pub(crate) input_src: Option<String>,
386 cursor: Option<tree_sitter::TreeCursor<'static>>,
387 tree: Option<&'static tree_sitter::Tree>,
388 cache: HashMap<NodeId, tree_sitter::Node<'static>>,
389}
390
391impl fmt::Debug for Context {
392 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393 f.debug_struct("Context")
394 .field("variables", &self.variables)
395 .field("language", &self.language)
396 .field("input_src", &self.input_src)
397 .field(
398 "cursor",
399 if self.cursor.is_some() {
400 &"Some(<cursor>)"
401 } else {
402 &"None"
403 },
404 )
405 .finish()
406 }
407}
408
409impl Context {
410 pub fn new(language: tree_sitter::Language) -> Self {
411 Self {
412 program: Default::default(),
413 variables: Default::default(),
414 language,
415 input_src: None,
416 cursor: None,
417 tree: None,
418 cache: HashMap::default(),
419 }
420 }
421
422 pub fn cache_node(&mut self, node: tree_sitter::Node<'static>) {
423 self.cache.entry(node.id()).or_insert(node);
424 }
425
426 pub fn get_node_by_id(&mut self, id: usize) -> Option<tree_sitter::Node<'static>> {
427 let root_node = self.tree.as_ref().map(|t| t.root_node())?;
428 self.get_node_by_id_helper(root_node, id)
429 }
430
431 fn get_node_by_id_helper(
432 &mut self,
433 start: tree_sitter::Node<'static>,
434 id: usize,
435 ) -> Option<tree_sitter::Node<'static>> {
436 self.cache_node(start);
437
438 if let Some(found) = self.cache.get(&id) {
439 return Some(*found);
440 }
441
442 if start.id() == id {
443 return Some(start);
444 } else {
445 for child in start.children(&mut start.walk()) {
446 if let Some(n) = self.get_node_by_id_helper(child, id) {
447 return Some(n);
448 };
449 }
450 }
451
452 None
453 }
454
455 pub fn with_program(mut self, program: ast::Program) -> Self {
456 self.program = program;
457 self
458 }
459
460 pub fn with_input(mut self, src: String) -> Self {
461 self.input_src = Some(src);
462 self
463 }
464
465 pub fn with_tree(mut self, tree: tree_sitter::Tree) -> Self {
466 let tree = Box::leak(Box::new(tree));
467 self.cursor = Some(tree.walk());
468 self.tree = Some(tree);
469 self
470 }
471
472 pub(crate) fn eval_expr(&mut self, expr: &ast::Expr) -> Result {
473 match expr {
474 ast::Expr::Unit => Ok(Value::Unit),
475 ast::Expr::Lit(lit) => self.eval_lit(lit),
476 ast::Expr::Ident(ident) => self.lookup(ident).map(Variable::value).cloned(),
477 ast::Expr::Bin(lhs, op, rhs) => self.eval_bin(&*lhs, *op, &*rhs),
478 ast::Expr::Unary(expr, op) => self.eval_unary(&*expr, *op),
479 ast::Expr::Call(call) => self.eval_call(&*call),
480 ast::Expr::List(list) => self.eval_list(&*list),
481 ast::Expr::Index(target, idx) => self.eval_index(&*target, &*idx),
482 ast::Expr::If(if_expr) => self.eval_if(if_expr),
483 ast::Expr::Block(block) => self.eval_block(block),
484 ast::Expr::Node => self.eval_node(),
485 ast::Expr::FieldAccess(expr, items) => self.eval_field_access(expr, items),
486 }
487 }
488
489 fn eval_lit(&mut self, lit: &ast::Literal) -> Result {
490 match lit {
491 ast::Literal::Str(s) => Ok(Value::String(s.to_owned())),
492 ast::Literal::Int(i) => Ok(Value::Integer(*i)),
493 ast::Literal::Bool(b) => Ok(Value::Boolean(*b)),
494 }
495 }
496
497 fn eval_node(&mut self) -> Result {
498 self.cursor
499 .as_ref()
500 .ok_or(Error::CurrentNodeNotPresent)?
501 .node()
502 .id()
503 .wrap(Value::Node)
504 .wrap_ok()
505 }
506
507 pub(crate) fn lookup(
508 &mut self,
509 ident: &ast::Identifier,
510 ) -> std::result::Result<&Variable, Error> {
511 self.variables
512 .get(ident)
513 .ok_or_else(|| Error::FailedLookup(ident.to_owned()))
514 }
515
516 pub(crate) fn lookup_mut(
517 &mut self,
518 ident: &ast::Identifier,
519 ) -> std::result::Result<&mut Variable, Error> {
520 self.variables
521 .get_mut(ident)
522 .ok_or_else(|| Error::FailedLookup(ident.to_owned()))
523 }
524
525 fn bind(
526 &mut self,
527 ident: &ast::Identifier,
528 ty: ast::Type,
529 ) -> std::result::Result<&mut Variable, Error> {
530 if self.lookup(ident).is_err() {
531 self.variables
532 .entry(ident.to_owned())
533 .or_insert_with(|| Variable {
534 name: ident.to_owned(),
535 value: Value::default(ty),
536 ty,
537 })
538 .wrap_ok()
539 } else {
540 Err(Error::AlreadyBound(ident.to_owned()))
541 }
542 }
543
544 fn eval_bin(&mut self, lhs: &ast::Expr, op: ast::BinOp, rhs: &ast::Expr) -> Result {
545 match op {
546 ast::BinOp::Assign(op) => self.eval_assign(lhs, op, rhs),
547 ast::BinOp::Arith(op) => self.eval_arith(lhs, op, rhs),
548 ast::BinOp::Cmp(op) => self.eval_cmp(lhs, op, rhs),
549 ast::BinOp::Logic(op) => self.eval_logic(lhs, op, rhs),
550 }
551 }
552
553 fn eval_assign(
554 &mut self,
555 lhs: &ast::Expr,
556 ast::AssignOp { op }: ast::AssignOp,
557 rhs: &ast::Expr,
558 ) -> Result {
559 let ast::Expr::Ident(ident) = lhs else {
560 return Err(Error::MalformedExpr(format!(
561 "malformed assigment, lhs: {:?}",
562 lhs
563 )));
564 };
565 let value = self.eval_expr(rhs)?;
566 let variable = self.lookup_mut(ident)?;
567 match op {
568 None => variable.assign(value),
569 Some(ast::ArithOp::Add) => variable.assign(variable.value().add(&value)?),
570 Some(ast::ArithOp::Sub) => variable.assign(variable.value().sub(&value)?),
571 Some(ast::ArithOp::Mul) => variable.assign(variable.value().mul(&value)?),
572 Some(ast::ArithOp::Div) => variable.assign(variable.value().div(&value)?),
573 Some(ast::ArithOp::Mod) => variable.assign(variable.value().mod_(&value)?),
574 }
575 }
576
577 fn eval_arith(&mut self, lhs: &ast::Expr, op: ast::ArithOp, rhs: &ast::Expr) -> Result {
578 let l = self.eval_expr(lhs)?;
579 let r = self.eval_expr(rhs)?;
580 match op {
581 ast::ArithOp::Add => l.add(&r),
582 ast::ArithOp::Sub => l.sub(&r),
583 ast::ArithOp::Mul => l.mul(&r),
584 ast::ArithOp::Div => l.div(&r),
585 ast::ArithOp::Mod => l.mod_(&r),
586 }
587 }
588
589 fn eval_cmp(&mut self, lhs: &ast::Expr, op: ast::CmpOp, rhs: &ast::Expr) -> Result {
590 let l = self.eval_expr(lhs)?;
591 let r = self.eval_expr(rhs)?;
592
593 match op {
594 ast::CmpOp::Eq => l.equals(&r),
595 ast::CmpOp::Gt => l.greater_than(&r),
596 ast::CmpOp::Lt => l.less_than(&r),
597 ast::CmpOp::Neq => l.equals(&r).and_then(|v| v.not()),
598 ast::CmpOp::Gte => l.greater_than_equals(&r),
599 ast::CmpOp::Lte => l.less_than_equals(&r),
600 }
601 }
602
603 fn eval_logic(&mut self, lhs: &ast::Expr, op: ast::LogicOp, rhs: &ast::Expr) -> Result {
604 let l = self.eval_expr(lhs)?;
605
606 // short-circuit
607 let l_value = l.as_boolean()?;
608
609 match op {
610 ast::LogicOp::Or => {
611 if l_value {
612 return Ok(l);
613 } else {
614 let r = self.eval_expr(rhs)?;
615 l.or(&r)
616 }
617 }
618 ast::LogicOp::And => {
619 if !l_value {
620 return Ok(l);
621 } else {
622 let r = self.eval_expr(rhs)?;
623 l.and(&r)
624 }
625 }
626 }
627 }
628
629 fn eval_unary(&mut self, expr: &ast::Expr, op: ast::UnaryOp) -> Result {
630 let val = self.eval_expr(expr)?;
631 match op {
632 ast::UnaryOp::Not => val.not(),
633 }
634 }
635
636 fn eval_if(&mut self, if_expr: &ast::IfExpr) -> Result {
637 let cond = self.eval_expr(&if_expr.condition)?;
638
639 if cond.as_boolean()? {
640 self.eval_block(&if_expr.then)
641 } else {
642 self.eval_block(&if_expr.else_)
643 }
644 }
645
646 fn eval_call(&mut self, call: &ast::Call) -> Result {
647 ((&*crate::builtins::BUILTINS)
648 .get(call.function.as_str())
649 .ok_or_else(|| Error::FailedLookup(call.function.to_owned()))?)(
650 self,
651 call.parameters.as_slice(),
652 )
653 }
654
655 fn eval_list(&mut self, list: &ast::List) -> Result {
656 let mut vals = vec![];
657 for i in &list.items {
658 vals.push(self.eval_expr(i)?);
659 }
660 Ok(vals.into())
661 }
662
663 fn eval_index(&mut self, target: &ast::Expr, idx: &ast::Expr) -> Result {
664 let mut target = self.eval_expr(target)?.as_list()?;
665 let idx = self.eval_expr(idx)?.as_int()?;
666 if idx < 0 || idx >= target.len() as i128 {
667 Err(Error::ArrayOutOfBounds {
668 idx,
669 len: target.len(),
670 })
671 } else {
672 Ok(target.remove(idx as usize))
673 }
674 }
675
676 fn eval_declaration(&mut self, decl: &ast::Declaration) -> Result {
677 let initial_value = match decl.init.as_ref() {
678 Some(init) => Some(self.eval_expr(&*init)?),
679 None => None,
680 };
681 let variable = self.bind(&decl.name, decl.ty)?;
682
683 if let Some(init) = initial_value {
684 variable.assign(init)?;
685 }
686
687 Ok(Value::Unit)
688 }
689
690 fn eval_statement(&mut self, stmt: &ast::Statement) -> Result {
691 match stmt {
692 ast::Statement::Bare(expr) => self.eval_expr(expr),
693 ast::Statement::Declaration(decl) => self.eval_declaration(decl),
694 }
695 }
696
697 fn eval_block(&mut self, block: &ast::Block) -> Result {
698 for stmt in block.body.iter() {
699 self.eval_statement(stmt)?;
700 }
701 Ok(Value::Unit)
702 }
703
704 fn eval_field_access(&mut self, expr: &ast::Expr, field: &ast::Identifier) -> Result {
705 let v = self.eval_expr(expr)?;
706 let base = v.as_node()?;
707 let base_node = self.get_node_by_id(base).unwrap();
708 base_node
709 .child_by_field_name(field)
710 .ok_or(Error::InvalidNodeKind(field.clone()))
711 .map(|n| n.id())
712 .map(Value::Node)
713 }
714
715 fn goto_first_child(&mut self) -> bool {
716 self.cursor
717 .as_mut()
718 .map(|c| c.goto_first_child())
719 .unwrap_or_default()
720 }
721
722 pub fn eval(&mut self) -> Result {
723 let program = std::mem::take(&mut self.program);
724 let mut has_next = true;
725 let mut postorder = Vec::new();
726
727 // BEGIN block
728 if let Some(block) = program.begin() {
729 self.eval_block(block)?;
730 }
731
732 while has_next {
733 let current_node = self.cursor.as_ref().unwrap().node();
734 postorder.push(current_node);
735
736 if let Some(block) = program.stanza_by_node(current_node, ast::Modifier::Enter) {
737 self.eval_block(block)?;
738 }
739
740 has_next = self.goto_first_child();
741
742 if !has_next {
743 has_next = self.cursor.as_mut().unwrap().goto_next_sibling();
744 if let Some(block) = postorder
745 .pop()
746 .and_then(|n| program.stanza_by_node(n, ast::Modifier::Leave))
747 {
748 self.eval_block(block)?;
749 };
750 }
751
752 while !has_next && self.cursor.as_mut().unwrap().goto_parent() {
753 has_next = self.cursor.as_mut().unwrap().goto_next_sibling();
754 if let Some(block) = postorder
755 .pop()
756 .and_then(|n| program.stanza_by_node(n, ast::Modifier::Leave))
757 {
758 self.eval_block(block)?;
759 };
760 }
761 }
762
763 // END block
764 if let Some(block) = program.end() {
765 self.eval_block(block)?;
766 }
767
768 Ok(Value::Unit)
769 }
770}
771
772pub fn evaluate(file: &str, program: &str, language: tree_sitter::Language) -> Result {
773 let mut parser = tree_sitter::Parser::new();
774 let _ = parser.set_language(&language);
775
776 let tree = parser.parse(file, None).unwrap();
777
778 let program = ast::Program::new().from_str(program).unwrap();
779 let mut ctx = Context::new(language)
780 .with_input(file.to_owned())
781 .with_tree(tree)
782 .with_program(program);
783
784 ctx.eval()
785}
786
787#[cfg(test)]
788mod test {
789 use super::*;
790 use crate::ast::*;
791
792 #[test]
793 fn bin() {
794 let language = tree_sitter_python::language();
795 let mut ctx = Context::new(language).with_program(Program::new());
796 assert_eq!(
797 ctx.eval_expr(&Expr::bin(Expr::int(5), "+", Expr::int(10),)),
798 Ok(Value::Integer(15))
799 );
800 assert_eq!(
801 ctx.eval_expr(&Expr::bin(Expr::int(5), "==", Expr::int(10),)),
802 Ok(Value::Boolean(false))
803 );
804 assert_eq!(
805 ctx.eval_expr(&Expr::bin(Expr::int(5), "<", Expr::int(10),)),
806 Ok(Value::Boolean(true))
807 );
808 assert_eq!(
809 ctx.eval_expr(&Expr::bin(
810 Expr::bin(Expr::int(5), "<", Expr::int(10),),
811 "&&",
812 Expr::false_(),
813 )),
814 Ok(Value::Boolean(false))
815 );
816 }
817
818 #[test]
819 fn test_evaluate_blocks() {
820 let language = tree_sitter_python::language();
821 let mut ctx = Context::new(language).with_program(Program::new());
822 assert_eq!(
823 ctx.eval_block(&Block {
824 body: vec![
825 Statement::Declaration(Declaration {
826 ty: Type::Integer,
827 name: "a".to_owned(),
828 init: None,
829 }),
830 Statement::Bare(Expr::bin(Expr::ident("a"), "+=", Expr::int(5),)),
831 ]
832 }),
833 Ok(Value::Unit)
834 );
835 assert_eq!(
836 ctx.lookup(&String::from("a")).unwrap().clone(),
837 Variable {
838 ty: Type::Integer,
839 name: "a".to_owned(),
840 value: Value::Integer(5)
841 }
842 );
843 }
844
845 #[test]
846 fn test_evaluate_if() {
847 let language = tree_sitter_python::language();
848 let mut ctx = Context::new(language).with_program(Program::new());
849 assert_eq!(
850 ctx.eval_block(&Block {
851 body: vec![
852 Statement::Declaration(Declaration {
853 ty: Type::Integer,
854 name: "a".to_owned(),
855 init: Some(Expr::int(1).boxed()),
856 }),
857 Statement::Bare(Expr::If(IfExpr {
858 condition: Expr::true_().boxed(),
859 then: Block {
860 body: vec![Statement::Bare(Expr::bin(
861 Expr::Ident("a".to_owned()),
862 "+=",
863 Expr::int(5),
864 ))]
865 },
866 else_: Block {
867 body: vec![Statement::Bare(Expr::bin(
868 Expr::ident("a"),
869 "+=",
870 Expr::int(10),
871 ))]
872 }
873 }))
874 ]
875 }),
876 Ok(Value::Unit)
877 );
878 assert_eq!(
879 ctx.lookup(&String::from("a")).unwrap().clone(),
880 Variable {
881 ty: Type::Integer,
882 name: "a".to_owned(),
883 value: Value::Integer(6)
884 }
885 );
886 }
887
888 #[test]
889 fn test_substring() {
890 let language = tree_sitter_python::language();
891 let mut ctx = Context::new(language).with_program(Program::new());
892 assert_eq!(
893 ctx.eval_block(&Block {
894 body: vec![
895 Statement::Declaration(Declaration {
896 ty: Type::String,
897 name: "a".to_owned(),
898 init: Some(Expr::str("foobar").boxed()),
899 }),
900 Statement::Declaration(Declaration {
901 ty: Type::String,
902 name: "b".to_owned(),
903 init: Some(
904 Expr::call(
905 "substr",
906 [Expr::Ident("a".to_owned()), Expr::int(0), Expr::int(3),]
907 )
908 .boxed()
909 ),
910 }),
911 ]
912 }),
913 Ok(Value::Unit)
914 );
915 assert_eq!(
916 ctx.lookup(&String::from("b")).unwrap().clone(),
917 Variable {
918 ty: Type::String,
919 name: "b".to_owned(),
920 value: "foo".into()
921 }
922 );
923 }
924
925 #[test]
926 fn test_list() {
927 let language = tree_sitter_python::language();
928 let mut ctx = Context::new(language).with_program(Program::new());
929 assert_eq!(
930 ctx.eval_block(&Block {
931 body: vec![Statement::Declaration(Declaration {
932 ty: Type::List,
933 name: "a".to_owned(),
934 init: Some(
935 Expr::List(List {
936 items: vec![Expr::int(5)]
937 })
938 .boxed()
939 ),
940 }),]
941 }),
942 Ok(Value::Unit)
943 );
944 assert_eq!(
945 ctx.lookup(&String::from("a")).unwrap().clone(),
946 Variable {
947 ty: Type::List,
948 name: "a".to_owned(),
949 value: vec![5usize.into()].into(),
950 }
951 );
952 }
953
954 #[test]
955 fn test_ts_builtins() {
956 let language = tree_sitter_python::language();
957 let mut ctx = Context::new(language).with_program(Program::new());
958 assert_eq!(
959 ctx.eval_block(&Block {
960 body: vec![Statement::decl(Type::List, "a", Expr::list([Expr::int(5)]),)]
961 }),
962 Ok(Value::Unit)
963 );
964 assert_eq!(
965 ctx.lookup(&String::from("a")).unwrap().clone(),
966 Variable {
967 ty: Type::List,
968 name: "a".to_owned(),
969 value: vec![5usize.into()].into(),
970 }
971 );
972 }
973}