use crate::compile::*;
grammar;
extern {
type Location = usize;
type Error = String;
}
pub Str: String = <s:r#""(\\.|[^"])*""#> => String::from(&s[1..s.len()-1]).replace("\\n","\n").replace("\\r","\r").replace("\\t","\t").replace("\\0","\0").replace("\\\"", "\"");
pub Char: char = <s:r#"'(\\.|[^"])'"#> => String::from(&s[1..s.len()-1]).replace("\\n","\n").replace("\\r","\r").replace("\\t","\t").replace("\\0","\0").replace("\\\"", "\"").chars().next().unwrap();
pub Num: Literal = {
r"([0-9]+([.][0-9]*)?|[.][0-9]+)" => match <>.parse::<u8>() {
Ok(val) => Literal::byte_int(val),
Err(_) => Literal::unsigned_short(<>.parse::<u16>().unwrap()),
},
}
pub Flag: Flag = {
"#" "[" <FlagName> "]" => <>
}
pub FlagName: Flag = {
"enable" "(" "brainfuck" ")" => Flag::EnableBrainFuck,
"enable" "(" "size_warn" ")" => Flag::EnableSizeWarn
}
pub Value: Eval = {
"(" <Value> ")" => <>,
"*" <name: Value> => Eval::Deref(Deref::new(name)),
<name: Ident> => Eval::Load(Load::new(name)),
"&" <name: Ident> => Eval::Refer(Refer::new(Eval::Load(Load::new(name)))),
<name: Ident> <args: List<"(", Value, ",", ")">> => Eval::Call(Call::new(name, args)),
<Literal> => Eval::Literal(<>)
}
pub Expr: Expr = {
<IfStatement> => <>,
<WhileLoop> => <>,
<Assign> ";" => <>,
<Value> ";" => Expr::Eval(<>),
"return" <ret: Value> ";" => Expr::Return(Return::new(ret))
}
pub Assign: Expr = {
<lhs: Value> "=" <rhs: Value> => Expr::Assign(Assign::new(lhs, rhs)),
"def" <lhs: Ident> "=" <rhs: Value> => Expr::Define(Define::new(lhs, rhs)),
}
pub Program: Program = {
<flags: Flag*> <fndefs: FunctionDef+> => Program::new(flags, fndefs)
}
pub Body: Vec<Expr> = Expr* => <>;
pub Ident: String = {
r"[a-zA-Z_][a-zA-Z0-9_]*" => <>.to_string()
}
pub WhileLoop: Expr = {
"while" <condition:Ident> "{" <body:Body> "}" => Expr::While(While::new(Eval::Load(Load::new(condition)), body))
}
pub IfStatement: Expr = {
"if" <condition:Value> "{" <then_body:Body> "}" <else_clause:("else" "{" <Body> "}")?> => {
match else_clause {
Some(clause) => {
Expr::If(If::new(condition, then_body, clause))
}
None => {
Expr::If(If::new(condition, then_body, vec![]))
}
}
}
}
FunctionDef: UserFn = "fn" <name: Ident> <args: List<"(", Ident, ",", ")">> "{" <body: Body> "}" => UserFn::new(name, args, body);
Literal: Literal = {
<Str> => Literal::string(<>),
<Char> => Literal::character(<>),
<Num> => <>
}
Infix<First, Operator, Second>: (First, Operator, Second) = {
<first:First> <op: Operator> <second:Second> => {
(<>)
}
}
List<Begin, T, Sep, End>: Vec<T> = {
<first:Begin> <list: (<T> <Sep>)*> <end:T?> <last:End> => {
match end {
None => list.iter().map(|(v, s)| v.clone()).collect(),
Some(val) => {
let mut list: Vec<_> = list.iter().map(|(v, s)| v.clone()).collect();
list.push(val);
list
}
}
}
}