// Copyright 2018-2020, Wayfair GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::ast::raw::*;
use crate::ast::query::raw::*;
use crate::ast::{BinOpKind, UnaryOpKind, LexicalUnit};
use crate::lexer::Token;
use crate::pos::Location;
use simd_json::{BorrowedValue as Value};
use simd_json::prelude::*;
use std::borrow::Cow;
grammar<'input>;
////////////////////////////// Root statements //////////////////////////////
// These statements for the root of the language.
/// Root
pub(crate) Query : QueryRaw<'input> = {
<config:ConfigDirectives> <stmts:Stmts> "<end-of-stream>"? => QueryRaw{config, stmts},
<stmts:Stmts> "<end-of-stream>"? => QueryRaw{config: vec![], stmts},
}
ConfigDirectives: WithExprsRaw<'input> = {
<directive:ConfigDirective> <directives:ConfigDirectives> => {
let mut directives = directives;
directives.insert(0, directive);
directives
},
<directive:ConfigDirective> => vec![directive]
}
ConfigDirective: (IdentRaw<'input>, ImutExprRaw<'input>) = {
"#!config" <WithExpr> => <>
}
Stmts: StmtsRaw<'input> = {
<stmt:Stmt> ";" <list:Stmts> => {
let mut list = list;
list.insert(0,stmt);
list
},
<item:Stmt> ";"? => vec![item],
}
ModuleStmt: ModuleStmtRaw<'input> = {
<start:@L> "mod" <name:Ident> "with" <doc:ModComment> <stmts:ModuleStmts> "end" <end:@L> => ModuleStmtRaw{name, start, end, stmts, doc: doc},
}
/// List of expressions at the root of the script
ModuleStmts: StmtsRaw<'input> = {
//<stmt:Stmt> ";" <list:ModuleStmts> => {
// let mut list = list;
// list.insert(0,stmt);
// list
// },
//<item:Stmt> ";"? => vec![item],
<stmt:ModuleInnerStmt> ";" <list:ModuleStmts> => {
let mut list = list;
list.insert(0,stmt);
list
},
<item:ModuleInnerStmt> ";"? => vec![item],
}
// In case we need to limit the content of stmt
ModuleInnerStmt: StmtRaw<'input> = {
<m:ModuleStmt> => StmtRaw::ModuleStmt(m),
<start:@L> "define" <kind:WindowKind> "window" <id:Ident> <params:WithScriptClause> <end:@L> => StmtRaw::WindowDecl(WindowDeclRaw { start, end, id: id.id.to_string(), kind, params: params.0, script: params.1 }),
<start:@L> "define" <kind:OperatorKind> "operator" <id:Ident> <params:WithClause> <end:@L> => StmtRaw::OperatorDecl(Box::new(OperatorDeclRaw { start, end, kind, id: id.id.to_string(), params: Some(params) })),
<start:@L> "define" <kind:OperatorKind> "operator" <id:Ident> <end:@L> => StmtRaw::OperatorDecl(Box::new(OperatorDeclRaw { start, end, kind, id: id.id.to_string(), params: None })),
<start:@L> "define" "script" <id:Ident> <params:ScriptWithClause> <script:EmbeddedScript> <end:@L> => StmtRaw::ScriptDecl(ScriptDeclRaw { start, end, id: id.id.to_string(), script, params: Some(params) }),
<start:@L> "define" "script" <id:Ident> <script:EmbeddedScript> <end:@L> => StmtRaw::ScriptDecl(ScriptDeclRaw { start, end, id: id.id.to_string(), script, params: None }),
Const => StmtRaw::Expr(Box::new(<>)),
FnDecl => StmtRaw::Expr(Box::new(ExprRaw::FnDecl(<>))),
Intrinsic => StmtRaw::Expr(Box::new(ExprRaw::FnDecl(<>))),
//
// FIXME - Future, allow modular subgraphs in query language
//
// <start:@L> "create" "stream" <id:Ident> <end:@L> => StmtRaw::Stream(StreamStmtRaw { start, end, id: id.id.to_string() }),
// <start:@L> "create" "operator" <id:Ident> "from" <target:Ident> <params:WithClause> <end:@L> => StmtRaw::Operator(OperatorStmtRaw { start, end, id: id.id.to_string(), target: target.id.to_string(), params: Some(params) }),
// <start:@L> "create" "operator" <id:Ident> "from" <target:Ident> <end:@L> => StmtRaw::Operator(OperatorStmtRaw { start, end, id: id.id.to_string(), target: target.id.to_string(), params: None }),
// <start:@L> "create" "operator" <id:Ident> <params:WithClause> <end:@L> => StmtRaw::Operator(OperatorStmtRaw { start, end, id: id.id.to_string(), target: id.id.to_string(), params: Some(params) }),
// <start:@L> "create" "operator" <id:Ident> <end:@L> => StmtRaw::Operator(OperatorStmtRaw { start, end, id: id.id.to_string(), target: id.id.to_string(), params: None }),
// <start:@L> "create" "script" <id:Ident> "from" <target:Ident> <params:WithClause> <end:@L> => StmtRaw::Script(ScriptStmtRaw { start, end, id: id.id.to_string(), target: target.id.to_string(), params: Some(params) }),
// <start:@L> "create" "script" <id:Ident> "from" <target:Ident> <end:@L> => StmtRaw::Script(ScriptStmtRaw { start, end, id: id.id.to_string(), target: target.id.to_string(), params: None }),
// <start:@L> "create" "script" <id:Ident> <params:WithClause> <end:@L> => StmtRaw::Script(ScriptStmtRaw { start, end, id: id.id.to_string(), target: id.id.to_string(), params: Some(params) }),
// <start:@L> "create" "script" <id:Ident> <end:@L> => StmtRaw::Script(ScriptStmtRaw { start, end, id: id.id.to_string(), target: id.id.to_string(), params: None }),
// <start:@L> "select" <target:ComplexExprImut> "from" <from:StreamPort> <windows:WindowClause> <maybe_where:WhereClause> <maybe_group_by:GroupByClause> "into" <into:StreamPort> <maybe_having:HavingClause> <end:@L> => StmtRaw::Select(Box::new(SelectRaw { start, end, from, into, target, maybe_where, maybe_having, windows, maybe_group_by})),
}
WindowKind: WindowKind = {
"sliding" => WindowKind::Sliding,
"tumbling" => WindowKind::Tumbling,
}
Stmt: StmtRaw<'input> = {
<m:ModuleStmt> => StmtRaw::ModuleStmt(m),
<start:@L> "define" <kind:WindowKind> "window" <id:Ident> <params:WithScriptClause> <end:@L> => StmtRaw::WindowDecl(WindowDeclRaw { start, end, id: id.id.to_string(), kind, params: params.0, script: params.1 }),
<start:@L> "define" <kind:OperatorKind> "operator" <id:Ident> <params:WithClause> <end:@L> => StmtRaw::OperatorDecl(Box::new(OperatorDeclRaw { start, end, kind, id: id.id.to_string(), params: Some(params) })),
<start:@L> "define" <kind:OperatorKind> "operator" <id:Ident> <end:@L> => StmtRaw::OperatorDecl(Box::new(OperatorDeclRaw { start, end, kind, id: id.id.to_string(), params: None })),
<start:@L> "define" "script" <id:Ident> <params:ScriptWithClause> <script:EmbeddedScript> <end:@L> => StmtRaw::ScriptDecl(ScriptDeclRaw { start, end, id: id.id.to_string(), script, params: Some(params) }),
<start:@L> "define" "script" <id:Ident> <script:EmbeddedScript> <end:@L> => StmtRaw::ScriptDecl(ScriptDeclRaw { start, end, id: id.id.to_string(), script, params: None }),
<start:@L> "create" "stream" <id:Ident> <end:@L> => StmtRaw::Stream(StreamStmtRaw { start, end, id: id.id.to_string() }),
<start:@L> "create" "operator" <id:Ident> "from" <target:ModularTarget> <params:WithClause> <end:@L> => StmtRaw::Operator(OperatorStmtRaw { start, end, id: id.id.to_string(), module: target.0, target: target.1.id.to_string(), params: Some(params) }),
<start:@L> "create" "operator" <id:Ident> "from" <target:ModularTarget> <end:@L> => StmtRaw::Operator(OperatorStmtRaw { start, end, id: id.id.to_string(), module: target.0, target: target.1.id.to_string(), params: None }),
<start:@L> "create" "operator" <id:Ident> <params:WithClause> <end:@L> => StmtRaw::Operator(OperatorStmtRaw { start, end, id: id.id.to_string(), module: vec![], target: id.id.to_string(), params: Some(params) }),
<start:@L> "create" "operator" <id:Ident> <end:@L> => StmtRaw::Operator(OperatorStmtRaw { start, end, id: id.id.to_string(), module: vec![], target: id.id.to_string(), params: None }),
<start:@L> "create" "script" <id:Ident> "from" <target:ModularTarget> <params:WithClause> <end:@L> => StmtRaw::Script(ScriptStmtRaw { start, end, module: vec![], id: id.id.to_string(), target: target.1.id.to_string(), params: Some(params) }),
<start:@L> "create" "script" <id:Ident> "from" <target:ModularTarget> <end:@L> => StmtRaw::Script(ScriptStmtRaw { start, end, id: id.id.to_string(), module: target.0, target: target.1.id.to_string(), params: None }),
<start:@L> "create" "script" <id:Ident> <params:WithClause> <end:@L> => StmtRaw::Script(ScriptStmtRaw { start, end, id: id.id.to_string(), module: vec![], target: id.id.to_string(), params: Some(params) }),
<start:@L> "create" "script" <id:Ident> <end:@L> => StmtRaw::Script(ScriptStmtRaw { start, end, id: id.id.to_string(), module: vec![], target: id.id.to_string(), params: None }),
<start:@L> "select" <target:ComplexExprImut> "from" <from:StreamPort> <windows:WindowClause> <maybe_where:WhereClause> <maybe_group_by:GroupByClause> "into" <into:StreamPort> <maybe_having:HavingClause> <end:@L> => StmtRaw::Select(Box::new(SelectRaw { start, end, from, into, target, maybe_where, maybe_having, windows, maybe_group_by})),
}
MaybePort: Option<IdentRaw<'input>> = {
("/" <Ident>)? => <>,
}
ModularTarget: (Vec<IdentRaw<'input>>, IdentRaw<'input>) = {
<target:Ident> => (vec![], target),
<m:ModPath> "::" <target:Ident> => (m, target),
}
StreamPort: (IdentRaw<'input>, Option<IdentRaw<'input>>) = {
<op:Ident> <port:MaybePort> => (op, port),
// <m:ModPath> "::" <op:Ident> <port:MaybePort> => (op, port) // FIXME future
}
WindowClause: Option<Vec<WindowDefnRaw<'input>>> = {
(<WindowDefn>)? => <>,
}
Window: WindowDefnRaw<'input> = {
<start:@L> <id:Ident> <end:@L> => WindowDefnRaw { start, end, module: vec![], id: id.id.to_string() },
<start:@L> <module:ModPath> "::" <id:Ident> <end:@L> => WindowDefnRaw { start, end, module, id: id.id.to_string() },
}
Windows: Vec<WindowDefnRaw<'input>> = {
<fields:Windows_> => {
let mut fields = fields;
fields.reverse();
fields
},
}
Windows_: Vec<WindowDefnRaw<'input>> = {
<Sep<Windows_, Window, ",">> => <>
}
WindowDefn: Vec<WindowDefnRaw<'input>> = {
"[" <windows:Windows> "]" => windows
}
WhereClause: Option<ImutExprRaw<'input>> = {
("where" <ComplexExprImut>)? => <>,
}
HavingClause: Option<ImutExprRaw<'input>> = {
("having" <ComplexExprImut>)? => <>,
}
GroupByClause: Option<GroupByRaw<'input>> = {
("group" "by" <GroupDef>)? => <>
}
GroupDef: GroupByRaw<'input> = {
<start:@L> <expr:ExprImut> <end:@L> => GroupByRaw::Expr{start, expr, end},
<start:@L> "set" "("<items:GroupDefs>")" <end:@L> => GroupByRaw::Set{start, items, end},
<start:@L> "each" "("<expr:ExprImut>")" <end:@L> => GroupByRaw::Each{start, expr, end},
}
GroupDefs: Vec<GroupByRaw<'input>> = {
<fields:GroupDefs_> => {
let mut fields = fields;
fields.reverse();
fields
},
}
GroupDefs_: Vec<GroupByRaw<'input>> = {
<Sep<GroupDefs_, GroupDef, ",">> => <>
}
EmbeddedScriptImut: Option<ScriptRaw<'input>> = {
("script" <EmbeddedScriptContent>)? => <>?,
}
EmbeddedScriptContent: Option<ScriptRaw<'input>> = {
<ExprImut> => Some(ScriptRaw::new(vec![ExprRaw::Imut(<>)], None)),
}
WithScriptClause: (WithExprsRaw<'input>, Option<ScriptRaw<'input>>) = {
"with" <with:WithExprs> <script:EmbeddedScriptImut> "end" => (with, script),
}
WithClause: WithExprsRaw<'input> = {
<ScriptWithClause> "end" => <>,
}
ScriptWithClause: WithExprsRaw<'input> = {
"with" <WithExprs> => <>,
}
WithExprs: WithExprsRaw<'input> = {
<fields:WithExprs_> => {
let mut fields = fields;
fields.reverse();
fields
},
}
WithExprs_: WithExprsRaw<'input> = {
<Sep<WithExprs_, WithExpr, ",">> => <>
}
WithExpr: (IdentRaw<'input>, ImutExprRaw<'input>) = {
<start:@L> <name:Ident> "=" <expr:ExprImut> => (name, expr)
}
OperatorKind: OperatorKindRaw = {
<start:@L> <module:Ident> "::" <oper:Ident> <end:@L> => OperatorKindRaw { start, end, module: module.id.to_string(), operation: oper.id.to_string() }
}
EmbeddedScript: ScriptRaw<'input> = {
"script" <exprs:Exprs> "end" => ScriptRaw::new(exprs, None),
}
///////////////////////////////////////
pub(crate) Script : ScriptRaw<'input> = {
<doc:ModComment> <exprs:Exprs> "<end-of-stream>"? => ScriptRaw::new(exprs, doc),
}
ModComment: Option<Vec<Cow<'input, str>>> = {
(<ModComment_>)? => <>
}
ModComment_: Vec<Cow<'input, str>> = {
<c:"<mod-comment>"> => vec![c.into()],
<v:ModComment_> <c:"<mod-comment>"> => {
let mut v = v;
v.push(c.into());
v
},
}
/// List of expressions at the root of the script
Exprs: ExprsRaw<'input> = {
<expr:MayBeConstExpr> ";" <list:Exprs> => {
let mut list = list;
list.insert(0,expr);
list
},
<item:MayBeConstExpr> ";"? => vec![item],
}
MayBeConstExpr: ExprRaw<'input> = {
Const => <>,
FnDecl => ExprRaw::FnDecl(<>),
Intrinsic => ExprRaw::FnDecl(<>),
Module => ExprRaw::Module(<>),
Expr => <>
}
/// A const expressions (this gets compiled out during the 2nd phjase)
Const: ExprRaw<'input> = {
<comment:DocComment> <start:@L> "const" <name:Ident> @L "=" @R <expr:SimpleExprImut> <end:@L> => ExprRaw::Const{name: name.id, expr: expr, start, end, comment},
}
DocComment: Option<Vec<Cow<'input, str>>> = {
(<DocComment_>)? => <>
}
DocComment_: Vec<Cow<'input, str>> = {
<c:"<doc-comment>"> => vec![c.into()],
<v:DocComment_> <c:"<doc-comment>"> => {
let mut v = v;
v.push(c.into());
v
},
}
////////////////////////////// Expr (mutable) //////////////////////////////
// Expressions are the fundamental building block of the language
// starting form binary operators to more complex things like match
// statements
/// Expression root
Expr: ExprRaw<'input> = {
SimpleExpr => <>,
}
/// Non precedence based expressions and language constructs
SimpleExpr: ExprRaw<'input> = {
<pp:Match> => ExprRaw::MatchExpr(Box::new(pp)),
<comprehension:For> => ExprRaw::Comprehension(Box::new(comprehension)),
Let => <>,
Drop => <>,
Emit => <>,
ExprImut => <>.into(),
}
/// Part of the expressions that are always immutable
AlwaysImutExpr: ImutExprRaw<'input> = {
<pp:Patch> => ImutExprRaw::Patch(Box::new(pp)),
<pp:Merge> => ImutExprRaw::Merge(Box::new(pp)),
<call:Invoke> => ImutExprRaw::Invoke(call),
<literal:Literal> => ImutExprRaw::Literal(literal),
<path:Path> => ImutExprRaw::Path(path),
<record:Record> => ImutExprRaw::Record(Box::new(record)),
<list:List> => ImutExprRaw::List(Box::new(list)),
<s:StringLiteral> => ImutExprRaw::String(s),
<r:Recur> => ImutExprRaw::Recur(r),
}
Recur: RecurRaw<'input> = {
<start:@L> "recur" "(" ")" <end:@L> => RecurRaw{start,end, exprs: vec![]},
<start:@L> "recur" "(" <args:InvokeArgs> ")" <end:@L> => RecurRaw{start, end, exprs: args},
}
////////////////////////////// Expr (immutable) ////////////////////////////////////////
// Immutable expressions are used in parts of the language that are not supposed to
// modify the event, locals, or metadata.
/// Expression root
ExprImut: ImutExprRaw<'input> = {
OrExprImut => <>,
}
/// Logical or
OrExprImut: ImutExprRaw<'input> = {
/// TODO should be OrExprImut?
<o:BinOp<BinOr, ExprImut, XorExprImut>> => <>,
XorExprImut => <>,
}
/// Logical xor
XorExprImut: ImutExprRaw<'input> = {
<o:BinOp<BinXor, XorExprImut, AndExprImut>> => <>,
AndExprImut => <>,
}
/// Logical and
AndExprImut: ImutExprRaw<'input> = {
BinOp<BinAnd, AndExprImut, BitOrExprImut> => <>,
BitOrExprImut => <>,
}
/// Bitwise or
BitOrExprImut: ImutExprRaw<'input> = {
<o:BinOp<BinBitOr, BitOrExprImut, BitXorExprImut>> => <>,
BitXorExprImut => <>,
}
/// Bitwise xor
BitXorExprImut: ImutExprRaw<'input> = {
<o:BinOp<BinBitXor, BitXorExprImut, BitAndExprImut>> => <>,
BitAndExprImut => <>,
}
/// Bitwise and
BitAndExprImut: ImutExprRaw<'input> = {
<o:BinOp<BinBitAnd, BitAndExprImut, EqExprImut>> => <>,
EqExprImut => <>,
}
/// Equality comparison operators
EqExprImut: ImutExprRaw<'input> = {
BinOp<BinEq, EqExprImut, CmpExprImut> => <>,
CmpExprImut => <>,
}
/// Relational comparison operators
CmpExprImut: ImutExprRaw<'input> = {
BinOp<BinCmp, CmpExprImut, BitShiftExprImut> => <>,
BitShiftExprImut => <>,
}
/// Bit shift operators (>>, >>>, <<)
BitShiftExprImut: ImutExprRaw<'input> = {
BinOp<BinBitShift, BitShiftExprImut, AddExprImut> => <>,
AddExprImut => <>,
}
/// Addition based math (+, -)
AddExprImut: ImutExprRaw<'input> = {
BinOp<BinAdd, AddExprImut, MulExprImut> => <>,
MulExprImut => <>,
}
/// Multiplication based math (*, /, %)
MulExprImut: ImutExprRaw<'input> = {
BinOp<BinMul, MulExprImut, UnaryExprImut> => <>,
UnaryExprImut => <>,
}
/// Mathematical unary expressions (unary +, unary - )
UnaryExprImut: ImutExprRaw<'input> = {
<start:@L> "+" <expr:UnaryExprImut> <end:@L> => ImutExprRaw::Unary(Box::new(UnaryExprRaw { kind: UnaryOpKind::Plus, expr: expr, start, end })),
<start:@L> "-" <expr:UnaryExprImut> <end:@L> => ImutExprRaw::Unary(Box::new(UnaryExprRaw { kind: UnaryOpKind::Minus, expr: expr, start, end })),
UnarySimpleExprImut => <>,
}
/// Logical and bitwise unary expressions (not, !)
UnarySimpleExprImut: ImutExprRaw<'input> = {
/// TODO ask about change from PresenceSimplExprImut
/// also should include these on the same level as unary +, -?
<start:@L> "not" <expr:UnarySimpleExprImut> <end:@L> => ImutExprRaw::Unary(Box::new(UnaryExprRaw { kind: UnaryOpKind::Not, expr: expr, start, end })),
<start:@L> "!" <expr:UnarySimpleExprImut> <end:@L> => ImutExprRaw::Unary(Box::new(UnaryExprRaw { kind: UnaryOpKind::BitNot, expr: expr, start, end })),
PresenceSimplExprImut => <>,
}
/// Presence operations (present, absent)
PresenceSimplExprImut: ImutExprRaw<'input> = {
<start:@L> "present" <path:Path> <end:@L> => ImutExprRaw::Present{path, start, end},
/// TODO link to !?
<start:@L> "absent" <path:Path> <end:@L> => ImutExprRaw::Unary(Box::new(UnaryExprRaw { kind: UnaryOpKind::Not, expr: ImutExprRaw::Present{path, start, end}, start, end })),
SimpleExprImut => <>,
}
/// Immutable language constructs that can be used without having to worry about
/// sideefects
ComplexExprImut: ImutExprRaw<'input> = {
<pp:MatchImut> => ImutExprRaw::Match(Box::new(pp)),
<comprehension:ForImut> => ImutExprRaw::Comprehension(Box::new(comprehension)),
ExprImut => <>
}
Intrinsic: AnyFnRaw<'input> = {
<doc:DocComment> <start:@L> "intrinsic" "fn" <name:Ident> "(" ")" "as" <imod:Ident> "::" <ifn:Ident> <end:@L> => {
let invoce_args = vec![];
let invoke = InvokeRaw{
start,
end,
module: vec!["core".into(), imod.id.to_string()],
fun: ifn.id.to_string(),
args: invoce_args
};
let body = vec![ExprRaw::Imut(ImutExprRaw::Invoke(invoke))];
AnyFnRaw::Normal(FnDeclRaw{name, args: vec![], body, start, end, doc, open: false, inline: true})
},
<doc:DocComment> <start:@L> "intrinsic" "fn" <name:Ident> "(" <args:FnArgs> ")" "as" <imod:Ident> "::" <ifn:Ident> <end:@L> => {
let invoce_args = args.iter().map(|a|
ImutExprRaw::Path(
PathRaw::Local(
LocalPathRaw{start: a.start, end: a.end, segments: vec![SegmentRaw::from_id(a.clone())]}
))).collect();
let invoke = InvokeRaw{
start,
end,
module: vec!["core".into(), imod.id.to_string()],
fun: ifn.id.to_string(),
args: invoce_args
};
let body = vec![ExprRaw::Imut(ImutExprRaw::Invoke(invoke))];
AnyFnRaw::Normal(FnDeclRaw{name, args, body, start, end, doc, open: false, inline: true})
},
<doc:DocComment> <start:@L> "intrinsic" "fn" <name:Ident> "(" <args:FnArgs> "," "." "." "." ")" "as" <imod:Ident> "::" <ifn:Ident> <end:@L> => {
let invoce_args = args.iter().map(|a|
ImutExprRaw::Path(
PathRaw::Local(
LocalPathRaw{start: a.start, end: a.end, segments: vec![SegmentRaw::from_id(a.clone())]}
))).collect();
let invoke = InvokeRaw{
start,
end,
module: vec!["core".into(), imod.id.to_string()],
fun: ifn.id.to_string(),
args: invoce_args
};
let body = vec![ExprRaw::Imut(ImutExprRaw::Invoke(invoke))];
AnyFnRaw::Normal(FnDeclRaw{name, args, body, start, end, doc, open: true, inline: true})
},
<doc:DocComment> <start:@L> "intrinsic" "fn" <name:Ident> "(" "." "." "." ")" "as" <imod:Ident> "::" <ifn:Ident> <end:@L> => {
let args = vec![];
let invoce_args = vec![];
let invoke = InvokeRaw{
start,
end,
module: vec!["core".into(), imod.id.to_string()],
fun: ifn.id.to_string(),
args: invoce_args
};
let body = vec![ExprRaw::Imut(ImutExprRaw::Invoke(invoke))];
AnyFnRaw::Normal(FnDeclRaw{name, args, body, start, end, doc, open: true, inline: true})
},
}
Module: ModuleRaw<'input> = {
<start:@L> "mod" <name:Ident> "with" <doc:ModComment> <exprs:ModuleExprs> "end" <end:@L> => ModuleRaw{name, start, end, exprs, doc: doc},
}
/// List of expressions at the root of the script
ModuleExprs: ExprsRaw<'input> = {
<expr:ModuleExpr> ";" <list:ModuleExprs> => {
let mut list = list;
list.insert(0,expr);
list
},
<item:ModuleExpr> ";"? => vec![item],
}
ModuleExpr: ExprRaw<'input> = {
Const => <>,
FnDecl => ExprRaw::FnDecl(<>),
Intrinsic => ExprRaw::FnDecl(<>),
Module => ExprRaw::Module(<>),
}
FnDecl: AnyFnRaw<'input> = {
<doc:DocComment> <start:@L> "fn" <name:Ident> "(" "." "." "." ")" "with" <body:Exprs> "end" <end:@L> => AnyFnRaw::Normal(FnDeclRaw{name, args: vec![], body, start, end, doc, open: true, inline: false}),
<doc:DocComment> <start:@L> "fn" <name:Ident> "(" <args:FnArgs> "," "." "." "." ")" "with" <body:Exprs> "end" <end:@L> => AnyFnRaw::Normal(FnDeclRaw{name, args, body, start, end, doc, open: true, inline: false}),
<doc:DocComment> <start:@L> "fn" <name:Ident> "(" ")" "with" <body:Exprs> "end" <end:@L> => AnyFnRaw::Normal(FnDeclRaw{name, args: vec![], body, start, end, doc, open: false, inline: false}),
<doc:DocComment> <start:@L> "fn" <name:Ident> "(" <args:FnArgs> ")" "with" <body:Exprs> "end" <end:@L> => AnyFnRaw::Normal(FnDeclRaw{name, args, body, start, end, doc, open: false, inline: false}),
<doc:DocComment> <start:@L> "fn" <name:Ident> "(" ")" "of" <cases:FnCases> "end" <end:@L> => AnyFnRaw::Match(MatchFnDeclRaw{name, args: vec![], start, end, cases, doc, open: false, inline: false}),
<doc:DocComment> <start:@L> "fn" <name:Ident> "(" <args:FnArgs> ")" "of" <cases:FnCases> "end" <end:@L> => AnyFnRaw::Match(MatchFnDeclRaw{name, args, start, end, cases, doc, open: false, inline: false}),
}
FnCases: Vec<PredicateClauseRaw<'input>> = {
<cases:FnCaseClauses> <default:FnCaseDefault> => {
let mut cases = cases;
cases.push(default);
cases
},
<start:@L> <default:FnCaseDefault> => {
let mut cases = Vec::new();
cases.push(default);
cases
}
}
FnCaseDefault: PredicateClauseRaw<'input> = {
<start:@L> "default" <exprs:Effectors> <end:@L> => {
PredicateClauseRaw { pattern: PatternRaw::Default, exprs, guard: None, start, end}
}
}
FnCase: PredicateClauseRaw<'input> = {
<start:@L> "case" <pstart:@L> "(" <pattern:ArrayPredicatePatterns> ")" <guard:WhenClause> <pend:@L> <exprs:Effectors> <end:@L> => PredicateClauseRaw {
pattern: PatternRaw::Assign(AssignPatternRaw {
id: FN_RES_NAME.into(),
pattern: Box::new(PatternRaw::Tuple(TuplePatternRaw{exprs: pattern, start: pstart, end: pend, open: false}))
}),
exprs,
guard,
start,
end
},
}
FnCaseClauses: Vec<PredicateClauseRaw<'input>> = {
<e:FnCase> => vec![e],
<v:FnCaseClauses> <e:FnCase> => {
let mut v = v;
v.push(e);
v
},
}
FnArgs: Vec<IdentRaw<'input>> = {
<e:Ident> => vec![e],
<v:FnArgs> "," <e:Ident> => {
let mut v = v;
v.push(e);
v
},
}
SimpleExprImut: ImutExprRaw<'input> = {
"(" <expr:ComplexExprImut> ")" => expr,
AlwaysImutExpr => <>
}
////////////////////////////// Literals and semi literals //////////////////////////////
// This section covers literals (strings, nil, etc) and semi literals.
// At this stage Lists and Records are considered semi literals
// as we only decide in the next step if they are literals or include
// variables and need to get constructed during runtime.
/// Basic literals
Literal: LiteralRaw<'input> = {
<start:@L> <v:Nil> <end:@L> => LiteralRaw{value: v, start, end},
<start:@L> <v:Bool> <end:@L> => LiteralRaw{value: v, start, end},
<start:@L> <v:Int> <end:@L> => LiteralRaw{value: v, start, end},
<start:@L> <v:Float> <end:@L> => LiteralRaw{value: v, start, end},
}
/// null
Nil: Value<'input> = {
<literal:"nil"> => Value::null(),
}
/// booleans
Bool: Value<'input> = {
<literal:"bool"> => Value::from(literal),
}
/// integers
Int: Value<'input> = {
<literal:"int"> => Value::from(literal as i64),
}
/// floats
Float: Value<'input> = {
<literal:"float"> => Value::from(literal.0),
}
StringLiteral: StringLitRaw<'input> = {
<start:@L> <doc:"heredoc"> <end:@L> => StringLitRaw {
start,
end,
string: doc.join("\n").into(),
exprs: vec![],
},
<start:@L> "\"" <es:StrLitElements> "\"" <end:@L> => {
let mut sl: StringLitRaw = es.into();
sl.start = start;
sl.end = end;
sl
},
<start:@L> "\"" "\"" <end:@L> => {
StringLitRaw {
start,
end,
string: "".into(),
exprs: vec![],
}
},
}
StrLitElements: StrLitElements<'input> = {
<literal:StringPart> <es:StrLitElements> => {
let mut es = es;
es.0.push(literal);
es
},
"{" <expr:ExprImut> "}" <es:StrLitElements> => {
let mut es = es;
es.0.push("{}".into());
es.1.push(expr);
es
},
<literal:StringPart> => StrLitElements(vec![literal], vec![]),
"{" <expr:ExprImut> "}" => StrLitElements(vec!["{}".into()], vec![expr]),
}
StringPart: Cow<'input, str> = {
"string" => <>
}
/// array semi literals
List: ListRaw<'input> = {
<start:@L> "[" <exprs:ListElements> "]" <end:@L> => ListRaw{start, end, exprs},
<start:@L> "[" "]" <end:@L> => ListRaw{start, end, exprs: vec![]},
}
ListElements: ImutExprsRaw<'input> = {
<fields:ListElements_> => {
let mut fields = fields;
fields.reverse();
fields
},
}
ListElements_: ImutExprsRaw<'input> = {
<Sep<ListElements_, ComplexExprImut, ",">> => <>,
}
/// A semi literal record
Record: RecordRaw<'input> = {
<start:@L> "{" <fields:Fields> "}" <end:@L> => RecordRaw { fields: fields, start, end },
<start:@L> "{" "}" <end:@L> => RecordRaw { fields: vec![], start, end }
}
/// Fields for a static record
Field: FieldRaw<'input> = {
<start:@L> <name:StringLiteral> ":" <value:ComplexExprImut> <end:@L> => {
FieldRaw { name, value, start, end }
}
}
////////////////////////////// Path ////////////////////////////////////////
// Path define lookups of data that is in either local variable, metadata
// or the event.
/// A path into one of the scopes
Path: PathRaw<'input> = {
MetaPath => <>,
EventPath => <>,
StatePath => <>,
LocalPath => <>,
ConstPath => <>,
AggrPath => <>,
ArgsPath => <>,
}
/// A metadata path
MetaPath: PathRaw<'input> = {
<start:@L> "$" <segment:PathSegment> <segments:PathSegments> <end:@L> => {
let mut segments = segments;
segments.insert(0, segment);
PathRaw::Meta(MetadataPathRaw { segments, start, end })
},
<start:@L> "$" <segment:PathSegment> <end:@L> => {
PathRaw::Meta(MetadataPathRaw { segments: vec![segment], start, end })
},
<start:@L> "$" <end:@L> => PathRaw::Meta(MetadataPathRaw { segments: vec![], start, end }),
}
/// A window/group path
AggrPath: PathRaw<'input> = {
<start:@L> "group" <mid:@L> <segments:PathSegments> <end:@L> => {
let mut segments = segments;
segments.insert(0, SegmentRaw::from_str("group", start, mid));
PathRaw::Local(LocalPathRaw { segments, start, end })
},
<start:@L> "group" <end:@L> => PathRaw::Local(LocalPathRaw { segments: vec![SegmentRaw::from_str("group", start, end)], start, end }),
<start:@L> "window" <mid:@L> <segments:PathSegments> <end:@L> => {
let mut segments = segments;
segments.insert(0, SegmentRaw::from_str("window", start, mid));
PathRaw::Local(LocalPathRaw { segments, start, end })
},
<start:@L> "window" <end:@L> => PathRaw::Local(LocalPathRaw { segments: vec![SegmentRaw::from_str("window", start, end)], start, end }),
}
/// Arguments to a script or function
ArgsPath: PathRaw<'input> = {
<start:@L> "args" <mid:@L> <segments:PathSegments> <end:@L> => {
let mut segments = segments;
segments.insert(0, SegmentRaw::from_str("args", start, mid));
PathRaw::Local(LocalPathRaw { segments, start, end })
},
<start:@L> "args" <end:@L> => PathRaw::Local(LocalPathRaw { segments: vec![SegmentRaw::from_str("args", start, end)], start, end }),
}
/// Local path
LocalPath: PathRaw<'input> = {
<start:@L> <segment:PathSegment> <segments:PathSegments> <end:@L> => {
let mut segments = segments;
segments.insert(0, segment);
PathRaw::Local(LocalPathRaw { segments, start, end })
},
<start:@L> <segment:PathSegment> <end:@L> => {
PathRaw::Local(LocalPathRaw { segments: vec![segment], start, end })
},
}
/// Local path
ConstPath: PathRaw<'input> = {
<start:@L> <module:ModPath> "::" <path:LocalPath> <end:@L> => {
if let PathRaw::Local(LocalPathRaw { segments, .. }) = path {
PathRaw::Const(ConstPathRaw { module, segments, start, end })
} else {
unreachable!()
}
},
}
/// State path
StatePath: PathRaw<'input> = {
<start:@L> "state" <segments:PathSegments> <end:@L> => PathRaw::State(StatePathRaw { segments, start, end }),
<start:@L> "state" <end:@L> => PathRaw::State(StatePathRaw { segments: vec![], start, end }),
}
/// Event path
EventPath: PathRaw<'input> = {
<start:@L> "event" <segments:PathSegments> <end:@L> => PathRaw::Event(EventPathRaw { segments, start, end }),
<start:@L> "event" <end:@L> => PathRaw::Event(EventPathRaw { segments: vec![], start, end }),
}
/// Segments of a path
PathSegments: SegmentsRaw<'input> = {
"." <segment:PathSegment> <segments:PathSegments> => {
let mut segments = segments;
segments.insert(0, segment);
segments
},
"[" <selector:Selector> "]" <segments:PathSegments> => {
let mut segments = segments;
segments.insert(0, selector);
segments
},
"[" <selector:Selector> "]" => vec![selector],
"." <segment:PathSegment> => vec![segment],
}
/// Singular part of a path
PathSegment: SegmentRaw<'input> = {
<id:Ident> => SegmentRaw::from_id(id),
}
/// A path selector aka [...]
Selector: SegmentRaw<'input> = {
<start_lower:@L> <range_start:ComplexExprImut> <end_lower:@L> ":" <start_upper:@L> <range_end:ComplexExprImut> <end_upper:@L> => SegmentRaw::Range(Box::new(SegmentRangeRaw{range_start, range_end, start_lower, end_lower, start_upper, end_upper})),
<start:@L> <expr:ComplexExprImut> <end:@L> => SegmentRaw::Element(Box::new(SegmentElementRaw{expr, start, end})),
}
////////////////////////////// Function invocations //////////////////////////////
// Function invocations consist of a module, function name and an
// argument list.
/// Function invocation
Invoke: InvokeRaw<'input> = {
<start:@L> <fun:FunctionName> "(" <args:InvokeArgs> ")" <end:@L> => InvokeRaw { module: fun.0, fun: fun.1, args, start, end },
<start:@L> <fun:FunctionName> "(" ")" <end:@L> => InvokeRaw { module: fun.0, fun: fun.1, args: vec![], start, end },
}
FunctionName: (Vec<String>, String) = {
<fun:Ident> => (vec![], fun.id.to_string()),
<p:ModPath> "::" <fun:Ident> => (p.iter().map(|i| i.id.to_string()).collect(), fun.id.to_string()),
}
ModPath: Vec<IdentRaw<'input>> = {
<v:ModPath> "::" <e:Ident> => {
let mut v = v;
v.push(e);
v
},
<e:Ident> => vec![e],
}
InvokeArgs: ImutExprsRaw<'input> = {
<fields:InvokeArgs_> => {
let mut fields = fields;
fields.reverse();
fields
},
}
InvokeArgs_: ImutExprsRaw<'input> = {
<Sep<InvokeArgs_, ComplexExprImut, ",">> => <>,
}
////////////////////////////// Terminal expressions //////////////////////////////
// These expressions terminate execution.
/// drop the current event.
Drop: ExprRaw<'input> = {
<start:@L> "drop" <end:@L> => ExprRaw::Drop{start, end } ,
}
/// emits the current event to a given output
Emit: ExprRaw<'input> = {
<start:@L> "emit" <expr:ComplexExprImut> "=>" <port:StringLiteral> <end:@L> => ExprRaw::Emit(Box::new(EmitExprRaw { expr: expr, start, end, port: Some(ImutExprRaw::String(port)) })),
<start:@L> "emit" <expr:ComplexExprImut> <end:@L> => ExprRaw::Emit(Box::new(EmitExprRaw { expr: expr, start, end, port: None })),
<start:@L> "emit" "=>" <port:StringLiteral> <end:@L> => ExprRaw::Emit(Box::new(EmitExprRaw { expr: ImutExprRaw::Path(PathRaw::Event(EventPathRaw { segments: vec![], start, end })).into(), start, end, port: Some(ImutExprRaw::String(port)) })) ,
<start:@L> "emit" <end:@L> => ExprRaw::Emit(Box::new(EmitExprRaw { expr: ImutExprRaw::Path(PathRaw::Event(EventPathRaw { segments: vec![], start, end })).into(), start, end, port: None })),
}
////////////////////////////// Let expression //////////////////////////////
// An expression that assigns a value to a variable
/// Let expression to assign values
Let: ExprRaw<'input> = {
<start:@L> "let" <expr:Assignment> <end:@L> => expr, // Expr::Let(Let { exprs: vec![expr], start, end }),
}
Assignment: ExprRaw<'input> = {
<start:@L> <path:Path> @L "=" @R <expr:SimpleExpr> <end:@L> => ExprRaw::Assign(Box::new(AssignRaw { path, expr: expr, start, end })),
}
////////////////////////////// patch expression //////////////////////////////
// Patches a input value with a set of instructions
Patch: PatchRaw<'input> = {
// NOTE: ASSUMPTION array and literal targets are banned
<start:@L> "patch" <target:ComplexExprImut> <end:@L> "of" <operations:PatchOperations> "end" => PatchRaw { target, operations, start, end }
}
PatchOperations: PatchOperationsRaw<'input> = {
<e:PatchOperationClause> => vec![e],
<v:PatchOperations> "," <e:PatchOperationClause> => {
let mut v = v;
v.push(e);
v
}
}
PatchField: ImutExprRaw<'input> = {
ComplexExprImut => <>
}
PatchOperationClause: PatchOperationRaw<'input> = {
"insert" <ident:PatchField> "=>" <expr:ComplexExprImut> => PatchOperationRaw::Insert{ ident, expr },
"upsert" <ident:PatchField> "=>" <expr:ComplexExprImut> => PatchOperationRaw::Upsert{ ident, expr },
"update" <ident:PatchField> "=>" <expr:ComplexExprImut> => PatchOperationRaw::Update{ ident, expr },
"erase" <ident:PatchField> => PatchOperationRaw::Erase{ ident },
"move" <from:PatchField> "=>" <to:PatchField> => PatchOperationRaw::Move{ from, to },
"copy" <from:PatchField> "=>" <to:PatchField> => PatchOperationRaw::Copy{ from, to },
"merge" <ident:PatchField> "=>" <expr:ComplexExprImut> => PatchOperationRaw::Merge { ident, expr },
"merge" "=>" <expr:ComplexExprImut> => PatchOperationRaw::TupleMerge { expr },
}
////////////////////////////// merge expression //////////////////////////////
// Merges a perge spec (record) into the target
Merge: MergeRaw<'input> = {
<start:@L> "merge" <target:ComplexExprImut> "of" <expr:ComplexExprImut> "end" <end:@L> => MergeRaw { target, expr, start, end }
}
////////////////////////////// for comprehension (mut) //////////////////////////////
// Merges a perge spec (record) into the target
For: ComprehensionRaw<'input> = {
<start:@L> "for" <target:ComplexExprImut> "of" <cases:ForCaseClauses> "end" <end:@L> => ComprehensionRaw{target, cases, start, end},
}
ForCaseClauses: ComprehensionCasesRaw<'input> = {
<e:ForCaseClause> => vec![e],
<v:ForCaseClauses> <e:ForCaseClause> => {
let mut v = v;
v.push(e);
v
}
}
ForCaseClause: ComprehensionCaseRaw<'input> = {
"case" <start:@L> "(" <k:Ident> "," <v:Ident> ")" <end:@L> <guard:WhenClause> <exprs:Effectors> => ComprehensionCaseRaw { key_name: k.id, value_name: v.id, exprs, guard, start, end },
}
// ////////////////////////////// for comprehension (imutmut) //////////////////////////////
// // Merges a perge spec (record) into the target
ForImut: ImutComprehensionRaw<'input> = {
<start:@L> "for" <target:ComplexExprImut> "of" <cases:ForCaseClausesImut> "end" <end:@L> => ImutComprehensionRaw{target, cases, start, end},
}
ForCaseClausesImut: ImutComprehensionCasesRaw<'input> = {
<e:ForCaseClauseImut> => vec![e],
<v:ForCaseClausesImut> <e:ForCaseClauseImut> => {
let mut v = v;
v.push(e);
v
}
}
ForCaseClauseImut: ImutComprehensionCaseRaw<'input> = {
"case" <start:@L> "(" <k:Ident> "," <v:Ident> ")" <end:@L> <guard:WhenClause> <exprs:EffectorsImut> => ImutComprehensionCaseRaw { key_name: k.id, value_name: v.id, exprs, guard, start, end },
}
////////////////////////////// match expression (mutating) //////////////////////////////
// An expression that assigns a value to a variable
/// A match expression
Match: MatchRaw<'input> = {
<start:@L> "match" <target:ComplexExprImut> "of" <patterns:Predicates> "end" <end:@L> => MatchRaw { target, patterns, start, end },
}
/// Predicates for a match statement (aka list of case statements)
Predicates: PredicatesRaw<'input> = {
<e:PredicateClause> => vec![e],
<v:Predicates> <e:PredicateClause> => {
let mut v = v;
v.push(e);
v
}
}
/// A case statement
PredicateClause: PredicateClauseRaw<'input> = {
<start:@L> "case" <rp:RecordCaseClause> <guard:WhenClause> <exprs:Effectors> <end:@L> => PredicateClauseRaw { pattern: rp, exprs, guard, start, end },
<start:@L> "case" <ap:ArrayCaseClause> <guard:WhenClause> <exprs:Effectors> <end:@L> => PredicateClauseRaw { pattern: ap, exprs, guard, start, end },
<start:@L> "case" <tp:TupleCaseClause> <guard:WhenClause> <exprs:Effectors> <end:@L> => PredicateClauseRaw { pattern: tp, exprs, guard, start, end },
<start:@L> "case" <lhs:ExprCaseClause> <guard:WhenClause> <rhs:Effectors> <end:@L> => PredicateClauseRaw { pattern: lhs, exprs: rhs, guard, start, end},
<start:@L> "case" "_" <guard:WhenClause> <rhs:Effectors> <end:@L> => PredicateClauseRaw { pattern: PatternRaw::DoNotCare, exprs: rhs, guard, start, end},
<start:@L> "default" <exprs:Effectors> <end:@L> => PredicateClauseRaw { pattern: PatternRaw::Default, exprs, guard: None, start, end },
}
/// Effoectors aka (=> ... )
Effectors: ExprsRaw<'input> = {
"=>" <exprs:Block> => exprs
}
/// The effectors for a case statement
Block: ExprsRaw<'input> = {
<e:Expr> => vec![e],
<v:Block> "," <e:Expr> => {
let mut v = v;
v.push(e);
v
}
}
////////////////////////////// match expression (non mutating) //////////////////////////////
// An expression that assigns a value to a variable
/// A match expression
MatchImut: ImutMatchRaw<'input> = {
<start:@L> "match" <target:ComplexExprImut> "of" <patterns:PredicatesImut> "end" <end:@L> => ImutMatchRaw { target, patterns, start, end },
}
/// Predicates for a match statement (aka list of case statements)
PredicatesImut: ImutPredicatesRaw<'input> = {
<e:PredicateClauseImut> => vec![e],
<v:PredicatesImut> <e:PredicateClauseImut> => {
let mut v = v;
v.push(e);
v
}
}
/// A case statement
PredicateClauseImut: ImutPredicateClauseRaw<'input> = {
<start:@L> "case" <rp:RecordCaseClause> <guard:WhenClause> <exprs:EffectorsImut> <end:@L> => ImutPredicateClauseRaw { pattern: rp, exprs, guard, start, end },
<start:@L> "case" <ap:ArrayCaseClause> <guard:WhenClause> <exprs:EffectorsImut> <end:@L> => ImutPredicateClauseRaw { pattern: ap, exprs, guard, start, end },
<start:@L> "case" <tp:TupleCaseClause> <guard:WhenClause> <exprs:EffectorsImut> <end:@L> => ImutPredicateClauseRaw { pattern: tp, exprs, guard, start, end },
<start:@L> "case" <lhs:ExprCaseClause> <guard:WhenClause> <rhs:EffectorsImut> <end:@L> => ImutPredicateClauseRaw { pattern: lhs, exprs: rhs, guard, start, end},
<start:@L> "default" <exprs:EffectorsImut> <end:@L> => ImutPredicateClauseRaw { pattern: PatternRaw::Default, exprs, guard: None, start, end },
}
/// Effoectors aka (=> ... )
EffectorsImut: ImutExprsRaw<'input> = {
"=>" <exprs:BlockImut> => exprs
}
/// The effectors for a case statement
BlockImut: ImutExprsRaw<'input> = {
<e:ComplexExprImut> => vec![e],
<v:BlockImut> "," <e:ComplexExprImut> => {
let mut v = v;
v.push(e);
v
}
}
////////////////////////////// match expression (shared) //////////////////////////////
// An expression that assigns a value to a variable
/// A record pattern aka [name = ] %{...}
RecordCaseClause: PatternRaw<'input> = {
<start:@L> <segment:Ident> "=" <rp:RecordPattern> <end:@L> => PatternRaw::Assign(AssignPatternRaw { id: segment.id, pattern: Box::new(PatternRaw::Record(rp)) }),
<rp:RecordPattern> => PatternRaw::Record(rp),
}
/// A array pattern aka [name = ] %[...]
ArrayCaseClause: PatternRaw<'input> = {
<start:@L> <segment:Ident> "=" <ap:ArrayPattern> <end:@L> => PatternRaw::Assign(AssignPatternRaw { id:segment.id, pattern: Box::new(PatternRaw::Array(ap)) }),
<ap:ArrayPattern> => PatternRaw::Array(ap),
}
/// A array pattern aka [name = ] %[...]
TupleCaseClause: PatternRaw<'input> = {
<start:@L> <segment:Ident> "=" <tp:TuplePattern> <end:@L> => PatternRaw::Assign(AssignPatternRaw { id:segment.id, pattern: Box::new(PatternRaw::Tuple(tp)) }),
<tp:TuplePattern> => PatternRaw::Tuple(tp),
}
/// An expression clause aka [name = ] <expr>
ExprCaseClause: PatternRaw<'input> = {
<start:@L> <segment:Ident> "=" <expr:ComplexExprImut> <end:@L> => PatternRaw::Assign(AssignPatternRaw { id: segment.id, pattern: Box::new(PatternRaw::Expr(expr)) }),
<expr:ComplexExprImut> => PatternRaw::Expr(expr),
}
/// When part of an expression (when ...)
WhenClause: Option<ImutExprRaw<'input>> = {
("when" <ComplexExprImut>)? => <>,
}
/// Predicate Patterns (aka tests) for record pattrens
PredicateFieldPattern: PredicatePatternRaw<'input> = {
<start:@L> <lhs:Ident> <op:"~="> <expr:TestExpr> <end:@L> => PredicatePatternRaw::TildeEq { assign: lhs.id.clone(), lhs: lhs.id, test: expr},
<start:@L> <assign:Ident> "=" <lhs:Ident> <op:"~="> <expr:TestExpr> <end:@L> => PredicatePatternRaw::TildeEq { assign: assign.id, lhs: lhs.id, test: expr} ,
<start:@L> <lhs:Ident> <op:"~="> <rp:RecordPattern> <end:@L> => PredicatePatternRaw::RecordPatternEq { lhs: lhs.id, pattern: rp },
<start:@L> <lhs:Ident> <op:"~="> <ap:ArrayPattern> <end:@L> => PredicatePatternRaw::ArrayPatternEq { lhs: lhs.id, pattern: ap },
<start:@L> "present" <lhs:Ident> <end:@L> => PredicatePatternRaw::FieldPresent { lhs: lhs.id },
<start:@L> "absent" <lhs:Ident> <end:@L> => PredicatePatternRaw::FieldAbsent { lhs: lhs.id },
<lhs:Ident> <kind:BinCmpEq> <expr:ComplexExprImut> => PredicatePatternRaw::Bin { lhs: lhs.id, rhs: expr, kind },
}
TestExpr: TestExprRaw = {
<start:@L> <id:Ident> <tl:TestLiteral> <end:@L> => {
TestExprRaw { id: id.id.to_string(), test: tl, start, end}
},
}
RecordPattern: RecordPatternRaw<'input> = {
<start:@L> "%{" <fields:PatternFields> "}" <end:@L> => RecordPatternRaw { fields: fields, start, end },
<start:@L> "%{" "}" <end:@L> => RecordPatternRaw { fields: vec![], start, end },
}
ArrayPattern: ArrayPatternRaw<'input> = {
<start:@L> "%[" <exprs:ArrayPredicatePatterns> "]" <end:@L> => ArrayPatternRaw { exprs, start, end },
<start:@L> "%[" "]" <end:@L> => ArrayPatternRaw { exprs: vec![], start, end },
}
TuplePattern: TuplePatternRaw<'input> = {
<start:@L> "%(" <exprs:TuplePredicatePatterns> <open:OpenTuple> ")" <end:@L> => TuplePatternRaw { exprs, start, end, open },
<start:@L> "%(" ")" <end:@L> => TuplePatternRaw { exprs: vec![], start, end, open: false },
<start:@L> "%(" "." "." "." ")" <end:@L> => TuplePatternRaw { exprs: vec![], start, end, open: true },
}
OpenTuple: bool = {
("," "." "." ".")? => <>.is_some()
}
TuplePredicatePatterns: ArrayPredicatePatternsRaw<'input> = {
<list:TuplePredicatePatterns> "," <item:TuplePredicatePattern> => {
let mut list = list;
list.push(item);
list
},
TuplePredicatePattern => vec![<>],
}
TuplePredicatePattern: ArrayPredicatePatternRaw<'input> = {
ArrayPredicatePattern => <>,
"_" => ArrayPredicatePatternRaw::Ignore,
}
ArrayPredicatePattern: ArrayPredicatePatternRaw<'input> = {
"~" <test:TestExpr> => ArrayPredicatePatternRaw::Tilde(test),
ComplexExprImut => ArrayPredicatePatternRaw::Expr(<>),
RecordPattern => ArrayPredicatePatternRaw::Record(<>),
}
ArrayPredicatePatterns: ArrayPredicatePatternsRaw<'input> = {
<list:ArrayPredicatePatterns> "," <item:ArrayPredicatePattern> => {
let mut list = list;
list.push(item);
list
},
ArrayPredicatePattern => vec![<>],
}
PatternFields: PatternFieldsRaw<'input> = {
<fields:PatternFields_> => {
let mut fields = fields;
fields.reverse();
fields
},
}
PatternFields_: PatternFieldsRaw<'input> = {
<fields:Sep<PatternFields_, PredicateFieldPattern, ",">> => fields,
}
Fields: FieldsRaw<'input> = {
<fields:Fields_> => {
let mut fields = fields;
fields.reverse();
fields
},
}
Fields_: FieldsRaw<'input> = {
<fields:Sep<Fields_, Field, ",">> => fields,
}
#[inline]
Ident: IdentRaw<'input> = {
<start:@L> <name:"<ident>"> <end:@L> => IdentRaw { id: name.0, start, end },
}
#[inline]
TestLiteral: String = {
"<extractor>" => <>.join(""),
}
Sep<L, T, D>: L = {
<item:T> D <list:L> => {
let mut list = list;
list.push(item);
list
},
<item:T> D? => vec![item],
}
/// Generic helper for binary operations
#[inline]
BinOp<Op, Current, Next>: ImutExprRaw<'input> = {
<start:@L> <lhs:(<Current>)> <op:(<Op>)> @L <rhs:Next> <end:@L> => ImutExprRaw::Binary(Box::new(BinExprRaw {
kind: op,
lhs: lhs,
rhs: rhs,
start,
end,
})),
}
BinCmpEq: BinOpKind = {
BinEq => <>,
BinCmp => <>
}
BinOr: BinOpKind = {
"or" => BinOpKind::Or,
}
BinXor: BinOpKind = {
"xor" => BinOpKind::Xor,
}
BinAnd: BinOpKind = {
"and" => BinOpKind::And,
}
BinBitOr: BinOpKind = {
"|" => BinOpKind::BitOr,
}
BinBitXor: BinOpKind = {
"^" => BinOpKind::BitXor,
}
BinBitAnd: BinOpKind = {
"&" => BinOpKind::BitAnd,
}
BinEq: BinOpKind = {
"==" => BinOpKind::Eq,
"!=" => BinOpKind::NotEq,
}
BinCmp: BinOpKind = {
">=" => BinOpKind::Gte,
">" => BinOpKind::Gt,
"<=" => BinOpKind::Lte,
"<" => BinOpKind::Lt,
}
BinBitShift: BinOpKind = {
">>" => BinOpKind::RBitShiftSigned,
">>>" => BinOpKind::RBitShiftUnsigned,
"<<" => BinOpKind::LBitShift,
}
BinAdd: BinOpKind = {
"+" => BinOpKind::Add,
"-" => BinOpKind::Sub,
}
BinMul: BinOpKind = {
"*" => BinOpKind::Mul,
"/" => BinOpKind::Div,
"%" => BinOpKind::Mod,
}
extern {
type Location = Location;
type Error = crate::errors::Error;
enum Token<'input> {
"<mod-comment>" => Token::ModComment(<&'input str>),
"<doc-comment>" => Token::DocComment(<&'input str>),
"<single-line-comment>" => Token::SingleLineComment(<&'input str>),
"let" => Token::Let,
"const" => Token::Const,
"match" => Token::Match,
"of" => Token::Of,
"end" => Token::End,
"case" => Token::Case,
"when" => Token::When,
"for" => Token::For,
"nil" => Token::Nil,
"and" => Token::And,
"or" => Token::Or,
"xor" => Token::Xor,
"not" => Token::Not,
"drop" => Token::Drop,
"emit" => Token::Emit,
"default" => Token::Default,
"patch" => Token::Patch,
"insert" => Token::Insert,
"upsert" => Token::Upsert,
"update" => Token::Update,
"erase" => Token::Erase,
"move" => Token::Move,
"copy" => Token::Copy,
"merge" => Token::Merge,
"event" => Token::Event,
"state" => Token::State,
"present" => Token::Present,
"absent" => Token::Absent,
"fn" => Token::Fun,
"intrinsic" => Token::Intrinsic,
"mod" => Token::Module,
"." => Token::Dot,
"\"" => Token::DQuote,
";" => Token::Semi,
"::" => Token::ColonColon,
":" => Token::Colon,
"," => Token::Comma,
"=" => Token::Eq,
"_" => Token::DontCare,
"==" => Token::EqEq,
"!=" => Token::NotEq,
"{" => Token::LBrace,
"}" => Token::RBrace,
"(" => Token::LParen,
")" => Token::RParen,
"." => Token::Dot,
"$" => Token::Dollar,
"=>" => Token::EqArrow,
"[" => Token::LBracket,
"]" => Token::RBracket,
">=" => Token::Gte,
">" => Token::Gt,
"<=" => Token::Lte,
"<" => Token::Lt,
">>" => Token::RBitShiftSigned,
">>>" => Token::RBitShiftUnsigned,
"<<" => Token::LBitShift,
"!" => Token::BitNot,
"|" => Token::BitOr,
"^" => Token::BitXor,
"&" => Token::BitAnd,
"+" => Token::Add,
"-" => Token::Sub,
"*" => Token::Mul,
"/" => Token::Div,
"%(" => Token::LPatParen,
"%[" => Token::LPatBracket,
"%{" => Token::LPatBrace,
"%" => Token::Mod,
"~=" => Token::TildeEq,
"~" => Token::Tilde,
"bool" => Token::BoolLiteral(<bool>),
"int" => Token::IntLiteral(<i64>),
"float" => Token::FloatLiteral(<f64>, <String>),
"string" => Token::StringLiteral(<Cow<'input, str>>),
"heredoc" => Token::HereDoc(_, <Vec<String>>),
"<extractor>" => Token::TestLiteral(_, <Vec<String>>),
"<ident>" => Token::Ident(<Cow<'input, str>>, <bool>),
"<error>" => Token::Bad(<String>),
"<end-of-stream>" => Token::EndOfStream,
"select" => Token::Select,
"from" => Token::From,
"into" => Token::Into,
"create" => Token::Create,
"tumbling" => Token::Tumbling,
"sliding" => Token::Sliding,
"window" => Token::Window,
"stream" => Token::Stream,
"operator" => Token::Operator,
"where" => Token::Where,
"with" => Token::With,
"script" => Token::Script,
"having" => Token::Having,
"group" => Token::Group,
"by" => Token::By,
"define" => Token::Define,
"args" => Token::Args,
"recur" => Token::Recur,
"set" => Token::Set,
"each" => Token::Each,
"use" => Token::Use,
"as" => Token::As,
"#!config" => Token::ConfigDirective,
}
}