meta {
    f64 := [f64: bool] => str("f64");
    str := [str: bool] => str("str");
    bool := [bool: bool] => str("bool");
    ty := select {f64, str, bool};
    type := [opt: opt[bool], ty <- ty]
        => {op: "type", val: ty, optional: opt == some(true)};
    ref := [rule: str, as: opt[str]]
        => {op: "ref", rule: rule, as: as};
    type_or_ref := select {type, ref};
    field := [name: str, tr <- type_or_ref]
        => if tr.op == "type" {
            {name: name, type: tr.val, optional: tr.optional}
        } else {
            {name: name, ref: {rule: tr.rule, as: tr.as}}
        };
    rep_fields := repeat field:"field";
    expr := [code: str] => code;
    fields := [fs <- rep_fields, expr <- expr:"expr"]
        => {op: "fields", fields: fs, expr: expr};
    repeat := [ref <- ref]
        => {op: "repeat", rule: ref.rule, as: ref.as};
    sel := repeat ref:"ref";
    select := [sel <- sel]
        => {op: "select", rules: sel};
    rule := select {
            fields:"fields",
            repeat:"repeat",
            select:"select"
        };
    decl := [name: str, rule <- rule:"rule"]
        => if rule.op == "fields" {
            {name: name, fields: rule.fields, expr: rule.expr}
        } else if rule.op == "repeat" {
            {name: name, repeat: {rule: rule.rule, as: rule.as}}
        } else if rule.op == "select" {
            {name: name, select: rule.rules}
        };
    rules := repeat decl:"decl";
    doc := [rules <- rules:"rules", start: str]
        => {rules: rules, start: start};
    -----------------------------------------------------------
    doc
}
