evaltrees 0.1.0

A simple term-rewriting interpreter that displays intermediate expressions.
Documentation
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)
};