use std::{fmt::Debug, hash::Hash, ops::Add, path::PathBuf}; use crate::token_stream::{ Parse, TokenRange, TokenStream, TokenStreamError, lexer::{Keyword, Position, Token}, }; pub type LuaNumber = f64; #[derive(Debug, Clone)] pub struct Node { pub kind: T, pub meta: Metadata, } impl PartialEq for Node { fn eq(&self, other: &Self) -> bool { self.kind == other.kind } } impl Eq for Node {} impl Hash for Node { fn hash(&self, state: &mut H) { self.kind.hash(state); } } impl Node { pub fn empty(kind: T) -> Node { Node { kind, meta: Metadata::empty(), } } pub fn with(&self, other: OtherT) -> Node { Node { kind: other, meta: self.meta.clone(), } } } #[derive(Clone, PartialEq, Hash, Eq)] pub struct Metadata { pub documentation: Option, pub token_range: TokenRange, pub position: Position, pub file_path: PathBuf, } impl Metadata { pub fn empty() -> Metadata { Metadata { documentation: None, token_range: Default::default(), position: Position(0, 0), file_path: PathBuf::new(), } } } impl Add for Metadata { type Output = Metadata; fn add(self, rhs: Metadata) -> Self::Output { Metadata { documentation: self.documentation, token_range: TokenRange { start: self.token_range.start, end: rhs.token_range.end, }, position: self.position, file_path: self.file_path, } } } impl Debug for Metadata { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self.token_range) } } impl Parse for Node { fn parse(mut stream: TokenStream) -> Result { let position = stream .get_position() .ok_or(stream.expecting_err(std::any::type_name::()))?; let documentation = stream.find_documentation("/").into_iter().last(); Ok(Node { kind: stream.parse()?, meta: Metadata { documentation, token_range: stream.get_range(), position, file_path: stream.file_path.clone(), }, }) } } impl Metadata { fn pre( stream: &mut TokenStream, expecting: &str, ) -> Result<(Option, Position), TokenStreamError> { Ok(( stream.find_documentation("/").into_iter().last(), stream .get_position() .ok_or(stream.expecting_err(expecting))?, )) } fn produce( stream: &mut TokenStream, (documentation, position): (Option, Position), ) -> Metadata { Metadata { documentation: documentation, token_range: stream.get_range(), position, file_path: stream.file_path.clone(), } } } #[derive(Debug, Clone)] pub struct Function { pub name: Option>, pub params: Vec>, pub block: Block, pub meta: Metadata, } impl Parse for Function { fn parse(mut stream: TokenStream) -> Result { let pre = Metadata::pre(&mut stream, "function")?; stream.expect(Token::Keyword(Keyword::Function))?; let name = stream.parse::>().ok(); stream.expect(Token::Symbol('('))?; let mut params = Vec::new(); if let Ok(param) = stream.parse() { params.push(param); while stream.peek() == Some(Token::Symbol(',')) { stream.next(); params.push(stream.parse()?); } } stream.expect(Token::Symbol(')'))?; let block = stream.parse()?; stream.expect(Token::Keyword(Keyword::End))?; Ok(Function { name, params, block, meta: Metadata::produce(&mut stream, pre), }) } } impl Parse for String { fn parse(mut stream: TokenStream) -> Result { if let Some(Token::Word(text)) = stream.next() { Ok(text) } else { Err(stream.expected_err("identifier")) } } } #[derive(Debug, Clone)] pub struct Block { pub statements: Vec>, pub meta: Metadata, } impl Parse for Block { fn parse(mut stream: TokenStream) -> Result { let pre = Metadata::pre(&mut stream, "block")?; let mut statements = Vec::new(); while !matches!( stream.peek(), Some(Token::Keyword(Keyword::End) | Token::Eof) ) { statements.push(stream.parse()?); } Ok(Block { statements, meta: Metadata::produce(&mut stream, pre), }) } } #[derive(Debug, Clone)] pub enum Statement { Assignment( Option, Vec<(Node, Vec>)>, ExpressionList, ), Return(ExpressionList), If(Node, Block), Expression(Node), } impl Parse for Statement { fn parse(mut stream: TokenStream) -> Result { let peeked = stream.peek(); if peeked == Some(Token::Keyword(Keyword::Function)) { let function = stream.parse::>()?; if let Some(name) = function.kind.name { Ok(Self::Assignment( None, vec![(name, Vec::new())], ExpressionList(vec![Node { kind: Expression::FunctionDefinition( function.kind.params, function.kind.block, ), meta: function.meta, }]), )) } else { Ok(Self::Expression(Node { kind: Expression::FunctionDefinition(function.kind.params, function.kind.block), meta: function.meta, })) } } else if peeked == Some(Token::Keyword(Keyword::Return)) { stream.next(); Ok(Statement::Return(stream.parse()?)) } else if peeked == Some(Token::Keyword(Keyword::If)) { stream.next(); // Consume if let cond = stream.parse()?; stream.expect(Token::Keyword(Keyword::Then))?; let then = stream.parse()?; stream.expect(Token::Keyword(Keyword::End))?; Ok(Self::If(cond, then)) } else if let Some(Token::Keyword(Keyword::Local | Keyword::Global)) = peeked { let access_modifier = match stream.next() { Some(Token::Keyword(Keyword::Local)) => AccessModifier::Local, Some(Token::Keyword(Keyword::Global)) => AccessModifier::Global, _ => panic!(), }; let mut names = Vec::new(); names.push((stream.parse()?, Vec::new())); while stream.peek() == Some(Token::Symbol(',')) { stream.next(); names.push((stream.parse()?, Vec::new())); } stream.expect(Token::Symbol('='))?; let expr = stream.parse()?; Ok(Statement::Assignment(Some(access_modifier), names, expr)) } else if stream.parse_peek::().is_ok() { let access = stream.parse::().unwrap(); let expression = stream.parse()?; Ok(Self::Assignment( None, vec![(access.0.0, access.0.1)], ExpressionList(vec![expression]), )) } else if let Ok(expr) = stream.parse() { Ok(Self::Expression(expr)) } else { Err(stream.expecting_err("statement")) } } } #[derive(Debug, Clone, PartialEq, Eq)] pub enum AccessModifier { Local, Global, } #[derive(Debug, Clone)] pub struct IndexedAccess(Node, Vec>); impl Parse for IndexedAccess { fn parse(mut stream: TokenStream) -> Result { let name = stream.parse()?; let mut expressions = Vec::new(); while let Some(Token::Symbol('[') | Token::Symbol('.')) = stream.peek() { match stream.next().unwrap() { Token::Symbol('[') => { let expression = stream.parse()?; stream.expect_symbol(']')?; expressions.push(expression); } Token::Symbol('.') => { let word = stream.parse::>()?; expressions.push(Node { kind: Expression::Literal(Literal::String(word.kind)), meta: word.meta, }); } _ => panic!(), } } Ok(IndexedAccess(name, expressions)) } } #[derive(Debug, Clone)] pub struct IndexedAssignment(IndexedAccess); impl Parse for IndexedAssignment { fn parse(mut stream: TokenStream) -> Result { let access = stream.parse()?; stream.expect_symbol('=')?; Ok(IndexedAssignment(access)) } } #[derive(Debug, Clone)] pub enum Expression { ValueRef(String), UnOp(UnaryOperator, Box>), BinOp(BinaryOperator, Box>, Box>), FunctionDefinition(Vec>, Block), FunctionCall(Box>, Node), Literal(Literal), TableConstructor, } impl Parse for Expression { fn parse(mut stream: TokenStream) -> Result { let primary_expr = stream.parse::()?; parse_binop_rhs(&mut stream, primary_expr, None).map(|v| v.kind) } } #[derive(Debug, Clone)] pub struct ExpressionList(pub Vec>); impl Parse for ExpressionList { fn parse(mut stream: TokenStream) -> Result { let mut list = Vec::new(); if let Ok(value) = stream.parse() { list.push(value); while stream.peek() == Some(Token::Symbol(',')) { stream.next(); list.push(stream.parse()?); } } Ok(ExpressionList(list)) } } #[derive(Debug, Clone)] pub struct PrimaryExpression(Node); #[derive(Debug, Clone, Copy)] pub enum UnaryOperator { Negation, } impl Parse for UnaryOperator { fn parse(mut stream: TokenStream) -> Result { if let Some(token) = stream.next() { match token { Token::Symbol('-') => Ok(UnaryOperator::Negation), _ => Err(stream.expected_err("unop")), } } else { Err(stream.expected_err("unop")) } } } #[derive(Debug, Clone, Copy)] pub enum BinaryOperator { And, Or, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual, Equal, Add, Sub, } impl BinaryOperator { pub fn precedence(&self) -> u32 { match self { BinaryOperator::Or => 0, BinaryOperator::And => 1, BinaryOperator::LessThan => 10, BinaryOperator::LessThanOrEqual => 10, BinaryOperator::GreaterThan => 10, BinaryOperator::GreaterThanOrEqual => 10, BinaryOperator::Equal => 10, BinaryOperator::Add => 20, BinaryOperator::Sub => 20, } } } impl Parse for BinaryOperator { fn parse(mut stream: TokenStream) -> Result { if let Some(token) = stream.next() { match (token, stream.peek()) { (Token::Word(word), _) => match word.as_str() { "and" => Ok(BinaryOperator::And), "or" => Ok(BinaryOperator::Or), _ => Err(stream.expected_err("binop")), }, (Token::Symbol('<'), Some(Token::Symbol('='))) => { stream.next(); Ok(BinaryOperator::LessThanOrEqual) } (Token::Symbol('>'), Some(Token::Symbol('='))) => { stream.next(); Ok(BinaryOperator::GreaterThanOrEqual) } (Token::Symbol('='), Some(Token::Symbol('='))) => { stream.next(); Ok(BinaryOperator::Equal) } (Token::Symbol('<'), _) => Ok(BinaryOperator::LessThan), (Token::Symbol('>'), _) => Ok(BinaryOperator::GreaterThan), (Token::Symbol('+'), _) => Ok(BinaryOperator::Add), (Token::Symbol('-'), _) => Ok(BinaryOperator::Sub), _ => Err(stream.expected_err("binop")), } } else { Err(stream.expected_err("binop")) } } } impl Parse for PrimaryExpression { fn parse(mut stream: TokenStream) -> Result { let pre = Metadata::pre(&mut stream, "expression")?; let mut unary_operators = Vec::new(); while let Ok(unop) = stream.parse::() { unary_operators.push(unop); } let peeked = stream.peek(); let mut expression = if peeked == Some(Token::Keyword(Keyword::Function)) { let function = stream.parse::>()?; Expression::FunctionDefinition(function.kind.params, function.kind.block) } else if let Some(Token::DecimalValue(value)) = peeked { stream.next(); // Consume decimal value Expression::Literal(Literal::Number( u64::from_str_radix(&value, 10).unwrap() as f64 )) } else if let Some(Token::StringLit(value)) = peeked { stream.next(); // Consume string-literal Expression::Literal(Literal::String(value)) } else if let Some(Token::Symbol('{')) = peeked { stream.next(); stream.expect_symbol('}')?; Expression::TableConstructor } else { Expression::ValueRef(stream.parse()?) }; while let Some(Token::Symbol('(') | Token::Symbol('[')) = stream.peek() { match stream.next().unwrap() { Token::Symbol('(') => { let expression_list = stream.parse::>()?; stream.expect(Token::Symbol(')'))?; expression = Expression::FunctionCall( Box::new(Node { kind: expression, meta: Metadata::produce(&mut stream, pre.clone()), }), expression_list, ); } Token::Symbol('[') => todo!(), _ => panic!(), } } for unop in unary_operators.into_iter().rev() { expression = Expression::UnOp( unop, Box::new(Node { kind: expression, meta: Metadata::produce(&mut stream, pre.clone()), }), ); } Ok(PrimaryExpression(Node { kind: expression, meta: Metadata::produce(&mut stream, pre), })) } } fn parse_binop_rhs( stream: &mut TokenStream, mut lhs: PrimaryExpression, prev_op: Option, ) -> Result, TokenStreamError> { let meta_pre = Metadata::pre(stream, "binary expression")?; let precedence = if let Some(op) = prev_op { op.precedence() } else { 0 }; while let Ok(curr_operator) = stream.parse_if::(|op| op.precedence() >= precedence) { let mut rhs = stream.parse::()?; if let Ok(next_op) = stream.parse_peek::() { if curr_operator.precedence() < next_op.precedence() { // Operator on the right of rhs has more precedence, turn // rhs into lhs for new binop let rhs_expr = stream .parse_with(|mut st| parse_binop_rhs(&mut st, rhs, Some(curr_operator)))?; rhs = PrimaryExpression(rhs_expr); } } lhs = PrimaryExpression(Node { kind: Expression::BinOp(curr_operator, Box::new(lhs.0), Box::new(rhs.0)), meta: Metadata::produce(stream, meta_pre.clone()), }); } Ok(lhs.0) } #[derive(Debug, Clone)] pub enum Literal { Number(LuaNumber), String(String), }