use super::{Program, SExpr, Term};
use super::SExpr::{Func, RuleOp};
use super::Term::{Constant, Variable, ExprTerm, Num};

#[pub]
program -> Program
    = __ exprs:sexpr* { Program { sexprs: exprs } }

sexpr -> SExpr
    = lparen e:func rparen { e }
    / lparen e:rule_op rparen { e }
    / e:func { e }

rule_op -> SExpr
    = '<=' __ t:term* { RuleOp(t) }

func -> SExpr
    = name:ident t:term* { Func(name, t) }

term -> Term
    = constant / variable / e:sexpr { ExprTerm(e) }

constant -> Term
    = name:ident { Constant(name.to_string()) }
    / n:num { Num(n) }

variable -> Term
    = '?' name:ident { Variable(name.to_string()) }

ident -> String
    = s:(letter (letter / digit / underscore)* { match_str.to_string() }) __ { s }

underscore -> char
    = '_' { match_str.char_at(0) }

letter -> char
    = [a-zA-Z] { match_str.char_at(0) }

digit -> char
    = [0-9] { match_str.char_at(0) }

num -> u8
    = i:(digit+ { match_str.parse().unwrap() }) __ { i }

lparen = '(' __
rparen = ')' __

__ = (whitespace / comment)*

whitespace = [ \t\n]
comment = ';' (!'\n' .)*