mirror of
https://github.com/gorules/zen.git
synced 2026-10-05 00:02:26 +00:00
feat: crates restructure (#22)
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(crate) enum Associativity {
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(crate) enum Arity {
|
||||
Single,
|
||||
Closure,
|
||||
Dual,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(crate) struct Operator {
|
||||
pub precedence: u8,
|
||||
pub associativity: Associativity,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(crate) struct BuiltIn {
|
||||
pub arity: Arity,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! hashmap {
|
||||
(@single $($x:tt)*) => (());
|
||||
(@count $($rest:expr),*) => (<[()]>::len(&[$(hashmap!(@single $rest)),*]));
|
||||
|
||||
($($key:expr => $value:expr,)+) => { hashmap!($($key => $value),+) };
|
||||
($($key:expr => $value:expr),*) => {
|
||||
{
|
||||
let _cap = hashmap!(@count $($key),*);
|
||||
let mut _map = ::std::collections::HashMap::default();
|
||||
_map.reserve(_cap);
|
||||
$(
|
||||
let _ = _map.insert($key, $value);
|
||||
)*
|
||||
_map
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Error)]
|
||||
pub enum ParserError {
|
||||
#[error("Token out of bounds")]
|
||||
TokenOutOfBounds,
|
||||
|
||||
#[error("Memory failure")]
|
||||
MemoryFailure,
|
||||
|
||||
#[error("Unexpected token: received {received} instead of {expected}")]
|
||||
UnexpectedToken { expected: String, received: String },
|
||||
|
||||
#[error("Failed to parse: {message}")]
|
||||
FailedToParse { message: String },
|
||||
|
||||
#[error("Unknown built in: {token}")]
|
||||
UnknownBuiltIn { token: String },
|
||||
|
||||
#[error("Unsupported built in: {token}")]
|
||||
UnsupportedBuiltIn { token: String },
|
||||
}
|
||||
|
||||
pub type ParserResult<T> = Result<T, ParserError>;
|
||||
@@ -0,0 +1,164 @@
|
||||
use std::cell::Cell;
|
||||
use std::fmt::Debug;
|
||||
|
||||
use bumpalo::Bump;
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
use crate::ast::Node;
|
||||
use crate::lexer::token::{Token, TokenKind};
|
||||
use crate::parser::error::{ParserError, ParserResult};
|
||||
|
||||
type TokenValues<'a> = Option<&'a [&'a str]>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ParserIterator<'a, 'b> {
|
||||
tokens: &'a Vec<Token<'a>>,
|
||||
current: Cell<&'a Token<'a>>,
|
||||
position: Cell<usize>,
|
||||
bump: &'b Bump,
|
||||
is_done: Cell<bool>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> ParserIterator<'a, 'b> {
|
||||
pub fn try_new(tokens: &'a Vec<Token<'a>>, bump: &'b Bump) -> Result<Self, ParserError> {
|
||||
let current = tokens.get(0).ok_or(ParserError::TokenOutOfBounds)?;
|
||||
|
||||
Ok(Self {
|
||||
tokens,
|
||||
bump,
|
||||
current: Cell::new(current),
|
||||
position: Cell::new(0),
|
||||
is_done: Cell::new(false),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn current(&self) -> &'a Token<'a> {
|
||||
self.current.get()
|
||||
}
|
||||
|
||||
pub fn is_done(&self) -> bool {
|
||||
self.is_done.get()
|
||||
}
|
||||
|
||||
pub fn next(&self) -> ParserResult<()> {
|
||||
self.position.set(self.position.get() + 1);
|
||||
|
||||
if let Some(token) = self.tokens.get(self.position.get()) {
|
||||
self.current.set(token);
|
||||
Ok(())
|
||||
} else {
|
||||
if self.is_done.get() {
|
||||
return Err(ParserError::TokenOutOfBounds);
|
||||
}
|
||||
|
||||
self.is_done.set(true);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn str_value(&self, str: &str) -> &'b str {
|
||||
self.bump.alloc_str(str)
|
||||
}
|
||||
|
||||
pub fn expect(&self, kind: TokenKind, values: TokenValues<'a>) -> Result<(), ParserError> {
|
||||
self.token_cmp(kind, values)?;
|
||||
self.next()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn lookup(&self, dx: usize, kind: TokenKind, values: TokenValues<'a>) -> bool {
|
||||
self.token_cmp_at_bool(self.position.get() + dx, kind, values)
|
||||
}
|
||||
|
||||
pub fn lookup_back(&self, dx: usize, kind: TokenKind, values: TokenValues<'a>) -> bool {
|
||||
if self.position.get() < dx {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.token_cmp_at_bool(self.position.get() - dx, kind, values)
|
||||
}
|
||||
|
||||
pub fn number(&self, token: &'a Token) -> Result<&'b Node<'b>, ParserError> {
|
||||
self.next()?;
|
||||
|
||||
let decimal =
|
||||
Decimal::from_str_exact(token.value).map_err(|_| ParserError::FailedToParse {
|
||||
message: format!("unknown float value: {:?}", token.value),
|
||||
})?;
|
||||
|
||||
self.node(Node::Number(decimal))
|
||||
}
|
||||
|
||||
pub fn string(&self, token: &'a Token) -> Result<&'b Node<'b>, ParserError> {
|
||||
self.next()?;
|
||||
self.node(Node::String(self.bump.alloc_str(token.value)))
|
||||
}
|
||||
|
||||
pub fn bool(&self, token: &'a Token) -> Result<&'b Node<'b>, ParserError> {
|
||||
match token.value {
|
||||
"true" => self.node(Node::Bool(true)),
|
||||
"false" => self.node(Node::Bool(false)),
|
||||
_ => Err(ParserError::FailedToParse {
|
||||
message: format!("unknown bool value: {:?}", token.value),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn null(&self, _token: &'a Token) -> Result<&'b Node<'b>, ParserError> {
|
||||
self.node(Node::Null)
|
||||
}
|
||||
|
||||
pub fn node(&self, node: Node<'b>) -> Result<&'b Node<'b>, ParserError> {
|
||||
Ok(self.bump.alloc(node))
|
||||
}
|
||||
|
||||
fn token_cmp_at_bool(&self, index: usize, kind: TokenKind, values: TokenValues<'a>) -> bool {
|
||||
return if let Some(token) = self.tokens.get(index) {
|
||||
if token.kind != kind {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(vals) = values {
|
||||
return vals.iter().any(|&c| c == token.value);
|
||||
}
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
}
|
||||
|
||||
fn token_cmp_at(
|
||||
&self,
|
||||
index: usize,
|
||||
kind: TokenKind,
|
||||
values: TokenValues<'a>,
|
||||
) -> Result<(), ParserError> {
|
||||
let token: &'a Token = self
|
||||
.tokens
|
||||
.get(index)
|
||||
.ok_or(ParserError::TokenOutOfBounds)?;
|
||||
|
||||
if token.kind != kind {
|
||||
return Err(ParserError::UnexpectedToken {
|
||||
expected: format!("{kind:?} {values:?}"),
|
||||
received: format!("{token:?}"),
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(vals) = values {
|
||||
if !vals.iter().any(|&c| c == token.value) {
|
||||
return Err(ParserError::UnexpectedToken {
|
||||
expected: format!("{kind:?} {values:?}"),
|
||||
received: format!("{token:?}"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn token_cmp(&self, kind: TokenKind, values: TokenValues<'a>) -> Result<(), ParserError> {
|
||||
self.token_cmp_at(self.position.get(), kind, values)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
pub use standard::StandardParser;
|
||||
pub use unary::UnaryParser;
|
||||
|
||||
pub mod error;
|
||||
|
||||
mod definitions;
|
||||
mod iter;
|
||||
mod standard;
|
||||
mod unary;
|
||||
@@ -0,0 +1,85 @@
|
||||
use std::collections::HashMap;
|
||||
use std::hash::BuildHasherDefault;
|
||||
|
||||
use ahash::AHasher;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::hashmap;
|
||||
use crate::parser::definitions::Associativity::{Left, Right};
|
||||
use crate::parser::definitions::{Arity, BuiltIn, Operator};
|
||||
|
||||
type ADefHasher = BuildHasherDefault<AHasher>;
|
||||
|
||||
pub(crate) static BUILT_INS: Lazy<HashMap<&'static str, BuiltIn, ADefHasher>> = Lazy::new(|| {
|
||||
hashmap! {
|
||||
"len" => BuiltIn { arity: Arity::Single },
|
||||
"date" => BuiltIn { arity: Arity::Single },
|
||||
"duration" => BuiltIn { arity: Arity::Single },
|
||||
"upper" => BuiltIn { arity: Arity::Single },
|
||||
"lower" => BuiltIn { arity: Arity::Single },
|
||||
|
||||
"abs" => BuiltIn { arity: Arity::Single },
|
||||
"sum" => BuiltIn { arity: Arity::Single },
|
||||
"avg" => BuiltIn { arity: Arity::Single },
|
||||
"min" => BuiltIn { arity: Arity::Single },
|
||||
"max" => BuiltIn { arity: Arity::Single },
|
||||
"rand" => BuiltIn { arity: Arity::Single },
|
||||
|
||||
"floor" => BuiltIn { arity: Arity::Single },
|
||||
"ceil" => BuiltIn { arity: Arity::Single },
|
||||
"round" => BuiltIn { arity: Arity::Single },
|
||||
|
||||
"dayOfWeek" => BuiltIn { arity: Arity::Single },
|
||||
"dayOfMonth" => BuiltIn { arity: Arity::Single },
|
||||
"dayOfYear" => BuiltIn { arity: Arity::Single },
|
||||
"weekOfMonth" => BuiltIn { arity: Arity::Single },
|
||||
"weekOfYear" => BuiltIn { arity: Arity::Single },
|
||||
"monthOfYear" => BuiltIn { arity: Arity::Single },
|
||||
"seasonOfYear" => BuiltIn { arity: Arity::Single },
|
||||
"monthString" => BuiltIn { arity: Arity::Single },
|
||||
"weekdayString" => BuiltIn { arity: Arity::Single },
|
||||
|
||||
"startsWith" => BuiltIn { arity: Arity::Dual },
|
||||
"endsWith" => BuiltIn { arity: Arity::Dual },
|
||||
"contains" => BuiltIn { arity: Arity::Dual },
|
||||
"all" => BuiltIn { arity: Arity::Closure },
|
||||
"some" => BuiltIn { arity: Arity::Closure },
|
||||
"none" => BuiltIn { arity: Arity::Closure },
|
||||
"filter" => BuiltIn { arity: Arity::Closure },
|
||||
"map" => BuiltIn { arity: Arity::Closure },
|
||||
"count" => BuiltIn { arity: Arity::Closure },
|
||||
"one" => BuiltIn { arity: Arity::Closure }
|
||||
}
|
||||
});
|
||||
|
||||
pub(crate) static BINARY_OPERATORS: Lazy<HashMap<&'static str, Operator, ADefHasher>> =
|
||||
Lazy::new(|| {
|
||||
hashmap! {
|
||||
"or" => Operator { precedence: 10, associativity: Left },
|
||||
"and" => Operator { precedence: 15, associativity: Left },
|
||||
"==" => Operator { precedence: 20, associativity: Left },
|
||||
"!=" => Operator { precedence: 20, associativity: Left },
|
||||
"<" => Operator { precedence: 20, associativity: Left },
|
||||
">" => Operator { precedence: 20, associativity: Left },
|
||||
"<=" => Operator { precedence: 20, associativity: Left },
|
||||
">=" => Operator { precedence: 20, associativity: Left },
|
||||
"not in" => Operator { precedence: 20, associativity: Left },
|
||||
"in" => Operator { precedence: 20, associativity: Left },
|
||||
"+" => Operator { precedence: 30, associativity: Left },
|
||||
"-" => Operator { precedence: 30, associativity: Left },
|
||||
"*" => Operator { precedence: 60, associativity: Left },
|
||||
"/" => Operator { precedence: 60, associativity: Left },
|
||||
"%" => Operator { precedence: 60, associativity: Left },
|
||||
"^" => Operator { precedence: 70, associativity: Right },
|
||||
}
|
||||
});
|
||||
|
||||
pub(crate) static UNARY_OPERATORS: Lazy<HashMap<&'static str, Operator, ADefHasher>> =
|
||||
Lazy::new(|| {
|
||||
hashmap! {
|
||||
"not" => Operator { precedence: 50, associativity: Left },
|
||||
"!" => Operator { precedence: 50, associativity: Left },
|
||||
"+" => Operator { precedence: 200, associativity: Left },
|
||||
"-" => Operator { precedence: 200, associativity: Left },
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,365 @@
|
||||
use std::cell::Cell;
|
||||
|
||||
use bumpalo::Bump;
|
||||
|
||||
use crate::ast::Node;
|
||||
use crate::lexer::token::{Token, TokenKind};
|
||||
use crate::parser::definitions::{Arity, Associativity};
|
||||
use crate::parser::error::ParserError::{MemoryFailure, UnexpectedToken, UnknownBuiltIn};
|
||||
use crate::parser::error::ParserResult;
|
||||
use crate::parser::iter::ParserIterator;
|
||||
use crate::parser::standard::constants::{BINARY_OPERATORS, BUILT_INS, UNARY_OPERATORS};
|
||||
|
||||
mod constants;
|
||||
|
||||
pub struct StandardParser<'a, 'b>
|
||||
where
|
||||
'b: 'a,
|
||||
{
|
||||
iterator: ParserIterator<'a, 'b>,
|
||||
bump: &'b Bump,
|
||||
depth: Cell<u8>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> StandardParser<'a, 'b>
|
||||
where
|
||||
'b: 'a,
|
||||
{
|
||||
pub fn try_new(tokens: &'a Vec<Token>, bump: &'b Bump) -> ParserResult<Self> {
|
||||
Ok(Self {
|
||||
iterator: ParserIterator::try_new(tokens, bump)?,
|
||||
bump,
|
||||
depth: Cell::new(0),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse(&self) -> ParserResult<&'b Node<'b>> {
|
||||
self.parse_expression(0)
|
||||
}
|
||||
|
||||
fn parse_expression(&self, precedence: u8) -> ParserResult<&'b Node<'b>> {
|
||||
let mut node_left = self.parse_primary()?;
|
||||
let mut token = self.iterator.current();
|
||||
|
||||
while !self.iterator.is_done() {
|
||||
if token.kind == TokenKind::Operator {
|
||||
if let Some(op) = BINARY_OPERATORS.get(token.value) {
|
||||
if op.precedence >= precedence {
|
||||
self.iterator.next()?;
|
||||
let node_right = match op.associativity {
|
||||
Associativity::Left => self.parse_expression(op.precedence + 1)?,
|
||||
_ => self.parse_expression(op.precedence)?,
|
||||
};
|
||||
|
||||
node_left = self.iterator.node(Node::Binary {
|
||||
operator: self.iterator.str_value(token.value),
|
||||
left: node_left,
|
||||
right: node_right,
|
||||
})?;
|
||||
token = self.iterator.current();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if precedence == 0 {
|
||||
node_left = self.parse_conditional(node_left)?;
|
||||
}
|
||||
|
||||
Ok(node_left)
|
||||
}
|
||||
|
||||
fn parse_primary(&self) -> ParserResult<&'b Node<'b>> {
|
||||
let token = self.iterator.current();
|
||||
if token.kind == TokenKind::Operator {
|
||||
if let Some(op) = UNARY_OPERATORS.get(token.value) {
|
||||
self.iterator.next()?;
|
||||
let expr = self.parse_expression(op.precedence)?;
|
||||
let node = self.iterator.node(Node::Unary {
|
||||
operator: self.iterator.str_value(token.value),
|
||||
node: expr,
|
||||
})?;
|
||||
|
||||
return self.parse_postfix(node);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(interval_node) = self.parse_interval()? {
|
||||
return self.parse_postfix(interval_node);
|
||||
}
|
||||
|
||||
if token.kind == TokenKind::Bracket && token.value == "(" {
|
||||
self.iterator.next()?;
|
||||
let expr = self.parse_expression(0)?;
|
||||
self.iterator.expect(TokenKind::Bracket, Some(&[")"]))?;
|
||||
return self.parse_postfix(expr);
|
||||
}
|
||||
|
||||
if self.depth.get() > 0 {
|
||||
if token.kind == TokenKind::Operator && (token.value == "#" || token.value == ".") {
|
||||
if token.value == "#" {
|
||||
self.iterator.next()?;
|
||||
}
|
||||
let node = self.iterator.node(Node::Pointer)?;
|
||||
return self.parse_postfix(node);
|
||||
}
|
||||
} else if token.kind == TokenKind::Operator && (token.value == "#" || token.value == ".") {
|
||||
return Err(UnexpectedToken {
|
||||
expected: "anything but Operator(#, .)".to_string(),
|
||||
received: format!("{token:?}"),
|
||||
});
|
||||
}
|
||||
|
||||
self.parse_primary_expression()
|
||||
}
|
||||
|
||||
fn parse_conditional(&self, node: &'b Node<'b>) -> ParserResult<&'b Node<'b>> {
|
||||
let mut nd = self.iterator.node(node.clone())?;
|
||||
let mut expr1: &'b Node;
|
||||
let mut expr2: &'b Node;
|
||||
|
||||
while self.iterator.current().kind == TokenKind::Operator
|
||||
&& self.iterator.current().value == "?"
|
||||
{
|
||||
self.iterator.next()?;
|
||||
|
||||
let token = self.iterator.current();
|
||||
if token.kind != TokenKind::Operator && token.value != ":" {
|
||||
expr1 = self.parse_expression(0)?;
|
||||
self.iterator.expect(TokenKind::Operator, Some(&[":"]))?;
|
||||
expr2 = self.parse_expression(0)?;
|
||||
} else {
|
||||
self.iterator.next()?;
|
||||
expr1 = node;
|
||||
expr2 = self.parse_expression(0)?;
|
||||
}
|
||||
|
||||
nd = self.iterator.node(Node::Conditional {
|
||||
condition: nd,
|
||||
on_true: expr1,
|
||||
on_false: expr2,
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(nd)
|
||||
}
|
||||
|
||||
fn parse_primary_expression(&self) -> ParserResult<&'b Node<'b>> {
|
||||
let node: &'b Node;
|
||||
let token = self.iterator.current();
|
||||
|
||||
match token.kind {
|
||||
TokenKind::Identifier => {
|
||||
self.iterator.next()?;
|
||||
match token.value {
|
||||
"true" | "false" => return self.iterator.bool(token),
|
||||
"null" => return self.iterator.null(token),
|
||||
_ => node = self.parse_identifier_expression(token)?,
|
||||
}
|
||||
}
|
||||
TokenKind::Number => return self.iterator.number(token),
|
||||
TokenKind::String => return self.iterator.string(token),
|
||||
_ => {
|
||||
if token.kind == TokenKind::Bracket && token.value == "[" {
|
||||
node = self.parse_array(token)?;
|
||||
} else {
|
||||
return Err(UnexpectedToken {
|
||||
expected: "identifier, string, number or opening bracket".to_string(),
|
||||
received: format!("{token:?}"),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.parse_postfix(node)
|
||||
}
|
||||
|
||||
fn parse_interval(&self) -> ParserResult<Option<&'b Node<'b>>> {
|
||||
if self.iterator.current().kind != TokenKind::Bracket {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
if !self.iterator.lookup(2, TokenKind::Operator, Some(&[".."])) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let left_bracket = self.iterator.current().value;
|
||||
self.iterator.expect(TokenKind::Bracket, None)?;
|
||||
let left = self.parse_primary_expression()?;
|
||||
self.iterator.expect(TokenKind::Operator, Some(&[".."]))?;
|
||||
let right = self.parse_primary_expression()?;
|
||||
let right_bracket = self.iterator.current().value;
|
||||
self.iterator.expect(TokenKind::Bracket, None)?;
|
||||
|
||||
let interval_node = self.iterator.node(Node::Interval {
|
||||
left_bracket: self.iterator.str_value(left_bracket),
|
||||
left,
|
||||
right,
|
||||
right_bracket: self.iterator.str_value(right_bracket),
|
||||
})?;
|
||||
|
||||
Ok(Some(interval_node))
|
||||
}
|
||||
fn parse_identifier_expression(&self, token: &Token) -> ParserResult<&'b Node<'b>> {
|
||||
if self.iterator.current().kind != TokenKind::Bracket
|
||||
|| self.iterator.current().value != "("
|
||||
{
|
||||
return self
|
||||
.iterator
|
||||
.node(Node::Identifier(self.iterator.str_value(token.value)));
|
||||
}
|
||||
|
||||
let builtin = BUILT_INS.get(token.value).ok_or_else(|| UnknownBuiltIn {
|
||||
token: token.value.to_string(),
|
||||
})?;
|
||||
|
||||
self.iterator.expect(TokenKind::Bracket, Some(&["("]))?;
|
||||
|
||||
return match builtin.arity {
|
||||
Arity::Single => {
|
||||
let arg = self.parse_expression(0)?;
|
||||
self.iterator.expect(TokenKind::Bracket, Some(&[")"]))?;
|
||||
|
||||
self.iterator.node(Node::BuiltIn {
|
||||
name: self.iterator.str_value(token.value),
|
||||
arguments: self.bump.alloc_slice_copy(&[arg]),
|
||||
})
|
||||
}
|
||||
Arity::Dual => {
|
||||
let arg1 = self.parse_expression(0)?;
|
||||
self.iterator.expect(TokenKind::Operator, Some(&[","]))?;
|
||||
let arg2 = self.parse_primary_expression()?;
|
||||
self.iterator.expect(TokenKind::Bracket, Some(&[")"]))?;
|
||||
|
||||
self.iterator.node(Node::BuiltIn {
|
||||
name: self.iterator.str_value(token.value),
|
||||
arguments: self.bump.alloc_slice_copy(&[arg1, arg2]),
|
||||
})
|
||||
}
|
||||
Arity::Closure => {
|
||||
let arg1 = self.parse_expression(0)?;
|
||||
self.iterator.expect(TokenKind::Operator, Some(&[","]))?;
|
||||
let arg2 = self.parse_closure()?;
|
||||
self.iterator.expect(TokenKind::Bracket, Some(&[")"]))?;
|
||||
|
||||
self.iterator.node(Node::BuiltIn {
|
||||
name: self.iterator.str_value(token.value),
|
||||
arguments: self.bump.alloc_slice_copy(&[arg1, arg2]),
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_array(&self, _token: &Token) -> ParserResult<&'b Node<'b>> {
|
||||
let mut nodes = Vec::new();
|
||||
|
||||
self.iterator.expect(TokenKind::Bracket, Some(&["["]))?;
|
||||
while self.iterator.current().kind != TokenKind::Bracket
|
||||
&& self.iterator.current().value != "]"
|
||||
{
|
||||
if !nodes.is_empty() {
|
||||
self.iterator.expect(TokenKind::Operator, Some(&[","]))?;
|
||||
if self.iterator.current().value == "]" {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nodes.push(self.parse_primary()?);
|
||||
}
|
||||
|
||||
self.iterator.expect(TokenKind::Bracket, Some(&["]"]))?;
|
||||
let node = Node::Array(self.bump.alloc_slice_copy(nodes.as_slice()));
|
||||
|
||||
self.iterator.node(node)
|
||||
}
|
||||
|
||||
fn parse_closure(&self) -> ParserResult<&'b Node<'b>> {
|
||||
self.depth.set(self.depth.get() + 1);
|
||||
let node = self.parse_expression(0)?;
|
||||
self.depth.set(self.depth.get() - 1);
|
||||
|
||||
return self.iterator.node(Node::Closure(node));
|
||||
}
|
||||
|
||||
fn parse_postfix(&self, node: &'b Node<'b>) -> ParserResult<&'b Node<'b>> {
|
||||
let mut postfix_token = self.iterator.current();
|
||||
let mut nd = self.iterator.node(node.clone())?;
|
||||
|
||||
while postfix_token.kind == TokenKind::Bracket || postfix_token.kind == TokenKind::Operator
|
||||
{
|
||||
if postfix_token.value == "." {
|
||||
self.iterator.next()?;
|
||||
let property_token = self.iterator.current();
|
||||
self.iterator.next()?;
|
||||
|
||||
if property_token.kind != TokenKind::Identifier
|
||||
&& (property_token.kind != TokenKind::Operator
|
||||
|| !is_valid_identifier(property_token.value))
|
||||
{
|
||||
return Err(UnexpectedToken {
|
||||
expected: "member identifier token".to_string(),
|
||||
received: format!("{postfix_token:?}"),
|
||||
});
|
||||
}
|
||||
|
||||
let property = self
|
||||
.iterator
|
||||
.node(Node::String(self.iterator.str_value(property_token.value)))?;
|
||||
nd = self.iterator.node(Node::Member { node: nd, property })?;
|
||||
} else if postfix_token.value == "[" {
|
||||
self.iterator.next()?;
|
||||
let mut from: Option<&'b Node<'b>> = None;
|
||||
let mut to: Option<&'b Node<'b>> = None;
|
||||
|
||||
let mut c = self.iterator.current();
|
||||
if c.kind == TokenKind::Operator && c.value == ":" {
|
||||
self.iterator.next()?;
|
||||
c = self.iterator.current();
|
||||
|
||||
if c.kind != TokenKind::Bracket && c.value != "]" {
|
||||
to = Some(self.parse_expression(0)?);
|
||||
}
|
||||
|
||||
nd = self.iterator.node(Node::Slice { node: nd, to, from })?;
|
||||
self.iterator.expect(TokenKind::Bracket, Some(&["]"]))?;
|
||||
} else {
|
||||
from = Some(self.parse_expression(0)?);
|
||||
c = self.iterator.current();
|
||||
|
||||
if c.kind == TokenKind::Operator && c.value == ":" {
|
||||
self.iterator.next()?;
|
||||
c = self.iterator.current();
|
||||
|
||||
if c.kind != TokenKind::Bracket && c.value != "]" {
|
||||
to = Some(self.parse_expression(0)?);
|
||||
}
|
||||
|
||||
nd = self.iterator.node(Node::Slice { node: nd, from, to })?;
|
||||
self.iterator.expect(TokenKind::Bracket, Some(&["]"]))?;
|
||||
} else {
|
||||
// Slice operator [:] was not found,
|
||||
// it should be just an index node.
|
||||
nd = self.iterator.node(Node::Member {
|
||||
node: nd,
|
||||
property: from.ok_or(MemoryFailure)?,
|
||||
})?;
|
||||
self.iterator.expect(TokenKind::Bracket, Some(&["]"]))?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
postfix_token = self.iterator.current();
|
||||
}
|
||||
|
||||
Ok(nd)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid_identifier(str: &str) -> bool {
|
||||
matches!(str, "and" | "or" | "in" | "not")
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
use phf::{phf_map, Map};
|
||||
|
||||
use crate::parser::definitions::Associativity::{Left, Right};
|
||||
use crate::parser::definitions::{Arity, BuiltIn, Operator};
|
||||
|
||||
pub(crate) const BUILT_INS: Map<&'static str, BuiltIn> = phf_map! {
|
||||
"date" => BuiltIn { arity: Arity::Single },
|
||||
"duration" => BuiltIn { arity: Arity::Single },
|
||||
|
||||
"upper" => BuiltIn { arity: Arity::Single },
|
||||
"lower" => BuiltIn { arity: Arity::Single },
|
||||
|
||||
"abs" => BuiltIn { arity: Arity::Single },
|
||||
"sum" => BuiltIn { arity: Arity::Single },
|
||||
"avg" => BuiltIn { arity: Arity::Single },
|
||||
"min" => BuiltIn { arity: Arity::Single },
|
||||
"max" => BuiltIn { arity: Arity::Single },
|
||||
"rand" => BuiltIn { arity: Arity::Single },
|
||||
|
||||
"floor" => BuiltIn { arity: Arity::Single },
|
||||
"ceil" => BuiltIn { arity: Arity::Single },
|
||||
"round" => BuiltIn { arity: Arity::Single },
|
||||
|
||||
"dayOfWeek" => BuiltIn { arity: Arity::Single },
|
||||
"dayOfMonth" => BuiltIn { arity: Arity::Single },
|
||||
"dayOfYear" => BuiltIn { arity: Arity::Single },
|
||||
"weekOfMonth" => BuiltIn { arity: Arity::Single },
|
||||
"weekOfYear" => BuiltIn { arity: Arity::Single },
|
||||
"monthOfYear" => BuiltIn { arity: Arity::Single },
|
||||
"seasonOfYear" => BuiltIn { arity: Arity::Single },
|
||||
"monthString" => BuiltIn { arity: Arity::Single },
|
||||
"weekdayString" => BuiltIn { arity: Arity::Single },
|
||||
};
|
||||
|
||||
pub(crate) const OPERATORS: Map<&'static str, Operator> = phf_map! {
|
||||
"or" => Operator { precedence: 10, associativity: Left },
|
||||
"and" => Operator { precedence: 15, associativity: Left },
|
||||
"==" => Operator { precedence: 20, associativity: Left },
|
||||
"!=" => Operator { precedence: 20, associativity: Left },
|
||||
"<" => Operator { precedence: 20, associativity: Left },
|
||||
">" => Operator { precedence: 20, associativity: Left },
|
||||
"<=" => Operator { precedence: 20, associativity: Left },
|
||||
">=" => Operator { precedence: 20, associativity: Left },
|
||||
"not in" => Operator { precedence: 20, associativity: Left },
|
||||
"in" => Operator { precedence: 20, associativity: Left },
|
||||
"+" => Operator { precedence: 30, associativity: Left },
|
||||
"-" => Operator { precedence: 30, associativity: Left },
|
||||
"*" => Operator { precedence: 60, associativity: Left },
|
||||
"/" => Operator { precedence: 60, associativity: Left },
|
||||
"%" => Operator { precedence: 60, associativity: Left },
|
||||
"^" => Operator { precedence: 70, associativity: Right },
|
||||
};
|
||||
@@ -0,0 +1,241 @@
|
||||
use bumpalo::Bump;
|
||||
|
||||
use crate::ast::Node;
|
||||
use crate::lexer::token::{Token, TokenKind};
|
||||
use crate::parser::definitions::{Arity, Associativity};
|
||||
use crate::parser::error::{ParserError, ParserResult};
|
||||
use crate::parser::iter::ParserIterator;
|
||||
use crate::parser::unary::constants::{BUILT_INS, OPERATORS};
|
||||
|
||||
mod constants;
|
||||
|
||||
pub struct UnaryParser<'a, 'b>
|
||||
where
|
||||
'b: 'a,
|
||||
{
|
||||
iterator: ParserIterator<'a, 'b>,
|
||||
bump: &'b Bump,
|
||||
}
|
||||
|
||||
const MAIN_NODE: Node<'static> = Node::Identifier("$");
|
||||
|
||||
impl<'a, 'b> UnaryParser<'a, 'b>
|
||||
where
|
||||
'b: 'a,
|
||||
{
|
||||
pub fn try_new(tokens: &'a Vec<Token>, bump: &'b Bump) -> ParserResult<Self> {
|
||||
Ok(Self {
|
||||
iterator: ParserIterator::try_new(tokens, bump)?,
|
||||
bump,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse(&self) -> ParserResult<&'b Node<'b>> {
|
||||
self.parse_expression(0, true)
|
||||
}
|
||||
|
||||
fn parse_expression(&self, precedence: u8, root: bool) -> ParserResult<&'b Node<'b>> {
|
||||
let mut node_left: &'b Node<'b> = self.iterator.node(MAIN_NODE)?;
|
||||
let mut token = self.iterator.current();
|
||||
|
||||
while !self.iterator.is_done() {
|
||||
match token.kind {
|
||||
TokenKind::Operator => {
|
||||
if token.value == "," {
|
||||
self.iterator.next()?;
|
||||
let node_right: &'b Node<'b> = self.parse_expression(0, true)?;
|
||||
|
||||
token = self.iterator.current();
|
||||
node_left = self.iterator.node(Node::Binary {
|
||||
left: node_left,
|
||||
operator: "or",
|
||||
right: node_right,
|
||||
})?;
|
||||
continue;
|
||||
} else if let Some(op) = OPERATORS.get(token.value) {
|
||||
if op.precedence >= precedence {
|
||||
self.iterator.next()?;
|
||||
let node_right = match op.associativity {
|
||||
Associativity::Left => {
|
||||
self.parse_expression(op.precedence + 1, false)?
|
||||
}
|
||||
Associativity::Right => {
|
||||
self.parse_expression(op.precedence, false)?
|
||||
}
|
||||
};
|
||||
|
||||
node_left = self.iterator.node(Node::Binary {
|
||||
left: node_left,
|
||||
operator: self.iterator.str_value(token.value),
|
||||
right: node_right,
|
||||
})?;
|
||||
token = self.iterator.current();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
TokenKind::Identifier | TokenKind::String | TokenKind::Number => {
|
||||
let node_right = self.parse_primary()?;
|
||||
if !root {
|
||||
return Ok(node_right);
|
||||
}
|
||||
|
||||
token = self.iterator.current();
|
||||
node_left = self.iterator.node(Node::Binary {
|
||||
left: node_left,
|
||||
operator: "==",
|
||||
right: node_right,
|
||||
})?;
|
||||
continue;
|
||||
}
|
||||
TokenKind::Bracket => {
|
||||
let node_right: &Node;
|
||||
|
||||
if let Some(interval) = self.parse_interval(node_left)? {
|
||||
node_left = interval;
|
||||
} else if token.value == "[" {
|
||||
let should_wrap = !self.iterator.lookup_back(
|
||||
1,
|
||||
TokenKind::Operator,
|
||||
Some(&["not in", "in"]),
|
||||
);
|
||||
node_right = self.parse_array(token)?;
|
||||
|
||||
if should_wrap {
|
||||
node_left = self.iterator.node(Node::Binary {
|
||||
left: node_left,
|
||||
right: node_right,
|
||||
operator: "in",
|
||||
})?;
|
||||
} else {
|
||||
node_left = node_right;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(node_left)
|
||||
}
|
||||
|
||||
fn parse_interval(&self, node: &'b Node<'b>) -> ParserResult<Option<&'b Node<'b>>> {
|
||||
let current_token = self.iterator.current();
|
||||
if current_token.kind != TokenKind::Bracket {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
if !self.iterator.lookup(2, TokenKind::Operator, Some(&[".."])) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let should_wrap =
|
||||
!self
|
||||
.iterator
|
||||
.lookup_back(1, TokenKind::Operator, Some(&["not in", "in"]));
|
||||
|
||||
let left_bracket = self.iterator.current().value;
|
||||
self.iterator.expect(TokenKind::Bracket, None)?;
|
||||
let left = self.parse_primary()?;
|
||||
self.iterator.expect(TokenKind::Operator, Some(&[".."]))?;
|
||||
let right = self.parse_primary()?;
|
||||
let right_bracket = self.iterator.current().value;
|
||||
self.iterator.expect(TokenKind::Bracket, None)?;
|
||||
|
||||
let interval_node = self.iterator.node(Node::Interval {
|
||||
left,
|
||||
left_bracket: self.iterator.str_value(left_bracket),
|
||||
right,
|
||||
right_bracket: self.iterator.str_value(right_bracket),
|
||||
})?;
|
||||
|
||||
if should_wrap {
|
||||
return Ok(Some(self.iterator.node(Node::Binary {
|
||||
left: node,
|
||||
right: interval_node,
|
||||
operator: "in",
|
||||
})?));
|
||||
}
|
||||
|
||||
Ok(Some(interval_node))
|
||||
}
|
||||
|
||||
fn parse_array(&self, _token: &Token) -> ParserResult<&'b Node<'b>> {
|
||||
let mut nodes = Vec::new();
|
||||
|
||||
self.iterator.expect(TokenKind::Bracket, Some(&["["]))?;
|
||||
while self.iterator.current().kind != TokenKind::Bracket
|
||||
&& self.iterator.current().value != "]"
|
||||
{
|
||||
if !nodes.is_empty() {
|
||||
self.iterator.expect(TokenKind::Operator, Some(&[","]))?;
|
||||
if self.iterator.current().value == "]" {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nodes.push(self.parse_primary()?);
|
||||
}
|
||||
|
||||
self.iterator.expect(TokenKind::Bracket, Some(&["]"]))?;
|
||||
let node = Node::Array(self.bump.alloc_slice_copy(nodes.as_slice()));
|
||||
self.iterator.node(node)
|
||||
}
|
||||
|
||||
fn parse_primary(&self) -> ParserResult<&'b Node<'b>> {
|
||||
let token = self.iterator.current();
|
||||
|
||||
match token.kind {
|
||||
TokenKind::Identifier => {
|
||||
self.iterator.next()?;
|
||||
match token.value {
|
||||
"true" | "false" => self.iterator.bool(token),
|
||||
"null" => self.iterator.null(token),
|
||||
_ => self.parse_prebuilt(token),
|
||||
}
|
||||
}
|
||||
TokenKind::Number => self.iterator.number(token),
|
||||
TokenKind::String => self.iterator.string(token),
|
||||
_ => Err(ParserError::UnexpectedToken {
|
||||
expected: "one of [identifier, number, string]".to_string(),
|
||||
received: format!("{:?}", token.kind),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_prebuilt(&self, token: &Token<'a>) -> ParserResult<&'b Node<'b>> {
|
||||
let current_token = self.iterator.current();
|
||||
let valid_token = current_token.kind == TokenKind::Bracket && current_token.value == "(";
|
||||
|
||||
if !valid_token {
|
||||
return Err(ParserError::UnknownBuiltIn {
|
||||
token: token.value.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let built_in = BUILT_INS
|
||||
.get(token.value)
|
||||
.ok_or_else(|| ParserError::UnknownBuiltIn {
|
||||
token: token.value.to_string(),
|
||||
})?;
|
||||
|
||||
self.iterator.expect(TokenKind::Bracket, Some(&["("]))?;
|
||||
|
||||
match built_in.arity {
|
||||
Arity::Single => {
|
||||
let arg = self.parse_primary()?;
|
||||
let node = self.iterator.node(Node::BuiltIn {
|
||||
name: self.iterator.str_value(token.value),
|
||||
arguments: self.bump.alloc_slice_copy(&[arg]),
|
||||
})?;
|
||||
|
||||
self.iterator.expect(TokenKind::Bracket, Some(&[")"]))?;
|
||||
|
||||
Ok(node)
|
||||
}
|
||||
_ => Err(ParserError::UnsupportedBuiltIn {
|
||||
token: token.value.to_string(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user