use symbol::Symbol;
use ast::{Literal, Op, Pattern, PrintStyle};
use cst::{Decl, Expr};
use eval::{CallByName, CallByValue, LazyEvaluation};
use repl::ReplCommand;
grammar;
pub ReplCommand: ReplCommand = {
<e: Expr> ";;"? => ReplCommand::Expr(e),
":ast" => ReplCommand::PrintStyle(PrintStyle::AST),
":cbn" => ReplCommand::Evaluator(|decls| Box::new(CallByName::new(decls))),
":cbv" => ReplCommand::Evaluator(|decls| Box::new(CallByValue::new(decls))),
":cst" => ReplCommand::PrintStyle(PrintStyle::CST),
":decl" <d: Decl> ";;"? => ReplCommand::Decl(d),
":help" => ReplCommand::Help,
":l" => ReplCommand::List,
":lazy" => ReplCommand::Evaluator(|decls| Box::new(LazyEvaluation::new(decls))),
":list" => ReplCommand::List,
":q" => ReplCommand::Quit,
":quit" => ReplCommand::Quit,
":reset" => ReplCommand::Reset,
":t" <e: Expr> => ReplCommand::Typeof(e),
};
pub Decls = DeclSemicolons*;
DeclSemicolons: Decl =
<d: Decl> ";;" => d;
pub Decl: Decl =
<name: Name> <args: Pattern2*> "=" <body: Expr> => Decl { name, args, body };
pub Expr: Expr = {
"if" <c: Expr> "then" <t: Expr> "else" <e: Expr> =>
Expr::If(Box::new(c), Box::new(t), Box::new(e)),
<l: Expr2> "::" <r: Expr> => Expr::Op(Op::Cons, Box::new(l), Box::new(r)),
Expr2,
};
Expr2: Expr = {
<l: Expr2> "+" <r: Expr3> => Expr::Op(Op::Add, Box::new(l), Box::new(r)),
<l: Expr2> "-" <r: Expr3> => Expr::Op(Op::Sub, Box::new(l), Box::new(r)),
Expr3,
};
Expr3: Expr = {
<l: Expr3> "*" <r: Expr4> => Expr::Op(Op::Mul, Box::new(l), Box::new(r)),
<l: Expr3> "/" <r: Expr4> => Expr::Op(Op::Div, Box::new(l), Box::new(r)),
<l: Expr3> "mod" <r: Expr4> => Expr::Op(Op::Mod, Box::new(l), Box::new(r)),
Expr4,
};
Expr4: Expr = {
<f: Expr4> <a: Expr5> => Expr::Op(Op::App, Box::new(f), Box::new(a)),
Expr5,
}
Expr5: Expr = {
"(" <e: Expr> ")" => e,
Name => Expr::Variable(<>),
Literal => Expr::Literal(<>),
"[" <h: Expr> <t: SemicolonExpr*> "]" => {
let mut l = t;
l.insert(0, h);
Expr::List(l)
},
};
SemicolonExpr: Expr = ";" <e: Expr> => e;
Pattern: Pattern<()> = {
<l: Pattern2> "::" <r: Pattern> => Pattern::Cons(Box::new(l), Box::new(r), ()),
Pattern2,
};
Pattern2: Pattern<()> = {
"(" <p: Pattern> ")" => p,
Name => Pattern::Binding(<>, ()),
Literal => Pattern::Literal(<>, ()),
};
Literal: Literal = {
"[" "]" => Literal::Nil,
"false" => Literal::False,
"true" => Literal::True,
<s: r"[0-9]+"> => Literal::Int(s.parse().unwrap()),
};
Name: Symbol = <name: r"[a-zA-Z_][0-9a-zA-Z_]*"> => {
if name == "_" {
warn!("_ is a valid variable name, not the wildcard pattern");
warn!("Instead, prefer _0, _1, etc.");
}
Symbol::from(name)
};