-
Notifications
You must be signed in to change notification settings - Fork 110
/
pyret-grammar.bnf
301 lines (227 loc) · 10.6 KB
/
pyret-grammar.bnf
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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
/*
name: PyretGrammar
*/
program: prelude block
prelude: [use-stmt] (provide-stmt|import-stmt)*
use-stmt: USE NAME import-source
import-stmt: INCLUDE import-source
import-stmt: INCLUDE FROM module-ref COLON [include-spec (COMMA include-spec)* [COMMA]] END
import-stmt: IMPORT import-source AS NAME
import-stmt: IMPORT comma-names FROM import-source
import-source: import-special | import-name
import-special: NAME PARENNOSPACE STRING (COMMA STRING)* RPAREN
import-name: NAME
include-spec: include-name-spec
| include-type-spec
| include-data-spec
| include-module-spec
include-name-spec: name-spec
include-type-spec: TYPE name-spec
include-data-spec: DATA data-name-spec [hiding-spec]
include-module-spec: MODULE name-spec
provide-stmt: provide-vals-stmt | provide-types-stmt | provide-block
provide-vals-stmt: PROVIDE stmt END | PROVIDE (STAR|TIMES)
provide-types-stmt: PROVIDE-TYPES record-ann | PROVIDE-TYPES (STAR|TIMES)
provide-block: PROVIDECOLON [provide-spec (COMMA provide-spec)* [COMMA]] END
provide-block: PROVIDE FROM module-ref COLON [provide-spec (COMMA provide-spec)* [COMMA]] END
provide-spec: provide-name-spec
| provide-type-spec
| provide-data-spec
| provide-module-spec
name-spec: (STAR|TIMES) [hiding-spec] | module-ref | module-ref AS NAME
data-name-spec: (STAR|TIMES) | module-ref
provide-name-spec: name-spec
provide-type-spec: TYPE name-spec
provide-data-spec: DATA data-name-spec [hiding-spec]
provide-module-spec: MODULE name-spec
hiding-spec: HIDING (PARENSPACE | PARENNOSPACE) [(NAME COMMA)* NAME] RPAREN
module-ref: (NAME DOT)* NAME
comma-names: NAME (COMMA NAME)*
block: stmt*
stmt: type-expr | newtype-expr | spy-stmt
| let-expr | fun-expr | data-expr | when-expr
| var-expr | rec-expr | assign-expr | check-test | check-expr
| contract-stmt
spy-stmt: SPY [binop-expr] COLON [spy-contents] END
spy-contents: spy-field (COMMA spy-field)*
spy-field: id-expr | NAME COLON binop-expr
type-expr: TYPE NAME ty-params EQUALS ann
newtype-expr: NEWTYPE NAME AS NAME
let-expr: toplevel-binding EQUALS binop-expr
binding: name-binding | tuple-binding
tuple-binding: LBRACE (binding SEMI)* binding [SEMI] RBRACE [AS name-binding]
name-binding: [SHADOW] NAME [COLONCOLON ann]
toplevel-binding: binding
# toplevel-binding: [SHADOW] NAME COLONCOLON noparen-arrow-ann
multi-let-expr: LET let-binding (COMMA let-binding)* (BLOCK|COLON) block END
let-binding: let-expr | var-expr
letrec-expr: LETREC let-expr (COMMA let-expr)* (BLOCK|COLON) block END
type-bind: NAME ty-params EQUALS ann
newtype-bind: NEWTYPE NAME AS NAME
type-let-bind: type-bind | newtype-bind
type-let-expr: TYPE-LET type-let-bind (COMMA type-let-bind)* (BLOCK|COLON) block END
contract-stmt: NAME COLONCOLON ty-params (ann | noparen-arrow-ann)
fun-expr: FUN NAME fun-header (BLOCK|COLON) doc-string block where-clause END
fun-header: ty-params args return-ann | ty-params bad-args return-ann
ty-params: [(LANGLE|LT) comma-names (RANGLE|GT)]
args: (PARENNOSPACE|PARENAFTERBRACE) [binding (COMMA binding)*] RPAREN
bad-args: PARENSPACE [binding (COMMA binding)*] RPAREN
return-ann: [THINARROW ann]
doc-string: [DOC STRING]
where-clause: [WHERE block]
check-expr: (CHECK|EXAMPLES) STRING COLON block END
check-expr: (CHECKCOLON|EXAMPLESCOLON) block END
check-test: binop-expr check-op [PERCENT (PARENSPACE|PARENNOSPACE) binop-expr RPAREN] binop-expr [BECAUSE binop-expr]
| binop-expr check-op-postfix [BECAUSE binop-expr]
| binop-expr
data-expr: DATA NAME ty-params COLON [first-data-variant] data-variant* data-sharing where-clause END
variant-constructor: NAME variant-members
first-data-variant: variant-constructor data-with | NAME data-with
data-variant: BAR variant-constructor data-with | BAR NAME data-with
variant-members: PARENNOSPACE [variant-member (COMMA variant-member)*] RPAREN
variant-member: [REF] binding
data-with: [WITH fields]
data-sharing: [SHARING fields]
var-expr: VAR toplevel-binding EQUALS binop-expr
rec-expr: REC toplevel-binding EQUALS binop-expr
assign-expr: NAME COLONEQUALS binop-expr
when-expr: WHEN binop-expr (BLOCK|COLON) block END
binop-expr: expr (binop expr)*
binop: PLUS | DASH | TIMES | SLASH | LEQ | GEQ | EQUALEQUAL | SPACESHIP | EQUALTILDE
| NEQ | LT | GT | AND | OR | CARET
check-op: IS | ISEQUALEQUAL | ISEQUALTILDE | ISSPACESHIP | ISROUGHLY | ISNOTROUGHLY
| ISNOT | ISNOTEQUALEQUAL | ISNOTEQUALTILDE | ISNOTSPACESHIP
| RAISES | RAISESOTHER
| SATISFIES | SATISFIESNOT
| RAISESSATISFIES | RAISESVIOLATES
check-op-postfix: RAISESNOT
expr: paren-expr | id-expr | prim-expr
| lambda-expr | method-expr | app-expr
| obj-expr | tuple-expr | tuple-get
| dot-expr
| template-expr
| bracket-expr # NOTE(joe): experimental for access
| get-bang-expr | update-expr
| extend-expr
| if-expr | if-pipe-expr | cases-expr
| for-expr
| user-block-expr | inst-expr
| multi-let-expr | letrec-expr
| type-let-expr
| construct-expr
| table-select
| table-extend
| table-filter
| table-order
| table-extract
| table-update
| table-expr
| load-table-expr
| reactor-expr
template-expr : DOTDOTDOT
bad-expr: UNTERMINATED-STRING | UNTERMINATED-BLOCK-COMMENT | BAD-OPER | BAD-NUMBER | UNKNOWN
# paren-exprs must be preceded by a space, so as not be be confused with
# function application
paren-expr: (PARENSPACE|PARENAFTERBRACE) binop-expr RPAREN
id-expr: NAME
prim-expr: num-expr | frac-expr | rfrac-expr | bool-expr | string-expr
num-expr: NUMBER
frac-expr: RATIONAL
rfrac-expr: ROUGHRATIONAL
bool-expr: TRUE | FALSE
string-expr: STRING
lambda-expr: LAM fun-header (BLOCK|COLON) doc-string block where-clause END
lambda-expr: LBRACE fun-header (BLOCK|COLON) doc-string block where-clause RBRACE
method-expr: METHOD fun-header (BLOCK|COLON) doc-string block where-clause END
app-expr: expr app-args
# These two productions are carefully rigged to *not* parse unary `f (x)`
# otherwise, we'd admit ambiguous parses. Instead, parse-pyret detects these
# two cases and produces a parse error, while well-formedness detects the unary
# case and produces a well-formedness error with a similar message.
| expr PARENSPACE RPAREN
| expr PARENSPACE binop-expr COMMA binop-expr (COMMA binop-expr)* RPAREN
# application must have the function expression immediately adjacent to
# the argument list, so as not to be confused with parenthesized exprs
app-args: PARENNOSPACE opt-comma-binops RPAREN
opt-comma-binops: [comma-binops]
comma-binops: binop-expr (COMMA binop-expr)*
trailing-opt-comma-binops: (comma-binops [COMMA] | )
# app-arg-elt: binop-expr COMMA
# at least one annotation must be provided
inst-expr: expr LANGLE ann (COMMA ann)* (RANGLE|GT)
tuple-expr: LBRACE tuple-fields RBRACE
tuple-fields: binop-expr (SEMI binop-expr)* [SEMI]
tuple-get: expr DOT LBRACE NUMBER RBRACE
obj-expr: LBRACE obj-fields RBRACE | LBRACE RBRACE
obj-fields: obj-field (COMMA obj-field)* [COMMA]
obj-field: key COLON binop-expr
| REF key [COLONCOLON ann] COLON binop-expr
| METHOD key fun-header (BLOCK|COLON) doc-string block where-clause END
fields: field (COMMA field)* [COMMA]
field: key COLON binop-expr
| METHOD key fun-header (BLOCK|COLON) doc-string block where-clause END
key: NAME
construct-expr: LBRACK construct-modifier binop-expr COLON trailing-opt-comma-binops RBRACK
construct-modifier: | LAZY
table-expr: TABLE table-headers table-rows END
table-headers: [list-table-header* table-header]
list-table-header: table-header COMMA
table-header: NAME [COLONCOLON ann]
table-rows: [table-row* table-row]
table-row: ROW table-items
table-items: [list-table-item* binop-expr]
list-table-item: binop-expr COMMA
# NOTE(joe): just parsing as "fields" for now, and handling naming in
# desugaring/well-formed, so that better error messages can be given
reactor-expr: REACTOR COLON
fields
END
dot-expr: expr DOT NAME
bracket-expr: expr LBRACK binop-expr RBRACK
get-bang-expr: expr BANG NAME
extend-expr: expr DOT LBRACE fields RBRACE
update-expr: expr BANG LBRACE fields RBRACE
if-expr: IF binop-expr (BLOCK|COLON) block else-if* [ELSECOLON block] END
else-if: ELSEIF binop-expr COLON block
if-pipe-expr: ASK (BLOCK|COLON) if-pipe-branch* [BAR OTHERWISECOLON block] END
if-pipe-branch: BAR binop-expr THENCOLON block
cases-binding: [REF] binding
cases-args: PARENNOSPACE [cases-binding (COMMA cases-binding)*] RPAREN
cases-expr: CASES (PARENSPACE|PARENNOSPACE) ann RPAREN binop-expr (BLOCK|COLON) cases-branch* [BAR ELSE THICKARROW block] END
cases-branch: BAR NAME [cases-args] THICKARROW block
for-bind: binding FROM binop-expr
for-expr: FOR expr PARENNOSPACE [for-bind (COMMA for-bind)*] RPAREN return-ann (BLOCK|COLON) block END
column-order : NAME (ASCENDING|DESCENDING)
table-select : TABLE-SELECT NAME (COMMA NAME)* FROM expr END
table-filter : TABLE-FILTER expr [USING binding (COMMA binding)*] COLON binop-expr END
table-order : TABLE-ORDER expr COLON column-order (COMMA column-order)* END
table-extract: TABLE-EXTRACT NAME FROM expr END
table-update : TABLE-UPDATE expr [USING binding (COMMA binding)*] COLON obj-fields END
table-extend : TABLE-EXTEND expr [USING binding (COMMA binding)*] COLON table-extend-fields END
table-extend-fields: list-table-extend-field* table-extend-field [COMMA]
list-table-extend-field: table-extend-field COMMA
table-extend-field: key [COLONCOLON ann] COLON binop-expr
# Commenting this out until we know whether or not it makes sense
# | REF key [COLONCOLON ann] COLON binop-expr
| key [COLONCOLON ann] COLON expr OF NAME
# More informative to allow missing load-table-specs to parse and mark it as a
# well-formedness error than to reject it at parse-time
load-table-expr: LOAD-TABLE COLON table-headers [load-table-specs] END
load-table-specs: load-table-spec* load-table-spec
load-table-spec: SOURCECOLON expr
| SANITIZE NAME USING expr
user-block-expr: BLOCK block END
ann: name-ann | record-ann | arrow-ann | app-ann | pred-ann | dot-ann | tuple-ann
name-ann: NAME
comma-ann-field: ann-field (COMMA ann-field)*
trailing-opt-comma-ann-field: (comma-ann-field [COMMA] | )
record-ann: LBRACE trailing-opt-comma-ann-field RBRACE
ann-field: NAME COLONCOLON ann
tuple-ann: LBRACE ann (SEMI ann)* [SEMI] RBRACE
noparen-arrow-ann: [arrow-ann-args] THINARROW ann
arrow-ann-args: comma-anns | (PARENSPACE|PARENNOSPACE|PARENAFTERBRACE) comma-ann-field RPAREN
arrow-ann: (PARENSPACE|PARENNOSPACE|PARENAFTERBRACE) [arrow-ann-args] THINARROW ann RPAREN
app-ann: (name-ann|dot-ann) LANGLE comma-anns (RANGLE|GT)
comma-anns: ann (COMMA ann)*
pred-ann: ann PERCENT (PARENSPACE|PARENNOSPACE) id-expr RPAREN
dot-ann : NAME DOT NAME