use std::borrow::Cow;
use serde_json::{Number, Value};
use super::super::{ast, lexer};
grammar<'i>;
extern {
type Location = lexer::Pos;
enum lexer::Token<'i> {
Fragment => lexer::Token::Fragment(<Cow<'i, str>>),
"}}" => lexer::Token::BlockEnd,
"elif" => lexer::Token::KwElif,
"else" => lexer::Token::KwElse,
"end" => lexer::Token::KwEnd,
"false" => lexer::Token::KwFalse,
"if" => lexer::Token::KwIf,
"let" => lexer::Token::KwLet,
"nil" => lexer::Token::KwNil,
"put" => lexer::Token::KwPut,
"then" => lexer::Token::KwThen,
"true" => lexer::Token::KwTrue,
"." => lexer::Token::Dot,
"!" => lexer::Token::Bang,
"," => lexer::Token::Comma,
"|!" => lexer::Token::PipeBang,
"|" => lexer::Token::Pipe,
"??" => lexer::Token::Coalesce,
"(" => lexer::Token::LParen,
")" => lexer::Token::RParen,
"[" => lexer::Token::LBrack,
"]" => lexer::Token::RBrack,
"||" => lexer::Token::Or,
"&&" => lexer::Token::And,
"==" => lexer::Token::Eq,
"!=" => lexer::Token::Neq,
"<" => lexer::Token::Lt,
">" => lexer::Token::Gt,
"<=" => lexer::Token::Le,
">=" => lexer::Token::Ge,
"$" => lexer::Token::Dollar,
":=" => lexer::Token::Declare,
Ident => lexer::Token::Ident(<&'i str>),
Number => lexer::Token::Number(<Number>),
String => lexer::Token::String(<String>),
}
}
pub Format: ast::Format<'i> = <Segment*> => ast::Format(<>);
pub FormatExtended: ast::FormatExtended<'i> = <Command*> => ast::FormatExtended(<>);
Segment: ast::Segment<'i> = {
Fragment => ast::Segment::Fragment(<>),
"}}" => ast::Segment::Blank,
<If<("}}" <Segment*>)>> => ast::Segment::If(<>),
<Let> "}}" => ast::Segment::Let(<>),
<Expr> "}}" => ast::Segment::Expr(<>),
};
Command: ast::Command<'i> = {
<If<Command*>> => ast::Command::If(<>),
<Let> => ast::Command::Let(<>),
"put" <l:(<Expr> ",")*> <r:Expr> => ast::Command::Put(l, r),
};
If<T>: ast::If<'i, T> = <i:IfGuard<T>> <l:ElifGuard<T>*> <e:Else<T>?> Endif => ast::If(i, l, e);
IfGuard<T>: ast::Guard<'i, T> = <c:IfPream> <t:T> => ast::Guard(c, t);
ElifGuard<T>: ast::Guard<'i, T> = <c:ElifPream> <t:T> => ast::Guard(c, t);
Else<T> = ElsePream <T>;
IfPream = "if" <Expr>;
ElifPream = "elif" <Expr>;
ElsePream = "else";
Endif = "end";
Let: ast::Let<'i> = "let" <i:Ident> ":=" <e:Expr> => ast::Let(i, e);
Expr: ast::Expr<'i> = {
Ternary => ast::Expr::Ternary(Box::new(<>)),
NullChain => ast::Expr::Next(Box::new(<>)),
};
Ternary: ast::Ternary<'i> = <i:IfGuard<("then" <Expr>)>> <e:Else<Expr>> => ast::Ternary(i, e);
NullChain: ast::NullChain<'i> = {
<l:NullChain> "??" <r:NullPipeline> => ast::NullChain::Chain(Box::new(l), r),
NullPipeline => ast::NullChain::Next(<>),
};
NullPipeline: ast::NullPipeline<'i> = {
<l:NullPipeline> "|!" <r:Pipeline> => ast::NullPipeline::Bang(Box::new(l), r),
Pipeline => ast::NullPipeline::Next(<>),
};
Pipeline: ast::Pipeline<'i> = {
<l:Pipeline> "|" <r:Binop> => ast::Pipeline::Pipe(Box::new(l), r),
Binop => ast::Pipeline::Next(<>),
};
Binop = Or;
Or: ast::Or<'i> = {
<l:And> "||" <r:Or> => ast::Or::Or(l, Box::new(r)),
And => ast::Or::Next(<>),
};
And: ast::And<'i> = {
<l:Compare> "&&" <r:And> => ast::And::And(l, Box::new(r)),
Compare => ast::And::Next(<>),
};
Compare: ast::Compare<'i> = {
<l:Unop> "==" <r:Unop> => ast::Compare::Eq(l, r),
<l:Unop> "!=" <r:Unop> => ast::Compare::Neq(l, r),
<l:Unop> "<" <r:Unop> => ast::Compare::Lt(l, r),
<l:Unop> ">" <r:Unop> => ast::Compare::Gt(l, r),
<l:Unop> "<=" <r:Unop> => ast::Compare::Le(l, r),
<l:Unop> ">=" <r:Unop> => ast::Compare::Ge(l, r),
Unop => ast::Compare::Next(<>),
};
Unop: ast::Unop<'i> = {
"!" <Unop> => ast::Unop::Not(Box::new(<>)),
Value => ast::Unop::Next(<>),
};
Value = Member;
Member: ast::Member<'i> = {
<l:Member> "." <r:Ident> => ast::Member::Dot(Box::new(l), r),
<l:Member> "[" <r:Expr> "]" => ast::Member::Index(Box::new(l), r),
Prim => ast::Member::Next(<>),
};
Prim: ast::Prim<'i> = {
"(" <Expr> ")" => ast::Prim::Paren(<>),
"." <Ident> => ast::Prim::LensIdent(<>),
"." "[" <Expr> "]" => ast::Prim::LensIndex(<>),
<Ident> "(" <Args?> ")" => ast::Prim::Call(<>),
"[" <Args?> "]" => ast::Prim::Array(<>),
"nil" => ast::Prim::Value(Value::Null),
"true" => ast::Prim::Value(true.into()),
"false" => ast::Prim::Value(false.into()),
Ident => ast::Prim::Ident(<>),
Number => ast::Prim::Value(<>.into()),
String => ast::Prim::Value(<>.into()),
};
Args: ast::Args<'i> = <l:(<Arg> ",")*> <r:Arg> => ast::Args(l, r);
Arg: ast::Arg<'i> = {
<Expr> "!" => ast::Arg::Coerce(<>),
Expr => ast::Arg::Expr(<>),
};