diff options
author | Akshay <[email protected]> | 2024-08-23 23:00:52 +0100 |
---|---|---|
committer | Akshay <[email protected]> | 2024-08-23 23:00:52 +0100 |
commit | 1702f955a4546828cd535be6cecad57b90128de8 (patch) | |
tree | 1fe50f313570839004e52d52cacddcc09a5b4cd7 /src | |
parent | 32de8bd5dac80a2c09e7106144cab5a8e16accc4 (diff) |
add lists and index exprs
Diffstat (limited to 'src')
-rw-r--r-- | src/ast.rs | 18 | ||||
-rw-r--r-- | src/eval.rs | 106 | ||||
-rw-r--r-- | src/parser.rs | 118 |
3 files changed, 229 insertions, 13 deletions
@@ -59,14 +59,15 @@ pub enum Statement { | |||
59 | #[derive(Debug, Eq, PartialEq, Clone)] | 59 | #[derive(Debug, Eq, PartialEq, Clone)] |
60 | pub enum Expr { | 60 | pub enum Expr { |
61 | Node, | 61 | Node, |
62 | FieldAccess(Box<Expr>, Identifier), | ||
63 | Unit, | 62 | Unit, |
64 | Lit(Literal), | 63 | Lit(Literal), |
65 | Ident(Identifier), | 64 | Ident(Identifier), |
66 | // List(Vec<Expr>), | 65 | FieldAccess(Box<Expr>, Identifier), |
66 | Index(Box<Expr>, Box<Expr>), | ||
67 | Bin(Box<Expr>, BinOp, Box<Expr>), | 67 | Bin(Box<Expr>, BinOp, Box<Expr>), |
68 | Unary(Box<Expr>, UnaryOp), | 68 | Unary(Box<Expr>, UnaryOp), |
69 | Call(Call), | 69 | Call(Call), |
70 | List(List), | ||
70 | If(IfExpr), | 71 | If(IfExpr), |
71 | Block(Block), | 72 | Block(Block), |
72 | } | 73 | } |
@@ -154,6 +155,18 @@ impl From<Call> for Expr { | |||
154 | } | 155 | } |
155 | } | 156 | } |
156 | 157 | ||
158 | /// A list construction expression | ||
159 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
160 | pub struct List { | ||
161 | pub items: Vec<Expr>, | ||
162 | } | ||
163 | |||
164 | impl From<List> for Expr { | ||
165 | fn from(list: List) -> Expr { | ||
166 | Expr::List(list) | ||
167 | } | ||
168 | } | ||
169 | |||
157 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 170 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
158 | pub enum Type { | 171 | pub enum Type { |
159 | Unit, | 172 | Unit, |
@@ -161,6 +174,7 @@ pub enum Type { | |||
161 | String, | 174 | String, |
162 | Boolean, | 175 | Boolean, |
163 | Node, | 176 | Node, |
177 | List, | ||
164 | } | 178 | } |
165 | 179 | ||
166 | #[derive(Debug, PartialEq, Eq, Clone)] | 180 | #[derive(Debug, PartialEq, Eq, Clone)] |
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 | } |
diff --git a/src/parser.rs b/src/parser.rs index 4ec8e57..15d03fe 100644 --- a/src/parser.rs +++ b/src/parser.rs | |||
@@ -169,28 +169,51 @@ fn parse_mul<'a>(i: &'a str) -> IResult<&'a str, Expr> { | |||
169 | let div = parse_op("/", BinOp::Arith(ArithOp::Div)); | 169 | let div = parse_op("/", BinOp::Arith(ArithOp::Div)); |
170 | let mod_ = parse_op("%", BinOp::Arith(ArithOp::Mod)); | 170 | let mod_ = parse_op("%", BinOp::Arith(ArithOp::Mod)); |
171 | let op = alt((mul, div, mod_)); | 171 | let op = alt((mul, div, mod_)); |
172 | let recursive = parse_binary(parse_field_access, op, parse_mul); | 172 | let recursive = parse_binary(parse_field_or_index, op, parse_mul); |
173 | let base = parse_field_access; | 173 | let base = parse_field_or_index; |
174 | alt((recursive, base)).parse(i) | 174 | alt((recursive, base)).parse(i) |
175 | } | 175 | } |
176 | 176 | ||
177 | fn parse_field_access<'a>(i: &'a str) -> IResult<&'a str, Expr> { | 177 | fn parse_field_or_index<'a>(i: &'a str) -> IResult<&'a str, Expr> { |
178 | let trailing = map(tuple((ws(char('.')), ws(parse_ident))), |(_, i)| i); | 178 | enum FieldOrIndex { |
179 | Field(String), | ||
180 | Index(Expr), | ||
181 | } | ||
182 | |||
179 | let (i, base) = parse_atom(i)?; | 183 | let (i, base) = parse_atom(i)?; |
180 | 184 | ||
185 | let field = map(tuple((ws(char('.')), ws(parse_ident))), |(_, i)| { | ||
186 | FieldOrIndex::Field(i) | ||
187 | }); | ||
188 | let index = map( | ||
189 | tuple((ws(char('[')), parse_expr, ws(char(']')))), | ||
190 | |(_, idx, _)| FieldOrIndex::Index(idx), | ||
191 | ); | ||
192 | |||
181 | fold_many0( | 193 | fold_many0( |
182 | trailing, | 194 | alt((field, index)), |
183 | move || base.clone(), | 195 | move || base.clone(), |
184 | move |acc, new| Expr::FieldAccess(acc.boxed(), new), | 196 | move |acc, new| match new { |
197 | FieldOrIndex::Field(f) => Expr::FieldAccess(acc.boxed(), f), | ||
198 | FieldOrIndex::Index(idx) => Expr::Index(acc.boxed(), idx.boxed()), | ||
199 | }, | ||
185 | )(i) | 200 | )(i) |
186 | } | 201 | } |
187 | 202 | ||
203 | fn parse_list<'a>(i: &'a str) -> IResult<&'a str, List> { | ||
204 | let open = ws(char('[')); | ||
205 | let items = separated_list0(char(','), parse_expr); | ||
206 | let close = ws(char(']')); | ||
207 | map(tuple((open, items, close)), |(_, items, _)| List { items }).parse(i) | ||
208 | } | ||
209 | |||
188 | fn parse_atom<'a>(i: &'a str) -> IResult<&'a str, Expr> { | 210 | fn parse_atom<'a>(i: &'a str) -> IResult<&'a str, Expr> { |
189 | let inner = alt(( | 211 | let inner = alt(( |
190 | map(tag("node"), |_| Expr::Node), | 212 | map(tag("node"), |_| Expr::Node), |
191 | map(parse_block, Expr::Block), | 213 | map(parse_block, Expr::Block), |
192 | map(parse_if, Expr::If), | 214 | map(parse_if, Expr::If), |
193 | map(parse_call, Expr::Call), | 215 | map(parse_call, Expr::Call), |
216 | map(parse_list, Expr::List), | ||
194 | map(parse_lit, Expr::Lit), | 217 | map(parse_lit, Expr::Lit), |
195 | map(parse_ident, Expr::Ident), | 218 | map(parse_ident, Expr::Ident), |
196 | map(parse_unit, |_| Expr::Unit), | 219 | map(parse_unit, |_| Expr::Unit), |
@@ -254,7 +277,8 @@ fn parse_type<'a>(i: &'a str) -> IResult<&'a str, Type> { | |||
254 | let int = value(Type::Integer, tag("int")); | 277 | let int = value(Type::Integer, tag("int")); |
255 | let string = value(Type::String, tag("string")); | 278 | let string = value(Type::String, tag("string")); |
256 | let bool_ = value(Type::Boolean, tag("bool")); | 279 | let bool_ = value(Type::Boolean, tag("bool")); |
257 | alt((int, string, bool_)).parse(i) | 280 | let list = value(Type::List, tag("list")); |
281 | alt((int, string, bool_, list)).parse(i) | ||
258 | } | 282 | } |
259 | 283 | ||
260 | fn parse_declaration<'a>(i: &'a str) -> IResult<&'a str, Declaration> { | 284 | fn parse_declaration<'a>(i: &'a str) -> IResult<&'a str, Declaration> { |
@@ -510,6 +534,27 @@ mod test { | |||
510 | ) | 534 | ) |
511 | )) | 535 | )) |
512 | ); | 536 | ); |
537 | assert_eq!( | ||
538 | parse_expr("a[0]"), | ||
539 | Ok(( | ||
540 | "", | ||
541 | Expr::Index(Expr::Ident("a".to_owned()).boxed(), Expr::int(0).boxed()) | ||
542 | )) | ||
543 | ); | ||
544 | assert_eq!( | ||
545 | parse_expr("children(node)[0]"), | ||
546 | Ok(( | ||
547 | "", | ||
548 | Expr::Index( | ||
549 | Expr::Call(Call { | ||
550 | function: "children".to_owned(), | ||
551 | parameters: vec![Expr::Node] | ||
552 | }) | ||
553 | .boxed(), | ||
554 | Expr::int(0).boxed() | ||
555 | ) | ||
556 | )) | ||
557 | ); | ||
513 | } | 558 | } |
514 | 559 | ||
515 | #[test] | 560 | #[test] |
@@ -544,6 +589,22 @@ mod test { | |||
544 | }) | 589 | }) |
545 | )) | 590 | )) |
546 | ); | 591 | ); |
592 | assert_eq!( | ||
593 | parse_statement(r#"list a =["a", "b", "c"]; "#), | ||
594 | Ok(( | ||
595 | "", | ||
596 | Statement::Declaration(Declaration { | ||
597 | ty: Type::List, | ||
598 | name: "a".to_owned(), | ||
599 | init: Some( | ||
600 | Expr::List(List { | ||
601 | items: vec![Expr::str("a"), Expr::str("b"), Expr::str("c"),] | ||
602 | }) | ||
603 | .boxed() | ||
604 | ) | ||
605 | }) | ||
606 | )) | ||
607 | ); | ||
547 | } | 608 | } |
548 | 609 | ||
549 | #[test] | 610 | #[test] |
@@ -624,6 +685,49 @@ mod test { | |||
624 | ); | 685 | ); |
625 | } | 686 | } |
626 | 687 | ||
688 | #[test] | ||
689 | fn test_parse_index() { | ||
690 | assert_eq!( | ||
691 | parse_expr( | ||
692 | r#" | ||
693 | a[0] | ||
694 | "# | ||
695 | ), | ||
696 | Ok(( | ||
697 | "", | ||
698 | Expr::Index(Expr::Ident("a".to_owned()).boxed(), Expr::int(0).boxed()), | ||
699 | )) | ||
700 | ); | ||
701 | assert_eq!( | ||
702 | parse_expr(r#"node.children[idx]"#), | ||
703 | Ok(( | ||
704 | "", | ||
705 | Expr::Index( | ||
706 | Expr::FieldAccess(Expr::Node.boxed(), Identifier::from("children")).boxed(), | ||
707 | Expr::Ident("idx".to_owned()).boxed() | ||
708 | ) | ||
709 | )) | ||
710 | ); | ||
711 | assert_eq!( | ||
712 | parse_expr(r#"foo[i].bar[j]"#), | ||
713 | Ok(( | ||
714 | "", | ||
715 | Expr::Index( | ||
716 | Expr::FieldAccess( | ||
717 | Expr::Index( | ||
718 | Expr::Ident("foo".to_owned()).boxed(), | ||
719 | Expr::Ident("i".to_owned()).boxed() | ||
720 | ) | ||
721 | .boxed(), | ||
722 | "bar".to_owned() | ||
723 | ) | ||
724 | .boxed(), | ||
725 | Expr::Ident("j".to_owned()).boxed() | ||
726 | ), | ||
727 | )) | ||
728 | ); | ||
729 | } | ||
730 | |||
627 | // #[test] | 731 | // #[test] |
628 | // fn test_skip_query() { | 732 | // fn test_skip_query() { |
629 | // assert_eq!( | 733 | // assert_eq!( |