rusty-peg 0.4.0

A macro for defining PEG parsers
Documentation
use regex::Regex;
use std::rc::Rc;
use Symbol;

#[derive(Debug)]
pub struct ClassDefn<'input> {
    name: &'input str,
    members: Vec<Rc<MemberDefn<'input>>>
}

#[derive(Debug)]
pub enum MemberDefn<'input> {
    Field(Box<FieldDefn<'input>>),
    Method(Box<MethodDefn<'input>>),
}

#[derive(Debug)]
pub struct FieldDefn<'input> {
    name: &'input str,
    ty: TypeRef<'input>,
}

#[derive(Debug)]
pub struct MethodDefn<'input> {
    name: &'input str,
    arg_tys: Vec<TypeRef<'input>>,
    ret_ty: TypeRef<'input>,
}

#[derive(Clone,Debug)]
pub struct TypeRef<'input> {
    id: &'input str
}

rusty_peg! {
    parser Classy<'input> {
        ID: &'input str =
            regex(r"^[a-zA-Z_][a-zA-Z_0-9]*") - ["class"];

        CLASS: Rc<ClassDefn<'input>> =
            ("class", <name:ID>, "{", <members:{MEMBER}>, "}") => {
                Rc::new(ClassDefn { name: name, members: members })
            };

        MEMBER: Rc<MemberDefn<'input>> =
            (FIELD_DEFN / METHOD_DEFN);

        FIELD_DEFN: Rc<MemberDefn<'input>> =
            (<name:ID>, ":", <ty:TYPE_REF>, ";") => {
                Rc::new(MemberDefn::Field(Box::new(
                    FieldDefn { name: name, ty: ty })))
            };

        TYPE_REF: TypeRef<'input> =
            (<id:ID>) => {
                TypeRef { id: id }
            };

        METHOD_DEFN: Rc<MemberDefn<'input>> =
            (<name:ID>, "(", <args:{TYPE_REF}>, ")", "->", <ret:TYPE_REF>, ";") => {
                Rc::new(MemberDefn::Method(Box::new(
                    MethodDefn { name: name, arg_tys: args, ret_ty: ret })))
            };
    }
}

#[test]
fn parse_a_class() {
    let mut classy = Classy::new(());
    let (_, result) =
        CLASS.parse_prefix(
            &mut classy,
            "class x { f: u32; g: i32; h(i32) -> u32; }").unwrap();

    assert_eq!(
        normalize_space(&format!("{:#?}", result)),
        normalize_space("ClassDefn {
                name: \"x\",
                members: [
                    Field(
                        FieldDefn {
                            name: \"f\",
                            ty: TypeRef {
                                id: \"u32\"
                            }
                        }
                        ),
                    Field(
                        FieldDefn {
                            name: \"g\",
                            ty: TypeRef {
                                id: \"i32\"
                            }
                        }
                        ),
                    Method(
                        MethodDefn {
                            name: \"h\",
                            arg_tys: [
                                TypeRef {
                                    id: \"i32\"
                                }
                                ],
                            ret_ty: TypeRef {
                                id: \"u32\"
                            }
                        }
                        )
                    ]
            }"));
}

fn normalize_space(text: &str) {
    Regex::new(r"\s+").unwrap().replace_all(text, " ");
}