mod parsed_funcattr; pub mod parsed_statement; pub mod parsed_type_modifier; mod parser_operators; #[cfg(test)] mod parser_tests; use super::lexer::lex_tokens::{LexToken, TokenType}; use crate::logger::messages::Message; use crate::logger::messages::Message::UnexpectedToken; use crate::modifiers::{FieldModifier, TypeModifier}; use crate::parsing::lexer::lex_tokens::TokenType::CloseBracket; use crate::parsing::parser::parsed_funcattr::FuncAttr; use crate::parsing::parser::parsed_statement::ParsedStatement::{ AnonymousCall, ExprPostOp, IndexingOperator, }; use crate::parsing::parser::parsed_type_modifier::{ParsedTypeModifier, ReferenceModifier}; use crate::parsing::parser::parser_operators::{ BinaryOperator, PostOperator, PreOperator, TernaryOperator, }; use crate::prim_type::PrimitiveType; use crate::span::Span; use enumflags2::BitFlags; use parsed_statement::ParsedStatement; use std::fs::read; use std::os::linux::raw::stat; struct ParseReader<'a> { tokens: &'a Vec, position: usize, } impl<'a> ParseReader<'a> { pub fn peek(&self) -> &LexToken { let t = self.tokens.get(self.position); match t { None => self.tokens.last().unwrap(), Some(v) => { if v.token_type == TokenType::WhiteSpace { self.peek_ahead(1) } else { v } } } } fn peek_ahead(&self, index: usize) -> &LexToken { let t = self.tokens.get(self.position + index); match t { None => self.tokens.last().unwrap(), Some(v) => { if v.token_type == TokenType::WhiteSpace { self.peek_ahead(index + 1) } else { v } } } } pub fn next(&mut self) -> &LexToken { let t = self.tokens.get(self.position); self.position += 1; match t { None => self.tokens.last().unwrap(), Some(v) => { if v.token_type == TokenType::WhiteSpace { self.next() } else { v } } } } pub fn consume( &mut self, expected: TokenType, log: &mut dyn FnMut(Message, Span), ) -> &LexToken { let n = self.next(); if n.token_type != expected { log( Message::UnexpectedToken { expected: vec![expected], found: n.token_type.clone(), }, n.span, ); } n } pub fn create_inner(&self) -> ParseReader<'a> { ParseReader { tokens: self.tokens, position: self.position, } } pub fn set_from_inner(&mut self, inner: &ParseReader) { self.position = inner.position; } } pub fn parse(tokens: Vec, log: &mut dyn FnMut(Message, Span)) -> Box { assert_ne!(tokens.len(), 0); let mut reader = ParseReader { tokens: &tokens, position: 0, }; parse_script(&mut reader, log) } fn parse_identifier( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), can_fail: bool, ) -> Option { let identifier_token = reader.peek(); let s: String; match &identifier_token.token_type { TokenType::Identifier(i) => { s = i.to_string(); reader.next(); } _ => { if !can_fail { log( Message::UnexpectedToken { found: identifier_token.token_type.clone(), expected: vec![TokenType::Identifier(String::new())], }, identifier_token.span, ); } return None; } } Some(s) } fn parse_script( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Box { let mut vec: Vec = Vec::new(); loop { let n = reader.peek(); let token_type = n.token_type.clone(); let span = n.span; match token_type { TokenType::NamespaceKeyword => { vec.push(*parse_namespace(reader, log)); } TokenType::InterfaceKeyword => vec.push(*parse_interface(reader, log).unwrap()), TokenType::EndOfFile => break, TokenType::CloseCurlyBracket => break, _ => { if let Some(s) = parse_interface(reader, log) { vec.push(*s); } else if let Some(s) = parse_var(reader, log) { vec.push(*s); } else { log( UnexpectedToken { expected: vec![TokenType::NamespaceKeyword], found: token_type, }, span, ); reader.next(); } } } } Box::new(ParsedStatement::Script { statements: vec }) } fn parse_namespace( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Box { reader.next(); // Consume namespace let identifier = parse_identifier(reader, log, false); if identifier.is_none() { return Box::new(ParsedStatement::Invalid); } reader.consume(TokenType::OpenCurlyBracket, log); let script = parse_script(reader, log); reader.consume(TokenType::CloseCurlyBracket, log); Box::new(ParsedStatement::Namespace { identifier: identifier.unwrap(), script, }) } fn parse_interface( outer_reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { let mut type_mod: BitFlags = BitFlags::empty(); let identifier: Option; let mut has_interface_keyword = false; let mut reader = outer_reader.create_inner(); loop { match &reader.next().token_type { TokenType::ExternalKeyword => type_mod |= TypeModifier::External, TokenType::SharedKeyword => type_mod |= TypeModifier::Shared, TokenType::Identifier(s) => { identifier = Some(s.clone()); break; } TokenType::InterfaceKeyword => { has_interface_keyword = true; } _ => { return None; } }; } if !has_interface_keyword { return None; } let mut statements: Vec = Vec::new(); let mut inherits: Vec = Vec::new(); loop { let t = reader.peek(); match t.token_type { TokenType::Semicolon => { reader.next(); if identifier.is_none() { return Some(Box::new(ParsedStatement::Invalid)); } return Some(Box::new(ParsedStatement::Interface { type_mod, identifier: identifier.unwrap(), inherits, statements, })); } TokenType::Colon | TokenType::OpenCurlyBracket => break, TokenType::EndOfFile => { log( Message::UnexpectedToken { found: t.token_type.clone(), expected: vec![ TokenType::Semicolon, TokenType::Colon, TokenType::OpenCurlyBracket, ], }, t.span, ); return Some(Box::new(ParsedStatement::Invalid)); } _ => { log( Message::UnexpectedToken { found: t.token_type.clone(), expected: vec![ TokenType::Semicolon, TokenType::Colon, TokenType::OpenCurlyBracket, ], }, t.span, ); } } } if reader.peek().token_type == TokenType::Colon { reader.next(); loop { let inherit_identifier = parse_identifier(&mut reader, log, false); if inherit_identifier.is_none() { continue; } inherits.push(inherit_identifier.unwrap()); if reader.peek().token_type != TokenType::Comma { break; } reader.next(); } } reader.consume(TokenType::OpenCurlyBracket, log); // TODO: parse interfacemethod loop { if reader.peek().token_type == TokenType::CloseCurlyBracket { break; } let prop = parse_virtprop(&mut reader, log); if prop.is_none() { break; } statements.push(*prop.unwrap()); } reader.consume(TokenType::CloseCurlyBracket, log); outer_reader.set_from_inner(&reader); if identifier.is_none() { return Some(Box::new(ParsedStatement::Invalid)); } Some(Box::new(ParsedStatement::Interface { type_mod, identifier: identifier.unwrap(), inherits, statements, })) } fn parse_interface_method( outer_reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // interfacemethod ::= type ['&'] identifier paramlist ['const'] ';'; let mut reader = outer_reader.create_inner(); let return_type = parse_type(&mut reader, log); if return_type.is_none() { return None; } let returns_reference = reader.peek().token_type == TokenType::Ampersand; if returns_reference { reader.next(); } let identifier = parse_identifier(&mut reader, log, true); if identifier.is_none() { return None; } let param_list = parse_paramlist(&mut reader, log); if param_list.is_none() { return None; } let is_const = reader.peek().token_type == TokenType::ConstKeyword; if is_const { reader.next(); } reader.consume(TokenType::Semicolon, log); Some(Box::new(ParsedStatement::InterfaceMethod { return_type: return_type.unwrap(), returns_reference, identifier: identifier.unwrap(), param_list: param_list.unwrap(), is_const, })) } fn parse_typedef( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // typedef ::= 'typedef' (primtype | identifier) identifier ';'; if reader.peek().token_type != TokenType::TypeDefKeyword { return None; } reader.next(); let mut left_type = parse_primtype(reader, log); if left_type.is_none() { let left_type_identifier = parse_identifier(reader, log, false); if left_type_identifier.is_some() { left_type = Some(Box::new(ParsedStatement::DataTypeIdentifier { identifier: left_type_identifier.unwrap(), })); } } let right_type_identifier = parse_identifier(reader, log, false); if right_type_identifier.is_none() { return None; } let right_type = Box::new(ParsedStatement::DataTypeIdentifier { identifier: right_type_identifier.unwrap(), }); reader.consume(TokenType::Semicolon, log); Some(Box::new(ParsedStatement::TypeDefStatement { from: left_type.unwrap(), to: right_type, })) } fn parse_import( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // import ::= 'import' type ['&'] identifier paramlist funcattr 'from' string ';'; if reader.peek().token_type != TokenType::ImportKeyword { return None; } reader.next(); let import_type = parse_type(reader, log); let is_reference_type = reader.peek().token_type == TokenType::Ampersand; if is_reference_type { reader.next(); } let identifier = parse_identifier(reader, log, false); identifier.as_ref()?; let param_list = parse_paramlist(reader, log); let func_attr = parse_funcattr(reader, log); reader.consume(TokenType::FromKeyword, log); let mut source = None; let source_token = reader.next(); if let TokenType::StringLiteral(s) = &source_token.token_type { source = Some(s.to_string()); } if source.is_none() { log( Message::UnexpectedToken { found: source_token.token_type.clone(), expected: vec![TokenType::StringLiteral("".to_string())], }, source_token.span, ); return None; } reader.consume(TokenType::Semicolon, log); Some(Box::new(ParsedStatement::ImportStatement { import_type: import_type.unwrap(), is_reference: is_reference_type, identifier: identifier.unwrap(), param_list: param_list.unwrap(), func_attr, source: source.unwrap(), })) } fn parse_enum( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { // enum ::= {'shared' | 'external'} 'enum' identifier [ ':' primtype ] (';' | ('{' identifier ['=' expr] {',' identifier ['=' expr]} '}')); unimplemented!(); } fn parse_class( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { // class ::= {'shared' | 'abstract' | 'final' | 'external' | 'mixin'} 'class' identifier // (';' | ([':' identifier {',' identifier}] '{' {virtprop | func | var | funcdef | class} '}')); unimplemented!(); } fn parse_funcdef( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { // funcdef ::= {'external' | 'shared'} 'funcdef' type ['&'] identifier paramlist ';' unimplemented!(); } fn parse_func( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { // func ::= {'shared' | 'external'} ['private' | 'protected'] [((type ['&']) | '~')] identifier paramlist ['const'] funcattr (';' | statblock); unimplemented!(); } fn parse_virtprop( outer_reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { let mut reader = outer_reader.create_inner(); let mut field_mod: BitFlags = BitFlags::empty(); let property_type: Option>; loop { let t = reader.peek(); match t.token_type { TokenType::PrivateKeyword => { field_mod |= FieldModifier::Private; reader.next(); } TokenType::ProtectedKeyword => { field_mod |= FieldModifier::Protected; reader.next(); } _ => { property_type = parse_type(&mut reader, log); property_type.as_ref()?; break; } } } let mut is_handle = false; if reader.peek().token_type == TokenType::AtSymbol { reader.next(); is_handle = true; } let identifier = parse_identifier(&mut reader, log, false); identifier.as_ref()?; let next = reader.next(); if next.token_type != TokenType::OpenCurlyBracket { return None; } let mut has_get = false; let mut is_get_const = false; let mut get_statement: Option> = None; let mut has_set = false; let mut is_set_const = false; let mut set_statement: Option> = None; let start_span = next.span; loop { let next = reader.peek(); match next.token_type { TokenType::GetKeyword => { reader.next(); has_get = true; let mut peek = reader.peek(); if peek.token_type == TokenType::ConstKeyword { reader.next(); is_get_const = true; peek = reader.peek(); } if peek.token_type != TokenType::Semicolon { get_statement = parse_statblock(&mut reader, log); } else { reader.next(); } } TokenType::SetKeyword => { reader.next(); has_set = true; let mut peek = reader.peek(); if peek.token_type == TokenType::ConstKeyword { reader.next(); is_set_const = true; peek = reader.peek(); } if peek.token_type != TokenType::Semicolon { set_statement = parse_statblock(&mut reader, log); } else { reader.next(); } } _ => break, } } let next = reader.next(); if next.token_type != TokenType::CloseCurlyBracket { return None; } if !has_get && !has_set { log( Message::EmptyProperty, Span { start: start_span.start, end: next.span.end, }, ) } outer_reader.set_from_inner(&reader); Some(Box::new(ParsedStatement::VirtProp { field_mod, property_type: property_type.unwrap(), identifier: identifier.unwrap(), is_handle, has_get, is_get_const, get_statement, has_set, is_set_const, set_statement, })) } fn parse_paramlist( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // paramlist ::= '(' ['void' | (type typemod [identifier] ['=' expr] {',' type typemod [identifier] ['=' expr]})] ')'; if reader.peek().token_type != TokenType::OpenBracket { return None; } reader.next(); // (void) is equivalent to () if reader.peek().token_type == TokenType::VoidKeyword { reader.next(); reader.consume(TokenType::CloseBracket, log); return Some(Box::new(ParsedStatement::ParamList { parameters: vec![] })); } let mut params = Vec::new(); loop { if reader.peek().token_type == TokenType::CloseBracket { reader.next(); break; } let param_type = parse_type(reader, log); // FIXME: Deal with empty param_type let type_mod = parse_typemod(reader, log); let identifier = parse_identifier(reader, log, true); let mut default = None; if reader.peek().token_type == TokenType::Equals { reader.next(); default = parse_expr(reader, log); // FIXME: log if default is emtpy } params.push((param_type.unwrap(), type_mod, identifier, default)); } Some(Box::new(ParsedStatement::ParamList { parameters: params })) } fn parse_funcattr( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> BitFlags { // funcattr ::= {'override' | 'final' | 'explicit' | 'property'}; let mut func_attr: BitFlags = BitFlags::empty(); loop { match reader.peek().token_type { TokenType::OverrideKeyword => func_attr |= FuncAttr::Override, TokenType::FinalKeyword => func_attr |= FuncAttr::Final, TokenType::ExplicitKeyword => func_attr |= FuncAttr::Explicit, TokenType::PropertyKeyword => func_attr |= FuncAttr::Property, _ => break, } reader.next(); } func_attr } fn parse_statblock( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // statblock ::= '{' {var | statement} '}'; if reader.peek().token_type != TokenType::OpenCurlyBracket { return None; } reader.consume(TokenType::OpenCurlyBracket, log); let mut children = Vec::new(); loop { if reader.peek().token_type == TokenType::CloseCurlyBracket { break; } let var = parse_var(reader, log); if let Some(..) = var { children.push(var.unwrap()); continue; } let statement = parse_statement(reader, log); if let Some(..) = statement { children.push(statement.unwrap()); continue; } // FIXME: Log error break; } reader.consume(TokenType::CloseCurlyBracket, log); Some(Box::new(ParsedStatement::StatBlock { statements: children, })) } fn parse_var( outer_reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // var ::= ['private'|'protected'] type identifier let mut reader = outer_reader.create_inner(); let mut field_mod: BitFlags = BitFlags::empty(); let property_type: Option>; loop { let t = reader.peek(); match t.token_type { TokenType::PrivateKeyword => { field_mod |= FieldModifier::Private; reader.next(); } TokenType::ProtectedKeyword => { field_mod |= FieldModifier::Protected; reader.next(); } _ => { property_type = parse_type(&mut reader, log); property_type.as_ref()?; break; } } } property_type.as_ref()?; let identifier = parse_identifier(&mut reader, log, false); identifier.as_ref()?; let mut assignment: Option> = None; // TODO: Implement arglist // [( '=' (initlist | expr)) | arglist] if reader.peek().token_type == TokenType::Equals { // Eat the equals token. reader.next(); // micro-optimization so we don't go into the initlist if not needed. if reader.peek().token_type == TokenType::OpenCurlyBracket { if let Some(s) = parse_initlist(&mut reader, log) { assignment = Some(s); } } if assignment.is_none() { assignment = parse_expr(&mut reader, log); } } //TODO: Multiple variable creation // {',' identifier [( '=' (initlist | expr)) | arglist]} ';'; outer_reader.set_from_inner(&reader); Some(Box::new(ParsedStatement::Var { modifier: field_mod, var_type: property_type.unwrap(), identifier: identifier.unwrap(), assignment, })) } fn parse_statement( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // statement ::= (if | for | while | return | statblock | break | continue | dowhile | switch | exprstat | try ); match reader.peek().token_type { TokenType::IfKeyword => parse_if(reader, log), TokenType::ForKeyword => parse_for(reader, log), TokenType::WhileKeyword => parse_while(reader, log), TokenType::ReturnKeyword => parse_return(reader, log), TokenType::OpenCurlyBracket => parse_statblock(reader, log), TokenType::BreakKeyword => parse_break(reader, log), TokenType::ContinueKeyword => parse_continue(reader, log), TokenType::DoKeyword => parse_dowhile(reader, log), TokenType::SwitchKeyword => parse_switch(reader, log), TokenType::TryKeyword => parse_try(reader, log), _ => parse_exprstat(reader, log), } } fn parse_switch( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // switch ::= 'switch' '(' assign ')' '{' {case} '}'; reader.consume(TokenType::SwitchKeyword, log); reader.consume(TokenType::OpenBracket, log); let assign = parse_assign(reader, log); // FIXME: Deal with None assign reader.consume(TokenType::CloseBracket, log); reader.consume(TokenType::OpenCurlyBracket, log); let mut vec = Vec::new(); loop { if reader.peek().token_type == TokenType::CloseCurlyBracket { break; } let case = parse_case(reader, log); if case.is_none() { break; } vec.push(case.unwrap()); } Some(Box::new(ParsedStatement::Switch { expression: assign.unwrap(), cases: vec, })) } fn parse_case( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // case ::= (('case' expr) | 'default') ':' {statement}; let mut expression = None; let initial_token = &reader.peek().token_type; if initial_token == &TokenType::DefaultKeyword { reader.next(); } else if initial_token == &TokenType::CaseKeyword { reader.next(); expression = parse_assign(reader, log); if expression.is_none() { // FIXME: log error } } reader.consume(TokenType::Colon, log); let statement = parse_statement(reader, log); // FIXME: deal with None statement Some(Box::new(ParsedStatement::Case { expression, statement: statement.unwrap(), })) } fn parse_try( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // try ::= 'try' statblock 'catch' statblock; reader.consume(TokenType::TryKeyword, log); let try_block = parse_statblock(reader, log); reader.consume(TokenType::CatchKeyword, log); let catch_block = parse_statblock(reader, log); // FIXME: Deal with empty try or catch blocks. Some(Box::new(ParsedStatement::TryStatement { try_block: try_block.unwrap(), catch_block: catch_block.unwrap(), })) } fn parse_dowhile( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // dowhile ::= 'do' statement 'while' '(' assign ')' ';'; reader.consume(TokenType::DoKeyword, log); let statement = parse_statement(reader, log); reader.consume(TokenType::WhileKeyword, log); reader.consume(TokenType::OpenBracket, log); let condition = parse_assign(reader, log); reader.consume(TokenType::CloseBracket, log); reader.consume(TokenType::Semicolon, log); // FIXME: Deal with empty statement or condition. Some(Box::new(ParsedStatement::DoWhileStatement { statement: statement.unwrap(), condition: condition.unwrap(), })) } fn parse_while( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // while ::= 'while' '(' assign ')' statement; reader.consume(TokenType::WhileKeyword, log); reader.consume(TokenType::OpenBracket, log); let condition = parse_assign(reader, log); reader.consume(TokenType::CloseBracket, log); let statement = parse_statement(reader, log); // FIXME: Deal with empty statement or condition. Some(Box::new(ParsedStatement::WhileStatement { condition: condition.unwrap(), statement: statement.unwrap(), })) } fn parse_for( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // for ::= 'for' '(' (var | exprstat) exprstat [assign {',' assign}] ')' statement; reader.consume(TokenType::ForKeyword, log); reader.consume(TokenType::OpenBracket, log); let mut initializer = parse_var(reader, log); if initializer.is_none() { initializer = parse_exprstat(reader, log); } // FIXME: initializer can still be None let bounds = parse_exprstat(reader, log); let mut increment_expressions = Vec::new(); loop { if reader.peek().token_type == TokenType::CloseBracket { break; } let assign = parse_assign(reader, log); if assign.is_some() { increment_expressions.push(assign.unwrap()); } if reader.peek().token_type != TokenType::Comma { break; } reader.next(); } Some(Box::new(ParsedStatement::ForStatement { initializer: initializer.unwrap(), bounds: bounds.unwrap(), increment: increment_expressions, })) } fn parse_if( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // if ::= 'if' '(' assign ')' statement ['else' statement]; reader.consume(TokenType::IfKeyword, log); reader.consume(TokenType::OpenBracket, log); let condition = parse_assign(reader, log); // FIXME: deal with empty condition reader.consume(TokenType::CloseBracket, log); let statement = parse_statement(reader, log); let mut else_statement = None; if reader.peek().token_type == TokenType::ElseKeyword { reader.next(); else_statement = parse_statement(reader, log); } Some(Box::new(ParsedStatement::IfStatement { condition: condition.unwrap(), statement: statement.unwrap(), else_statement, })) } fn parse_break( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // break ::= 'break' ';'; reader.consume(TokenType::BreakKeyword, log); reader.consume(TokenType::Semicolon, log); Some(Box::new(ParsedStatement::BreakStatement {})) } fn parse_continue( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // continue ::= 'continue' ';'; reader.consume(TokenType::ContinueKeyword, log); reader.consume(TokenType::Semicolon, log); Some(Box::new(ParsedStatement::ContinueStatement {})) } fn parse_exprstat( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // exprstat ::= assign ';'; let expression = parse_assign(reader, log); expression.as_ref()?; reader.consume(TokenType::Semicolon, log); expression } fn parse_return( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // return ::= 'return' [assign] ';'; reader.consume(TokenType::ReturnKeyword, log); let expression = parse_assign(reader, log); reader.consume(TokenType::Semicolon, log); Some(Box::new(ParsedStatement::ReturnStatement { expression })) } fn parse_ternary( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // ternary ::= expr ['?' assign ':' assign]; let expr = parse_expr(reader, log); expr.as_ref()?; if reader.peek().token_type == TokenType::QuestionMark { reader.next(); let a = parse_assign(reader, log); reader.consume(TokenType::Colon, log); let b = parse_assign(reader, log); // FIXME: Deal with None a or b return Some(Box::new(ParsedStatement::TernaryExpr { left: expr.unwrap(), operator: TernaryOperator::Conditional, middle: a.unwrap(), right: b.unwrap(), })); } expr } fn parse_expr( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // expr ::= exprterm {(mathop | compop | logicop | bitop) exprterm}; let expr_term = parse_exprterm(reader, log); expr_term.as_ref()?; let mut binary_operand = parse_mathop(reader, log); if binary_operand.is_none() { binary_operand = parse_compop(reader, log); } if binary_operand.is_none() { binary_operand = parse_logicop(reader, log); } if binary_operand.is_none() { binary_operand = parse_bitop(reader, log); } if let Some(..) = binary_operand { let expr_term2 = parse_exprterm(reader, log); // FIXME: deal with empty expr_term2 return Some(Box::new(ParsedStatement::BinaryExpr { left: expr_term.unwrap(), operator: binary_operand.unwrap(), right: expr_term2.unwrap(), })); } expr_term } fn parse_exprterm( outer_reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { let mut reader = outer_reader.create_inner(); // exprterm ::= ([type '='] initlist) | ({exprpreop} exprvalue {exprpostop}); let expr_type = parse_type(&mut reader, log); if expr_type.is_some() { outer_reader.consume(TokenType::Equals, log); } let mut init_list = None; if reader.peek().token_type == TokenType::OpenCurlyBracket { init_list = parse_initlist(&mut reader, log); } if let Some(initlist) = init_list { outer_reader.set_from_inner(&reader); return Some(Box::new(ParsedStatement::ExprTermInitList { statement_type: expr_type, initlist, })); } // Reset to initial here. reader = outer_reader.create_inner(); let mut expr_pre_op = Vec::new(); while let Some(s) = parse_exprpreop(&mut reader, log) { expr_pre_op.push(s); } let expr_value = parse_exprvalue(&mut reader, log); expr_value.as_ref()?; let mut real_value = expr_value.unwrap(); loop { let post_op_value = parse_exprpostop(&mut reader, log, real_value); real_value = post_op_value.0; if !post_op_value.1 { break; } } for op in expr_pre_op.iter().rev() { real_value = Box::new(ParsedStatement::ExprPreOp { operator: *op, operand: real_value, }) } outer_reader.set_from_inner(&reader); Some(real_value) } fn parse_exprpostop( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), base: Box, ) -> (Box, bool) { // exprpostop ::= ('.' (funccall | identifier)) | ('[' [identifier ':'] assign {',' [identifier ':' assign} ']') | arglist | '++' | '--'; // ('.' (funccall | identifier)) if reader.peek().token_type == TokenType::Dot { reader.next(); if let Some(s) = parse_funccall(reader, log) { return ( Box::new(ParsedStatement::MemberFuncCall { operand: base, func_call: s, }), true, ); } if let Some(s) = parse_identifier(reader, log, false) { return ( Box::new(ParsedStatement::MemberAccess { operand: base, identifier: s, }), true, ); } // We've already errored if we've reached this point (through the parse_identifier), so just // return. return (base, false); } // ( '[' [ identifier ':'] assign { ',' [ identifier ':' assign } ']' ) if reader.peek().token_type == TokenType::OpenBlockBracket { reader.next(); let mut vec = Vec::new(); let mut inner_reader = reader.create_inner(); loop { let mut identifier = None; if let Some(s) = parse_identifier(&mut inner_reader, log, true) { if inner_reader.peek().token_type == TokenType::Colon { inner_reader.next(); identifier = Some(s); } } let assign = parse_assign(&mut inner_reader, log); if assign.is_none() { break; } vec.push((identifier, assign.unwrap())); if inner_reader.peek().token_type == TokenType::CloseBlockBracket { break; } inner_reader.consume(TokenType::Comma, log); } if vec.is_empty() { log(Message::EmptyIndex, reader.peek().span); } reader.set_from_inner(&inner_reader); reader.consume(TokenType::CloseBlockBracket, log); return ( Box::new(IndexingOperator { operand: base, index: vec, }), true, ); } // arglist // We know an arglist always opens with a '(', so we can just check for that to avoid a function // call if reader.peek().token_type == TokenType::OpenBracket { if let Some(s) = parse_arglist(reader, log) { return ( Box::new(AnonymousCall { operand: base, arg_list: s, }), true, ); } } // '++' if reader.peek().token_type == TokenType::PlusPlus { reader.next(); return ( Box::new(ExprPostOp { operand: base, operator: PostOperator::Increment, }), true, ); } // '--' if reader.peek().token_type == TokenType::MinusMinus { reader.next(); return ( Box::new(ExprPostOp { operand: base, operator: PostOperator::Decrement, }), true, ); } (base, false) } fn parse_exprvalue( outer_reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // exprvalue ::= 'void' | constructcall | funccall | varaccess | cast | literal | '(' assign ')' | lambda; if outer_reader.peek().token_type == TokenType::VoidKeyword { outer_reader.next(); return Some(Box::new(ParsedStatement::ExprVoidValue {})); } let mut reader = outer_reader.create_inner(); if let Some(s) = parse_constructcall(&mut reader, log) { outer_reader.set_from_inner(&reader); return Some(s); } if let Some(s) = parse_funccall(&mut reader, log) { outer_reader.set_from_inner(&reader); return Some(s); } if let Some(s) = parse_varaccess(&mut reader, log) { outer_reader.set_from_inner(&reader); return Some(s); } if let Some(s) = parse_cast(&mut reader, log) { outer_reader.set_from_inner(&reader); return Some(s); } if let Some(s) = parse_literal(&mut reader, log) { outer_reader.set_from_inner(&reader); return Some(s); } if reader.peek().token_type == TokenType::OpenBracket { reader.next(); let inner = parse_assign(&mut reader, log); // FIXME: deal with None value reader.consume(TokenType::CloseBracket, log); outer_reader.set_from_inner(&reader); return inner; } if let Some(s) = parse_lambda(&mut reader, log) { outer_reader.set_from_inner(&reader); return Some(s); } None } fn parse_lambda( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { // lambda ::= 'function' '(' [[type typemod] identifier {',' [type typemod] identifier}] ')' statblock; unimplemented!(); } fn parse_typemod( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // typemod ::= ['&' ['in' | 'out' | 'inout']]; if reader.peek().token_type == TokenType::Ampersand { reader.next(); } else { return None; } let mut type_mod: BitFlags = BitFlags::from(ReferenceModifier::In) | ReferenceModifier::Out; match reader.peek().token_type { TokenType::InKeyword => { type_mod = BitFlags::from(ReferenceModifier::In); reader.next(); } TokenType::OutKeyword => { type_mod = BitFlags::from(ReferenceModifier::Out); reader.next(); } TokenType::InOutKeyword => { // This is implicit if not otherwise stated, so just consume the token and continue. reader.next(); } _ => {} } Some(type_mod) } fn parse_literal( reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { let value = match &reader.peek().token_type { TokenType::IntegerLiteral(v) => Some(Box::new(ParsedStatement::IntegerLiteral(*v))), TokenType::FloatLiteral(v) => Some(Box::new(ParsedStatement::FloatLiteral(*v))), TokenType::TrueKeyword => Some(Box::new(ParsedStatement::BoolLiteral(true))), TokenType::FalseKeyword => Some(Box::new(ParsedStatement::BoolLiteral(false))), // FIXME: String copy, too slow. TokenType::StringLiteral(v) => { Some(Box::new(ParsedStatement::StringLiteral(v.to_string()))) } _ => None, }; if value.is_some() { reader.next(); } value } fn parse_cast( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // cast ::= 'cast' '<' type '>' '(' assign ')'; if reader.peek().token_type != TokenType::CastKeyword { return None; } reader.next(); reader.consume(TokenType::LessThan, log); let cast_type = parse_type(reader, log); // FIXME: deal with no cast type reader.consume(TokenType::GreaterThan, log); reader.consume(TokenType::OpenBracket, log); let assign = parse_assign(reader, log); // FIXME: deal with no assign reader.consume(TokenType::CloseBracket, log); Some(Box::new(ParsedStatement::Cast { cast_type: cast_type.unwrap(), assign: assign.unwrap(), })) } fn parse_varaccess( outer_reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // scope identifier let mut reader = outer_reader.create_inner(); let scope = parse_scope(&mut reader, log); let identifier = parse_identifier(&mut reader, log, true); identifier.as_ref()?; outer_reader.set_from_inner(&reader); Some(Box::new(ParsedStatement::VarAccess { scope, identifier: identifier.unwrap(), })) } fn parse_constructcall( outer_reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // type arglist let mut reader = outer_reader.create_inner(); let construct_type = parse_type(&mut reader, log); construct_type.as_ref()?; let arg_list = parse_arglist(&mut reader, log); // FIXME: deal with None value for arg list outer_reader.set_from_inner(&reader); Some(Box::new(ParsedStatement::ConstructCall { statement_type: construct_type, arglist: arg_list.unwrap(), })) } fn parse_funccall( outer_reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // scope identifier arglist let mut reader = outer_reader.create_inner(); let scope = parse_scope(&mut reader, log); let identifier = parse_identifier(&mut reader, log, true); identifier.as_ref()?; let arg_list = parse_arglist(&mut reader, log); arg_list.as_ref()?; outer_reader.set_from_inner(&reader); Some(Box::new(ParsedStatement::FuncCall { scope, identifier: identifier.unwrap(), arglist: arg_list.unwrap(), })) } fn parse_arglist( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { // arglist ::= '(' [identifier ':'] assign {',' [identifier ':'] assign} ')'; unimplemented!(); } fn parse_exprpreop( reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option { // exprpreop ::= '-' | '+' | '!' | '++' | '--' | '~' | '@'; let op = match reader.peek().token_type { TokenType::Minus => Some(PreOperator::Negative), TokenType::Plus => Some(PreOperator::Identity), TokenType::ExclamationMark => Some(PreOperator::Negation), TokenType::PlusPlus => Some(PreOperator::Increment), TokenType::MinusMinus => Some(PreOperator::Decrement), TokenType::Tilde => Some(PreOperator::Complement), TokenType::AtSymbol => Some(PreOperator::HandleOf), _ => None, }; if op.is_some() { reader.next(); } op } fn parse_initlist( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { // initlist ::= '{' [assign | initlist] {',' [assign | initlist]} '}'; unimplemented!(); } fn parse_assign( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // ternary [ assignop assign ]; let ternary = parse_ternary(reader, log); ternary.as_ref()?; if let Some(assign_op) = parse_assignop(reader, log) { let assign = parse_assign(reader, log); // FIXME: deal with None assign. return Some(Box::new(ParsedStatement::Assignment { left: ternary.unwrap(), operator: assign_op, right: assign.unwrap(), })); } ternary } fn parse_type( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { // type ::= ['const'] scope datatype ['<' type {',' type} '>'] { ('[' ']') | ('@' ['const']) }; let f = reader.peek(); let mut is_const = false; if f.token_type == TokenType::ConstKeyword { reader.next(); is_const = true; } let scope = parse_scope(reader, log); let datatype = parse_datatype(reader, log); datatype.as_ref()?; // TODO: Generics let mut modifiers: Vec = Vec::new(); loop { let n = reader.peek(); match n.token_type { TokenType::OpenBlockBracket => { reader.next(); reader.consume(TokenType::CloseBlockBracket, log); modifiers.push(ParsedTypeModifier::Array); } TokenType::AtSymbol => { reader.next(); if reader.peek().token_type == TokenType::ConstKeyword { reader.next(); modifiers.push(ParsedTypeModifier::ConstHandle); } else { modifiers.push(ParsedTypeModifier::Handle); } } _ => break, } } Some(Box::new(ParsedStatement::Type { is_const, scope, datatype: datatype.unwrap(), modifiers, })) } fn parse_scope( outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { // scope ::= ['::'] {identifier '::'} [identifier ['<' type {',' type} '>'] '::'] let mut reader = outer_reader.create_inner(); let is_global = reader.peek().token_type == TokenType::ColonColon; if is_global { reader.next(); } let mut scope: Vec = Vec::new(); loop { let n = reader.peek(); if let TokenType::Identifier(s) = &n.token_type { let identifier = s.to_string(); if reader.peek().token_type == TokenType::ColonColon { reader.next(); reader.next(); scope.push(identifier); } else { break; } } else { break; } } // TODO: generics if !is_global && scope.is_empty() { None } else { outer_reader.set_from_inner(&reader); Some(Box::new(ParsedStatement::Scope { is_global, scope, generic_types: None, })) } } fn parse_datatype( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { if let Some(identifier) = parse_identifier(reader, log, true) { return Some(Box::new(ParsedStatement::DataTypeIdentifier { identifier })); } if reader.peek().token_type == TokenType::AutoKeyword { reader.next(); return Some(Box::new(ParsedStatement::DataTypeAuto {})); } parse_primtype(reader, log) } fn parse_primtype( reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { let key = reader.peek(); let res = match &key.token_type { TokenType::VoidKeyword => Some(Box::new(ParsedStatement::DataTypePrimType { prim_type: PrimitiveType::Void, })), TokenType::Int8Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { prim_type: PrimitiveType::Int8, })), TokenType::Int16Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { prim_type: PrimitiveType::Int16, })), TokenType::Int32Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { prim_type: PrimitiveType::Int32, })), TokenType::Int64Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { prim_type: PrimitiveType::Int64, })), TokenType::Uint8Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { prim_type: PrimitiveType::UInt8, })), TokenType::Uint16Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { prim_type: PrimitiveType::UInt16, })), TokenType::Uint32Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { prim_type: PrimitiveType::UInt32, })), TokenType::Uint64Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { prim_type: PrimitiveType::UInt64, })), TokenType::FloatKeyword => Some(Box::new(ParsedStatement::DataTypePrimType { prim_type: PrimitiveType::Float, })), TokenType::DoubleKeyword => Some(Box::new(ParsedStatement::DataTypePrimType { prim_type: PrimitiveType::Double, })), TokenType::BoolKeyword => Some(Box::new(ParsedStatement::DataTypePrimType { prim_type: PrimitiveType::Bool, })), _ => None, }; if res.is_some() { reader.next(); } res } fn parse_bitop( reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option { // bitop ::= '&' | '|' | '^' | '<<' | '>>' | '>>>'; let operand = match reader.peek().token_type { TokenType::Ampersand => Some(BinaryOperator::BitwiseAnd), TokenType::VerticalLine => Some(BinaryOperator::BitwiseOr), TokenType::Roof => Some(BinaryOperator::BitwiseXor), TokenType::LeftLeft => Some(BinaryOperator::LeftShift), TokenType::RightRight => Some(BinaryOperator::RightShift), TokenType::RightRightRight => Some(BinaryOperator::ArithmeticRightShift), _ => None, }; if operand.is_some() { reader.next(); } operand } fn parse_mathop( reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option { // mathop := '+' | '-' | '*' | '/' | '%' | '**'; let operand = match reader.peek().token_type { TokenType::Plus => Some(BinaryOperator::Addition), TokenType::Minus => Some(BinaryOperator::Subtraction), TokenType::Star => Some(BinaryOperator::Multiplication), TokenType::Slash => Some(BinaryOperator::Division), TokenType::Percent => Some(BinaryOperator::Modulo), TokenType::StarStar => Some(BinaryOperator::Exponentiation), _ => None, }; if operand.is_some() { reader.next(); } operand } fn parse_compop( reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option { // compop ::= '==' | '!=' | '<' | '<=' | '>' | '>=' | 'is' | '!is'; let operand = match reader.peek().token_type { TokenType::EqualsEquals => Some(BinaryOperator::Equality), TokenType::NotEquals => Some(BinaryOperator::Inequality), TokenType::LessThan => Some(BinaryOperator::LessThan), TokenType::LessThanEquals => Some(BinaryOperator::LessThanEquals), TokenType::GreaterThan => Some(BinaryOperator::GreaterThan), TokenType::GreaterThanEquals => Some(BinaryOperator::GreaterThanEquals), TokenType::IsKeyword => Some(BinaryOperator::IdentityEquality), TokenType::NotIsKeyword => Some(BinaryOperator::IdentityInequality), _ => None, }; if operand.is_some() { reader.next(); } operand } fn parse_logicop( reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option { // logicop ::= '&&' | '||' | '^^' | 'and' | 'or' | 'xor'; let operand = match reader.peek().token_type { TokenType::AmpersandAmpersand => Some(BinaryOperator::And), TokenType::LineLine => Some(BinaryOperator::Or), TokenType::RoofRoof => Some(BinaryOperator::Xor), TokenType::AndKeyword => Some(BinaryOperator::And), TokenType::OrKeyword => Some(BinaryOperator::Or), TokenType::XorKeyword => Some(BinaryOperator::Xor), _ => None, }; if operand.is_some() { reader.next(); } operand } fn parse_assignop( reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option { // assignop ::= '=' | '+=' | '-=' | '*=' | '/=' | '|=' | '&=' | '^=' | '%=' | '**=' | '<<=' | '>>=' | '>>>='; let operand = match reader.peek().token_type { TokenType::Equals => Some(BinaryOperator::Assignment), TokenType::PlusEquals => Some(BinaryOperator::AssignmentAddition), TokenType::MinusEquals => Some(BinaryOperator::AssignmentSubtraction), TokenType::StarEquals => Some(BinaryOperator::AssignmentMultiplication), TokenType::PercentEquals => Some(BinaryOperator::AssignmentModulo), TokenType::StarStarEquals => Some(BinaryOperator::AssignmentExponentiation), TokenType::SlashEquals => Some(BinaryOperator::AssignmentDivision), TokenType::LineEquals => Some(BinaryOperator::AssignmentBitwiseOr), TokenType::AmpersandEquals => Some(BinaryOperator::AssignmentBitwiseAnd), TokenType::RoofEquals => Some(BinaryOperator::AssignmentBitwiseXor), TokenType::LeftLeftEquals => Some(BinaryOperator::AssignmentLeftShift), TokenType::RightRightEquals => Some(BinaryOperator::AssignmentRightShift), TokenType::RightRightRightEquals => Some(BinaryOperator::AssignmentArithmeticRightShift), _ => None, }; if operand.is_some() { reader.next(); } operand }