empress 3.0.3

A D-Bus MPRIS daemon for controlling media players.
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(<>),
};