pub mod parsed_statement; pub mod parsed_type_modifier; #[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_type_modifier::ParsedTypeModifier; use crate::span::Span; use enumflags2::BitFlags; use parsed_statement::ParsedStatement; struct ParseReader<'a> { tokens: &'a Vec, position: usize, peek_distance: usize, } impl<'a> ParseReader<'a> { pub fn peek(&mut self) -> &LexToken { let t = self.tokens.get(self.position + self.peek_distance); self.peek_distance += 1; match t { None => self.tokens.last().unwrap(), Some(v) => { if v.token_type == TokenType::WhiteSpace { self.peek() } else { v } } } } pub fn next(&mut self) -> &LexToken { let t = self.tokens.get(self.position); self.position += 1; self.peek_distance = 0; match t { None => self.tokens.last().unwrap(), Some(v) => { if v.token_type == TokenType::WhiteSpace { self.next() } else { v } } } } pub fn move_to_peek(&mut self) { self.position += self.peek_distance; self.peek_distance = 0; } 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 } #[inline(always)] pub fn reset_peek(&mut self) { self.peek_distance = 0; } pub fn create_inner(&self) -> ParseReader<'a> { ParseReader { tokens: self.tokens, position: self.position, peek_distance: self.peek_distance, } } pub fn set_from_inner(&mut self, inner: &ParseReader) { self.position = inner.position; self.peek_distance = inner.peek_distance; } } pub fn parse(tokens: Vec, log: &mut dyn FnMut(Message, Span)) -> Box { assert_ne!(tokens.len(), 0); let mut reader = ParseReader { tokens: &tokens, position: 0, peek_distance: 0, }; parse_script(&mut reader, log) } fn parse_script( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Box { let mut vec: Vec = Vec::new(); loop { let n = reader.peek(); let token_type = n.token_type.clone(); let span = n.span; match token_type { TokenType::NamespaceKeyword => { vec.push(*parse_namespace(reader, log)); } TokenType::InterfaceKeyword => vec.push(*parse_interface(reader, log).unwrap()), TokenType::EndOfFile => break, TokenType::CloseCurlyBracket => break, _ => { if let Some(s) = parse_interface(reader, log) { vec.push(*s); } else { log( UnexpectedToken { expected: vec![TokenType::NamespaceKeyword], found: token_type, }, span, ); reader.next(); } } } } Box::new(ParsedStatement::Script { statements: vec }) } fn parse_identifier( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option { let identifier_token = reader.next(); let s: String; match &identifier_token.token_type { TokenType::Identifier(i) => { s = i.to_string(); } _ => { log( Message::UnexpectedToken { found: identifier_token.token_type.clone(), expected: vec![TokenType::Identifier(String::new())], }, identifier_token.span, ); return None; } } Some(s) } fn parse_namespace( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Box { reader.next(); // Consume namespace let identifier = parse_identifier(reader, log); 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( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { let mut type_mod: BitFlags = BitFlags::empty(); let identifier: Option; let mut has_interface_keyword = false; reader.reset_peek(); loop { match &reader.peek().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; } reader.move_to_peek(); let mut statements: Vec = Vec::new(); let mut inherits: Vec = Vec::new(); loop { let t = reader.peek(); match t.token_type { TokenType::Semicolon => { reader.next(); if identifier.is_none() { return Some(Box::new(ParsedStatement::Invalid)); } return Some(Box::new(ParsedStatement::Interface { type_mod, identifier: identifier.unwrap(), inherits, statements, })); } TokenType::Colon | TokenType::OpenCurlyBracket => break, TokenType::EndOfFile => { log( Message::UnexpectedToken { found: t.token_type.clone(), expected: vec![ TokenType::Semicolon, TokenType::Colon, TokenType::OpenCurlyBracket, ], }, t.span, ); return Some(Box::new(ParsedStatement::Invalid)); } _ => { log( Message::UnexpectedToken { found: t.token_type.clone(), expected: vec![ TokenType::Semicolon, TokenType::Colon, TokenType::OpenCurlyBracket, ], }, t.span, ); } } } reader.reset_peek(); if reader.peek().token_type == TokenType::Colon { reader.next(); loop { let inherit_identifier = parse_identifier(reader, log); if inherit_identifier.is_none() { continue; } inherits.push(inherit_identifier.unwrap()); if reader.peek().token_type != TokenType::Comma { break; } reader.next(); } } reader.consume(TokenType::OpenCurlyBracket, log); // TODO: parse interfacemethod loop { if reader.peek().token_type == TokenType::CloseCurlyBracket { break; } let prop = parse_virtprop(reader, log); if prop.is_none() { break; } statements.push(*prop.unwrap()); } reader.consume(TokenType::CloseCurlyBracket, log); reader.move_to_peek(); if identifier.is_none() { return Some(Box::new(ParsedStatement::Invalid)); } Some(Box::new(ParsedStatement::Interface { type_mod, identifier: identifier.unwrap(), inherits, statements, })) } fn parse_statblock( _outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { unimplemented!(); } fn parse_virtprop( outer_reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { let mut reader = outer_reader.create_inner(); let mut field_mod: BitFlags = BitFlags::empty(); let property_type: Option>; loop { let t = reader.peek(); match t.token_type { TokenType::PrivateKeyword => { field_mod |= FieldModifier::Private; reader.next(); } TokenType::ProtectedKeyword => { field_mod |= FieldModifier::Protected; reader.next(); } _ => { property_type = parse_type(&mut reader, log); property_type.as_ref()?; break; } } } let mut is_handle = false; if reader.peek().token_type == TokenType::Ampersand { reader.next(); is_handle = true; } let identifier = parse_identifier(&mut reader, log); identifier.as_ref()?; let next = reader.next(); if next.token_type != TokenType::OpenCurlyBracket { return None; } let mut has_get = false; let mut is_get_const = false; let mut get_statement: Option> = None; let mut has_set = false; let mut is_set_const = false; let mut set_statement: Option> = None; let start_span = next.span; loop { let next = reader.peek(); match next.token_type { TokenType::GetKeyword => { reader.next(); has_get = true; let mut peek = reader.peek(); if peek.token_type == TokenType::ConstKeyword { reader.next(); is_get_const = true; peek = reader.peek(); } if peek.token_type != TokenType::Semicolon { get_statement = parse_statblock(&mut reader, log); } else { reader.next(); } } TokenType::SetKeyword => { reader.next(); has_set = true; let mut peek = reader.peek(); if peek.token_type == TokenType::ConstKeyword { reader.next(); is_set_const = true; peek = reader.peek(); } if peek.token_type != TokenType::Semicolon { set_statement = parse_statblock(&mut reader, log); } else { reader.next(); } } _ => break, } } let next = reader.next(); if next.token_type != TokenType::CloseCurlyBracket { return None; } if !has_get && !has_set { log( Message::EmptyProperty, Span { start: start_span.start, end: next.span.end, }, ) } outer_reader.set_from_inner(&reader); Some(Box::new(ParsedStatement::VirtProp { field_mod, property_type: property_type.unwrap(), identifier: identifier.unwrap(), is_handle, has_get, is_get_const, get_statement, has_set, is_set_const, set_statement, })) } fn parse_type( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { 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 identifier = parse_identifier(reader, log); // if none, we already logged an error. Return None. identifier.as_ref()?; // TODO: Generics let mut modifiers: Vec = Vec::new(); loop { let n = reader.peek(); match n.token_type { TokenType::OpenBlockBracket => { reader.next(); reader.consume(TokenType::CloseBlockBracket, log); modifiers.push(ParsedTypeModifier::Array); } TokenType::Ampersand => { 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, identifier: identifier.unwrap(), modifiers, })) } fn parse_scope( outer_reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { let mut reader = outer_reader.create_inner(); let is_global = reader.peek().token_type == TokenType::ColonColon; if is_global { reader.next(); } let mut scope: Vec = Vec::new(); loop { let n = reader.peek(); if let TokenType::Identifier(s) = &n.token_type { let identifier = s.to_string(); if reader.peek().token_type == TokenType::ColonColon { reader.next(); reader.next(); scope.push(identifier); } else { break; } } else { break; } } // TODO: generics if !is_global && scope.is_empty() { None } else { outer_reader.set_from_inner(&reader); Some(Box::new(ParsedStatement::Scope { is_global, scope, generic_types: None, })) } }