#![allow(unused_variables)]
use topdown::{CharSeq, EOF, split, many_until, LocationInfo, re, wrap, chainl, keyword, opt, many, Parser, choice, ParserResult};
use topdown::ParserResult::{Succ, Error, Fail};
use self::AST::*;
use self::BinOps::*;
use self::UnOps::*;
use std::fmt;
use std::collections::HashMap;
#[derive(Clone, Show)]
pub enum AST {
If(Box<AST>, Box<AST>, Box<AST>, LocationInfo),
For(String, Box<AST>, Box<AST>, LocationInfo),
Assign(Box<AST>, Box<AST>, LocationInfo),
Print(Box<AST>, LocationInfo),
Block(Vec<AST>, LocationInfo),
DefFunc(String, Vec<String>, Box<AST>, LocationInfo),
Int_(int),
Float_(f64),
String_(String),
Bool_(bool),
Null,
Empty,
List_(Vec<AST>, LocationInfo),
Object_(HashMap<String, AST>, LocationInfo),
UnOp(UnOps, Box<AST>),
BinOp(BinOps, Box<AST>, Box<AST>),
VarRef(String, LocationInfo),
IndexRef(Box<AST>, Box<AST>),
FunCall(String, Vec<AST>, LocationInfo),
Return(Box<AST>, LocationInfo),
Break(LocationInfo),
Continue(LocationInfo)
}
#[derive(Clone, Copy, Show)]
pub enum UnOps {
PLUS,
MINUS,
NOT
}
#[derive(Clone, Copy)]
pub enum BinOps {
ADD,
SUB,
MUL,
DIV,
MOD,
EQ,
NE,
GT,
GE,
LT,
LE,
LOR,
LAND
}
impl fmt::Show for BinOps {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let d = match *self {
ADD => "+",
SUB => "-",
MUL => "*",
DIV => "/",
MOD => "%",
EQ => "==",
NE => "!=",
GT => ">",
GE => ">=",
LT => "<",
LE => "<=",
LOR => "||",
LAND => "&&"
};
f.write_str(d)
}
}
pub fn script(cs: &mut CharSeq) -> ParserResult<Vec<AST>> {
let w = wrap(statement);
let e = EOF;
cs.accept(&many_until(&w, &e))
}
fn statement(cs: &mut CharSeq) -> ParserResult<AST> {
let _if = wrap(if_);
let _for = wrap(for_);
let _as = wrap(assign);
let _p = wrap(print_);
let _f = wrap(funcall_s);
let _def = wrap(deffunc);
let _ret = wrap(return_);
let _cont = wrap(continue_);
let _brk = wrap(break_);
let l = [
&_if as &Parser<AST>,
&_for as &Parser<AST>,
&_def as &Parser<AST>,
&_as as &Parser<AST>,
&_p as &Parser<AST>,
&_ret as &Parser<AST>,
&_cont as &Parser<AST>,
&_brk as &Parser<AST>,
&_f as &Parser<AST>
];
let s = choice(&l);
cs.accept(&s)
}
#[allow(unused_variables)]
fn if_(cs: &mut CharSeq) -> ParserResult<AST> {
let loc = cs.get_location();
let k = "if";
let cond = wrap(expr);
let _el = wrap(else_);
let blk = wrap(block);
let el = opt(&_el, Empty);
run_parser!(
cs >> &keyword(k) -> |i|
&cond -> |c|
&blk -> |b|
&el -> |e| {
If(box c.clone(), box b.clone(), box e.clone(), loc.clone())
}
)
}
#[allow(unused_variables)]
fn else_(cs: &mut CharSeq) -> ParserResult<AST> {
let k = "else";
let i = wrap(if_);
let b = wrap(block);
let l = [&i as &Parser<AST>, &b as &Parser<AST>];
let c = choice(&l);
run_parser!(cs >> &keyword(k) -> |i| &c -> |b| b)
}
#[allow(unused_variables)]
fn block(cs: &mut CharSeq) -> ParserResult<AST> {
let loc = cs.get_location();
let bo = "{";
let _stmt = wrap(statement);
let bc = "}";
let body = many_until(&_stmt, &bc);
run_parser!(cs >> &bo -> |i| &body -> |b| &bc -> |i| Block(b.clone(), loc.clone()))
}
#[allow(unused_variables)]
fn for_(cs: &mut CharSeq) -> ParserResult<AST> {
let loc = cs.get_location();
let k = "for";
let id = wrap(ident);
let i = "in";
let it = wrap(expr);
let b = wrap(block);
run_parser!(
cs >> &keyword(k) -> |ign|
&id -> |n|
&keyword(i) -> |ign|
&it -> |ex|
&b -> |body| For(n.clone(), box ex.clone(), box body.clone(), loc.clone())
)
}
fn ident(cs: &mut CharSeq) -> ParserResult<String> {
let i = re("[a-zA-Z_][a-zA-Z0-9_]*");
cs.accept(&i)
}
#[allow(unused_variables)]
fn assign(cs: &mut CharSeq) -> ParserResult<AST> {
let loc = cs.get_location();
let i = wrap(ident);
let ia = wrap(index_access);
let fa = wrap(field_access);
let cl = [&ia as &Parser<AST>, &fa as &Parser<AST>];
let ch = choice(&cl);
let q = "=";
let e = wrap(expr);
let s = ";";
run_parser!(
cs >> &i -> |id|
&many(&ch) -> |idx|
&q -> |ign|
&e -> |ex|
&s -> |ign| {
if idx.len() == 0 {
Assign(box String_(id.clone()), box ex.clone(), loc.clone())
} else {
let s = VarRef(id.clone(), loc.clone());
let n = make_index_access_node(s, idx.clone());
Assign(box n, box ex.clone(), loc.clone())
}
}
)
}
#[allow(unused_variables)]
fn print_(cs: &mut CharSeq) -> ParserResult<AST> {
let loc = cs.get_location();
let k = "print";
let e = wrap(expr);
let s = ";";
run_parser!(
cs >> &keyword(k) -> |ign|
&e -> |ex|
&s -> |ign| Print(box ex.clone(), loc.clone())
)
}
#[allow(unused_variables)]
fn deffunc(cs: &mut CharSeq) -> ParserResult<AST> {
let loc = cs.get_location();
let k = "fn";
let i = wrap(ident);
let op = "(";
let e = wrap(ident);
let c = ",";
let sp = split(&e, &c, false);
let cp = ")";
let b = wrap(block);
run_parser!(
cs >> &keyword(k) -> |ign|
&i -> |name|
&op -> |ign|
&sp -> |args|
&cp -> |ign|
&b -> |body| DefFunc(name.clone(), args.clone(), box body.clone(), loc.clone())
)
}
#[allow(unused_variables)]
fn funcall(cs: &mut CharSeq) -> ParserResult<AST> {
let loc = cs.get_location();
let n = wrap(ident);
let op = "(";
let e = wrap(expr);
let c = ",";
let sp = split(&e, &c, false);
let cp = ")";
run_parser!(
cs >> &n -> |name|
&op -> |ign|
&sp -> |args|
&cp -> |ign| FunCall(name.clone(), args.clone(), loc.clone())
)
}
#[allow(unused_variables)]
fn funcall_s(cs: &mut CharSeq) -> ParserResult<AST> {
match funcall(cs) {
Succ(r) => {
let s = ";";
cs.accept(&s);
Succ(r)
},
Fail(m, l) => Fail(m, l),
Error(m, l) => Error(m, l)
}
}
#[allow(unused_variables)]
fn return_(cs: &mut CharSeq) -> ParserResult<AST> {
let loc = cs.get_location();
let k = "return";
let e = wrap(expr);
let s = ";";
run_parser!(
cs >> &keyword(k) -> |ign|
&e -> |ex|
&s -> |ign| Return(box ex.clone(), loc.clone())
)
}
fn continue_(cs: &mut CharSeq) -> ParserResult<AST> {
let loc = cs.get_location();
let k = "continue";
let s = ";";
run_parser!(
cs >> &keyword(k) -> |ign|
&s -> |ign| Continue(loc.clone())
)
}
fn break_(cs: &mut CharSeq) -> ParserResult<AST> {
let loc = cs.get_location();
let k = "break";
let s = ";";
run_parser!(
cs >> &keyword(k) -> |ign|
&s -> |ign| Break(loc.clone())
)
}
fn expr(cs: &mut CharSeq) -> ParserResult<AST> {
let t = wrap(expr1);
let o = wrap(op2);
let cl = chainl(&t, &o, false);
match cs.accept(&re("-|\\+|!")) {
Succ(o) => match o.as_slice() {
"-" => cs.accept(&cl).map(|o| UnOp(MINUS, box o.clone())),
"+" => cs.accept(&cl).map(|o| UnOp(PLUS, box o.clone())),
"!" => cs.accept(&cl).map(|o| UnOp(NOT, box o.clone())),
_ => panic!(o)
},
Fail(m, l) => cs.accept(&cl),
Error(m, l) => Error(m, l)
}
}
fn expr1(cs: &mut CharSeq) -> ParserResult<AST> {
let t = wrap(term1);
let o = wrap(op1);
let cl = chainl(&t, &o, false);
cs.accept(&cl)
}
fn term1(cs : &mut CharSeq) -> ParserResult<AST> {
let f = wrap(factor);
let t = wrap(term0);
let l = [&t as &Parser<AST>, &f as &Parser<AST>];
let c = choice(&l);
let o = wrap(op0);
let cl = chainl(&c, &o, false);
cs.accept(&cl)
}
#[allow(unused_variables)]
fn factor(cs: &mut CharSeq) -> ParserResult<AST> {
run_parser!(
cs >> &"(" -> |op|
&wrap(expr) -> |e|
&")" -> |cp| e.clone()
)
}
fn op0<'a>(cs: &mut CharSeq) -> ParserResult<|AST, AST|:'a -> AST> {
cs.accept(&re("\\*|/|%")).map(|o| {
match o.as_slice() {
"*" => |a:AST, b:AST| BinOp(MUL, box a.clone(), box b.clone()),
"/" => |a:AST, b:AST| BinOp(DIV, box a.clone(), box b.clone()),
"%" => |a:AST, b:AST| BinOp(MOD, box a.clone(), box b.clone()),
_ => panic!(o)
}
})
}
fn op1<'a>(cs: &mut CharSeq) -> ParserResult<|AST, AST|:'a -> AST> {
cs.accept(&re("\\+|-|(==)|(<=)|(>=)|(!=)|<|>")).map(|o| {
match o.as_slice() {
"+" => |a:AST, b:AST| BinOp(ADD, box a.clone(), box b.clone()),
"-" => |a:AST, b:AST| BinOp(SUB, box a.clone(), box b.clone()),
"==" => |a:AST, b:AST| BinOp(EQ, box a.clone(), box b.clone()),
"!=" => |a:AST, b:AST| BinOp(NE, box a.clone(), box b.clone()),
">" => |a:AST, b:AST| BinOp(GT, box a.clone(), box b.clone()),
">=" => |a:AST, b:AST| BinOp(GE, box a.clone(), box b.clone()),
"<" => |a:AST, b:AST| BinOp(LT, box a.clone(), box b.clone()),
"<=" => |a:AST, b:AST| BinOp(LE, box a.clone(), box b.clone()),
_ => panic!(o)
}
})
}
fn op2<'a>(cs: &mut CharSeq) -> ParserResult<|AST, AST|:'a -> AST> {
cs.accept(&re("\\|\\||&&")).map(|o| {
match o.as_slice() {
"||" => |a:AST, b:AST| BinOp(LOR, box a.clone(), box b.clone()),
"&&" => |a:AST, b:AST| BinOp(LAND, box a.clone(), box b.clone()),
_ => panic!(o)
}
})
}
fn term0(cs: &mut CharSeq) -> ParserResult<AST> {
let i = wrap(integer);
let n = wrap(number);
let s = wrap(string_);
let nl = wrap(null);
let b = wrap(bool_);
let l = wrap(list_);
let o = wrap(object_);
let fc = wrap(funcall);
let vr = wrap(varref);
let ls = [&n as &Parser<AST>
, &i as &Parser<AST>
, &s as &Parser<AST>
, &b as &Parser<AST>
, &l as &Parser<AST>
, &o as &Parser<AST>
, &nl as &Parser<AST>
, &fc as &Parser<AST>
, &vr as &Parser<AST>];
match cs.accept(&choice(&ls)) {
Succ(a) => {
let ia = wrap(index_access);
let fa = wrap(field_access);
let cl = [&ia as &Parser<AST>, &fa as &Parser<AST>];
let ch = choice(&cl);
match cs.accept(&many(&ch)) {
Succ(accs) => Succ(make_index_access_node(a.clone(), accs)),
Fail(msg, loc) => Fail(msg.clone(), loc.clone()),
Error(msg, loc) => Error(msg.clone(), loc.clone())
}
},
Fail(msg, loc) => Fail(msg.clone(), loc.clone()),
Error(msg, loc) => Error(msg.clone(), loc.clone())
}
}
fn make_index_access_node(expr: AST, accs: Vec<AST>) -> AST {
if accs.len() == 0 {
return expr;
} else {
let t = accs[0].clone();
let rest = accs.slice_from(1).to_vec();
return make_index_access_node(IndexRef(box expr, box t), rest);
}
}
#[allow(unused_variables)]
fn index_access(cs: &mut CharSeq) -> ParserResult<AST> {
let i = wrap(integer);
let s = wrap(string_);
let v = wrap(varref);
let l = [&i as &Parser<AST>, &s as &Parser<AST>, &v as &Parser<AST>];
run_parser!(
cs >> &"[" -> |ign|
&choice(&l) -> |idx|
&"]" -> |ign| idx.clone()
)
}
#[allow(unused_variables)]
fn field_access(cs: &mut CharSeq) -> ParserResult<AST> {
let i = wrap(ident);
run_parser!(
cs >> &"." -> |ign|
&i -> |idx| String_(idx)
)
}
fn integer(cs: &mut CharSeq) -> ParserResult<AST> {
let r = re("(([1-9][0-9]+)|([0-9]))");
cs.accept(&r).map(|x| Int_(x.as_slice().parse().unwrap()))
}
#[allow(unused_variables)]
fn list_(cs: &mut CharSeq) -> ParserResult<AST> {
let loc = cs.get_location();
let oc = "[";
let e = wrap(expr);
let c = ",";
let ls = split(&e, &c, true);
let cc = "]";
run_parser!(
cs >> &oc -> |ign|
&ls -> |l|
&cc -> |ign| List_(l.clone(), loc.clone())
)
}
#[allow(unused_variables)]
fn object_(cs: &mut CharSeq) -> ParserResult<AST> {
let loc = cs.get_location();
let ob = "{";
let e = wrap(item);
let c = ",";
let ls = split(&e, &c, true);
let cb = "}";
run_parser!(
cs >> &ob -> |ign|
&ls -> |l|
&cb -> |ign| {
let mut m = HashMap::new();
for t in l.iter() {
m.insert(t.0.clone(), t.1.clone());
}
Object_(m.clone(), loc.clone())
}
)
}
#[allow(unused_variables)]
fn item(cs: &mut CharSeq) -> ParserResult<(String, AST)> {
let i = wrap(ident);
let c = ":";
let e = wrap(expr);
run_parser!(
cs >> &i -> |id|
&c -> |ign|
&e -> |exp| (id.clone(), exp.clone())
)
}
fn number(cs: &mut CharSeq) -> ParserResult<AST> {
let r = re("(([0-9])|([1-9][0-9]+))\\.[0-9]*");
cs.accept(&r).map(|x| Float_(x.as_slice().parse().unwrap()))
}
fn string_(cs: &mut CharSeq) -> ParserResult<AST> {
let loc = cs.get_location();
let q = "\"";
let h = cs.enable_hook;
cs.enable_hook = false;
let mut escaping = false;
let mut r = String::new();
match cs.accept(&q) {
Fail(m, l) => {
cs.enable_hook = h;
return Fail(m, l);
},
Error(m, l) => {
cs.enable_hook = h;
return Fail(m, l);
},
Succ(s) => ()
}
while !cs.eof() {
let c = cs.current();
if c == '"' {
if escaping {
escaping = false;
r.push(c);
} else {
cs.next();
break;
}
} else if c == '\\' {
if escaping {
escaping = false;
r.push(c);
} else {
escaping = true;
}
} else {
if escaping {
if c == 'n' {
r.push('\n');
escaping = false;
} else if c == 't' {
r.push('\t');
escaping = false;
} else if c == 'r' {
r.push('\r');
escaping = false;
} else {
cs.enable_hook = h;
r.push(c);
return Fail(r, loc.clone());
}
} else {
r.push(c);
}
}
cs.next();
}
cs.enable_hook = h;
return Succ(String_(r));
}
fn bool_(cs: &mut CharSeq) -> ParserResult<AST> {
let t = "true";
let f = "false";
let l = [&t as &Parser<String>, &f as &Parser<String>];
let c = choice(&l);
cs.accept(&c).map(|r| if r.as_slice() == "true" { Bool_(true) } else { Bool_(false) } )
}
fn null(cs: &mut CharSeq) -> ParserResult<AST> {
let n = "null";
cs.accept(&n).map(|x| Null)
}
fn varref(cs: &mut CharSeq) -> ParserResult<AST> {
let loc = cs.get_location();
cs.accept(&wrap(ident)).map(|o| VarRef(o, loc.clone()))
}
#[feature(globs)]
#[cfg(test)]
mod tests {
use super::*;
use std::io::File;
use std::os;
use topdown::{CharSeq, skip, Succ, Fail ,Error};
#[test]
fn test_parser() {
let path = Path::new("./sample.sc");
let mut file = match File::open(&path) {
Ok(f) => f,
Err(w) => panic!("{}", w)
};
let content = match file.read_to_string() {
Ok(f) => f,
Err(w) => panic!("{}", w)
};
let mut cs = CharSeq::new(content.as_slice(), path.as_str().unwrap());
let skip = skip(" \t\r\n");
cs.add_hook(&skip);
match script(&mut cs) {
Succ(ast) => {
if !cs.eof() {
assert!(false, format!("{}", cs.get_location()))
}
},
Fail(m, l) => assert!(false, format!("{}", cs.get_location())),
Error(m, l) => assert!(false, format!("{}", cs.get_location()))
};
}
}