From f004c191332071cc532fc7513af50dfcd1bf85c0 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 3 Apr 2022 19:13:36 +0200 Subject: [PATCH] More parsing work --- grammar.ebnf | 5 +- src/parsing/parser/mod.rs | 166 ++++++++++++++++++--- src/parsing/parser/parsed_funcattr.rs | 11 ++ src/parsing/parser/parsed_statement.rs | 20 +++ src/parsing/parser/parsed_type_modifier.rs | 2 +- 5 files changed, 177 insertions(+), 27 deletions(-) create mode 100644 src/parsing/parser/parsed_funcattr.rs diff --git a/grammar.ebnf b/grammar.ebnf index 799c3c5..d177f05 100644 --- a/grammar.ebnf +++ b/grammar.ebnf @@ -85,9 +85,8 @@ paramlist ::= '(' ['void' | (type typemod [identifier] ['=' expr] {',' virtprop ::= ['private' | 'protected'] type ['&'] identifier '{' {('get' | 'set') ['const'] funcattr (statblock | ';')} '}'; func ::= {'shared' | 'external'} ['private' | 'protected'] [((type ['&']) | '~')] identifier paramlist ['const'] funcattr (';' | statblock); funcdef ::= {'external' | 'shared'} 'funcdef' type ['&'] identifier paramlist ';' -class ::= {'shared' | 'abstract' | 'final' | 'external'} 'class' identifier +class ::= {'shared' | 'abstract' | 'final' | 'external' | 'mixin'} 'class' identifier (';' | ([':' identifier {',' identifier}] '{' {virtprop | func | var | funcdef | class} '}')); -mixin ::= 'mixin' class; enum ::= {'shared' | 'external'} 'enum' identifier [ ':' primtype ] (';' | ('{' identifier ['=' expr] {',' identifier ['=' expr]} '}')); import ::= 'import' type ['&'] identifier paramlist funcattr 'from' string ';'; typedef ::= 'typedef' (primtype | identifier) identifier ';'; @@ -96,4 +95,4 @@ interfacemethod ::= type ['&'] identifier paramlist ['const'] ';'; interface ::= {'external' | 'shared'} 'interface' identifier (';' | ([':' identifier {',' identifier}] '{' {virtprop | interfacemethod} '}')); namespace ::= 'namespace' identifier '{' script '}'; -script ::= {import | enum | typedef | class | mixin | interface | funcdef | virtprop | var | func | namespace | ';'}; +script ::= {import | enum | typedef | class | interface | funcdef | virtprop | var | func | namespace | ';'}; diff --git a/src/parsing/parser/mod.rs b/src/parsing/parser/mod.rs index c27ab33..20e35e1 100644 --- a/src/parsing/parser/mod.rs +++ b/src/parsing/parser/mod.rs @@ -1,3 +1,4 @@ +mod parsed_funcattr; pub mod parsed_statement; pub mod parsed_type_modifier; mod parser_operators; @@ -9,6 +10,7 @@ use crate::logger::messages::Message; use crate::logger::messages::Message::UnexpectedToken; use crate::modifiers::{FieldModifier, TypeModifier}; use crate::parsing::lexer::lex_tokens::TokenType::CloseBracket; +use crate::parsing::parser::parsed_funcattr::FuncAttr; use crate::parsing::parser::parsed_statement::ParsedStatement::{ AnonymousCall, ExprPostOp, IndexingOperator, }; @@ -311,37 +313,126 @@ fn parse_interface( } fn parse_interface_method( - _reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + outer_reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // interfacemethod ::= type ['&'] identifier paramlist ['const'] ';'; + let mut reader = outer_reader.create_inner(); + let return_type = parse_type(&mut reader, log); + if return_type.is_none() { + return None; + } + let returns_reference = reader.peek().token_type == TokenType::Ampersand; + if returns_reference { + reader.next(); + } + let identifier = parse_identifier(&mut reader, log, true); + if identifier.is_none() { + return None; + } + let param_list = parse_paramlist(&mut reader, log); + if param_list.is_none() { + return None; + } + let is_const = reader.peek().token_type == TokenType::ConstKeyword; + if is_const { + reader.next(); + } + reader.consume(TokenType::Semicolon, log); + + Some(Box::new(ParsedStatement::InterfaceMethod { + return_type: return_type.unwrap(), + returns_reference, + identifier: identifier.unwrap(), + param_list: param_list.unwrap(), + is_const, + })) } fn parse_typedef( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // typedef ::= 'typedef' (primtype | identifier) identifier ';'; + if reader.peek().token_type != TokenType::TypeDefKeyword { + return None; + } + reader.next(); + let mut left_type = parse_primtype(reader, log); + if left_type.is_none() { + let left_type_identifier = parse_identifier(reader, log, false); + if left_type_identifier.is_some() { + left_type = Some(Box::new(ParsedStatement::DataTypeIdentifier { + identifier: left_type_identifier.unwrap(), + })); + } + } + let right_type_identifier = parse_identifier(reader, log, false); + if right_type_identifier.is_none() { + return None; + } + let right_type = Box::new(ParsedStatement::DataTypeIdentifier { + identifier: right_type_identifier.unwrap(), + }); + + reader.consume(TokenType::Semicolon, log); + Some(Box::new(ParsedStatement::TypeDefStatement { + from: left_type.unwrap(), + to: right_type, + })) } fn parse_import( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); + // import ::= 'import' type ['&'] identifier paramlist funcattr 'from' string ';'; + if reader.peek().token_type != TokenType::ImportKeyword { + return None; + } + reader.next(); + let import_type = parse_type(reader, log); + let is_reference_type = reader.peek().token_type == TokenType::Ampersand; + if is_reference_type { + reader.next(); + } + let identifier = parse_identifier(reader, log, false); + identifier.as_ref()?; + let param_list = parse_paramlist(reader, log); + let func_attr = parse_funcattr(reader, log); + reader.consume(TokenType::FromKeyword, log); + let mut source = None; + let source_token = reader.next(); + if let TokenType::StringLiteral(s) = &source_token.token_type { + source = Some(s.to_string()); + } + if source.is_none() { + log( + Message::UnexpectedToken { + found: source_token.token_type.clone(), + expected: vec![TokenType::StringLiteral("".to_string())], + }, + source_token.span, + ); + return None; + } + reader.consume(TokenType::Semicolon, log); + + Some(Box::new(ParsedStatement::ImportStatement { + import_type: import_type.unwrap(), + is_reference: is_reference_type, + identifier: identifier.unwrap(), + param_list: param_list.unwrap(), + func_attr, + source: source.unwrap(), + })) } fn parse_enum( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { - unimplemented!(); -} - -fn parse_mixin( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), -) -> Option> { + // enum ::= {'shared' | 'external'} 'enum' identifier [ ':' primtype ] (';' | ('{' identifier ['=' expr] {',' identifier ['=' expr]} '}')); unimplemented!(); } @@ -349,6 +440,8 @@ fn parse_class( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { + // class ::= {'shared' | 'abstract' | 'final' | 'external' | 'mixin'} 'class' identifier + // (';' | ([':' identifier {',' identifier}] '{' {virtprop | func | var | funcdef | class} '}')); unimplemented!(); } @@ -356,6 +449,7 @@ fn parse_funcdef( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { + // funcdef ::= {'external' | 'shared'} 'funcdef' type ['&'] identifier paramlist ';' unimplemented!(); } @@ -363,6 +457,7 @@ fn parse_func( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { + // func ::= {'shared' | 'external'} ['private' | 'protected'] [((type ['&']) | '~')] identifier paramlist ['const'] funcattr (';' | statblock); unimplemented!(); } @@ -511,17 +606,29 @@ fn parse_paramlist( default = parse_expr(reader, log); // FIXME: log if default is emtpy } - params.push((param_type, type_mod, identifier, default)); + params.push((param_type.unwrap(), type_mod, identifier, default)); } - return Some(Box::new(ParsedStatement::ParamList { parameters: params })); + Some(Box::new(ParsedStatement::ParamList { parameters: params })) } fn parse_funcattr( - _outer_reader: &mut ParseReader, - _log: &mut dyn FnMut(Message, Span), -) -> Option> { - unimplemented!(); + reader: &mut ParseReader, + log: &mut dyn FnMut(Message, Span), +) -> BitFlags { + // funcattr ::= {'override' | 'final' | 'explicit' | 'property'}; + let mut func_attr: BitFlags = BitFlags::empty(); + loop { + match reader.peek().token_type { + TokenType::OverrideKeyword => func_attr |= FuncAttr::Override, + TokenType::FinalKeyword => func_attr |= FuncAttr::Final, + TokenType::ExplicitKeyword => func_attr |= FuncAttr::Explicit, + TokenType::PropertyKeyword => func_attr |= FuncAttr::Property, + _ => break, + } + reader.next(); + } + func_attr } fn parse_statblock( @@ -1123,6 +1230,7 @@ fn parse_lambda( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { + // lambda ::= 'function' '(' [[type typemod] identifier {',' [type typemod] identifier}] ')' statblock; unimplemented!(); } @@ -1262,6 +1370,7 @@ fn parse_arglist( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { + // arglist ::= '(' [identifier ':'] assign {',' [identifier ':'] assign} ')'; unimplemented!(); } @@ -1292,6 +1401,7 @@ fn parse_initlist( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { + // initlist ::= '{' [assign | initlist] {',' [assign | initlist]} '}'; unimplemented!(); } @@ -1408,9 +1518,19 @@ fn parse_datatype( if let Some(identifier) = parse_identifier(reader, log, true) { return Some(Box::new(ParsedStatement::DataTypeIdentifier { identifier })); } + if reader.peek().token_type == TokenType::AutoKeyword { + reader.next(); + return Some(Box::new(ParsedStatement::DataTypeAuto {})); + } + parse_primtype(reader, log) +} + +fn parse_primtype( + reader: &mut ParseReader, + _log: &mut dyn FnMut(Message, Span), +) -> Option> { let key = reader.peek(); let res = match &key.token_type { - TokenType::AutoKeyword => Some(Box::new(ParsedStatement::DataTypeAuto {})), TokenType::VoidKeyword => Some(Box::new(ParsedStatement::DataTypePrimType { prim_type: PrimitiveType::Void, })), diff --git a/src/parsing/parser/parsed_funcattr.rs b/src/parsing/parser/parsed_funcattr.rs new file mode 100644 index 0000000..70ca619 --- /dev/null +++ b/src/parsing/parser/parsed_funcattr.rs @@ -0,0 +1,11 @@ +use enumflags2::bitflags; + +#[bitflags] +#[repr(u8)] +#[derive(Eq, PartialEq, Debug, Copy, Clone)] +pub enum FuncAttr { + Override, + Final, + Explicit, + Property, +} diff --git a/src/parsing/parser/parsed_statement.rs b/src/parsing/parser/parsed_statement.rs index e0ddb63..ed76ae8 100644 --- a/src/parsing/parser/parsed_statement.rs +++ b/src/parsing/parser/parsed_statement.rs @@ -1,6 +1,7 @@ use super::parsed_type_modifier::ParsedTypeModifier; use crate::defines::{LiteralFloat, LiteralInt}; use crate::modifiers::{FieldModifier, TypeModifier}; +use crate::parsing::parser::parsed_funcattr::FuncAttr; use crate::parsing::parser::parsed_type_modifier::ReferenceModifier; use crate::parsing::parser::parser_operators::{ BinaryOperator, PostOperator, PreOperator, TernaryOperator, @@ -175,4 +176,23 @@ pub enum ParsedStatement { Option>, // default expression )>, }, + InterfaceMethod { + return_type: Box, + returns_reference: bool, + identifier: String, + param_list: Box, + is_const: bool, + }, + TypeDefStatement { + from: Box, + to: Box, + }, + ImportStatement { + import_type: Box, + is_reference: bool, + identifier: String, + param_list: Box, + func_attr: BitFlags, + source: String, + }, } diff --git a/src/parsing/parser/parsed_type_modifier.rs b/src/parsing/parser/parsed_type_modifier.rs index 08dc634..a210003 100644 --- a/src/parsing/parser/parsed_type_modifier.rs +++ b/src/parsing/parser/parsed_type_modifier.rs @@ -9,7 +9,7 @@ pub enum ParsedTypeModifier { #[bitflags] #[repr(u8)] -#[derive(Eq, PartialEq, Debug)] +#[derive(Eq, PartialEq, Debug, Copy, Clone)] pub enum ReferenceModifier { In, Out,