Files
JsonRPC-Rust/libjrpc/src/parser.rs

684 lines
18 KiB
Rust

use anyhow::Result;
use log::{debug, trace};
use std::{error::Error, fmt::Display, sync::Arc};
use crate::{Token, TokenPosition, TokenType};
pub type PResult<T> = Result<T, ParserError>;
#[derive(Debug, Clone)]
pub struct ParserPosition {
path: Arc<String>,
position: usize,
token_positions: Vec<TokenPosition>,
}
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<TypeFieldNode>,
}
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<String>,
}
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<EnumValueNode>,
}
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<i64>,
}
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<ServiceMethodNode>,
}
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<ServiceMethodInputNode>,
pub return_type: Option<ServiceMethodReturnNode>,
pub decorators: Vec<Decorator>,
}
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<String>,
}
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<Token>,
position: usize,
}
impl Parser {
pub fn new(tokens: Vec<Token>) -> 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<String> {
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<i64> {
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<DefineStatement> {
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<ImportStatement> {
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<EnumValueNode> {
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<EnumStatement> {
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<EnumValueNode> = 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<TypeFieldNode> {
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<TypeStatement> {
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<Decorator> {
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<Decorator>,
notification: bool,
) -> PResult<ServiceMethodNode> {
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<ServiceStatement> {
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<RootNode> {
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<Vec<RootNode>> {
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)
}
}