diff options
Diffstat (limited to 'src/eval.rs')
-rw-r--r-- | src/eval.rs | 106 |
1 files changed, 102 insertions, 4 deletions
diff --git a/src/eval.rs b/src/eval.rs index 7822419..104571b 100644 --- a/src/eval.rs +++ b/src/eval.rs | |||
@@ -15,17 +15,17 @@ impl Variable { | |||
15 | &self.value | 15 | &self.value |
16 | } | 16 | } |
17 | 17 | ||
18 | fn ty(&self) -> ast::Type { | 18 | fn ty(&self) -> &ast::Type { |
19 | self.ty | 19 | &self.ty |
20 | } | 20 | } |
21 | 21 | ||
22 | fn assign(&mut self, value: Value) -> Result { | 22 | fn assign(&mut self, value: Value) -> Result { |
23 | if self.ty() == value.ty() { | 23 | if self.ty() == &value.ty() { |
24 | self.value = value; | 24 | self.value = value; |
25 | Ok(self.value.clone()) | 25 | Ok(self.value.clone()) |
26 | } else { | 26 | } else { |
27 | Err(Error::TypeMismatch { | 27 | Err(Error::TypeMismatch { |
28 | expected: self.ty(), | 28 | expected: self.ty().clone(), |
29 | got: value.ty(), | 29 | got: value.ty(), |
30 | }) | 30 | }) |
31 | } | 31 | } |
@@ -39,6 +39,7 @@ pub enum Value { | |||
39 | String(String), | 39 | String(String), |
40 | Boolean(bool), | 40 | Boolean(bool), |
41 | Node(NodeId), | 41 | Node(NodeId), |
42 | List(Vec<Value>), | ||
42 | } | 43 | } |
43 | 44 | ||
44 | type NodeId = usize; | 45 | type NodeId = usize; |
@@ -51,6 +52,7 @@ impl Value { | |||
51 | Self::String(_) => ast::Type::String, | 52 | Self::String(_) => ast::Type::String, |
52 | Self::Boolean(_) => ast::Type::Boolean, | 53 | Self::Boolean(_) => ast::Type::Boolean, |
53 | Self::Node(_) => ast::Type::Node, | 54 | Self::Node(_) => ast::Type::Node, |
55 | Self::List(_) => ast::Type::List, | ||
54 | } | 56 | } |
55 | } | 57 | } |
56 | 58 | ||
@@ -61,6 +63,7 @@ impl Value { | |||
61 | ast::Type::String => Self::default_string(), | 63 | ast::Type::String => Self::default_string(), |
62 | ast::Type::Boolean => Self::default_bool(), | 64 | ast::Type::Boolean => Self::default_bool(), |
63 | ast::Type::Node => unreachable!(), | 65 | ast::Type::Node => unreachable!(), |
66 | ast::Type::List => Self::default_list(), | ||
64 | } | 67 | } |
65 | } | 68 | } |
66 | 69 | ||
@@ -76,6 +79,10 @@ impl Value { | |||
76 | Self::String(String::default()) | 79 | Self::String(String::default()) |
77 | } | 80 | } |
78 | 81 | ||
82 | fn default_list() -> Self { | ||
83 | Self::List(Vec::new()) | ||
84 | } | ||
85 | |||
79 | fn as_boolean(&self) -> std::result::Result<bool, Error> { | 86 | fn as_boolean(&self) -> std::result::Result<bool, Error> { |
80 | match self { | 87 | match self { |
81 | Self::Boolean(b) => Ok(*b), | 88 | Self::Boolean(b) => Ok(*b), |
@@ -116,6 +123,16 @@ impl Value { | |||
116 | } | 123 | } |
117 | } | 124 | } |
118 | 125 | ||
126 | fn as_list(&self) -> std::result::Result<Vec<Value>, Error> { | ||
127 | match self { | ||
128 | Self::List(values) => Ok(values.clone()), | ||
129 | v => Err(Error::TypeMismatch { | ||
130 | expected: ast::Type::List, | ||
131 | got: v.ty(), | ||
132 | }), | ||
133 | } | ||
134 | } | ||
135 | |||
119 | fn add(&self, other: &Self) -> Result { | 136 | fn add(&self, other: &Self) -> Result { |
120 | match (self, other) { | 137 | match (self, other) { |
121 | (Self::Integer(s), Self::Integer(o)) => Ok(Self::Integer(*s + *o)), | 138 | (Self::Integer(s), Self::Integer(o)) => Ok(Self::Integer(*s + *o)), |
@@ -278,6 +295,13 @@ impl fmt::Display for Value { | |||
278 | Self::String(s) => write!(f, "{s}"), | 295 | Self::String(s) => write!(f, "{s}"), |
279 | Self::Boolean(b) => write!(f, "{b}"), | 296 | Self::Boolean(b) => write!(f, "{b}"), |
280 | Self::Node(id) => write!(f, "<node #{id}>"), | 297 | Self::Node(id) => write!(f, "<node #{id}>"), |
298 | Self::List(items) => { | ||
299 | write!(f, "[")?; | ||
300 | for i in items { | ||
301 | write!(f, "{i}")?; | ||
302 | } | ||
303 | write!(f, "]") | ||
304 | } | ||
281 | } | 305 | } |
282 | } | 306 | } |
283 | } | 307 | } |
@@ -300,6 +324,12 @@ impl From<&str> for Value { | |||
300 | } | 324 | } |
301 | } | 325 | } |
302 | 326 | ||
327 | impl From<Vec<Value>> for Value { | ||
328 | fn from(value: Vec<Value>) -> Self { | ||
329 | Self::List(value) | ||
330 | } | ||
331 | } | ||
332 | |||
303 | type NodeKind = u16; | 333 | type NodeKind = u16; |
304 | 334 | ||
305 | #[derive(Debug, Default)] | 335 | #[derive(Debug, Default)] |
@@ -371,11 +401,16 @@ pub enum Error { | |||
371 | AlreadyBound(ast::Identifier), | 401 | AlreadyBound(ast::Identifier), |
372 | MalformedExpr(String), | 402 | MalformedExpr(String), |
373 | InvalidNodeKind(String), | 403 | InvalidNodeKind(String), |
404 | NoParentNode(tree_sitter::Node<'static>), | ||
374 | InvalidStringSlice { | 405 | InvalidStringSlice { |
375 | length: usize, | 406 | length: usize, |
376 | start: i128, | 407 | start: i128, |
377 | end: i128, | 408 | end: i128, |
378 | }, | 409 | }, |
410 | ArrayOutOfBounds { | ||
411 | idx: i128, | ||
412 | len: usize | ||
413 | }, | ||
379 | // current node is only set in visitors, not in BEGIN or END blocks | 414 | // current node is only set in visitors, not in BEGIN or END blocks |
380 | CurrentNodeNotPresent, | 415 | CurrentNodeNotPresent, |
381 | } | 416 | } |
@@ -484,6 +519,8 @@ impl Context { | |||
484 | ast::Expr::Bin(lhs, op, rhs) => self.eval_bin(&*lhs, *op, &*rhs), | 519 | ast::Expr::Bin(lhs, op, rhs) => self.eval_bin(&*lhs, *op, &*rhs), |
485 | ast::Expr::Unary(expr, op) => self.eval_unary(&*expr, *op), | 520 | ast::Expr::Unary(expr, op) => self.eval_unary(&*expr, *op), |
486 | ast::Expr::Call(call) => self.eval_call(&*call), | 521 | ast::Expr::Call(call) => self.eval_call(&*call), |
522 | ast::Expr::List(list) => self.eval_list(&*list), | ||
523 | ast::Expr::Index(target, idx) => self.eval_index(&*target, &*idx), | ||
487 | ast::Expr::If(if_expr) => self.eval_if(if_expr), | 524 | ast::Expr::If(if_expr) => self.eval_if(if_expr), |
488 | ast::Expr::Block(block) => self.eval_block(block), | 525 | ast::Expr::Block(block) => self.eval_block(block), |
489 | ast::Expr::Node => self.eval_node(), | 526 | ast::Expr::Node => self.eval_node(), |
@@ -704,10 +741,40 @@ impl Context { | |||
704 | .unwrap(); | 741 | .unwrap(); |
705 | Ok(Value::String(text.to_owned())) | 742 | Ok(Value::String(text.to_owned())) |
706 | } | 743 | } |
744 | ("parent", [arg]) => { | ||
745 | let v = self.eval_expr(arg)?; | ||
746 | let id = v.as_node()?; | ||
747 | let node = self.get_node_by_id(id).unwrap(); | ||
748 | let parent = node.parent(); | ||
749 | parent | ||
750 | .map(|n| Value::Node(n.id())) | ||
751 | .ok_or(Error::NoParentNode(node)) | ||
752 | } | ||
707 | (s, _) => Err(Error::FailedLookup(s.to_owned())), | 753 | (s, _) => Err(Error::FailedLookup(s.to_owned())), |
708 | } | 754 | } |
709 | } | 755 | } |
710 | 756 | ||
757 | fn eval_list(&mut self, list: &ast::List) -> Result { | ||
758 | let mut vals = vec![]; | ||
759 | for i in &list.items { | ||
760 | vals.push(self.eval_expr(i)?); | ||
761 | } | ||
762 | Ok(vals.into()) | ||
763 | } | ||
764 | |||
765 | fn eval_index(&mut self, target: &ast::Expr, idx: &ast::Expr) -> Result { | ||
766 | let mut target = self.eval_expr(target)?.as_list()?; | ||
767 | let idx = self.eval_expr(idx)?.as_int()?; | ||
768 | if idx < 0 || idx >= target.len() as i128 { | ||
769 | Err(Error::ArrayOutOfBounds { | ||
770 | idx, | ||
771 | len: target.len() | ||
772 | }) | ||
773 | } else { | ||
774 | Ok(target.remove(idx as usize)) | ||
775 | } | ||
776 | } | ||
777 | |||
711 | fn eval_declaration(&mut self, decl: &ast::Declaration) -> Result { | 778 | fn eval_declaration(&mut self, decl: &ast::Declaration) -> Result { |
712 | let initial_value = match decl.init.as_ref() { | 779 | let initial_value = match decl.init.as_ref() { |
713 | Some(init) => Some(self.eval_expr(&*init)?), | 780 | Some(init) => Some(self.eval_expr(&*init)?), |
@@ -986,4 +1053,35 @@ mod test { | |||
986 | } | 1053 | } |
987 | ); | 1054 | ); |
988 | } | 1055 | } |
1056 | |||
1057 | #[test] | ||
1058 | fn test_list() { | ||
1059 | let language = tree_sitter_python::language(); | ||
1060 | let mut ctx = Context::new(language) | ||
1061 | .with_program(ast::Program::new()) | ||
1062 | .unwrap(); | ||
1063 | assert_eq!( | ||
1064 | ctx.eval_block(&ast::Block { | ||
1065 | body: vec![ast::Statement::Declaration(ast::Declaration { | ||
1066 | ty: ast::Type::List, | ||
1067 | name: "a".to_owned(), | ||
1068 | init: Some( | ||
1069 | ast::Expr::List(ast::List { | ||
1070 | items: vec![ast::Expr::int(5)] | ||
1071 | }) | ||
1072 | .boxed() | ||
1073 | ), | ||
1074 | }),] | ||
1075 | }), | ||
1076 | Ok(Value::Unit) | ||
1077 | ); | ||
1078 | assert_eq!( | ||
1079 | ctx.lookup(&String::from("a")).unwrap().clone(), | ||
1080 | Variable { | ||
1081 | ty: ast::Type::List, | ||
1082 | name: "a".to_owned(), | ||
1083 | value: vec![5.into()].into(), | ||
1084 | } | ||
1085 | ); | ||
1086 | } | ||
989 | } | 1087 | } |