use crate::ast::{Expression, OpCode}; use crate::lexer::Token; grammar<'input>(); extern { type Location = usize; type Error = crate::lexer::LexError; enum Token<'input> { // Literals Number => Token::Number(), DoubleQuotedString => Token::DoubleQuotedString(<&'input str>), SingleQuotedString => Token::SingleQuotedString(<&'input str>), Boolean => Token::Boolean(), Null => Token::Null, Identifier => Token::Identifier(<&'input str>), // Operators "+" => Token::Plus, "-" => Token::Minus, "*" => Token::Multiply, "/" => Token::Divide, "//" => Token::FloorDivide, "%" => Token::Modulus, "^" => Token::Exponent, // Comparison "==" => Token::Equal, "!=" => Token::NotEqual, ">" => Token::Greater, ">=" => Token::GreaterEqual, "<" => Token::Less, "<=" => Token::LessEqual, "in" => Token::In, // Logical "&&" => Token::And, "||" => Token::Or, // Punctuation "(" => Token::LeftParen, ")" => Token::RightParen, "[" => Token::LeftBracket, "]" => Token::RightBracket, "{" => Token::LeftBrace, "}" => Token::RightBrace, "," => Token::Comma, "." => Token::Dot, ":" => Token::Colon, "?" => Token::Question, "|" => Token::Pipe, } } pub Expression: Box = Expr00; Expr00: Box = { => Box::new(Expression::BinaryOperation { left, right, operation }), Expr10, }; Expr10: Box = { => Box::new(Expression::BinaryOperation { left, right, operation }), Expr20, }; Expr20: Box = { => Box::new(Expression::BinaryOperation { left, right, operation }), Expr30, }; Expr30: Box = { => Box::new(Expression::BinaryOperation { left, right, operation }), Expr40, }; Expr40: Box = { => Box::new(Expression::BinaryOperation { left, right, operation }), Expr50, }; Expr50: Box = { "?" ":" => Box::new(Expression::Conditional {left, truthy, falsy}), Expr60, } Expr60: Box = { "|" => Box::new(Expression::Transform{name: name.to_string(), subject, args}), Expr70 }; /// Expression for dereferencing. /// Used for dereferencing object literals, array literals, and the context /// There are two types of operations here: /// - Either a `dot` operation, taking an expression on the left hand side, and an identifier on the right hand side (a string without the quotations) /// - Or an `index` operation, taking an expression on the left hand side, and another expression inside square ("[]") brackets. /// /// # Examples: /// /// Assume our context is the following /// ``` ///{ /// "foo": /// { /// "bar": [{"baz": 1}, {"bobo": [13, 12]}] // } // } /// ``` /// /// `foo.bar == [{"baz": 1}, {"bobo": [13, 12]]` /// `foo.bar[0] == {"baz": 1}` /// `foo.bar[1].bobo[0] == 13` /// `[1, 2, 3][1] == 2` Expr70: Box = { => Box::new(Expression::IndexOperation{subject, index}), "." => Box::new(Expression::DotOperation{subject, ident: ident.to_string()}), Expr80 }; Expr80: Box = { Number => Box::new(Expression::Number(<>)), Boolean => Box::new(Expression::Boolean(<>)), String => Box::new(Expression::String(<>)), Array => Box::new(Expression::Array(<>)), Object => Box::new(Expression::Object(<>)), Null => Box::new(Expression::Null), Identifier => Box::new(Expression::Identifier(<>.to_string())), "(" ")", }; Args: Vec> = { "(" > ")" }; Op10: OpCode = { "&&" => OpCode::And, "||" => OpCode::Or, }; Op20: OpCode = { "==" => OpCode::Equal, "!=" => OpCode::NotEqual, ">=" => OpCode::GreaterEqual, "<=" => OpCode::LessEqual, ">" => OpCode::Greater, "<" => OpCode::Less, "in" => OpCode::In, }; Op30: OpCode = { "+" => OpCode::Add, "-" => OpCode::Subtract, }; Op40: OpCode = { "*" => OpCode::Multiply, "//" => OpCode::FloorDivide, "/" => OpCode::Divide, }; Op50: OpCode = { "%" => OpCode::Modulus, "^" => OpCode::Exponent, }; // The weird string literal handling here to preserve the weird semantics of the previous lexer implementation: // String: String = { // => s[1..s.len() - 1].to_string().replace("\\\"", "\""), // => s[1..s.len() - 1].to_string().replace("\\'", "'"), // }; String: String = { => s.replace("\\\"", "\""), => s.replace("\\'", "'"), }; Index: Box = { "[" "." "]" => Box::new(Expression::Filter {ident: ident.to_string(), op, right}), "[" "]", } // Boolean tokens are now handled by the external lexer Comma: Vec = { ",")*> => match e { None => v, Some(e) => { let mut v = v; v.push(e); v } } }; Array: Vec> = { "[" > "]" } Object: Vec<(String, Box)> = { "{" ":" )>> "}", } ObjectIdentifier: String = { String, Identifier => <>.to_string() }