SeraphScript/src/parsing/parser/mod.rs

2062 lines
65 KiB
Rust

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::parser::parsed_funcattr::FuncAttr;
use crate::parsing::parser::parsed_statement::ParsedParameter;
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;
struct ParseReader<'a> {
tokens: &'a Vec<LexToken>,
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<LexToken>, log: &mut dyn FnMut(Message, Span)) -> Box<ParsedStatement> {
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<String> {
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<ParsedStatement> {
// script ::= {import | enum | typedef | class | interface | funcdef | virtprop | var | func | namespace | ';'};
let mut vec: Vec<ParsedStatement> = Vec::new();
loop {
let n = reader.peek();
let token_type = n.token_type.clone();
let span = n.span;
match token_type {
TokenType::ImportKeyword => {
vec.push(*parse_import(reader, log).unwrap());
}
TokenType::TypeDefKeyword => {
vec.push(*parse_typedef(reader, log).unwrap());
}
TokenType::FuncDefKeyword => {
vec.push(*parse_funcdef(reader, log).unwrap());
}
TokenType::NamespaceKeyword => {
vec.push(*parse_namespace(reader, log));
}
TokenType::InterfaceKeyword => vec.push(*parse_interface(reader, log).unwrap()),
TokenType::EnumKeyword => vec.push(*parse_enum(reader, log).unwrap()),
TokenType::EndOfFile => break,
TokenType::CloseCurlyBracket => break,
_ => {
if let Some(s) = parse_enum(reader, log) {
vec.push(*s);
} else if let Some(s) = parse_class(reader, log) {
vec.push(*s);
} else if let Some(s) = parse_interface(reader, log) {
vec.push(*s);
} else if let Some(s) = parse_virtprop(reader, log) {
vec.push(*s);
} else if let Some(s) = parse_var(reader, log) {
vec.push(*s);
} else if let Some(s) = parse_func(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<ParsedStatement> {
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<Box<ParsedStatement>> {
// interface ::= {'external' | 'shared'} 'interface' identifier (';' | ([':' identifier {',' identifier}] '{' {virtprop | interfacemethod} '}'));
let mut type_mod: BitFlags<TypeModifier> = BitFlags::empty();
let identifier: Option<String>;
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<ParsedStatement> = Vec::new();
let mut inherits: Vec<String> = 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);
loop {
if reader.peek().token_type == TokenType::CloseCurlyBracket {
break;
}
let mut prop = parse_virtprop(&mut reader, log);
if prop.is_none() {
prop = parse_interface_method(&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<Box<ParsedStatement>> {
// interfacemethod ::= type ['&'] identifier paramlist ['const'] ';';
let mut reader = outer_reader.create_inner();
let return_type = parse_type(&mut reader, log);
return_type.as_ref()?;
let returns_reference = reader.peek().token_type == TokenType::Ampersand;
if returns_reference {
reader.next();
}
let identifier = parse_identifier(&mut reader, log, true);
identifier.as_ref()?;
let param_list = parse_paramlist(&mut reader, log);
param_list.as_ref()?;
let is_const = reader.peek().token_type == TokenType::ConstKeyword;
if is_const {
reader.next();
}
reader.consume(TokenType::Semicolon, log);
outer_reader.set_from_inner(&reader);
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<Box<ParsedStatement>> {
// 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 let Some(s) = left_type_identifier {
left_type = Some(Box::new(ParsedStatement::DataTypeIdentifier {
identifier: s,
}));
}
}
let right_type_identifier = parse_identifier(reader, log, false);
right_type_identifier.as_ref()?;
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<Box<ParsedStatement>> {
// 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(
reader: &mut ParseReader,
log: &mut dyn FnMut(Message, Span),
) -> Option<Box<ParsedStatement>> {
// enum ::= {'shared' | 'external'} 'enum' identifier [ ':' primtype ] (';' | ('{' identifier ['=' expr] {',' identifier ['=' expr]} '}'));
let mut inner_reader = reader.create_inner();
let mut modifiers: BitFlags<TypeModifier> = BitFlags::empty();
loop {
match inner_reader.peek().token_type {
TokenType::SharedKeyword => {
inner_reader.next();
modifiers |= TypeModifier::Shared;
}
TokenType::ExternalKeyword => {
inner_reader.next();
modifiers |= TypeModifier::External;
}
TokenType::EnumKeyword => {
break;
}
_ => {
return None;
}
}
}
inner_reader.consume(TokenType::EnumKeyword, log);
reader.set_from_inner(&inner_reader);
let name = parse_identifier(reader, log, false);
if name.is_none() {
return Some(Box::new(ParsedStatement::Invalid));
}
let mut base_type = None;
if reader.peek().token_type == TokenType::Colon {
reader.next();
let prim_type = parse_primtype(reader, log);
if prim_type.is_none() {
// FIXME: make clearer
log(
UnexpectedToken {
found: reader.peek().token_type.clone(),
expected: vec![],
},
reader.peek().span,
);
return Some(Box::new(ParsedStatement::Invalid));
}
base_type = prim_type;
}
let mut values = Vec::new();
if reader.peek().token_type == TokenType::OpenCurlyBracket {
reader.next();
loop {
if reader.peek().token_type == TokenType::CloseCurlyBracket
|| reader.peek().token_type == TokenType::EndOfFile
{
break;
}
let identifier = parse_identifier(reader, log, false);
let mut value = None;
if reader.peek().token_type == TokenType::Equals {
reader.next();
value = parse_assign(reader, log);
// FIXME: Add error log if value is None
}
values.push((identifier.unwrap(), value));
if reader.peek().token_type != TokenType::Comma {
break;
}
reader.next();
}
reader.consume(TokenType::CloseCurlyBracket, log);
}
Some(Box::new(ParsedStatement::EnumDeclaration {
modifiers,
identifier: name.unwrap(),
base_type,
values,
}))
}
fn parse_class(
reader: &mut ParseReader,
log: &mut dyn FnMut(Message, Span),
) -> Option<Box<ParsedStatement>> {
// class ::= {'shared' | 'abstract' | 'final' | 'external' | 'mixin'} 'class' identifier
// (';' | ([':' identifier {',' identifier}] '{' {virtprop | func | var | funcdef | class} '}'));
let mut inner_reader = reader.create_inner();
let mut modifiers: BitFlags<TypeModifier> = BitFlags::empty();
loop {
match inner_reader.peek().token_type {
TokenType::SharedKeyword => {
inner_reader.next();
modifiers |= TypeModifier::Shared;
}
TokenType::AbstractKeyword => {
inner_reader.next();
modifiers |= TypeModifier::Abstract;
}
TokenType::FinalKeyword => {
inner_reader.next();
modifiers |= TypeModifier::Final;
}
TokenType::ExternalKeyword => {
inner_reader.next();
modifiers |= TypeModifier::External;
}
TokenType::MixinKeyword => {
inner_reader.next();
modifiers |= TypeModifier::Mixin;
}
_ => {
break;
}
}
}
if inner_reader.peek().token_type != TokenType::ClassKeyword {
return None;
}
inner_reader.next();
reader.set_from_inner(&inner_reader);
let name = parse_identifier(reader, log, false);
// (';' |
// (
// [':' identifier {',' identifier}]
// '{' {virtprop | func | var | funcdef | class} '}'
// )
// )
// FIXME: Do we need predeclaring class (class foo;)?
let mut inherits = Vec::new();
if reader.peek().token_type == TokenType::Colon {
reader.next();
loop {
let inherit = parse_identifier(reader, log, false);
if let Some(s) = inherit {
inherits.push(s);
}
if reader.peek().token_type != TokenType::Comma {
break;
}
reader.next();
}
}
reader.consume(TokenType::OpenCurlyBracket, log);
let mut statements = Vec::new();
loop {
let mut statement = parse_virtprop(reader, log);
if statement.is_none() {
statement = parse_func(reader, log);
if statement.is_none() {
statement = parse_var(reader, log);
if statement.is_none() {
statement = parse_funcdef(reader, log);
if statement.is_none() {
statement = parse_class(reader, log);
}
}
}
}
if let Some(s) = statement {
statements.push(s);
} else {
break;
}
}
reader.consume(TokenType::CloseCurlyBracket, log);
if name.is_none() {
return Some(Box::new(ParsedStatement::Invalid));
}
Some(Box::new(ParsedStatement::ClassDeclaration {
modifiers,
name: name.unwrap(),
inherits,
statements,
}))
}
fn parse_funcdef(
outer_reader: &mut ParseReader,
log: &mut dyn FnMut(Message, Span),
) -> Option<Box<ParsedStatement>> {
// funcdef ::= {'external' | 'shared'} 'funcdef' type ['&'] identifier paramlist ';'
let mut reader = outer_reader.create_inner();
let mut modifiers: BitFlags<TypeModifier> = BitFlags::empty();
loop {
match reader.peek().token_type {
TokenType::SharedKeyword => {
reader.next();
modifiers |= TypeModifier::Shared;
}
TokenType::ExternalKeyword => {
reader.next();
modifiers |= TypeModifier::External;
}
_ => {
break;
}
}
}
if reader.peek().token_type != TokenType::FuncDefKeyword {
return None;
}
reader.next();
let return_type = parse_type(&mut reader, log);
return_type.as_ref()?;
let returns_reference = reader.peek().token_type == TokenType::Ampersand;
if returns_reference {
reader.next();
}
let identifier = parse_identifier(&mut reader, log, true);
identifier.as_ref()?;
let param_list = parse_paramlist(&mut reader, log);
param_list.as_ref()?;
if reader.peek().token_type != TokenType::Semicolon {
return None;
}
reader.next();
outer_reader.set_from_inner(&reader);
if identifier.is_none() || param_list.is_none() {
Some(Box::new(ParsedStatement::Invalid));
}
Some(Box::new(ParsedStatement::FuncDefDeclaration {
modifiers,
returns_reference,
return_type,
name: identifier.unwrap(),
param_list: param_list.unwrap(),
}))
}
fn parse_func(
outer_reader: &mut ParseReader,
log: &mut dyn FnMut(Message, Span),
) -> Option<Box<ParsedStatement>> {
// func ::= {'shared' | 'external'} ['private' | 'protected'] [((type ['&']) | '~')] identifier paramlist ['const'] funcattr (';' | statblock);
let mut reader = outer_reader.create_inner();
let mut modifiers: BitFlags<TypeModifier> = BitFlags::empty();
loop {
match reader.peek().token_type {
TokenType::SharedKeyword => {
reader.next();
modifiers |= TypeModifier::Shared;
}
TokenType::ExternalKeyword => {
reader.next();
modifiers |= TypeModifier::External;
}
_ => {
break;
}
}
}
let mut field_mod: Option<FieldModifier> = None;
match reader.peek().token_type {
TokenType::PrivateKeyword => {
field_mod = Some(FieldModifier::Private);
reader.next();
}
TokenType::ProtectedKeyword => {
field_mod = Some(FieldModifier::Protected);
reader.next();
}
_ => {}
}
// [((type ['&']) | '~')]
let mut is_destructor = false;
let mut returns_reference = false;
let mut return_type = None;
if reader.peek().token_type == TokenType::Tilde {
is_destructor = true;
reader.next();
} else {
return_type = parse_type(&mut reader, log);
if return_type.is_some() && reader.peek().token_type == TokenType::Ampersand {
returns_reference = true;
reader.next();
}
}
let name = parse_identifier(&mut reader, log, true);
name.as_ref()?;
let param_list = parse_paramlist(&mut reader, log);
param_list.as_ref()?;
let is_const = reader.peek().token_type == TokenType::ConstKeyword;
if is_const {
reader.next();
}
let func_attr = parse_funcattr(&mut reader, log);
let mut block = None;
if reader.peek().token_type == TokenType::Semicolon {
reader.next();
} else {
block = parse_statblock(&mut reader, log);
}
outer_reader.set_from_inner(&reader);
Some(Box::new(ParsedStatement::FuncDeclaration {
modifiers,
field_mod,
is_destructor,
returns_reference,
return_type,
name: name.unwrap(),
param_list: param_list.unwrap(),
is_const,
func_attr,
block,
}))
}
fn parse_virtprop(
outer_reader: &mut ParseReader,
log: &mut dyn FnMut(Message, Span),
) -> Option<Box<ParsedStatement>> {
let mut reader = outer_reader.create_inner();
let mut field_mod: Option<FieldModifier> = None;
match reader.peek().token_type {
TokenType::PrivateKeyword => {
field_mod = Some(FieldModifier::Private);
reader.next();
}
TokenType::ProtectedKeyword => {
field_mod = Some(FieldModifier::Protected);
reader.next();
}
_ => {}
}
let property_type = parse_type(&mut reader, log);
property_type.as_ref()?;
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<Box<ParsedStatement>> = None;
let mut has_set = false;
let mut is_set_const = false;
let mut set_statement: Option<Box<ParsedStatement>> = 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<Box<ParsedStatement>> {
// 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 {
break;
}
if reader.peek().token_type == TokenType::EndOfFile {
break;
}
let param_type = parse_type(reader, log);
if param_type.is_none() {
// FIXME: Add logging
break;
}
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(ParsedParameter {
parameter_type: param_type.unwrap(),
type_mod,
identifier,
default,
});
if reader.peek().token_type != TokenType::Comma {
break;
}
reader.next();
}
reader.consume(TokenType::CloseBracket, log);
Some(Box::new(ParsedStatement::ParamList { parameters: params }))
}
fn parse_funcattr(
reader: &mut ParseReader,
_log: &mut dyn FnMut(Message, Span),
) -> BitFlags<FuncAttr> {
// funcattr ::= {'override' | 'final' | 'explicit' | 'property'};
let mut func_attr: BitFlags<FuncAttr> = 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<Box<ParsedStatement>> {
// 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;
}
if reader.peek().token_type == TokenType::EndOfFile {
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<Box<ParsedStatement>> {
// var ::= ['private'|'protected'] type identifier [( '=' (initlist | expr)) | arglist] {',' identifier [( '=' (initlist | expr)) | arglist]} ';';
// var ::= ['private'|'protected'] type identifier
let mut reader = outer_reader.create_inner();
let mut field_mod: BitFlags<FieldModifier> = BitFlags::empty();
let property_type: Option<Box<ParsedStatement>>;
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<Box<ParsedStatement>> = 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]} ';';
if reader.peek().token_type != TokenType::Semicolon {
return None;
}
reader.next();
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<Box<ParsedStatement>> {
// 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<Box<ParsedStatement>> {
// 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;
}
if reader.peek().token_type == TokenType::EndOfFile {
break;
}
let case = parse_case(reader, log);
if case.is_none() {
break;
}
vec.push(case.unwrap());
}
reader.consume(TokenType::CloseCurlyBracket, log);
Some(Box::new(ParsedStatement::Switch {
expression: assign.unwrap(),
cases: vec,
}))
}
fn parse_case(
reader: &mut ParseReader,
log: &mut dyn FnMut(Message, Span),
) -> Option<Box<ParsedStatement>> {
// 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<Box<ParsedStatement>> {
// 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<Box<ParsedStatement>> {
// 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<Box<ParsedStatement>> {
// 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<Box<ParsedStatement>> {
// 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;
}
if reader.peek().token_type == TokenType::EndOfFile {
break;
}
let assign = parse_assign(reader, log);
if let Some(s) = assign {
increment_expressions.push(s);
}
if reader.peek().token_type != TokenType::Comma {
break;
}
reader.next();
}
reader.consume(TokenType::CloseBracket, log);
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<Box<ParsedStatement>> {
// 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<Box<ParsedStatement>> {
// 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<Box<ParsedStatement>> {
// 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<Box<ParsedStatement>> {
// 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<Box<ParsedStatement>> {
// 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<Box<ParsedStatement>> {
// 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<Box<ParsedStatement>> {
// 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);
if expr_term2.is_none() {
return Some(Box::new(ParsedStatement::Invalid));
}
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<Box<ParsedStatement>> {
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() && reader.peek().token_type == TokenType::Equals {
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,
})
}
println!("{:?}", 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<ParsedStatement>,
) -> (Box<ParsedStatement>, 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<Box<ParsedStatement>> {
// 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(
reader: &mut ParseReader,
log: &mut dyn FnMut(Message, Span),
) -> Option<Box<ParsedStatement>> {
// lambda ::= 'function' '(' [[type typemod] identifier {',' [type typemod] identifier}] ')' statblock;
if reader.peek().token_type != TokenType::FunctionKeyword {
return None;
}
unimplemented!();
}
fn parse_typemod(
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(
reader: &mut ParseReader,
_log: &mut dyn FnMut(Message, Span),
) -> Option<Box<ParsedStatement>> {
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<Box<ParsedStatement>> {
// 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<Box<ParsedStatement>> {
// 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<Box<ParsedStatement>> {
// 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);
arg_list.as_ref()?;
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<Box<ParsedStatement>> {
// 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(
reader: &mut ParseReader,
log: &mut dyn FnMut(Message, Span),
) -> Option<Box<ParsedStatement>> {
// arglist ::= '(' [identifier ':'] assign {',' [identifier ':'] assign} ')';
if reader.peek().token_type != TokenType::OpenBracket {
return None;
}
reader.next();
let mut args = Vec::new();
loop {
if reader.peek().token_type == TokenType::CloseBracket
|| reader.peek().token_type == TokenType::EndOfFile
{
break;
}
let mut inner_reader = reader.create_inner();
let identifier = parse_identifier(&mut inner_reader, log, true);
if inner_reader.peek().token_type == TokenType::Colon {
// identifier: ...
inner_reader.next();
reader.set_from_inner(&inner_reader);
}
let mut expression = parse_assign(reader, log);
if expression.is_none() {
// FIXME: logging
expression = Some(Box::new(ParsedStatement::Invalid {}));
}
args.push((identifier, expression.unwrap()));
}
reader.consume(TokenType::CloseBracket, log);
Some(Box::new(ParsedStatement::ArgList { args }))
}
fn parse_exprpreop(
reader: &mut ParseReader,
_log: &mut dyn FnMut(Message, Span),
) -> Option<PreOperator> {
// 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<Box<ParsedStatement>> {
// initlist ::= '{' [assign | initlist] {',' [assign | initlist]} '}';
unimplemented!();
}
fn parse_assign(
reader: &mut ParseReader,
log: &mut dyn FnMut(Message, Span),
) -> Option<Box<ParsedStatement>> {
// 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 {
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<ParsedTypeModifier> = 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<Box<ParsedStatement>> {
// 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<String> = 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<Box<ParsedStatement>> {
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<Box<ParsedStatement>> {
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::IntKeyword => 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::UintKeyword => 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<BinaryOperator> {
// 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<BinaryOperator> {
// 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<BinaryOperator> {
// 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<BinaryOperator> {
// 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<BinaryOperator> {
// 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
}