use anyhow::Result; use log::{debug, trace}; use std::{error::Error, fmt::Display, sync::Arc}; use crate::{Token, TokenPosition, TokenType}; pub type PResult = Result; #[derive(Debug, Clone)] pub struct ParserPosition { path: Arc, position: usize, token_positions: Vec, } impl ParserPosition { pub fn from_token(token: &Token) -> Self { Self { path: token.2.path.clone(), position: token.2.start, token_positions: vec![token.2.clone()], } } } pub trait Node { fn get_position(&self) -> ParserPosition; fn get_name(&self) -> String { String::from("") } } #[derive(Debug, Clone)] pub enum RootNode { Define(DefineStatement), Import(ImportStatement), Service(ServiceStatement), Type(TypeStatement), Enum(EnumStatement), } impl Node for RootNode { fn get_position(&self) -> ParserPosition { match self { RootNode::Define(stmt) => stmt.get_position(), RootNode::Import(stmt) => stmt.get_position(), RootNode::Service(stmt) => stmt.get_position(), RootNode::Type(stmt) => stmt.get_position(), RootNode::Enum(stmt) => stmt.get_position(), } } fn get_name(&self) -> String { match self { RootNode::Define(_) => String::from("define"), RootNode::Import(_) => String::from("import"), RootNode::Service(_) => String::from("service"), RootNode::Type(_) => String::from("type"), RootNode::Enum(_) => String::from("enum"), } } } #[derive(Debug, Clone)] pub struct DefineStatement { pub position: ParserPosition, pub key: String, pub value: String, } impl Node for DefineStatement { fn get_position(&self) -> ParserPosition { self.position.clone() } fn get_name(&self) -> String { format!("define {}", self.key) } } #[derive(Debug, Clone)] pub struct ImportStatement { pub position: ParserPosition, pub path: String, } impl Node for ImportStatement { fn get_position(&self) -> ParserPosition { self.position.clone() } fn get_name(&self) -> String { format!("import {}", self.path) } } #[derive(Debug, Clone)] pub struct TypeStatement { pub position: ParserPosition, pub name: String, pub fields: Vec, } impl Node for TypeStatement { fn get_position(&self) -> ParserPosition { self.position.clone() } fn get_name(&self) -> String { format!("type {}", self.name) } } #[derive(Debug, Clone)] pub struct TypeFieldNode { pub position: ParserPosition, pub name: String, pub optional: bool, pub fieldtype: String, pub array: bool, pub map: Option, } impl Node for TypeFieldNode { fn get_position(&self) -> ParserPosition { self.position.clone() } fn get_name(&self) -> String { format!("type_field {}", self.name) } } #[derive(Debug, Clone)] pub struct EnumStatement { pub position: ParserPosition, pub name: String, pub values: Vec, } impl Node for EnumStatement { fn get_position(&self) -> ParserPosition { self.position.clone() } fn get_name(&self) -> String { format!("enum {}", self.name) } } #[derive(Debug, Clone)] pub struct EnumValueNode { pub position: ParserPosition, pub name: String, pub value: Option, } impl Node for EnumValueNode { fn get_position(&self) -> ParserPosition { self.position.clone() } fn get_name(&self) -> String { format!("enum_field {}", self.name) } } #[derive(Debug, Clone)] pub struct ServiceStatement { pub position: ParserPosition, pub name: String, pub methods: Vec, } impl Node for ServiceStatement { fn get_position(&self) -> ParserPosition { self.position.clone() } fn get_name(&self) -> String { format!("service {}", self.name) } } #[derive(Debug, Clone)] pub struct ServiceMethodNode { pub position: ParserPosition, pub name: String, pub inputs: Vec, pub return_type: Option, pub decorators: Vec, } impl Node for ServiceMethodNode { fn get_position(&self) -> ParserPosition { self.position.clone() } fn get_name(&self) -> String { format!("method {}", self.name) } } #[derive(Debug, Clone)] pub struct Decorator { pub position: ParserPosition, pub name: String, pub args: Vec, } impl Node for Decorator { fn get_position(&self) -> ParserPosition { self.position.clone() } fn get_name(&self) -> String { format!("decorator {}", self.name) } } #[derive(Debug, Clone)] pub struct ServiceMethodInputNode { pub position: ParserPosition, pub name: String, pub fieldtype: String, pub optional: bool, pub array: bool, } impl Node for ServiceMethodInputNode { fn get_position(&self) -> ParserPosition { self.position.clone() } fn get_name(&self) -> String { format!("method_arg {}", self.name) } } #[derive(Debug, Clone)] pub struct ServiceMethodReturnNode { pub position: ParserPosition, pub fieldtype: String, pub array: bool, } impl Node for ServiceMethodReturnNode { fn get_position(&self) -> ParserPosition { self.position.clone() } } #[derive(Debug, Clone)] pub struct Parser { tokens: Vec, position: usize, } impl Parser { pub fn new(tokens: Vec) -> Parser { // Remove all comments and spaces at this stage let tokens = tokens .into_iter() .filter(|e| e.0 != TokenType::Comment && e.0 != TokenType::Space) .collect(); Parser { tokens, position: 0, } } fn has_current_token(&self) -> bool { self.position < self.tokens.len() } fn current_token(&mut self) -> &Token { &self.tokens[self.position] } fn assert_types(&mut self, token_types: &[TokenType]) -> PResult<()> { if token_types.iter().any(|t| *t == self.current_token().0) { Ok(()) } else { Err(ParserError::new( &format!("Unexpected token. Expected on of {:?}", token_types), self.current_token(), )) } } fn eat_token(&mut self) -> PResult<(String, ParserPosition)> { debug!("Parser::eat_token()"); let pos = ParserPosition::from_token(self.current_token()); let value = self.current_token().1.clone(); self.position += 1; Ok((value, pos)) } fn eat_token_value(&mut self, value: &str) -> PResult<(String, ParserPosition)> { debug!("Parser::eat_token_value({})", value); let (val, pos) = self.eat_token()?; if val != value { return Err(ParserError::new( &format!("Expected token of value {}", value), self.current_token(), )); } Ok((val, pos)) } fn eat_token_type(&mut self, token_type: TokenType) -> PResult<(String, ParserPosition)> { debug!("Parser::eat_token_type({:?})", token_type); if self.current_token().0 != token_type { return Err(ParserError::new( &format!("Expected token of type {:?}", token_type), self.current_token(), )); } self.eat_token() } fn eat_text(&mut self) -> PResult<(String, ParserPosition)> { debug!("Parser::eat_text()"); self.eat_token_type(TokenType::Text) } fn eat_text_with_keywords(&mut self) -> PResult<(String, ParserPosition)> { debug!("Parser::eat_text_with_keywords()"); self.assert_types(&[TokenType::Text, TokenType::Keyword])?; self.eat_token() } fn eat_string_or_text_as_raw(&mut self) -> PResult { debug!("Parser::eat_string_or_text_as_raw()"); self.assert_types(&[TokenType::String, TokenType::Text])?; let token = self.current_token(); if token.0 == TokenType::String { let (value, _) = self.eat_token()?; let count = value.chars().count(); Ok(value.chars().skip(1).take(count - 2).collect()) } else { let (value, _) = self.eat_token()?; Ok(value) } } fn eat_number(&mut self) -> PResult { debug!("Parser::eat_number()"); self.assert_types(&[TokenType::Number])?; let (value, _) = self.eat_token()?; value .parse() .map_err(|_| ParserError::new("Invalid number", self.current_token())) } fn parse_define(&mut self) -> PResult { debug!("Parser::parse_define()"); let (_, position) = self.eat_token_value("define")?; let (key, _) = self.eat_token()?; trace!("Parser::parse_define()::key = {}", key); let value = self.eat_string_or_text_as_raw()?; self.eat_token_type(TokenType::Semicolon)?; Ok(DefineStatement { position, key, value, }) } fn parse_import(&mut self) -> PResult { debug!("Parser::parse_import()"); let (_, pos) = self.eat_token_value("import")?; let path = self.eat_string_or_text_as_raw()?; self.eat_token_type(TokenType::Semicolon)?; Ok(ImportStatement { position: pos, path, }) } fn parse_enum_value(&mut self) -> PResult { debug!("Parser::parse_enum_value()"); let (name, pos) = self.eat_token()?; let value = if self.current_token().0 == TokenType::Equals { self.eat_token()?; Some(self.eat_number()?) } else { None }; Ok(EnumValueNode { position: pos, name, value, }) } fn parse_enum(&mut self) -> PResult { debug!("Parser::parse_enum()"); let (_, pos) = self.eat_token_value("enum")?; let (name, _) = self.eat_token()?; trace!("Parser::parse_enum()::name = {}", name); self.eat_token_type(TokenType::CurlyOpen)?; let mut values: Vec = Vec::new(); while self.current_token().0 == TokenType::Text { values.push(self.parse_enum_value()?); if self.current_token().0 == TokenType::Comma { //TODO: Maybe use a next flag or break or something with the commas self.eat_token()?; } } self.eat_token_type(TokenType::CurlyClose)?; Ok(EnumStatement { position: pos, name, values, }) } fn parse_type_field(&mut self) -> PResult { debug!("Parser::parse_type_field()"); let (name, pos) = self.eat_text_with_keywords()?; trace!("Parser::parse_type_field()::name = {}", name); let mut optional = false; let mut array = false; let mut map = None; if self.current_token().0 == TokenType::Questionmark { optional = true; self.eat_token()?; } _ = self.eat_token_type(TokenType::Colon); let fieldtype = if self.current_token().0 == TokenType::CurlyOpen { self.eat_token()?; let (key_type, _) = self.eat_text()?; self.eat_token_type(TokenType::Comma)?; let (value_type, _) = self.eat_text()?; self.eat_token_type(TokenType::CurlyClose)?; map = Some(key_type); value_type } else { let (type_name, _) = self.eat_text()?; if self.current_token().0 == TokenType::Array { array = true; self.eat_token()?; } type_name }; self.eat_token_type(TokenType::Semicolon)?; Ok(TypeFieldNode { position: pos, name, optional, fieldtype, map, array, }) } fn parse_type(&mut self) -> PResult { debug!("Parser::parse_type()"); let (_, pos) = self.eat_token_value("type")?; let (name, _) = self.eat_text()?; trace!("Parser::prase_type()::name = {}", name); self.eat_token_type(TokenType::CurlyOpen)?; let mut fields = Vec::new(); while self.current_token().0 == TokenType::Text || self.current_token().0 == TokenType::Keyword { fields.push(self.parse_type_field()?); } self.eat_token_type(TokenType::CurlyClose)?; Ok(TypeStatement { position: pos, name, fields, }) } fn parse_decorator(&mut self) -> PResult { debug!("Parser::parse_decorator()"); let (_, position) = self.eat_token_type(TokenType::At)?; let (decorator, _) = self.eat_text()?; trace!("Parser::parse_decorator()::name = {}", decorator); self.eat_token_type(TokenType::BracketOpen)?; let mut args = Vec::new(); let mut first = true; while self.current_token().0 != TokenType::BracketClose { if first { first = false } else { self.eat_token_type(TokenType::Comma)?; } args.push(self.eat_string_or_text_as_raw()?); } self.eat_token_type(TokenType::BracketClose)?; Ok(Decorator { name: decorator, args, position, }) } fn parse_method( &mut self, decorators: Vec, notification: bool, ) -> PResult { debug!( "Parser::parse_method({}, {})", decorators.len(), notification ); let (name, pos) = self.eat_text()?; trace!("Parser::parse_method()::name = {}", name); self.eat_token_type(TokenType::BracketOpen)?; let mut inputs = Vec::new(); while self.current_token().0 != TokenType::BracketClose { let (name, position) = self.eat_text_with_keywords()?; let mut optional = false; if self.current_token().0 == TokenType::Questionmark { optional = true; self.eat_token()?; } self.eat_token_type(TokenType::Colon)?; let (fieldtype, _) = self.eat_text()?; let mut array = false; if self.current_token().0 == TokenType::Array { array = true; self.eat_token()?; } inputs.push(ServiceMethodInputNode { name, fieldtype, array, optional, position, }); if self.current_token().0 == TokenType::Comma { self.eat_token()?; } trace!( "Parser::parse_method()::params_next_token: {}", self.current_token().1 ); } self.eat_token_type(TokenType::BracketClose)?; let mut return_type = None; if !notification { self.eat_token_type(TokenType::Colon)?; let (fieldtype, position) = self.eat_text()?; let mut array = false; if self.current_token().0 == TokenType::Array { array = true; self.eat_token()?; } return_type = Some(ServiceMethodReturnNode { position, fieldtype, array, }); } self.eat_token_type(TokenType::Semicolon)?; Ok(ServiceMethodNode { position: pos, name, inputs, return_type, decorators, }) } fn parse_service(&mut self) -> PResult { debug!("Parser::parse_service()"); let (_, pos) = self.eat_token_value("service")?; let (name, _) = self.eat_text()?; trace!("Parser::parse_service()::name = {}", name); self.eat_token_type(TokenType::CurlyOpen)?; let mut methods = Vec::new(); while self.current_token().0 != TokenType::CurlyClose { let mut decorators = Vec::new(); while self.current_token().0 == TokenType::At { decorators.push(self.parse_decorator()?); } let mut notification = false; if self.current_token().1 == "notification" { self.eat_token()?; notification = true; } methods.push(self.parse_method(decorators, notification)?); } self.eat_token_type(TokenType::CurlyClose)?; Ok(ServiceStatement { position: pos, name, methods, }) } fn parse_statement(&mut self) -> PResult { debug!("Parser::parse_statement()"); let token = self.current_token(); if let TokenType::Keyword = token.0 { trace!("Parser::parse_statement()::type = {}", token.1); return match token.1.as_str() { "define" => Ok(RootNode::Define(self.parse_define()?)), "import" => Ok(RootNode::Import(self.parse_import()?)), "type" => Ok(RootNode::Type(self.parse_type()?)), "service" => Ok(RootNode::Service(self.parse_service()?)), "enum" => Ok(RootNode::Enum(self.parse_enum()?)), _ => Err(ParserError::new("Unknown keyword", token)), }; } else { Err(ParserError::new("Expected keyword", token)) } } pub fn parse(&mut self) -> PResult> { debug!("Parser::parse()"); let mut nodes = Vec::new(); while self.has_current_token() { nodes.push(self.parse_statement()?); } Ok(nodes) } } #[derive(Debug, Clone)] pub struct ParserError { pub message: String, pub token: Token, } impl ParserError { fn new(msg: &str, token: &Token) -> ParserError { ParserError { message: format!("{}: {}", msg, token.1), token: token.clone(), } } } impl Error for ParserError {} impl Display for ParserError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "ParserError: {} at {:?}", self.message, self.token) } }