n3-parser 0.3.5

Super-Simple semantic neural network model parser.
use crate::ast;
use crate::error::LexicalError;
use crate::lexer;
use crate::location;

grammar;

pub InputFile: ast::File = StartFile <u:Use*> <m:Model> => ast::File {
    uses: u,
    model: m,
};

Use: ast::Use = "use" <m:name+> <o:UseOrigin> "\n" => ast::Use {
    model: m.join(" "),
    origin: o,
};
UseOrigin: ast::UseOrigin = {
    "by" <s:string> => ast::UseOrigin::Site(s),
    "by" <u:name+> => ast::UseOrigin::User(u.join(" ")),
    => ast::UseOrigin::Local,
}

Model: ast::Model = <e:IsExtern> "[" <n:name+> "]" "\n" <i:ModelInner> => ast::Model {
    name: n.join(" "),
    inner: i,
    is_extern: e,
};
IsExtern: bool = {
    "extern" => true,
    => false,
}

ModelInner: ast::ModelInner = {
    Indent <v:Variable*> <c:Model*> <g:Graph*> Dedent => ast::ModelInner {
        variables: v,
        children: c,
        graph: g,
    },
    => ast::ModelInner::default(),
}

Variable: ast::Variable = {
    "*" <nd:VariableNameDesc> <v:MaybeValue> "\n" => ast::Variable {
        name: nd.name,
        description: nd.description,
        default: v,
        is_model: false,
    },
    "*" "[" <nd:VariableNameDesc> "]" <v:MaybeValueModel> "\n" => ast::Variable {
        name: nd.name,
        description: nd.description,
        default: v,
        is_model: true,
    },
};
VariableNameDesc: ast::temp::VariableNameDesc = {
    <n:name> ":" <d:name+> => ast::temp::VariableNameDesc {
        name: Some(n),
        description: d.join(" "),
    },
    <d:name+> => ast::temp::VariableNameDesc {
        name: None,
        description: d.join(" "),
    },
}
MaybeValue: Option<ast::Value> = {
    "=" <v:Value> => Some(v),
    => None,
}
MaybeValueModel: Option<ast::Value> = {
    "=" <m: name+> => Some(ast::Value::Model(m.join(" "))),
    => None,
}
Value: ast::Value = {
    <b: Bool> => ast::Value::Bool(b),
    <i: int> => ast::Value::Int(i),
    <u: uint> => ast::Value::UInt(u),
    <r: float> => ast::Value::Real(r),
}

Graph: ast::Graph = {
    <n:Node> <p:OneOrMore<GraphPass, "+">> <s:Shapes> "\n" => ast::Graph {
        id: n,
        passes: p,
        inline: None,
        shapes: s,
    },
    <n:Node> <m:Model> => ast::Graph {
        id: n,
        passes: vec![ast::GraphPass {
            name: m.name.clone(),
            repeat: 1,
            ..Default::default()
        }],
        inline: Some(m),
        shapes: None,
    },
}
GraphPass: ast::GraphPass = {
    <n:name+> <a:GraphPassArgs> <r:GraphPassRepeat> => ast::GraphPass {
        name: n.join(" "),
        args: a,
        repeat: r,
    },
}
GraphPassArgs: Vec<ast::GraphPassArg> = {
    "(" <a:OneOrMore<GraphPassArg, ",">> ")" => a,
    => vec![],
}
GraphPassArg: ast::GraphPassArg = {
    <n:OneOrMore<NodeArg, "+">> => ast::GraphPassArg::NodeArg(n),
    <n:name> "=" <v:Value> => ast::GraphPassArg::Keyword {
        name: n,
        value: v,
    },
}
GraphPassRepeat: u64 = {
    "*" <n:uint> => n,
    => 1,
}

Shapes: Option<ast::Shapes> = {
    "=" <s: OneOrMore<IndexedShape, ",">> => Some(ast::Shapes::many(s)),
    "=" <s: Shape> => Some(ast::Shapes::one(s)),
    => None,
}
IndexedShape: (u64, ast::Shape) = "[" <i: uint> ":" <s: Shape> "]" => (i, s);
Shape: ast::Shape = <d: OneOrMore<DimExpr, ",">> => ast::Shape(d);
DimExpr: ast::Dim = {
    <lhs:DimExpr> "+" <rhs:DimTerm> => ast::Dim::Expr {
        lhs: Box::new(lhs),
        rhs: Box::new(rhs),
        op: ast::DimOp::Add,
    },
    <lhs:DimExpr> "-" <rhs:DimTerm> => ast::Dim::Expr {
        lhs: Box::new(lhs),
        rhs: Box::new(rhs),
        op: ast::DimOp::Sub,
    },
    <t:DimTerm> => t,
}
DimTerm: ast::Dim = {
    <lhs:DimTerm> "*" <rhs:DimAtom> => ast::Dim::Expr {
        lhs: Box::new(lhs),
        rhs: Box::new(rhs),
        op: ast::DimOp::Mul,
    },
    <lhs:DimTerm> "/" <rhs:DimAtom> => ast::Dim::Expr {
        lhs: Box::new(lhs),
        rhs: Box::new(rhs),
        op: ast::DimOp::Div,
    },
    "(" <e:DimExpr> ")" => e,
    <a:DimAtom> => a,
}
DimAtom: ast::Dim = {
    <u:uint> => ast::Dim::Fixed(u),
    <n:name> => ast::Dim::Semantic(n),
}

Node: ast::Node = "#" <u:uint> => u;
NodeArg: ast::NodeArg = {
    <n: Node> ":" <a: uint> => ast::NodeArg {
        node: n,
        arg: a,
    },
    <n: Node> => ast::NodeArg {
        node: n,
        arg: 0,
    },
};

int: i64 = "-" <u:uint> => u as i64;

Bool: bool = {
    "yes" => true,
    "no" => false,
}

#[inline]
OneOrMore<T, S>: Vec<T> = {
    <i1: T> <i2:(S T)*> S? => {
        let mut items = vec![i1];
        items.extend(i2.into_iter().map(|e| e.1));
        items
    }
};

// Hook external lexer:
extern {
    type Location = location::Location;
    type Error = LexicalError;

    enum lexer::Tok {
        Indent => lexer::Tok::Indent,
        Dedent => lexer::Tok::Dedent,
        uint => lexer::Tok::UInt { value: <u64> },
        float => lexer::Tok::Float { value: <f64> },
        string => lexer::Tok::String { value: <String> },
        bytes => lexer::Tok::Bytes { value: <Vec<u8>> },
        name => lexer::Tok::Name { name: <String> },
        StartFile => lexer::Tok::StartFile,
        "\n" => lexer::Tok::Newline,
        "=" => lexer::Tok::Equal,
        "#" => lexer::Tok::Number,
        "." => lexer::Tok::Dot,
        "," => lexer::Tok::Comma,
        "(" => lexer::Tok::Lpar,
        ")" => lexer::Tok::Rpar,
        "[" => lexer::Tok::Lbracket,
        "]" => lexer::Tok::Rbracket,
        ":" => lexer::Tok::Colon,
        "+" => lexer::Tok::Add,
        "-" => lexer::Tok::Sub,
        "*" => lexer::Tok::Mul,
        "/" => lexer::Tok::Div,
        "**" => lexer::Tok::Pow,
        "--" => lexer::Tok::Seq,
        "yes" => lexer::Tok::BoolYes,
        "no" => lexer::Tok::BoolNo,
        "use" => lexer::Tok::Use,
        "by" => lexer::Tok::By,
        "extern" => lexer::Tok::Extern,
    }
}