diff --git a/README.md b/README.md index 842c8d3..3d99ec9 100644 --- a/README.md +++ b/README.md @@ -265,6 +265,7 @@ Five types of literals are implemented. }; 载体["name"]; +载体.name; 载体["a" + "ge"]; 载体[三七五]; 载体[99]; diff --git a/src/evaluator/mod.rs b/src/evaluator/mod.rs index 6054a2f..4d83aca 100644 --- a/src/evaluator/mod.rs +++ b/src/evaluator/mod.rs @@ -581,7 +581,9 @@ let two = "two"; fn test_hash_index_expr() { let tests = vec![ ("{\"foo\": 5}[\"foo\"]", Some(Object::Int(5))), + ("{\"foo\": 5}.foo", Some(Object::Int(5))), ("{\"foo\": 5}[\"bar\"]", Some(Object::Null)), + ("{\"foo\": 5}.bar", Some(Object::Null)), ("let key = \"foo\"; {\"foo\": 5}[key]", Some(Object::Int(5))), ("{}[\"foo\"]", Some(Object::Null)), ("{5: 5}[5]", Some(Object::Int(5))), diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index b209228..77283cd 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -197,6 +197,7 @@ impl Lexer { '}' => Token::Rbrace, '[' => Token::Lbracket, ']' => Token::Rbracket, + '.' => Token::Dot, ',' => Token::Comma, ';' => Token::Semicolon, ':' => Token::Colon, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 0338c12..ec45c27 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -51,6 +51,7 @@ impl Parser { Token::Plus | Token::Minus => Precedence::Sum, Token::Slash | Token::Asterisk => Precedence::Product, Token::Lbracket => Precedence::Index, + Token::Dot => Precedence::Index, Token::Lparen => Precedence::Call, _ => Precedence::Lowest, } @@ -267,6 +268,10 @@ impl Parser { self.bump(); left = self.parse_index_expr(left.unwrap()); } + Token::Dot => { + self.bump(); + left = self.parse_dot_access_expr(left.unwrap()); + } Token::Lparen => { self.bump(); left = self.parse_call_expr(left.unwrap()); @@ -432,6 +437,20 @@ impl Parser { Some(Expr::Index(Box::new(left), Box::new(index))) } + fn parse_dot_access_expr(&mut self, left: Expr) -> Option { + self.bump(); + + match self.parse_ident() { + Some(name) => match name { + Ident(str) => { + Some(Expr::Index(Box::new(left), Box::new(Expr::Literal(Literal::String(str))))) + }, + _ => return None + }, + None => return None, + } + } + fn parse_grouped_expr(&mut self) -> Option { self.bump(); @@ -858,6 +877,23 @@ return 993322; ); } + #[test] + fn test_dot_access_expr() { + let input = "myHash.key"; + + let mut parser = Parser::new(Lexer::new(input)); + let program = parser.parse(); + + check_parse_errors(&mut parser); + assert_eq!( + vec![Stmt::Expr(Expr::Index( + Box::new(Expr::Ident(Ident(String::from("myHash")))), + Box::new(Expr::Literal(Literal::String(String::from("key")))), + ))], + program + ); + } + #[test] fn test_prefix_expr() { let tests = vec![ diff --git a/src/token.rs b/src/token.rs index 4409ef9..7a36457 100644 --- a/src/token.rs +++ b/src/token.rs @@ -42,6 +42,7 @@ pub enum Token { Rbrace, Lbracket, Rbracket, + Dot, // Reseved keywords Func,