aboutsummaryrefslogtreecommitdiffstats
path: root/modelica-parser-lalrpop/src/parser.lalrpop
blob: 36aa07d4b14ea7e23178ed8b4bde3bace4156a6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use std::str::FromStr;
use ast::{ModelicaModel, ComponentDeclaration, ComponentClause, ComponentPrefix, Connection,
    SimpleEquation, Expr, BinOperator, MathUnaryFunc};

// This is an incomplete, non-standards-compliant, minimum-viable parser
// Based on the Modelica 3.3r1 Spec

grammar;

// === Lexical Tokens ===
// Roughly (but possibly not exactly) follows B.1

pub identifier: String = {
    r"[a-zA-Z_][a-zA-Z_0-9]*" => <>.to_string(),
};

string_literal: String = {
    r#""[^"\\]*""# => <>.to_string(),
    //<s:r#""[^"\\]*""#> => &s[1..s.len()-1],
};

pub integer: i64 = {
    r"[+-]?\d+" => i64::from_str(<>).unwrap(),
};

pub float: f64 = {
    r"[+-]?\d+\.\d*([eE][-+]?\d+)?" => f64::from_str(<>).unwrap(),
};

pub boolean: bool = {
    "true" => true,
    "false" => false,
};

// Grammar

pub model: ModelicaModel = {
    "model" <n:identifier> <desc:string_literal?> <cpc:component_clause*> "equation" <cc:connect_clause*> <se:simple_equation*> "end" identifier ";" =>
        ModelicaModel { name:n, description:desc, component_clauses:cpc, connections:cc, equations:se, extends:vec![] },
};

value_declaration: Expr = {
    "=" <value:expr> => value
};

units_declaration: String = {
    "(" "unit" "=" <units:string_literal> ")" => units
};

component_clause: ComponentClause = {
    <prefix:component_prefix?> <specifier:identifier> <declarations:component_declaration+> ";" =>
        ComponentClause { prefix:prefix, specifier:specifier, declarations:declarations },
};

component_declaration: ComponentDeclaration = {
    <name:identifier> <units:units_declaration?> <value:value_declaration?> <desc:string_literal?> (",")? =>
        ComponentDeclaration { name:name, description:desc, value:value, units:units, quantity:None },
};

component_prefix: ComponentPrefix = {
    "flow" => ComponentPrefix::Flow,
    "stream" => ComponentPrefix::Stream,
    "input" => ComponentPrefix::Input,
    "output" => ComponentPrefix::Output,
    "discrete" => ComponentPrefix::Discrete,
    "parameter" => ComponentPrefix::Parameter,
    "constant" => ComponentPrefix::Constant,
};

simple_equation: SimpleEquation = {
    <lhs:expr> ":=" <rhs:expr> ";" => SimpleEquation {lhs:lhs, rhs:rhs},
    <lhs:expr> "="  <rhs:expr> ";" => SimpleEquation {lhs:lhs, rhs:rhs},
};

connect_clause: Connection = {
    "connect" "(" <a:identifier> "," <b:identifier> ")" ";" =>
        Connection { a: a.to_string(), b: b.to_string()},
};

// This weird expr/factor/term hierarchy is for binary operator precedence
expr: Expr = {
    <lhs:expr> "+" <rhs:factor> =>
        Expr::BinExpr(BinOperator::Add, Box::new(lhs), Box::new(rhs)),
    <lhs:expr> "-" <rhs:factor> =>
        Expr::BinExpr(BinOperator::Subtract, Box::new(lhs), Box::new(rhs)),
    factor,
};

factor: Expr = {
    <lhs:factor> "*" <rhs:term> =>
        Expr::BinExpr(BinOperator::Multiply, Box::new(lhs), Box::new(rhs)),
    <lhs:factor> "/" <rhs:term> =>
        Expr::BinExpr(BinOperator::Divide, Box::new(lhs), Box::new(rhs)),
    <lhs:factor> "^" <rhs:term> =>
        Expr::BinExpr(BinOperator::Divide, Box::new(lhs), Box::new(rhs)),
    "-" <t:term> =>
        Expr::BinExpr(BinOperator::Multiply, Box::new(Expr::Integer(-1)), Box::new(t)),
    term,
};

// TODO: elementwise operators (".+", "./", ".*", ".-")

term: Expr = {
    integer => Expr::Integer(<>),
    boolean => Expr::Boolean(<>),
    float => Expr::Float(<>),
    identifier => Expr::Ident(<>),
    "der"   "(" <e:expr> ")" => Expr::Der(Box::new(e)),
    "abs"   "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Abs, Box::new(e)),
    "sqrt"  "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Sqrt, Box::new(e)),
    "sin"   "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Sin, Box::new(e)),
    "cos"   "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Cos, Box::new(e)),
    "tan"   "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Tan, Box::new(e)),
    "asin"  "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Asin, Box::new(e)),
    "acos"  "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Acos, Box::new(e)),
    "atan"  "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Atan, Box::new(e)),
    "sinh"  "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Sinh, Box::new(e)),
    "cosh"  "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Cosh, Box::new(e)),
    "tanh"  "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Tanh, Box::new(e)),
    "exp"   "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Exp, Box::new(e)),
    "log"   "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Log, Box::new(e)),
    "log10" "(" <e:expr> ")" => Expr::MathUnaryExpr(MathUnaryFunc::Log10, Box::new(e)),
    "(" <e:expr> ")" => e,
    // Obviously a hack here, only supporting up to 4 elements in an array
    "[" <e:expr> "]" => Expr::Array(vec![e]),
    "[" <e1:expr> "," <e2:expr> "]" => Expr::Array(vec![e1, e2]),
    "[" <e1:expr> "," <e2:expr> "," <e3:expr> "]" => Expr::Array(vec![e1, e2, e3]),
    "[" <e1:expr> "," <e2:expr> "," <e3:expr> "," <e4:expr> "]" => Expr::Array(vec![e1, e2, e3, e4]),
};