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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
|
// Copyright ⓒ 2017 David Li.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
use std::str::FromStr;
use ast::{self, WithLocation};
grammar;
pub Program: ast::Program = {
Expression => ast::Program(<>),
};
FieldList: Vec<WithLocation<ast::RecordField>> = {
<l: @L> <n:Name> ":" <v:Ty> <r: @R> "," <rest: FieldList> => {
let mut rest = rest;
rest.push(WithLocation::new(ast::RecordField::new(n, v), l, r));
rest
},
<l: @L> <n:Name> ":" <v:Ty> <r: @R> "," => vec![WithLocation::new(ast::RecordField::new(n, v), l, r)],
<l: @L> <n:Name> ":" <v:Ty> <r: @R> => vec![WithLocation::new(ast::RecordField::new(n, v), l, r)],
};
RecordFields: WithLocation<Vec<WithLocation<ast::RecordField>>> = {
<l: @L> "{" <v: FieldList> "}" <r: @R> => WithLocation::new(v, l, r),
<l: @L> "{" "}" <r: @R> => WithLocation::new(vec![], l, r),
};
Parameters: WithLocation<Vec<WithLocation<ast::RecordField>>> = {
<l: @L> "(" <v: FieldList> ")" <r: @R> => WithLocation::new(v, l, r),
<l: @L> "(" ")" <r: @R> => WithLocation::new(vec![], l, r),
};
Ty: WithLocation<ast::Ty> = {
<Name> => <>.map(|v| ast::Ty::Name(v)),
<l: @L> "array" "of" <n: Name> <r: @R> =>
WithLocation::new(ast::Ty::Array(Box::new(n.map(|v| ast::Ty::Name(v)))), l, r),
<RecordFields> => <>.map(|v| ast::Ty::Record(v)),
};
Declaration: Box<WithLocation<ast::Declaration>> = {
<l: @L> "var" <name: Name> ":" <ty: Ty> "=" <exp: Expression> <r: @R> =>
Box::new(WithLocation::new(ast::Declaration::new_var(name, Some(ty), exp), l, r)),
<l: @L> "var" <name: Name> "=" <exp: Expression> <r: @R> =>
Box::new(WithLocation::new(ast::Declaration::new_var(name, None, exp), l, r)),
<l: @L> "type" <name: Name> "=" <ty: Ty> <r: @R> =>
Box::new(WithLocation::new(ast::Declaration::new_ty(name, ty), l, r)),
<l: @L> "function" <name: Name> <params: Parameters> "=" <body: Expression> <r: @R> =>
Box::new(WithLocation::new(ast::Declaration::new_fun(name, params.value, None, body), l, r)),
<l: @L> "function" <name: Name> <params: Parameters> ":" <ty: Ty> "=" <body: Expression> <r: @R> =>
Box::new(WithLocation::new(ast::Declaration::new_fun(name, params.value, Some(ty), body), l, r)),
};
DeclarationsList: Vec<WithLocation<ast::Declaration>> = {
<h: DeclarationsList> <t: Declaration> => {
let mut h = h;
h.push(*t);
h
},
<Declaration> => vec![*<>],
};
Expression: Box<ast::WithLocation<ast::Expression>> = {
<e1:Expression> "&&" <e2:ExpressionEq> => Box::new(e1.join_map(*e2, |v1, v2| {
ast::Expression::BinOp(ast::BinOp::And, Box::new(v1), Box::new(v2))
})),
<e1:Expression> "||" <e2:ExpressionEq> => Box::new(e1.join_map(*e2, |v1, v2| {
ast::Expression::BinOp(ast::BinOp::Or, Box::new(v1), Box::new(v2))
})),
<l: @L> "!" <e: ExpressionEq> <r: @R> => Box::new(WithLocation::new(
ast::Expression::UnaryOp(ast::UnaryOp::Not, e),
l, r
)),
<ExpressionEq> => <>,
};
ExpressionEq: Box<ast::WithLocation<ast::Expression>> = {
<e1:ExpressionEq> "=" <e2:ExpressionCmp> => Box::new(e1.join_map(*e2, |v1, v2| {
ast::Expression::BinOp(ast::BinOp::Eq, Box::new(v1), Box::new(v2))
})),
<e1:ExpressionEq> "!=" <e2:ExpressionCmp> => Box::new(e1.join_map(*e2, |v1, v2| {
ast::Expression::BinOp(ast::BinOp::Neq, Box::new(v1), Box::new(v2))
})),
<ExpressionCmp> => <>,
};
ExpressionCmp: Box<ast::WithLocation<ast::Expression>> = {
<e1:ExpressionCmp> ">" <e2:ExpressionAdd> => Box::new(e1.join_map(*e2, |v1, v2| {
ast::Expression::BinOp(ast::BinOp::Gt, Box::new(v1), Box::new(v2))
})),
<e1:ExpressionCmp> "<" <e2:ExpressionAdd> => Box::new(e1.join_map(*e2, |v1, v2| {
ast::Expression::BinOp(ast::BinOp::Lt, Box::new(v1), Box::new(v2))
})),
<e1:ExpressionCmp> ">=" <e2:ExpressionAdd> => Box::new(e1.join_map(*e2, |v1, v2| {
ast::Expression::BinOp(ast::BinOp::Ge, Box::new(v1), Box::new(v2))
})),
<e1:ExpressionCmp> "<=" <e2:ExpressionAdd> => Box::new(e1.join_map(*e2, |v1, v2| {
ast::Expression::BinOp(ast::BinOp::Le, Box::new(v1), Box::new(v2))
})),
<ExpressionAdd> => <>,
};
ExpressionAdd: Box<ast::WithLocation<ast::Expression>> = {
<e1:ExpressionAdd> "+" <e2:ExpressionMul> => Box::new(e1.join_map(*e2, |v1, v2| {
ast::Expression::BinOp(ast::BinOp::Add, Box::new(v1), Box::new(v2))
})),
<e1:ExpressionAdd> "-" <e2:ExpressionMul> => Box::new(e1.join_map(*e2, |v1, v2| {
ast::Expression::BinOp(ast::BinOp::Sub, Box::new(v1), Box::new(v2))
})),
<ExpressionMul> => <>,
};
ExpressionMul: Box<ast::WithLocation<ast::Expression>> = {
<e1:ExpressionMul> "*" <e2:ExpressionSign> => Box::new(e1.join_map(*e2, |v1, v2| {
ast::Expression::BinOp(ast::BinOp::Mul, Box::new(v1), Box::new(v2))
})),
<e1:ExpressionMul> "/" <e2:ExpressionSign> => Box::new(e1.join_map(*e2, |v1, v2| {
ast::Expression::BinOp(ast::BinOp::Div, Box::new(v1), Box::new(v2))
})),
<e1:ExpressionMul> "//" <e2:ExpressionSign> => Box::new(e1.join_map(*e2, |v1, v2| {
ast::Expression::BinOp(ast::BinOp::FloorDiv, Box::new(v1), Box::new(v2))
})),
<ExpressionSign> => <>,
};
ExpressionSign: Box<ast::WithLocation<ast::Expression>> = {
<l: @L> "+" <e: ExpressionBase> <r: @R> => Box::new(WithLocation::new(
ast::Expression::UnaryOp(ast::UnaryOp::Pos, e),
l, r
)),
<l: @L> "-" <e: ExpressionBase> <r: @R> => Box::new(WithLocation::new(
ast::Expression::UnaryOp(ast::UnaryOp::Neg, e),
l, r
)),
<ExpressionBase> => <>,
};
CallArgsList: Vec<WithLocation<ast::Expression>> = {
<exp: Expression> "," <rest: CallArgsList> => {
let mut rest = rest;
rest.push(*exp);
rest
},
<exp: Expression> "," => vec![*exp],
<exp: Expression> => vec![*exp],
};
CallArgs: Vec<WithLocation<ast::Expression>> = {
"(" <v: CallArgsList> ")" => v,
"(" ")" => vec![],
};
ExpressionBase: Box<ast::WithLocation<ast::Expression>> = {
Num => Box::new(<>.map(|v| ast::Expression::Number(v))),
String => Box::new(<>.map(|v| ast::Expression::String(v))),
Name => Box::new(<>.map(|v| ast::Expression::Name(v))),
<l: @L> <func: Name> <args: CallArgs> <r: @R> =>
Box::new(WithLocation::new(ast::Expression::Call(func.value, args), l, r)),
Spanned<r"nil"> => Box::new(<>.map(|v| ast::Expression::Nil)),
<l: @L> "let" <d: DeclarationsList> "in" <e: Expression> "end" <r: @R> =>
Box::new(WithLocation::new(ast::Expression::Let(d, e), l, r)),
"(" <Expression> ")" => <>,
};
Name: WithLocation<String> = <e: Spanned<r"[[:alpha:]_][[:alpha:]_0-9]*">> => e.map(|v| v.to_owned());
Num: WithLocation<u64> = <e: Spanned<r"[0-9]+">> => e.map(|v| u64::from_str(v).unwrap());
String: WithLocation<String> = <l: @L> <v:r##""(?:[^"\\]|\\\\)*""##> <r: @R> => {
WithLocation::new(v[1..v.len() - 1].to_owned(), l, r)
};
Spanned<T>: WithLocation<T> = {
<l: @L> <v: T> <r: @R> => WithLocation::new(v, l, r)
};
match {
"nil",
"var",
"let",
"in",
"end",
"type",
"function",
}
else {
r"[[:alpha:]_][[:alpha:]_0-9]*",
}
else {
_,
}
|