From 2bc3bee344286d3210897a9039b86eef263457ce Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 3 Apr 2022 15:25:26 +0200 Subject: [PATCH] Loads more parsing work --- Cargo.toml | 13 +- grammar.ebnf | 4 +- src/lib.rs | 1 - src/logger/messages.rs | 2 + src/parsing/lexer/lex_tokens.rs | 1 + src/parsing/lexer/mod.rs | 2 +- src/parsing/parser/mod.rs | 520 +++++++++++++++++---- src/parsing/parser/parsed_statement.rs | 88 +++- src/parsing/parser/parsed_type_modifier.rs | 10 + src/parsing/parser/parser_operators.rs | 15 +- src/parsing/parser/parser_tests.rs | 22 +- src/prim_type.rs | 1 + 12 files changed, 571 insertions(+), 108 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6b30b99..c8841e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,9 +2,18 @@ name = "seraph_script" version = "0.1.0" authors = ["Deukhoofd "] -edition = "2018" +edition = "2021" [dependencies] itertools = "0.10.0" enumflags2 = "0.7.1" -backtrace = "0.3.63" \ No newline at end of file +backtrace = "0.3.63" + +[profile.release] +lto = true +codegen-units = 1 +debug = true +opt-level = 3 + +[profile.dev] +opt-level = 1 \ No newline at end of file diff --git a/grammar.ebnf b/grammar.ebnf index 87f243f..799c3c5 100644 --- a/grammar.ebnf +++ b/grammar.ebnf @@ -56,10 +56,10 @@ typemod ::= ['&' ['in' | 'out' | 'inout']]; lambda ::= 'function' '(' [[type typemod] identifier {',' [type typemod] identifier}] ')' statblock; exprvalue ::= 'void' | constructcall | funccall | varaccess | cast | literal | '(' assign ')' | lambda; -exprpostop ::= ('.' (funccall | identifier)) | ('[' [identifier ':'] assign {',' [identifier ':' assign} ']') | arglist | '++' | '--'; +exprpostop ::= ('.' (funccall | identifier)) | ('[' [ identifier ':'] assign {',' [ identifier ':' assign } ']' ) | arglist | '++' | '--'; exprterm ::= ([type '='] initlist) | ({exprpreop} exprvalue {exprpostop}); expr ::= exprterm {(mathop | compop | logicop | bitop) exprterm}; -ternary ::= expr ['?' assign : assign]; +ternary ::= expr ['?' assign ':' assign]; return ::= 'return' [assign] ';'; exprstat ::= assign ';'; diff --git a/src/lib.rs b/src/lib.rs index 608c100..a6fa792 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ #![feature(exclusive_range_pattern)] #![feature(assert_matches)] #![feature(fn_traits)] -#![feature(macro_attributes_in_derive_output)] #![feature(iter_advance_by)] #![feature(backtrace)] diff --git a/src/logger/messages.rs b/src/logger/messages.rs index 4e85c28..07f0793 100644 --- a/src/logger/messages.rs +++ b/src/logger/messages.rs @@ -13,6 +13,7 @@ pub enum Message { expected: Vec, }, EmptyProperty, + EmptyIndex, } impl Message { @@ -35,6 +36,7 @@ impl Message { ) } Message::EmptyProperty => "Property encountered without a getter or setter".to_string(), + Message::EmptyIndex => "Index operator had an empty index".to_string(), } } } diff --git a/src/parsing/lexer/lex_tokens.rs b/src/parsing/lexer/lex_tokens.rs index 8385fe5..cba1f84 100644 --- a/src/parsing/lexer/lex_tokens.rs +++ b/src/parsing/lexer/lex_tokens.rs @@ -20,6 +20,7 @@ pub enum TokenType { ColonColon, Comma, Dot, + QuestionMark, OpenBracket, CloseBracket, OpenCurlyBracket, diff --git a/src/parsing/lexer/mod.rs b/src/parsing/lexer/mod.rs index be4fa45..27956ec 100644 --- a/src/parsing/lexer/mod.rs +++ b/src/parsing/lexer/mod.rs @@ -426,7 +426,6 @@ pub fn lex(s: &str, log: &mut dyn FnMut(Message, Span)) -> Vec { add_token(TT::ExclamationMark, start_pos, chars.real_position); } } - '~' => lex_and_consume(&mut chars, TT::Tilde, &mut add_token), '@' => lex_and_consume(&mut chars, TT::AtSymbol, &mut add_token), ';' => lex_and_consume(&mut chars, TT::Semicolon, &mut add_token), @@ -450,6 +449,7 @@ pub fn lex(s: &str, log: &mut dyn FnMut(Message, Span)) -> Vec { ']' => lex_and_consume(&mut chars, TT::CloseBlockBracket, &mut add_token), ',' => lex_and_consume(&mut chars, TT::Comma, &mut add_token), '.' => lex_and_consume(&mut chars, TT::Dot, &mut add_token), + '?' => lex_and_consume(&mut chars, TT::QuestionMark, &mut add_token), '0'..'9' => lex_numeric(&mut chars, &mut add_token), 'a'..'z' | 'A'..'Z' | '_' => lex_keyword_or_identifier(&mut chars, &mut add_token), diff --git a/src/parsing/parser/mod.rs b/src/parsing/parser/mod.rs index 4d926d5..c27ab33 100644 --- a/src/parsing/parser/mod.rs +++ b/src/parsing/parser/mod.rs @@ -8,12 +8,20 @@ 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::parser::parsed_type_modifier::ParsedTypeModifier; -use crate::parsing::parser::parser_operators::{BinaryOperator, PreOperator}; +use crate::parsing::lexer::lex_tokens::TokenType::CloseBracket; +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, @@ -21,7 +29,7 @@ struct ParseReader<'a> { } impl<'a> ParseReader<'a> { - pub fn peek(&mut self) -> &LexToken { + pub fn peek(&self) -> &LexToken { let t = self.tokens.get(self.position); match t { None => self.tokens.last().unwrap(), @@ -35,7 +43,7 @@ impl<'a> ParseReader<'a> { } } - fn peek_ahead(&mut self, index: usize) -> &LexToken { + fn peek_ahead(&self, index: usize) -> &LexToken { let t = self.tokens.get(self.position + index); match t { None => self.tokens.last().unwrap(), @@ -471,10 +479,42 @@ fn parse_virtprop( } fn parse_paramlist( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // 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, type_mod, identifier, default)); + } + + return Some(Box::new(ParsedStatement::ParamList { parameters: params })); } fn parse_funcattr( @@ -486,13 +526,35 @@ fn parse_funcattr( fn parse_statblock( reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + log: &mut dyn FnMut(Message, Span), ) -> Option> { - // FIXME + // statblock ::= '{' {var | statement} '}'; if reader.peek().token_type != TokenType::OpenCurlyBracket { return None; } - 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( @@ -522,16 +584,14 @@ fn parse_var( } } } - if property_type.is_none() { - return None; - } + property_type.as_ref()?; let identifier = parse_identifier(&mut reader, log, false); identifier.as_ref()?; let mut assignment: Option> = None; - // FIXME: Implement arglist + // TODO: Implement arglist // [( '=' (initlist | expr)) | arglist] if reader.peek().token_type == TokenType::Equals { // Eat the equals token. @@ -547,6 +607,8 @@ fn parse_var( } } + //TODO: Multiple variable creation + // {',' identifier [( '=' (initlist | expr)) | arglist]} ';'; outer_reader.set_from_inner(&reader); @@ -559,94 +621,257 @@ fn parse_var( } fn parse_statement( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // 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( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // 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( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // 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( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // 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( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // 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( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // 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( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // 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( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // 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( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // break ::= 'break' ';'; + reader.consume(TokenType::BreakKeyword, log); + reader.consume(TokenType::Semicolon, log); + Some(Box::new(ParsedStatement::BreakStatement {})) } fn parse_continue( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // continue ::= 'continue' ';'; + reader.consume(TokenType::ContinueKeyword, log); + reader.consume(TokenType::Semicolon, log); + Some(Box::new(ParsedStatement::ContinueStatement {})) } fn parse_exprstat( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // exprstat ::= assign ';'; + let expression = parse_assign(reader, log); + expression.as_ref()?; + reader.consume(TokenType::Semicolon, log); + expression } fn parse_return( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // 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( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // 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( @@ -669,7 +894,7 @@ fn parse_expr( binary_operand = parse_bitop(reader, log); } - if binary_operand.is_some() { + if let Some(..) = binary_operand { let expr_term2 = parse_exprterm(reader, log); // FIXME: deal with empty expr_term2 return Some(Box::new(ParsedStatement::BinaryExpr { @@ -717,34 +942,135 @@ fn parse_exprterm( let mut real_value = expr_value.unwrap(); - let real_value = parse_exprpostop(&mut reader, log, real_value); + 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(Box::new(ParsedStatement::ExprTerm { - pre_op: expr_pre_op, - exp_value: real_value, - })) + Some(real_value) } fn parse_exprpostop( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), base: Box, -) -> Box { +) -> (Box, bool) { // exprpostop ::= ('.' (funccall | identifier)) | ('[' [identifier ':'] assign {',' [identifier ':' assign} ']') | arglist | '++' | '--'; - // FIXME: This needs to be implemented. - // ('.' (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} ']') - // arglist - // '++' - // '--' - base + // ( '[' [ 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( @@ -801,10 +1127,35 @@ fn parse_lambda( } fn parse_typemod( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), -) -> Option> { - unimplemented!(); + 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( @@ -945,16 +1296,30 @@ fn parse_initlist( } fn parse_assign( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // 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 { @@ -1090,13 +1455,6 @@ fn parse_datatype( res } -fn parse_primtype( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), -) -> Option> { - unimplemented!(); -} - fn parse_bitop( reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), diff --git a/src/parsing/parser/parsed_statement.rs b/src/parsing/parser/parsed_statement.rs index e28ab07..e0ddb63 100644 --- a/src/parsing/parser/parsed_statement.rs +++ b/src/parsing/parser/parsed_statement.rs @@ -1,7 +1,10 @@ use super::parsed_type_modifier::ParsedTypeModifier; use crate::defines::{LiteralFloat, LiteralInt}; use crate::modifiers::{FieldModifier, TypeModifier}; -use crate::parsing::parser::parser_operators::{BinaryOperator, PreOperator}; +use crate::parsing::parser::parsed_type_modifier::ReferenceModifier; +use crate::parsing::parser::parser_operators::{ + BinaryOperator, PostOperator, PreOperator, TernaryOperator, +}; use crate::prim_type::PrimitiveType; use enumflags2::BitFlags; @@ -63,12 +66,13 @@ pub enum ParsedStatement { statement_type: Option>, initlist: Box, }, - ExprTerm { - pre_op: Vec, - exp_value: Box, - }, ExprPreOp { operator: PreOperator, + operand: Box, + }, + ExprPostOp { + operator: PostOperator, + operand: Box, }, ExprVoidValue {}, ConstructCall { @@ -97,4 +101,78 @@ pub enum ParsedStatement { operator: BinaryOperator, right: Box, }, + TernaryExpr { + left: Box, + operator: TernaryOperator, + middle: Box, + right: Box, + }, + MemberAccess { + operand: Box, + identifier: String, + }, + MemberFuncCall { + operand: Box, + func_call: Box, + }, + IndexingOperator { + operand: Box, + index: Vec<(Option, Box)>, + }, + AnonymousCall { + operand: Box, + arg_list: Box, + }, + Assignment { + left: Box, + operator: BinaryOperator, + right: Box, + }, + Switch { + expression: Box, + cases: Vec>, + }, + Case { + // None for default + expression: Option>, + statement: Box, + }, + TryStatement { + try_block: Box, + catch_block: Box, + }, + StatBlock { + statements: Vec>, + }, + DoWhileStatement { + statement: Box, + condition: Box, + }, + WhileStatement { + condition: Box, + statement: Box, + }, + ForStatement { + initializer: Box, + bounds: Box, + increment: Vec>, + }, + IfStatement { + condition: Box, + statement: Box, + else_statement: Option>, + }, + BreakStatement {}, + ContinueStatement {}, + ReturnStatement { + expression: Option>, + }, + ParamList { + parameters: Vec<( + Box, // type + Option>, // typemod + Option, // identifier + Option>, // default expression + )>, + }, } diff --git a/src/parsing/parser/parsed_type_modifier.rs b/src/parsing/parser/parsed_type_modifier.rs index bcd4671..08dc634 100644 --- a/src/parsing/parser/parsed_type_modifier.rs +++ b/src/parsing/parser/parsed_type_modifier.rs @@ -1,6 +1,16 @@ +use enumflags2::bitflags; + #[derive(Eq, PartialEq, Debug)] pub enum ParsedTypeModifier { Array, Handle, ConstHandle, } + +#[bitflags] +#[repr(u8)] +#[derive(Eq, PartialEq, Debug)] +pub enum ReferenceModifier { + In, + Out, +} diff --git a/src/parsing/parser/parser_operators.rs b/src/parsing/parser/parser_operators.rs index 958569f..156275c 100644 --- a/src/parsing/parser/parser_operators.rs +++ b/src/parsing/parser/parser_operators.rs @@ -1,4 +1,4 @@ -#[derive(Eq, PartialEq, Debug)] +#[derive(Eq, PartialEq, Debug, Copy, Clone)] pub enum PreOperator { Negative, Identity, @@ -9,7 +9,13 @@ pub enum PreOperator { HandleOf, } -#[derive(Eq, PartialEq, Debug)] +#[derive(Eq, PartialEq, Debug, Copy, Clone)] +pub enum PostOperator { + Increment, + Decrement, +} + +#[derive(Eq, PartialEq, Debug, Copy, Clone)] pub enum BinaryOperator { // math op Addition, @@ -53,3 +59,8 @@ pub enum BinaryOperator { AssignmentRightShift, AssignmentArithmeticRightShift, } + +#[derive(Eq, PartialEq, Debug, Copy, Clone)] +pub enum TernaryOperator { + Conditional, +} diff --git a/src/parsing/parser/parser_tests.rs b/src/parsing/parser/parser_tests.rs index 8389864..c73a9fd 100644 --- a/src/parsing/parser/parser_tests.rs +++ b/src/parsing/parser/parser_tests.rs @@ -254,10 +254,7 @@ fn test_assign_to_global_variable() { assert!(assignment.is_some()); assert_eq!( *(assignment.as_ref().unwrap().as_ref()), - ParsedStatement::ExprTerm { - pre_op: vec![], - exp_value: Box::from(ParsedStatement::IntegerLiteral(100)), - } + ParsedStatement::IntegerLiteral(100) ); } else { unreachable!() @@ -308,9 +305,9 @@ fn test_assign_negative_to_global_variable() { assert!(assignment.is_some()); assert_eq!( *(assignment.as_ref().unwrap().as_ref()), - ParsedStatement::ExprTerm { - pre_op: vec![PreOperator::Negative], - exp_value: Box::from(ParsedStatement::IntegerLiteral(100)), + ParsedStatement::ExprPreOp { + operator: PreOperator::Negative, + operand: Box::from(ParsedStatement::IntegerLiteral(100)), } ); } else { @@ -365,14 +362,11 @@ fn test_assign_addition_to_global_variable() { assert_eq!( *(assignment.as_ref().unwrap().as_ref()), ParsedStatement::BinaryExpr { - left: Box::new(ParsedStatement::ExprTerm { - pre_op: vec![], - exp_value: Box::new(ParsedStatement::IntegerLiteral(100)), - }), + left: Box::new(ParsedStatement::IntegerLiteral(100)), operator: BinaryOperator::Addition, - right: Box::new(ParsedStatement::ExprTerm { - pre_op: vec![PreOperator::Negative], - exp_value: Box::new(ParsedStatement::IntegerLiteral(20)), + right: Box::new(ParsedStatement::ExprPreOp { + operator: PreOperator::Negative, + operand: Box::new(ParsedStatement::IntegerLiteral(20)), }), } ); diff --git a/src/prim_type.rs b/src/prim_type.rs index b854f02..b4d27eb 100644 --- a/src/prim_type.rs +++ b/src/prim_type.rs @@ -16,6 +16,7 @@ pub enum PrimitiveType { Bool, } +#[allow(dead_code)] pub fn get_primitive_type_byte_size(t: PrimitiveType) -> PointerSize { match t { PrimitiveType::Void => 0,