aboutsummaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
authorAkshay <[email protected]>2024-10-07 16:18:23 +0100
committerAkshay <[email protected]>2024-10-07 16:18:23 +0100
commit1c33b810521b2ffe5108d8cef32439aef975c48d (patch)
tree7e936f8283acd14a7c8b6e3da9dc75bf6268bd32 /src/eval
parent7c9c73af1bc6cb4bbf9eff077bb524ca21031082 (diff)
refactor; start adding expect tests
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/builtins.rs256
-rw-r--r--src/eval/mod.rs1051
2 files changed, 1307 insertions, 0 deletions
diff --git a/src/eval/builtins.rs b/src/eval/builtins.rs
new file mode 100644
index 0000000..7820a8e
--- /dev/null
+++ b/src/eval/builtins.rs
@@ -0,0 +1,256 @@
1use std::{collections::HashMap, sync::LazyLock};
2
3use crate::{
4 ast,
5 eval::{Context, Error, Result, Value},
6 Wrap,
7};
8
9macro_rules! builtins {
10 ($($f:ident),* $(,)?) => {
11 pub static BUILTINS: LazyLock<HashMap<&'static str, Box<dyn Fn(&mut Context, &[ast::Expr]) -> Result + Sync + Send>>> =
12 LazyLock::new(|| {
13 [
14 $((
15 stringify!($f),
16 Box::new($f) as Box<dyn Fn(&mut Context, &[ast::Expr]) -> Result + Sync + Send>,
17 )),*
18 ]
19 .into_iter()
20 .collect()
21 });
22 }
23}
24
25builtins! {
26 print,
27 println,
28
29 // string
30 isupper,
31 islower,
32 substr,
33
34 // node
35 text,
36 parent,
37 children,
38 kind,
39
40 // list
41 length,
42 member,
43 push,
44 pop,
45 isempty,
46}
47
48fn print(ctx: &mut Context, args: &[ast::Expr]) -> Result {
49 for arg in args {
50 let val = ctx.eval_expr(arg)?;
51 let mut default_stream =Box::new(std::io::stdout()) as Box<dyn std::io::Write> ;
52 let stream = ctx
53 .output_stream
54 .as_mut()
55 .unwrap_or(&mut default_stream);
56 write!(stream, "{val}").unwrap();
57 }
58 Ok(Value::Unit)
59}
60
61fn println(ctx: &mut Context, args: &[ast::Expr]) -> Result {
62 print(ctx, args)?;
63 print(ctx, &[ast::Expr::Lit(ast::Literal::Str("\n".to_owned()))])
64}
65
66fn isupper(ctx: &mut Context, args: &[ast::Expr]) -> Result {
67 Ok(ctx
68 .eval_expr(&get_args::<1>(args)?[0])?
69 .as_str()?
70 .chars()
71 .all(|c| c.is_ascii_uppercase())
72 .into())
73}
74
75fn islower(ctx: &mut Context, args: &[ast::Expr]) -> Result {
76 Ok(ctx
77 .eval_expr(&get_args::<1>(args)?[0])?
78 .as_str()?
79 .chars()
80 .all(|c| c.is_ascii_lowercase())
81 .into())
82}
83
84fn substr(ctx: &mut Context, args: &[ast::Expr]) -> Result {
85 if let Ok([string, start, end]) = get_args::<3>(args) {
86 let v = ctx.eval_expr(string)?;
87 let s = v.as_str()?;
88 let start = ctx.eval_expr(start)?.as_int()?;
89 let end = ctx.eval_expr(end)?.as_int()?;
90 if start < 0 || start >= s.len() as i128 || end >= s.len() as i128 || start > end {
91 return Err(Error::InvalidStringSlice {
92 length: s.len(),
93 start,
94 end,
95 });
96 }
97 Ok(s[start as usize..end as usize].into())
98 } else {
99 let [string, end] = get_args::<2>(args)?;
100 let v = ctx.eval_expr(string)?;
101 let s = v.as_str()?;
102 let end = ctx.eval_expr(end)?.as_int()?;
103 if end >= s.len() as i128 {
104 return Err(Error::InvalidStringSlice {
105 length: s.len(),
106 start: 0,
107 end,
108 });
109 }
110 Ok(s[..end as usize].into())
111 }
112}
113
114fn text(ctx: &mut Context, args: &[ast::Expr]) -> Result {
115 let v = ctx.eval_expr(&get_args::<1>(args)?[0])?;
116 let id = v.as_node()?;
117 let node = ctx.get_node_by_id(id).unwrap();
118 let text = node
119 .utf8_text(ctx.input_src.as_ref().unwrap().as_bytes())
120 .unwrap();
121 text.to_owned().wrap(Value::String).wrap(Ok)
122}
123
124fn parent(ctx: &mut Context, args: &[ast::Expr]) -> Result {
125 let v = ctx.eval_expr(&get_args::<1>(args)?[0])?;
126 let id = v.as_node()?;
127 let node = ctx.get_node_by_id(id).unwrap();
128 let parent = node.parent();
129 parent
130 .map(|n| Value::Node(n.id()))
131 .ok_or(Error::NoParentNode(node))
132}
133
134fn children(ctx: &mut Context, args: &[ast::Expr]) -> Result {
135 let v = ctx.eval_expr(&get_args::<1>(args)?[0])?;
136 let id = v.as_node()?;
137 let node = ctx.get_node_by_id(id).unwrap();
138 let children = node
139 .children(&mut node.walk())
140 .map(|c| Value::Node(c.id()))
141 .collect::<Vec<_>>();
142 Ok(Value::List(children))
143}
144
145fn length(ctx: &mut Context, args: &[ast::Expr]) -> Result {
146 let v = ctx.eval_expr(&get_args::<1>(args)?[0])?;
147 let l = v.as_list()?;
148 (l.len() as i128).wrap(Value::Integer).wrap(Ok)
149}
150
151fn kind(ctx: &mut Context, args: &[ast::Expr]) -> Result {
152 let v = ctx.eval_expr(&get_args::<1>(args)?[0])?;
153 let id = v.as_node()?;
154 let node = ctx.get_node_by_id(id).unwrap();
155 node.kind().to_owned().wrap(Value::String).wrap(Ok)
156}
157
158fn member(ctx: &mut Context, args: &[ast::Expr]) -> Result {
159 let [list_expr, element_expr] = get_args::<2>(args)?;
160 let list = ctx.eval_expr(&list_expr)?;
161 let v = list.as_list()?;
162 let element = ctx.eval_expr(&element_expr)?;
163 v.iter()
164 .any(|item| item == &element)
165 .wrap(Value::Boolean)
166 .wrap(Ok)
167}
168
169fn push(ctx: &mut Context, args: &[ast::Expr]) -> Result {
170 let [lhs, rhs] = get_args::<2>(args)?;
171 let ast::Expr::Ident(ident) = lhs else {
172 return Err(Error::MalformedExpr(format!(
173 "malformed assigment, lhs: {:?}",
174 lhs
175 )));
176 };
177 let element = ctx.eval_expr(&rhs)?;
178 let variable = ctx.lookup_mut(ident)?;
179 variable.mutate(|v| match &mut v.value {
180 Value::List(l) => {
181 l.push(element);
182 Ok(Value::Unit)
183 }
184 _ => Err(v.ty().expected([ast::Type::List])),
185 })
186}
187
188fn pop(ctx: &mut Context, args: &[ast::Expr]) -> Result {
189 let [lhs] = get_args::<1>(args)?;
190 let ast::Expr::Ident(ident) = lhs else {
191 return Err(Error::MalformedExpr(format!(
192 "malformed assigment, lhs: {:?}",
193 lhs
194 )));
195 };
196 let variable = ctx.lookup_mut(ident)?;
197 variable.mutate(|v| match &mut v.value {
198 Value::List(l) => l
199 .pop()
200 .ok_or_else(|| Error::ArrayOutOfBounds { idx: 0, len: 0 }),
201 _ => Err(v.ty().expected([ast::Type::List])),
202 })
203}
204
205fn isempty(ctx: &mut Context, args: &[ast::Expr]) -> Result {
206 let v = ctx.eval_expr(&get_args::<1>(args)?[0])?;
207 match v.ty() {
208 ast::Type::List => v
209 .as_list()
210 .unwrap()
211 .is_empty()
212 .wrap(Value::Boolean)
213 .wrap(Ok),
214 ast::Type::String => v
215 .as_str()
216 .unwrap()
217 .is_empty()
218 .wrap(Value::Boolean)
219 .wrap(Ok),
220 _ => Err(v.ty().expected([ast::Type::List])),
221 }
222}
223
224fn get_args<const N: usize>(args: &[ast::Expr]) -> std::result::Result<&[ast::Expr; N], Error> {
225 args.try_into().map_err(|_| Error::IncorrectArgFormat {
226 wanted: N,
227 got: args.len(),
228 })
229}
230
231#[cfg(test)]
232mod test {
233 use super::*;
234 use crate::{ast::*, eval::*};
235
236 #[test]
237 fn test_ts_builtins() {
238 let language = tree_sitter_python::language();
239 let mut ctx = Context::new(language).with_program(Program::new());
240
241 assert_eq!(
242 ctx.eval_block(&Block {
243 body: vec![Statement::decl(Type::List, "a", Expr::list([Expr::int(5)]),)]
244 }),
245 Ok(Value::Unit)
246 );
247 assert_eq!(
248 ctx.lookup(&String::from("a")).unwrap().clone(),
249 Variable {
250 ty: Type::List,
251 name: "a".to_owned(),
252 value: vec![5usize.into()].into(),
253 }
254 );
255 }
256}
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
new file mode 100644
index 0000000..c4460c0
--- /dev/null
+++ b/src/eval/mod.rs
@@ -0,0 +1,1051 @@
1//! tree walking interpreter for tbsp
2
3use crate::{ast, Wrap};
4use std::{collections::HashMap, fmt, io};
5
6mod builtins;
7
8#[derive(Debug, PartialEq, Eq, Clone)]
9pub struct Variable {
10 pub ty: ast::Type,
11 pub name: ast::Identifier,
12 pub value: Value,
13}
14
15impl Variable {
16 fn value(&self) -> &Value {
17 &self.value
18 }
19
20 pub(crate) fn ty(&self) -> ast::Type {
21 self.ty
22 }
23
24 fn assign(&mut self, value: Value) -> Result {
25 if self.ty() == value.ty() {
26 self.value = value;
27 Ok(self.value.clone())
28 } else {
29 Err(value.ty().expected([self.ty()]))
30 }
31 }
32
33 pub(crate) fn mutate(&mut self, f: impl FnOnce(&mut Self) -> Result) -> Result {
34 f(self)
35 }
36}
37
38#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
39pub enum Value {
40 Unit,
41 Integer(i128),
42 String(String),
43 Boolean(bool),
44 Node(NodeId),
45 List(Vec<Value>),
46}
47
48type NodeId = usize;
49
50impl Value {
51 pub(crate) fn ty(&self) -> ast::Type {
52 match self {
53 Self::Unit => ast::Type::Unit,
54 Self::Integer(_) => ast::Type::Integer,
55 Self::String(_) => ast::Type::String,
56 Self::Boolean(_) => ast::Type::Boolean,
57 Self::Node(_) => ast::Type::Node,
58 Self::List(_) => ast::Type::List,
59 }
60 }
61
62 fn default(ty: ast::Type) -> Self {
63 match ty {
64 ast::Type::Unit => Self::Unit,
65 ast::Type::Integer => Self::default_int(),
66 ast::Type::String => Self::default_string(),
67 ast::Type::Boolean => Self::default_bool(),
68 ast::Type::Node => unreachable!(),
69 ast::Type::List => Self::default_list(),
70 }
71 }
72
73 fn default_int() -> Self {
74 Self::Integer(0)
75 }
76
77 fn default_bool() -> Self {
78 Self::Boolean(false)
79 }
80
81 fn default_string() -> Self {
82 Self::String(String::default())
83 }
84
85 fn default_list() -> Self {
86 Self::List(Vec::new())
87 }
88
89 fn as_boolean(&self) -> std::result::Result<bool, Error> {
90 match self {
91 Self::Boolean(b) => Ok(*b),
92 v => Err(v.ty().expected([ast::Type::Boolean])),
93 }
94 }
95
96 pub(crate) fn as_str(&self) -> std::result::Result<&str, Error> {
97 match self {
98 Self::String(s) => Ok(s.as_str()),
99 v => Err(v.ty().expected([ast::Type::String])),
100 }
101 }
102
103 pub(crate) fn as_int(&self) -> std::result::Result<i128, Error> {
104 match self {
105 Self::Integer(i) => Ok(*i),
106 v => Err(v.ty().expected([ast::Type::Integer])),
107 }
108 }
109
110 pub(crate) fn as_node(&self) -> std::result::Result<NodeId, Error> {
111 match self {
112 Self::Node(id) => Ok(*id),
113 v => Err(v.ty().expected([ast::Type::Node])),
114 }
115 }
116
117 pub(crate) fn as_list(&self) -> std::result::Result<Vec<Value>, Error> {
118 match self {
119 Self::List(values) => Ok(values.clone()),
120 v => Err(v.ty().expected([ast::Type::List])),
121 }
122 }
123
124 fn add(&self, other: &Self) -> Result {
125 match (self, other) {
126 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Integer(*s + *o)),
127 (Self::String(s), Self::String(o)) => Ok(Self::String(format!("{s}{o}"))),
128 (Self::List(l), o) => Ok(Self::List(l.iter().cloned().chain([o.clone()]).collect())),
129 _ => Err(Error::UndefinedBinOp(
130 ast::BinOp::Arith(ast::ArithOp::Add),
131 self.ty(),
132 other.ty(),
133 )),
134 }
135 }
136
137 fn sub(&self, other: &Self) -> Result {
138 match (self, other) {
139 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Integer(*s - *o)),
140 (Self::String(s), Self::String(o)) => {
141 Ok(Self::String(s.strip_suffix(o).unwrap_or(s).to_owned()))
142 }
143 _ => Err(Error::UndefinedBinOp(
144 ast::BinOp::Arith(ast::ArithOp::Sub),
145 self.ty(),
146 other.ty(),
147 )),
148 }
149 }
150
151 fn mul(&self, other: &Self) -> Result {
152 match (self, other) {
153 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Integer(*s * *o)),
154 (Self::Integer(s), Self::String(o)) => Ok(Self::String(o.repeat(*s as usize))),
155 (Self::String(_), Self::Integer(_)) => other.mul(self),
156 _ => Err(Error::UndefinedBinOp(
157 ast::BinOp::Arith(ast::ArithOp::Mul),
158 self.ty(),
159 other.ty(),
160 )),
161 }
162 }
163
164 fn div(&self, other: &Self) -> Result {
165 match (self, other) {
166 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Integer(*s / *o)),
167 _ => Err(Error::UndefinedBinOp(
168 ast::BinOp::Arith(ast::ArithOp::Div),
169 self.ty(),
170 other.ty(),
171 )),
172 }
173 }
174
175 fn mod_(&self, other: &Self) -> Result {
176 match (self, other) {
177 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Integer(*s % *o)),
178 _ => Err(Error::UndefinedBinOp(
179 ast::BinOp::Arith(ast::ArithOp::Mod),
180 self.ty(),
181 other.ty(),
182 )),
183 }
184 }
185
186 fn equals(&self, other: &Self) -> Result {
187 match (self, other) {
188 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Boolean(s == o)),
189 (Self::String(s), Self::String(o)) => Ok(Self::Boolean(s == o)),
190 (Self::Boolean(s), Self::Boolean(o)) => Ok(Self::Boolean(s == o)),
191 _ => Err(Error::UndefinedBinOp(
192 ast::BinOp::Cmp(ast::CmpOp::Eq),
193 self.ty(),
194 other.ty(),
195 )),
196 }
197 }
198
199 fn greater_than(&self, other: &Self) -> Result {
200 match (self, other) {
201 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Boolean(s > o)),
202 (Self::String(s), Self::String(o)) => Ok(Self::Boolean(s.cmp(o).is_gt())),
203 _ => Err(Error::UndefinedBinOp(
204 ast::BinOp::Cmp(ast::CmpOp::Gt),
205 self.ty(),
206 other.ty(),
207 )),
208 }
209 }
210
211 fn less_than(&self, other: &Self) -> Result {
212 match (self, other) {
213 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Boolean(s < o)),
214 (Self::String(s), Self::String(o)) => Ok(Self::Boolean(s.cmp(o).is_lt())),
215 _ => Err(Error::UndefinedBinOp(
216 ast::BinOp::Cmp(ast::CmpOp::Lt),
217 self.ty(),
218 other.ty(),
219 )),
220 }
221 }
222
223 fn greater_than_equals(&self, other: &Self) -> Result {
224 match (self, other) {
225 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Boolean(s >= o)),
226 (Self::String(s), Self::String(o)) => Ok(Self::Boolean(s.cmp(o).is_ge())),
227 (Self::Boolean(s), Self::Boolean(o)) => Ok(Self::Boolean(s == o)),
228 _ => Err(Error::UndefinedBinOp(
229 ast::BinOp::Cmp(ast::CmpOp::Gte),
230 self.ty(),
231 other.ty(),
232 )),
233 }
234 }
235
236 fn less_than_equals(&self, other: &Self) -> Result {
237 match (self, other) {
238 (Self::Integer(s), Self::Integer(o)) => Ok(Self::Boolean(s <= o)),
239 (Self::String(s), Self::String(o)) => Ok(Self::Boolean(s.cmp(o).is_le())),
240 (Self::Boolean(s), Self::Boolean(o)) => Ok(Self::Boolean(s == o)),
241 _ => Err(Error::UndefinedBinOp(
242 ast::BinOp::Cmp(ast::CmpOp::Lte),
243 self.ty(),
244 other.ty(),
245 )),
246 }
247 }
248
249 fn not(&self) -> Result {
250 match self {
251 Self::Boolean(s) => Ok(Self::Boolean(!s)),
252 _ => Err(Error::UndefinedUnaryOp(ast::UnaryOp::Not, self.ty())),
253 }
254 }
255
256 fn and(&self, other: &Self) -> Result {
257 match (self, other) {
258 (Self::Boolean(s), Self::Boolean(o)) => Ok(Self::Boolean(*s && *o)),
259 _ => Err(Error::UndefinedBinOp(
260 ast::BinOp::Logic(ast::LogicOp::And),
261 self.ty(),
262 other.ty(),
263 )),
264 }
265 }
266
267 fn or(&self, other: &Self) -> Result {
268 match (self, other) {
269 (Self::Boolean(s), Self::Boolean(o)) => Ok(Self::Boolean(*s || *o)),
270 _ => Err(Error::UndefinedBinOp(
271 ast::BinOp::Logic(ast::LogicOp::Or),
272 self.ty(),
273 other.ty(),
274 )),
275 }
276 }
277}
278
279impl fmt::Display for Value {
280 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281 match self {
282 Self::Unit => write!(f, "()"),
283 Self::Integer(i) => write!(f, "{i}"),
284 Self::String(s) => write!(f, "{s}"),
285 Self::Boolean(b) => write!(f, "{b}"),
286 Self::Node(id) => write!(f, "<node #{id}>"),
287 Self::List(items) => {
288 write!(f, "[")?;
289 let mut iterable = items.iter().peekable();
290 while let Some(item) = iterable.next() {
291 if iterable.peek().is_none() {
292 write!(f, "{item}")?;
293 } else {
294 write!(f, "{item}, ")?;
295 }
296 }
297 write!(f, "]")
298 }
299 }
300 }
301}
302
303impl From<bool> for Value {
304 fn from(value: bool) -> Self {
305 Self::Boolean(value)
306 }
307}
308
309impl From<i128> for Value {
310 fn from(value: i128) -> Self {
311 Self::Integer(value)
312 }
313}
314
315impl From<usize> for Value {
316 fn from(value: usize) -> Self {
317 (value as i128).into()
318 }
319}
320
321impl From<&str> for Value {
322 fn from(value: &str) -> Self {
323 Self::String(value.to_owned())
324 }
325}
326
327impl From<Vec<Value>> for Value {
328 fn from(value: Vec<Value>) -> Self {
329 Self::List(value)
330 }
331}
332
333#[derive(Debug, PartialEq, Eq)]
334pub enum Error {
335 FailedLookup(ast::Identifier),
336 TypeMismatch {
337 expected: Vec<ast::Type>,
338 got: ast::Type,
339 },
340 UndefinedBinOp(ast::BinOp, ast::Type, ast::Type),
341 UndefinedUnaryOp(ast::UnaryOp, ast::Type),
342 AlreadyBound(ast::Identifier),
343 MalformedExpr(String),
344 InvalidNodeKind(String),
345 NoParentNode(tree_sitter::Node<'static>),
346 IncorrectArgFormat {
347 wanted: usize,
348 got: usize,
349 },
350 InvalidStringSlice {
351 length: usize,
352 start: i128,
353 end: i128,
354 },
355 ArrayOutOfBounds {
356 idx: i128,
357 len: usize,
358 },
359 // current node is only set in visitors, not in BEGIN or END blocks
360 CurrentNodeNotPresent,
361}
362
363impl ast::Type {
364 pub fn expected<const N: usize>(self, expected: [Self; N]) -> Error {
365 Error::TypeMismatch {
366 expected: expected.to_vec(),
367 got: self,
368 }
369 }
370}
371
372pub type Result = std::result::Result<Value, Error>;
373
374pub struct Context<'s> {
375 variables: HashMap<ast::Identifier, Variable>,
376 language: tree_sitter::Language,
377 program: ast::Program,
378 pub(crate) input_src: Option<String>,
379 cursor: Option<tree_sitter::TreeCursor<'static>>,
380 tree: Option<&'static tree_sitter::Tree>,
381 cache: HashMap<NodeId, tree_sitter::Node<'static>>,
382 output_stream: Option<Box<dyn io::Write + 's>>,
383}
384
385impl<'s> fmt::Debug for Context<'s> {
386 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
387 f.debug_struct("Context")
388 .field("variables", &self.variables)
389 .field("language", &self.language)
390 .field("input_src", &self.input_src)
391 .field(
392 "cursor",
393 if self.cursor.is_some() {
394 &"Some(<cursor>)"
395 } else {
396 &"None"
397 },
398 )
399 .finish()
400 }
401}
402
403impl<'s> Context<'s> {
404 pub fn new(language: tree_sitter::Language) -> Self {
405 Self {
406 program: Default::default(),
407 variables: Default::default(),
408 language,
409 input_src: None,
410 cursor: None,
411 tree: None,
412 cache: HashMap::default(),
413 output_stream: Some(Box::new(io::stdout()) as Box<dyn io::Write + 's>),
414 }
415 }
416
417 pub fn cache_node(&mut self, node: tree_sitter::Node<'static>) {
418 self.cache.entry(node.id()).or_insert(node);
419 }
420
421 pub fn get_node_by_id(&mut self, id: usize) -> Option<tree_sitter::Node<'static>> {
422 let root_node = self.tree.as_ref().map(|t| t.root_node())?;
423 self.get_node_by_id_helper(root_node, id)
424 }
425
426 fn get_node_by_id_helper(
427 &mut self,
428 start: tree_sitter::Node<'static>,
429 id: usize,
430 ) -> Option<tree_sitter::Node<'static>> {
431 self.cache_node(start);
432
433 if let Some(found) = self.cache.get(&id) {
434 return Some(*found);
435 }
436
437 if start.id() == id {
438 return Some(start);
439 } else {
440 for child in start.children(&mut start.walk()) {
441 if let Some(n) = self.get_node_by_id_helper(child, id) {
442 return Some(n);
443 };
444 }
445 }
446
447 None
448 }
449
450 pub fn with_program(mut self, program: ast::Program) -> Self {
451 self.program = program;
452 self
453 }
454
455 pub fn with_input(mut self, src: String) -> Self {
456 self.input_src = Some(src);
457 self
458 }
459
460 pub fn with_tree(mut self, tree: tree_sitter::Tree) -> Self {
461 let tree = Box::leak(Box::new(tree));
462 self.cursor = Some(tree.walk());
463 self.tree = Some(tree);
464 self
465 }
466
467 pub fn with_output_stream(mut self, stream: Box<dyn io::Write + 's>) -> Self {
468 self.output_stream = Some(stream);
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 ((&*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_output_stream(Box::new(io::stdout()))
783 .with_program(program);
784
785 ctx.eval()
786}
787
788#[cfg(test)]
789mod test {
790 use super::*;
791 use crate::ast::*;
792 use expect_test::{expect, Expect};
793
794 fn gen_test(file: &str, program: &str, expected: Expect) {
795 let language = tree_sitter_python::language();
796 let mut parser = tree_sitter::Parser::new();
797 let _ = parser.set_language(&language);
798 let tree = parser.parse(file, None).unwrap();
799 let program = ast::Program::new().from_str(program).unwrap();
800
801 let mut output = Vec::new();
802 let mut ctx = Context::new(language)
803 .with_input(file.to_owned())
804 .with_tree(tree)
805 .with_program(program)
806 .with_output_stream(Box::new(&mut output) as Box<dyn io::Write>);
807
808 ctx.eval().unwrap();
809
810 drop(ctx);
811
812 expected.assert_eq(&String::from_utf8(output).unwrap())
813 }
814
815 #[test]
816 fn bin() {
817 let language = tree_sitter_python::language();
818 let mut ctx = Context::new(language).with_program(Program::new());
819 assert_eq!(
820 ctx.eval_expr(&Expr::bin(Expr::int(5), "+", Expr::int(10),)),
821 Ok(Value::Integer(15))
822 );
823 assert_eq!(
824 ctx.eval_expr(&Expr::bin(Expr::int(5), "==", Expr::int(10),)),
825 Ok(Value::Boolean(false))
826 );
827 assert_eq!(
828 ctx.eval_expr(&Expr::bin(Expr::int(5), "<", Expr::int(10),)),
829 Ok(Value::Boolean(true))
830 );
831 assert_eq!(
832 ctx.eval_expr(&Expr::bin(
833 Expr::bin(Expr::int(5), "<", Expr::int(10),),
834 "&&",
835 Expr::false_(),
836 )),
837 Ok(Value::Boolean(false))
838 );
839 }
840
841 #[test]
842 fn test_evaluate_blocks() {
843 let language = tree_sitter_python::language();
844 let mut ctx = Context::new(language).with_program(Program::new());
845 assert_eq!(
846 ctx.eval_block(&Block {
847 body: vec![
848 Statement::Declaration(Declaration {
849 ty: Type::Integer,
850 name: "a".to_owned(),
851 init: None,
852 }),
853 Statement::Bare(Expr::bin(Expr::ident("a"), "+=", Expr::int(5),)),
854 ]
855 }),
856 Ok(Value::Unit)
857 );
858 assert_eq!(
859 ctx.lookup(&String::from("a")).unwrap().clone(),
860 Variable {
861 ty: Type::Integer,
862 name: "a".to_owned(),
863 value: Value::Integer(5)
864 }
865 );
866 }
867
868 #[test]
869 fn test_evaluate_if() {
870 let language = tree_sitter_python::language();
871 let mut ctx = Context::new(language).with_program(Program::new());
872 assert_eq!(
873 ctx.eval_block(&Block {
874 body: vec![
875 Statement::Declaration(Declaration {
876 ty: Type::Integer,
877 name: "a".to_owned(),
878 init: Some(Expr::int(1).boxed()),
879 }),
880 Statement::Bare(Expr::If(IfExpr {
881 condition: Expr::true_().boxed(),
882 then: Block {
883 body: vec![Statement::Bare(Expr::bin(
884 Expr::Ident("a".to_owned()),
885 "+=",
886 Expr::int(5),
887 ))]
888 },
889 else_: Block {
890 body: vec![Statement::Bare(Expr::bin(
891 Expr::ident("a"),
892 "+=",
893 Expr::int(10),
894 ))]
895 }
896 }))
897 ]
898 }),
899 Ok(Value::Unit)
900 );
901 assert_eq!(
902 ctx.lookup(&String::from("a")).unwrap().clone(),
903 Variable {
904 ty: Type::Integer,
905 name: "a".to_owned(),
906 value: Value::Integer(6)
907 }
908 );
909 }
910
911 #[test]
912 fn test_substring() {
913 let language = tree_sitter_python::language();
914 let mut ctx = Context::new(language).with_program(Program::new());
915 assert_eq!(
916 ctx.eval_block(&Block {
917 body: vec![
918 Statement::Declaration(Declaration {
919 ty: Type::String,
920 name: "a".to_owned(),
921 init: Some(Expr::str("foobar").boxed()),
922 }),
923 Statement::Declaration(Declaration {
924 ty: Type::String,
925 name: "b".to_owned(),
926 init: Some(
927 Expr::call(
928 "substr",
929 [Expr::Ident("a".to_owned()), Expr::int(0), Expr::int(3),]
930 )
931 .boxed()
932 ),
933 }),
934 ]
935 }),
936 Ok(Value::Unit)
937 );
938 assert_eq!(
939 ctx.lookup(&String::from("b")).unwrap().clone(),
940 Variable {
941 ty: Type::String,
942 name: "b".to_owned(),
943 value: "foo".into()
944 }
945 );
946 }
947
948 #[test]
949 fn test_list() {
950 let language = tree_sitter_python::language();
951 let mut ctx = Context::new(language).with_program(Program::new());
952 assert_eq!(
953 ctx.eval_block(&Block {
954 body: vec![Statement::Declaration(Declaration {
955 ty: Type::List,
956 name: "a".to_owned(),
957 init: Some(
958 Expr::List(List {
959 items: vec![Expr::int(5)]
960 })
961 .boxed()
962 ),
963 }),]
964 }),
965 Ok(Value::Unit)
966 );
967 assert_eq!(
968 ctx.lookup(&String::from("a")).unwrap().clone(),
969 Variable {
970 ty: Type::List,
971 name: "a".to_owned(),
972 value: vec![5usize.into()].into(),
973 }
974 );
975 }
976
977 #[test]
978 fn list_builtins() {
979 gen_test(
980 "",
981 "BEGIN {
982 list a = [5];
983 print(a);
984 }
985 ",
986 expect!["[5]"]
987 );
988
989 gen_test(
990 "",
991 "BEGIN {
992 list a = [5, 4, 3];
993 print(length(a));
994 }
995 ",
996 expect!["3"]
997 );
998
999 gen_test(
1000 "",
1001 r#"BEGIN {
1002 list a = [5, 4, 3];
1003 print(member(a, 3));
1004 print(", ");
1005 print(member(a, 6));
1006 }
1007 "#,
1008 expect!["true, false"]
1009 );
1010
1011 gen_test(
1012 "",
1013 r#"BEGIN {
1014 list a = [5];
1015 println(a);
1016 push(a, 4);
1017 println(a);
1018 push(a, 3);
1019 println(a);
1020 pop(a);
1021 println(a);
1022 pop(a);
1023 println(a);
1024 }
1025 "#,
1026 expect![[r#"
1027 [5]
1028 [5, 4]
1029 [5, 4, 3]
1030 [5, 4]
1031 [5]
1032 "#]]
1033 );
1034
1035 gen_test(
1036 "",
1037 r#"BEGIN {
1038 list a = [5];
1039 println(isempty(a));
1040 pop(a);
1041 println(isempty(a));
1042 }
1043 "#,
1044 expect![[r#"
1045 false
1046 true
1047 "#]]
1048 );
1049
1050 }
1051}