|
|
|
@ -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<LexToken>, |
|
|
|
@ -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<Box<ParsedStatement>> { |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
// 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<Box<ParsedStatement>> = 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<Box<ParsedStatement>> { |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
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<ParsedStatement>, |
|
|
|
|
) -> Box<ParsedStatement> { |
|
|
|
|
) -> (Box<ParsedStatement>, 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} ']')
|
|
|
|
|
|
|
|
|
|
// ( '[' [ 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 |
|
|
|
|
(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<Box<ParsedStatement>> { |
|
|
|
|
unimplemented!(); |
|
|
|
|
reader: &mut ParseReader, |
|
|
|
|
log: &mut dyn FnMut(Message, Span), |
|
|
|
|
) -> Option<BitFlags<ReferenceModifier>> { |
|
|
|
|
// typemod ::= ['&' ['in' | 'out' | 'inout']];
|
|
|
|
|
if reader.peek().token_type == TokenType::Ampersand { |
|
|
|
|
reader.next(); |
|
|
|
|
} else { |
|
|
|
|
return None; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let mut type_mod: BitFlags<ReferenceModifier> = |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
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<Box<ParsedStatement>> { |
|
|
|
|
// 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<Box<ParsedStatement>> { |
|
|
|
|
unimplemented!(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn parse_bitop( |
|
|
|
|
reader: &mut ParseReader, |
|
|
|
|
_log: &mut dyn FnMut(Message, Span), |
|
|
|
|