SeraphScript/src/parsing/parser/mod.rs

503 lines
14 KiB
Rust

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<LexToken>,
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<LexToken>, log: &mut dyn FnMut(Message, Span)) -> Box<ParsedStatement> {
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<ParsedStatement> {
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::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<String> {
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<ParsedStatement> {
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<Box<ParsedStatement>> {
let mut type_mod: BitFlags<TypeModifier> = BitFlags::empty();
let identifier: Option<String>;
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<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,
);
}
}
}
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<Box<ParsedStatement>> {
unimplemented!();
}
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: 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;
}
}
}
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<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_type(
reader: &mut ParseReader,
log: &mut dyn FnMut(Message, Span),
) -> Option<Box<ParsedStatement>> {
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<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::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<Box<ParsedStatement>> {
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,
}))
}
}