diff options
Diffstat (limited to 'src/eval.rs')
-rw-r--r-- | src/eval.rs | 282 |
1 files changed, 107 insertions, 175 deletions
diff --git a/src/eval.rs b/src/eval.rs index 104571b..35cba82 100644 --- a/src/eval.rs +++ b/src/eval.rs | |||
@@ -93,7 +93,7 @@ impl Value { | |||
93 | } | 93 | } |
94 | } | 94 | } |
95 | 95 | ||
96 | fn as_str(&self) -> std::result::Result<&str, Error> { | 96 | pub(crate) fn as_str(&self) -> std::result::Result<&str, Error> { |
97 | match self { | 97 | match self { |
98 | Self::String(s) => Ok(s.as_str()), | 98 | Self::String(s) => Ok(s.as_str()), |
99 | v => Err(Error::TypeMismatch { | 99 | v => Err(Error::TypeMismatch { |
@@ -103,7 +103,7 @@ impl Value { | |||
103 | } | 103 | } |
104 | } | 104 | } |
105 | 105 | ||
106 | fn as_int(&self) -> std::result::Result<i128, Error> { | 106 | pub(crate) fn as_int(&self) -> std::result::Result<i128, Error> { |
107 | match self { | 107 | match self { |
108 | Self::Integer(i) => Ok(*i), | 108 | Self::Integer(i) => Ok(*i), |
109 | v => Err(Error::TypeMismatch { | 109 | v => Err(Error::TypeMismatch { |
@@ -113,7 +113,7 @@ impl Value { | |||
113 | } | 113 | } |
114 | } | 114 | } |
115 | 115 | ||
116 | fn as_node(&self) -> std::result::Result<NodeId, Error> { | 116 | pub(crate) fn as_node(&self) -> std::result::Result<NodeId, Error> { |
117 | match self { | 117 | match self { |
118 | Self::Node(id) => Ok(*id), | 118 | Self::Node(id) => Ok(*id), |
119 | v => Err(Error::TypeMismatch { | 119 | v => Err(Error::TypeMismatch { |
@@ -123,7 +123,7 @@ impl Value { | |||
123 | } | 123 | } |
124 | } | 124 | } |
125 | 125 | ||
126 | fn as_list(&self) -> std::result::Result<Vec<Value>, Error> { | 126 | pub(crate) fn as_list(&self) -> std::result::Result<Vec<Value>, Error> { |
127 | match self { | 127 | match self { |
128 | Self::List(values) => Ok(values.clone()), | 128 | Self::List(values) => Ok(values.clone()), |
129 | v => Err(Error::TypeMismatch { | 129 | v => Err(Error::TypeMismatch { |
@@ -137,6 +137,7 @@ impl Value { | |||
137 | match (self, other) { | 137 | match (self, other) { |
138 | (Self::Integer(s), Self::Integer(o)) => Ok(Self::Integer(*s + *o)), | 138 | (Self::Integer(s), Self::Integer(o)) => Ok(Self::Integer(*s + *o)), |
139 | (Self::String(s), Self::String(o)) => Ok(Self::String(format!("{s}{o}"))), | 139 | (Self::String(s), Self::String(o)) => Ok(Self::String(format!("{s}{o}"))), |
140 | (Self::List(l), o) => Ok(Self::List(l.iter().cloned().chain([o.clone()]).collect())), | ||
140 | _ => Err(Error::UndefinedBinOp( | 141 | _ => Err(Error::UndefinedBinOp( |
141 | ast::BinOp::Arith(ast::ArithOp::Add), | 142 | ast::BinOp::Arith(ast::ArithOp::Add), |
142 | self.ty(), | 143 | self.ty(), |
@@ -297,8 +298,13 @@ impl fmt::Display for Value { | |||
297 | Self::Node(id) => write!(f, "<node #{id}>"), | 298 | Self::Node(id) => write!(f, "<node #{id}>"), |
298 | Self::List(items) => { | 299 | Self::List(items) => { |
299 | write!(f, "[")?; | 300 | write!(f, "[")?; |
300 | for i in items { | 301 | let mut iterable = items.iter().peekable(); |
301 | write!(f, "{i}")?; | 302 | while let Some(item) = iterable.next() { |
303 | if iterable.peek().is_none() { | ||
304 | write!(f, "{item}")?; | ||
305 | } else { | ||
306 | write!(f, "{item}, ")?; | ||
307 | } | ||
302 | } | 308 | } |
303 | write!(f, "]") | 309 | write!(f, "]") |
304 | } | 310 | } |
@@ -318,6 +324,12 @@ impl From<i128> for Value { | |||
318 | } | 324 | } |
319 | } | 325 | } |
320 | 326 | ||
327 | impl From<usize> for Value { | ||
328 | fn from(value: usize) -> Self { | ||
329 | (value as i128).into() | ||
330 | } | ||
331 | } | ||
332 | |||
321 | impl From<&str> for Value { | 333 | impl From<&str> for Value { |
322 | fn from(value: &str) -> Self { | 334 | fn from(value: &str) -> Self { |
323 | Self::String(value.to_owned()) | 335 | Self::String(value.to_owned()) |
@@ -402,6 +414,10 @@ pub enum Error { | |||
402 | MalformedExpr(String), | 414 | MalformedExpr(String), |
403 | InvalidNodeKind(String), | 415 | InvalidNodeKind(String), |
404 | NoParentNode(tree_sitter::Node<'static>), | 416 | NoParentNode(tree_sitter::Node<'static>), |
417 | IncorrectArgFormat { | ||
418 | wanted: usize, | ||
419 | got: usize, | ||
420 | }, | ||
405 | InvalidStringSlice { | 421 | InvalidStringSlice { |
406 | length: usize, | 422 | length: usize, |
407 | start: i128, | 423 | start: i128, |
@@ -409,7 +425,7 @@ pub enum Error { | |||
409 | }, | 425 | }, |
410 | ArrayOutOfBounds { | 426 | ArrayOutOfBounds { |
411 | idx: i128, | 427 | idx: i128, |
412 | len: usize | 428 | len: usize, |
413 | }, | 429 | }, |
414 | // current node is only set in visitors, not in BEGIN or END blocks | 430 | // current node is only set in visitors, not in BEGIN or END blocks |
415 | CurrentNodeNotPresent, | 431 | CurrentNodeNotPresent, |
@@ -421,7 +437,7 @@ pub struct Context { | |||
421 | variables: HashMap<ast::Identifier, Variable>, | 437 | variables: HashMap<ast::Identifier, Variable>, |
422 | language: tree_sitter::Language, | 438 | language: tree_sitter::Language, |
423 | visitors: Visitors, | 439 | visitors: Visitors, |
424 | input_src: Option<String>, | 440 | pub(crate) input_src: Option<String>, |
425 | cursor: Option<tree_sitter::TreeCursor<'static>>, | 441 | cursor: Option<tree_sitter::TreeCursor<'static>>, |
426 | tree: Option<&'static tree_sitter::Tree>, | 442 | tree: Option<&'static tree_sitter::Tree>, |
427 | cache: HashMap<NodeId, tree_sitter::Node<'static>>, | 443 | cache: HashMap<NodeId, tree_sitter::Node<'static>>, |
@@ -511,7 +527,7 @@ impl Context { | |||
511 | self | 527 | self |
512 | } | 528 | } |
513 | 529 | ||
514 | fn eval_expr(&mut self, expr: &ast::Expr) -> Result { | 530 | pub(crate) fn eval_expr(&mut self, expr: &ast::Expr) -> Result { |
515 | match expr { | 531 | match expr { |
516 | ast::Expr::Unit => Ok(Value::Unit), | 532 | ast::Expr::Unit => Ok(Value::Unit), |
517 | ast::Expr::Lit(lit) => self.eval_lit(lit), | 533 | ast::Expr::Lit(lit) => self.eval_lit(lit), |
@@ -680,78 +696,10 @@ impl Context { | |||
680 | } | 696 | } |
681 | 697 | ||
682 | fn eval_call(&mut self, call: &ast::Call) -> Result { | 698 | fn eval_call(&mut self, call: &ast::Call) -> Result { |
683 | match (call.function.as_str(), call.parameters.as_slice()) { | 699 | (&*crate::builtins::BUILTINS) |
684 | ("print", args) => { | 700 | .get(call.function.as_str()) |
685 | for arg in args { | 701 | .ok_or_else(|| Error::FailedLookup(call.function.to_owned()))? |
686 | let val = self.eval_expr(arg)?; | 702 | .eval(self, call.parameters.as_slice()) |
687 | print!("{val}"); | ||
688 | } | ||
689 | Ok(Value::Unit) | ||
690 | } | ||
691 | (predicate @ ("isupper" | "islower"), [arg]) => Ok(self | ||
692 | .eval_expr(arg)? | ||
693 | .as_str()? | ||
694 | .chars() | ||
695 | .all(|c| match predicate { | ||
696 | "isupper" => c.is_ascii_uppercase(), | ||
697 | "islower" => c.is_ascii_lowercase(), | ||
698 | _ => unreachable!(), | ||
699 | }) | ||
700 | .into()), | ||
701 | ("substr", [string, indices @ ..]) => { | ||
702 | let v = self.eval_expr(string)?; | ||
703 | let s = v.as_str()?; | ||
704 | match indices { | ||
705 | [start, end] => { | ||
706 | let start = self.eval_expr(start)?.as_int()?; | ||
707 | let end = self.eval_expr(end)?.as_int()?; | ||
708 | if start < 0 | ||
709 | || start >= s.len() as i128 | ||
710 | || end >= s.len() as i128 | ||
711 | || start > end | ||
712 | { | ||
713 | return Err(Error::InvalidStringSlice { | ||
714 | length: s.len(), | ||
715 | start, | ||
716 | end, | ||
717 | }); | ||
718 | } | ||
719 | Ok(s[start as usize..end as usize].into()) | ||
720 | } | ||
721 | [end] => { | ||
722 | let end = self.eval_expr(end)?.as_int()?; | ||
723 | if end >= s.len() as i128 { | ||
724 | return Err(Error::InvalidStringSlice { | ||
725 | length: s.len(), | ||
726 | start: 0, | ||
727 | end, | ||
728 | }); | ||
729 | } | ||
730 | Ok(s[..end as usize].into()) | ||
731 | } | ||
732 | _ => todo!(), | ||
733 | } | ||
734 | } | ||
735 | ("text", [arg]) => { | ||
736 | let v = self.eval_expr(arg)?; | ||
737 | let id = v.as_node()?; | ||
738 | let node = self.get_node_by_id(id).unwrap(); | ||
739 | let text = node | ||
740 | .utf8_text(self.input_src.as_ref().unwrap().as_bytes()) | ||
741 | .unwrap(); | ||
742 | Ok(Value::String(text.to_owned())) | ||
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 | } | ||
753 | (s, _) => Err(Error::FailedLookup(s.to_owned())), | ||
754 | } | ||
755 | } | 703 | } |
756 | 704 | ||
757 | fn eval_list(&mut self, list: &ast::List) -> Result { | 705 | fn eval_list(&mut self, list: &ast::List) -> Result { |
@@ -768,7 +716,7 @@ impl Context { | |||
768 | if idx < 0 || idx >= target.len() as i128 { | 716 | if idx < 0 || idx >= target.len() as i128 { |
769 | Err(Error::ArrayOutOfBounds { | 717 | Err(Error::ArrayOutOfBounds { |
770 | idx, | 718 | idx, |
771 | len: target.len() | 719 | len: target.len(), |
772 | }) | 720 | }) |
773 | } else { | 721 | } else { |
774 | Ok(target.remove(idx as usize)) | 722 | Ok(target.remove(idx as usize)) |
@@ -881,47 +829,29 @@ pub fn evaluate(file: &str, program: &str, language: tree_sitter::Language) -> R | |||
881 | #[cfg(test)] | 829 | #[cfg(test)] |
882 | mod test { | 830 | mod test { |
883 | use super::*; | 831 | use super::*; |
832 | use crate::ast::*; | ||
884 | 833 | ||
885 | #[test] | 834 | #[test] |
886 | fn bin() { | 835 | fn bin() { |
887 | let language = tree_sitter_python::language(); | 836 | let language = tree_sitter_python::language(); |
888 | let mut ctx = Context::new(language) | 837 | let mut ctx = Context::new(language).with_program(Program::new()).unwrap(); |
889 | .with_program(ast::Program::new()) | ||
890 | .unwrap(); | ||
891 | assert_eq!( | 838 | assert_eq!( |
892 | ctx.eval_expr(&ast::Expr::Bin( | 839 | ctx.eval_expr(&Expr::bin(Expr::int(5), "+", Expr::int(10),)), |
893 | ast::Expr::int(5).boxed(), | ||
894 | ast::BinOp::Arith(ast::ArithOp::Add), | ||
895 | ast::Expr::int(10).boxed(), | ||
896 | )), | ||
897 | Ok(Value::Integer(15)) | 840 | Ok(Value::Integer(15)) |
898 | ); | 841 | ); |
899 | assert_eq!( | 842 | assert_eq!( |
900 | ctx.eval_expr(&ast::Expr::Bin( | 843 | ctx.eval_expr(&Expr::bin(Expr::int(5), "==", Expr::int(10),)), |
901 | ast::Expr::int(5).boxed(), | ||
902 | ast::BinOp::Cmp(ast::CmpOp::Eq), | ||
903 | ast::Expr::int(10).boxed(), | ||
904 | )), | ||
905 | Ok(Value::Boolean(false)) | 844 | Ok(Value::Boolean(false)) |
906 | ); | 845 | ); |
907 | assert_eq!( | 846 | assert_eq!( |
908 | ctx.eval_expr(&ast::Expr::Bin( | 847 | ctx.eval_expr(&Expr::bin(Expr::int(5), "<", Expr::int(10),)), |
909 | ast::Expr::int(5).boxed(), | ||
910 | ast::BinOp::Cmp(ast::CmpOp::Lt), | ||
911 | ast::Expr::int(10).boxed(), | ||
912 | )), | ||
913 | Ok(Value::Boolean(true)) | 848 | Ok(Value::Boolean(true)) |
914 | ); | 849 | ); |
915 | assert_eq!( | 850 | assert_eq!( |
916 | ctx.eval_expr(&ast::Expr::Bin( | 851 | ctx.eval_expr(&Expr::bin( |
917 | ast::Expr::Bin( | 852 | Expr::bin(Expr::int(5), "<", Expr::int(10),), |
918 | ast::Expr::int(5).boxed(), | 853 | "&&", |
919 | ast::BinOp::Cmp(ast::CmpOp::Lt), | 854 | Expr::false_(), |
920 | ast::Expr::int(10).boxed(), | ||
921 | ) | ||
922 | .boxed(), | ||
923 | ast::BinOp::Logic(ast::LogicOp::And), | ||
924 | ast::Expr::false_().boxed() | ||
925 | )), | 855 | )), |
926 | Ok(Value::Boolean(false)) | 856 | Ok(Value::Boolean(false)) |
927 | ); | 857 | ); |
@@ -930,24 +860,16 @@ mod test { | |||
930 | #[test] | 860 | #[test] |
931 | fn test_evaluate_blocks() { | 861 | fn test_evaluate_blocks() { |
932 | let language = tree_sitter_python::language(); | 862 | let language = tree_sitter_python::language(); |
933 | let mut ctx = Context::new(language) | 863 | let mut ctx = Context::new(language).with_program(Program::new()).unwrap(); |
934 | .with_program(ast::Program::new()) | ||
935 | .unwrap(); | ||
936 | assert_eq!( | 864 | assert_eq!( |
937 | ctx.eval_block(&ast::Block { | 865 | ctx.eval_block(&Block { |
938 | body: vec![ | 866 | body: vec![ |
939 | ast::Statement::Declaration(ast::Declaration { | 867 | Statement::Declaration(Declaration { |
940 | ty: ast::Type::Integer, | 868 | ty: Type::Integer, |
941 | name: "a".to_owned(), | 869 | name: "a".to_owned(), |
942 | init: None, | 870 | init: None, |
943 | }), | 871 | }), |
944 | ast::Statement::Bare(ast::Expr::Bin( | 872 | Statement::Bare(Expr::bin(Expr::ident("a"), "+=", Expr::int(5),)), |
945 | ast::Expr::Ident("a".to_owned()).boxed(), | ||
946 | ast::BinOp::Assign(ast::AssignOp { | ||
947 | op: Some(ast::ArithOp::Add) | ||
948 | }), | ||
949 | ast::Expr::int(5).boxed() | ||
950 | )), | ||
951 | ] | 873 | ] |
952 | }), | 874 | }), |
953 | Ok(Value::Unit) | 875 | Ok(Value::Unit) |
@@ -955,7 +877,7 @@ mod test { | |||
955 | assert_eq!( | 877 | assert_eq!( |
956 | ctx.lookup(&String::from("a")).unwrap().clone(), | 878 | ctx.lookup(&String::from("a")).unwrap().clone(), |
957 | Variable { | 879 | Variable { |
958 | ty: ast::Type::Integer, | 880 | ty: Type::Integer, |
959 | name: "a".to_owned(), | 881 | name: "a".to_owned(), |
960 | value: Value::Integer(5) | 882 | value: Value::Integer(5) |
961 | } | 883 | } |
@@ -965,35 +887,29 @@ mod test { | |||
965 | #[test] | 887 | #[test] |
966 | fn test_evaluate_if() { | 888 | fn test_evaluate_if() { |
967 | let language = tree_sitter_python::language(); | 889 | let language = tree_sitter_python::language(); |
968 | let mut ctx = Context::new(language) | 890 | let mut ctx = Context::new(language).with_program(Program::new()).unwrap(); |
969 | .with_program(ast::Program::new()) | ||
970 | .unwrap(); | ||
971 | assert_eq!( | 891 | assert_eq!( |
972 | ctx.eval_block(&ast::Block { | 892 | ctx.eval_block(&Block { |
973 | body: vec![ | 893 | body: vec![ |
974 | ast::Statement::Declaration(ast::Declaration { | 894 | Statement::Declaration(Declaration { |
975 | ty: ast::Type::Integer, | 895 | ty: Type::Integer, |
976 | name: "a".to_owned(), | 896 | name: "a".to_owned(), |
977 | init: Some(ast::Expr::int(1).boxed()), | 897 | init: Some(Expr::int(1).boxed()), |
978 | }), | 898 | }), |
979 | ast::Statement::Bare(ast::Expr::If(ast::IfExpr { | 899 | Statement::Bare(Expr::If(IfExpr { |
980 | condition: ast::Expr::true_().boxed(), | 900 | condition: Expr::true_().boxed(), |
981 | then: ast::Block { | 901 | then: Block { |
982 | body: vec![ast::Statement::Bare(ast::Expr::Bin( | 902 | body: vec![Statement::Bare(Expr::bin( |
983 | ast::Expr::Ident("a".to_owned()).boxed(), | 903 | Expr::Ident("a".to_owned()), |
984 | ast::BinOp::Assign(ast::AssignOp { | 904 | "+=", |
985 | op: Some(ast::ArithOp::Add) | 905 | Expr::int(5), |
986 | }), | ||
987 | ast::Expr::int(5).boxed() | ||
988 | ))] | 906 | ))] |
989 | }, | 907 | }, |
990 | else_: ast::Block { | 908 | else_: Block { |
991 | body: vec![ast::Statement::Bare(ast::Expr::Bin( | 909 | body: vec![Statement::Bare(Expr::bin( |
992 | ast::Expr::Ident("a".to_owned()).boxed(), | 910 | Expr::ident("a"), |
993 | ast::BinOp::Assign(ast::AssignOp { | 911 | "+=", |
994 | op: Some(ast::ArithOp::Add) | 912 | Expr::int(10), |
995 | }), | ||
996 | ast::Expr::int(10).boxed() | ||
997 | ))] | 913 | ))] |
998 | } | 914 | } |
999 | })) | 915 | })) |
@@ -1004,7 +920,7 @@ mod test { | |||
1004 | assert_eq!( | 920 | assert_eq!( |
1005 | ctx.lookup(&String::from("a")).unwrap().clone(), | 921 | ctx.lookup(&String::from("a")).unwrap().clone(), |
1006 | Variable { | 922 | Variable { |
1007 | ty: ast::Type::Integer, | 923 | ty: Type::Integer, |
1008 | name: "a".to_owned(), | 924 | name: "a".to_owned(), |
1009 | value: Value::Integer(6) | 925 | value: Value::Integer(6) |
1010 | } | 926 | } |
@@ -1014,29 +930,23 @@ mod test { | |||
1014 | #[test] | 930 | #[test] |
1015 | fn test_substring() { | 931 | fn test_substring() { |
1016 | let language = tree_sitter_python::language(); | 932 | let language = tree_sitter_python::language(); |
1017 | let mut ctx = Context::new(language) | 933 | let mut ctx = Context::new(language).with_program(Program::new()).unwrap(); |
1018 | .with_program(ast::Program::new()) | ||
1019 | .unwrap(); | ||
1020 | assert_eq!( | 934 | assert_eq!( |
1021 | ctx.eval_block(&ast::Block { | 935 | ctx.eval_block(&Block { |
1022 | body: vec![ | 936 | body: vec![ |
1023 | ast::Statement::Declaration(ast::Declaration { | 937 | Statement::Declaration(Declaration { |
1024 | ty: ast::Type::String, | 938 | ty: Type::String, |
1025 | name: "a".to_owned(), | 939 | name: "a".to_owned(), |
1026 | init: Some(ast::Expr::str("foobar").boxed()), | 940 | init: Some(Expr::str("foobar").boxed()), |
1027 | }), | 941 | }), |
1028 | ast::Statement::Declaration(ast::Declaration { | 942 | Statement::Declaration(Declaration { |
1029 | ty: ast::Type::String, | 943 | ty: Type::String, |
1030 | name: "b".to_owned(), | 944 | name: "b".to_owned(), |
1031 | init: Some( | 945 | init: Some( |
1032 | ast::Expr::Call(ast::Call { | 946 | Expr::call( |
1033 | function: "substr".into(), | 947 | "substr", |
1034 | parameters: vec![ | 948 | [Expr::Ident("a".to_owned()), Expr::int(0), Expr::int(3),] |
1035 | ast::Expr::Ident("a".to_owned()), | 949 | ) |
1036 | ast::Expr::int(0), | ||
1037 | ast::Expr::int(3), | ||
1038 | ] | ||
1039 | }) | ||
1040 | .boxed() | 950 | .boxed() |
1041 | ), | 951 | ), |
1042 | }), | 952 | }), |
@@ -1047,7 +957,7 @@ mod test { | |||
1047 | assert_eq!( | 957 | assert_eq!( |
1048 | ctx.lookup(&String::from("b")).unwrap().clone(), | 958 | ctx.lookup(&String::from("b")).unwrap().clone(), |
1049 | Variable { | 959 | Variable { |
1050 | ty: ast::Type::String, | 960 | ty: Type::String, |
1051 | name: "b".to_owned(), | 961 | name: "b".to_owned(), |
1052 | value: "foo".into() | 962 | value: "foo".into() |
1053 | } | 963 | } |
@@ -1057,17 +967,15 @@ mod test { | |||
1057 | #[test] | 967 | #[test] |
1058 | fn test_list() { | 968 | fn test_list() { |
1059 | let language = tree_sitter_python::language(); | 969 | let language = tree_sitter_python::language(); |
1060 | let mut ctx = Context::new(language) | 970 | let mut ctx = Context::new(language).with_program(Program::new()).unwrap(); |
1061 | .with_program(ast::Program::new()) | ||
1062 | .unwrap(); | ||
1063 | assert_eq!( | 971 | assert_eq!( |
1064 | ctx.eval_block(&ast::Block { | 972 | ctx.eval_block(&Block { |
1065 | body: vec![ast::Statement::Declaration(ast::Declaration { | 973 | body: vec![Statement::Declaration(Declaration { |
1066 | ty: ast::Type::List, | 974 | ty: Type::List, |
1067 | name: "a".to_owned(), | 975 | name: "a".to_owned(), |
1068 | init: Some( | 976 | init: Some( |
1069 | ast::Expr::List(ast::List { | 977 | Expr::List(List { |
1070 | items: vec![ast::Expr::int(5)] | 978 | items: vec![Expr::int(5)] |
1071 | }) | 979 | }) |
1072 | .boxed() | 980 | .boxed() |
1073 | ), | 981 | ), |
@@ -1078,9 +986,33 @@ mod test { | |||
1078 | assert_eq!( | 986 | assert_eq!( |
1079 | ctx.lookup(&String::from("a")).unwrap().clone(), | 987 | ctx.lookup(&String::from("a")).unwrap().clone(), |
1080 | Variable { | 988 | Variable { |
1081 | ty: ast::Type::List, | 989 | ty: Type::List, |
990 | name: "a".to_owned(), | ||
991 | value: vec![5usize.into()].into(), | ||
992 | } | ||
993 | ); | ||
994 | } | ||
995 | |||
996 | #[test] | ||
997 | fn test_ts_builtins() { | ||
998 | let language = tree_sitter_python::language(); | ||
999 | let mut ctx = Context::new(language).with_program(Program::new()).unwrap(); | ||
1000 | assert_eq!( | ||
1001 | ctx.eval_block(&Block { | ||
1002 | body: vec![Statement::decl( | ||
1003 | Type::List, | ||
1004 | "a", | ||
1005 | Expr::list([Expr::int(5)]), | ||
1006 | )] | ||
1007 | }), | ||
1008 | Ok(Value::Unit) | ||
1009 | ); | ||
1010 | assert_eq!( | ||
1011 | ctx.lookup(&String::from("a")).unwrap().clone(), | ||
1012 | Variable { | ||
1013 | ty: Type::List, | ||
1082 | name: "a".to_owned(), | 1014 | name: "a".to_owned(), |
1083 | value: vec![5.into()].into(), | 1015 | value: vec![5usize.into()].into(), |
1084 | } | 1016 | } |
1085 | ); | 1017 | ); |
1086 | } | 1018 | } |