-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Expand file tree
/
Copy pathpde.g
More file actions
394 lines (347 loc) · 12.4 KB
/
pde.g
File metadata and controls
394 lines (347 loc) · 12.4 KB
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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
/* -*- mode: antlr; c-basic-offset: 4; indent-tabs-mode: nil -*- */
header {
package processing.mode.java.preproc;
}
class PdeRecognizer extends JavaRecognizer;
options {
importVocab = Java;
exportVocab = PdePartial;
//codeGenMakeSwitchThreshold=10; // this is set high for debugging
//codeGenBitsetTestThreshold=10; // this is set high for debugging
// developers may to want to set this to true for better
// debugging messages, however, doing so disables highlighting errors
// in the editor.
defaultErrorHandler = false; //true;
}
tokens {
CONSTRUCTOR_CAST; EMPTY_FIELD;
}
{
// this clause copied from java15.g! ANTLR does not copy this
// section from the super grammar.
/**
* Counts the number of LT seen in the typeArguments production.
* It is used in semantic predicates to ensure we have seen
* enough closing '>' characters; which actually may have been
* either GT, SR or BSR tokens.
*/
private int ltCounter = 0;
private PdePreprocessor pp;
public PdeRecognizer(final PdePreprocessor pp, final TokenStream ts) {
this(ts);
this.pp = pp;
}
private void mixed() throws RecognitionException, TokenStreamException {
throw new RecognitionException("It looks like you're mixing \"active\" and \"static\" modes.",
getFilename(), LT(1).getLine(), LT(1).getColumn());
}
}
pdeProgram
:
// Some programs can be equally well interpreted as STATIC or ACTIVE;
// this forces the parser to prefer the STATIC interpretation.
(staticProgram) => staticProgram
{ pp.setMode(PdePreprocessor.Mode.STATIC); }
| (activeProgram) => activeProgram
{ pp.setMode(PdePreprocessor.Mode.ACTIVE); }
| staticProgram
{ pp.setMode(PdePreprocessor.Mode.STATIC); }
;
// advanced mode is really just a normal java file
javaProgram
: compilationUnit
;
activeProgram
: (
(IDENT LPAREN) => IDENT LPAREN { mixed(); }
| possiblyEmptyField
)+ EOF!
;
staticProgram
: (
statement
)* EOF!
;
// copy of the java.g rule with WEBCOLOR_LITERAL added
constant
: NUM_INT
| CHAR_LITERAL
| STRING_LITERAL
| NUM_FLOAT
| NUM_LONG
| NUM_DOUBLE
| webcolor_literal
;
// fix bug http://dev.processing.org/bugs/show_bug.cgi?id=1519
// by altering a syntactic predicate whose sole purpose is to
// emit a useless error with no line numbers.
// These are from Java15.g, with a few lines edited to make nice errors.
// Type arguments to a class or interface type
typeArguments
{int currentLtLevel = 0;}
:
{currentLtLevel = ltCounter;}
LT! {ltCounter++;}
typeArgument
(options{greedy=true;}: // match as many as possible
{if (! (inputState.guessing !=0 || ltCounter == currentLtLevel + 1)) {
throw new RecognitionException("Maybe too many > characters?",
getFilename(), LT(1).getLine(), LT(1).getColumn());
}}
COMMA! typeArgument
)*
( // turn warning off since Antlr generates the right code,
// plus we have our semantic predicate below
options{generateAmbigWarnings=false;}:
typeArgumentsOrParametersEnd
)?
// make sure we have gobbled up enough '>' characters
// if we are at the "top level" of nested typeArgument productions
{if (! ((currentLtLevel != 0) || ltCounter == currentLtLevel)) {
throw new RecognitionException("Maybe too many > characters?",
getFilename(), LT(1).getLine(), LT(1).getColumn());
}}
{#typeArguments = #(#[TYPE_ARGUMENTS, "TYPE_ARGUMENTS"], #typeArguments);}
;
typeParameters
{int currentLtLevel = 0;}
:
{currentLtLevel = ltCounter;}
LT! {ltCounter++;}
typeParameter (COMMA! typeParameter)*
(typeArgumentsOrParametersEnd)?
// make sure we have gobbled up enough '>' characters
// if we are at the "top level" of nested typeArgument productions
{if (! ((currentLtLevel != 0) || ltCounter == currentLtLevel)) {
throw new RecognitionException("Maybe too many > characters?",
getFilename(), LT(1).getLine(), LT(1).getColumn());
}}
{#typeParameters = #(#[TYPE_PARAMETERS, "TYPE_PARAMETERS"], #typeParameters);}
;
// this gobbles up *some* amount of '>' characters, and counts how many
// it gobbled.
protected typeArgumentsOrParametersEnd
: GT! {ltCounter-=1;}
| SR! {ltCounter-=2;}
| BSR! {ltCounter-=3;}
;
// of the form #cc008f in PDE
webcolor_literal
: w:WEBCOLOR_LITERAL
{ if (! (processing.app.Preferences.getBoolean("preproc.web_colors")
&&
w.getText().length() == 6)) {
throw new RecognitionException("Web colors must be exactly 6 hex digits. This looks like " + w.getText().length() + ".",
getFilename(), LT(1).getLine(), LT(1).getColumn());
}} // must be exactly 6 hex digits
;
// copy of the java.g builtInType rule
builtInConsCastType
: "void"
| "boolean"
| "byte"
| "char"
| "short"
| "int"
| "float"
| "long"
| "double"
;
// our types include the java types and "color". this is separated into two
// rules so that constructor casts can just use the original typelist, since
// we don't want to support the color type as a constructor cast.
//
builtInType
: builtInConsCastType
| "color" // aliased to an int in PDE
{ processing.app.Preferences.getBoolean("preproc.color_datatype") }?
;
// constructor style casts.
constructorCast!
: t:consCastTypeSpec[true]
LPAREN!
e:expression
RPAREN!
// if this is a string literal, make sure the type we're trying to cast
// to is one of the supported ones
//
{ (#e == null) ||
( (#e.getType() != STRING_LITERAL) ||
( #t.getType() == LITERAL_boolean ||
#t.getType() == LITERAL_double ||
#t.getType() == LITERAL_float ||
#t.getType() == LITERAL_int ||
#t.getType() == LITERAL_long ||
#t.getType() == LITERAL_short )) }?
// create the node
//
{#constructorCast = #(#[CONSTRUCTOR_CAST,"CONSTRUCTOR_CAST"], t, e);}
;
// A list of types that be used as the destination type in a constructor-style
// cast. Ideally, this would include all class types, not just "String".
// Unfortunately, it's not possible to tell whether Foo(5) is supposed to be
// a method call or a constructor cast without have a table of all valid
// types or methods, which requires semantic analysis (eg processing of import
// statements). So we accept the set of built-in types plus "String".
//
consCastTypeSpec[boolean addImagNode]
// : stringTypeSpec[addImagNode]
// | builtInConsCastTypeSpec[addImagNode]
: builtInConsCastTypeSpec[addImagNode]
// trying to remove String() cast [fry]
;
//stringTypeSpec[boolean addImagNode]
// : id:IDENT { #id.getText().equals("String") }?
// {
// if ( addImagNode ) {
// #stringTypeSpec = #(#[TYPE,"TYPE"],
// #stringTypeSpec);
// }
// }
// ;
builtInConsCastTypeSpec[boolean addImagNode]
: builtInConsCastType
{
if ( addImagNode ) {
#builtInConsCastTypeSpec = #(#[TYPE,"TYPE"],
#builtInConsCastTypeSpec);
}
}
;
// Since "color" tokens are lexed as LITERAL_color now, we need to have a rule
// that can generate a method call from an expression that starts with this
// token
//
colorMethodCall
: c:"color" {#c.setType(IDENT);} // this would default to LITERAL_color
lp:LPAREN^ {#lp.setType(METHOD_CALL);}
argList
RPAREN!
;
// copy of the java.g rule with added constructorCast and colorMethodCall
// alternatives
primaryExpression
: (consCastTypeSpec[false] LPAREN) => constructorCast
{ processing.app.Preferences.getBoolean("preproc.enhanced_casting") }?
| identPrimary ( options {greedy=true;} : DOT^ "class" )?
| constant
| "true"
| "false"
| "null"
| newExpression
| "this"
| "super"
| LPAREN! assignmentExpression RPAREN!
| colorMethodCall
// look for int.class and int[].class
| builtInType
( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )*
DOT^ "class"
;
// the below variable rule hacks are needed so that it's possible for the
// emitter to correctly output variable declarations of the form "float a, b"
// from the AST. This means that our AST has a somewhat different form in
// these rules than the java one does, and this new form may have its own
// semantic issues. But it seems to fix the comma declaration issues.
//
variableDefinitions![AST mods, AST t]
: vd:variableDeclarator[getASTFactory().dupTree(mods),
getASTFactory().dupTree(t)]
{#variableDefinitions = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods,
t, vd);}
;
variableDeclarator[AST mods, AST t]
: ( id:IDENT (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
v:varInitializer (COMMA!)? )+
;
// java.g builds syntax trees with an inconsistent structure. override one of
// the rules there to fix this.
//
explicitConstructorInvocation!
: (typeArguments)?
t:"this" LPAREN a1:argList RPAREN SEMI
{#explicitConstructorInvocation = #(#[CTOR_CALL, "CTOR_CALL"],
#t, #a1);}
| s:"super" LPAREN a2:argList RPAREN SEMI
{#explicitConstructorInvocation = #(#[SUPER_CTOR_CALL,
"SUPER_CTOR_CALL"],
#s, #a2);}
;
// quick-n-dirty hack to the get the advanced class name. we should
// really be getting it from the AST and not forking this rule from
// the java.g copy at all. Since this is a recursive descent parser, we get
// the last class name in the file so that we don't end up with the classname
// of an inner class. If there is more than one "outer" class in a file,
// this heuristic will fail.
//
classDefinition![AST modifiers]
: "class" i:IDENT
// it _might_ have type paramaters
(tp:typeParameters)?
// it _might_ have a superclass...
sc:superClassClause
// it might implement some interfaces...
ic:implementsClause
// now parse the body of the class
cb:classBlock
{#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"],
modifiers,i,tp,sc,ic,cb);
pp.setAdvClassName(i.getText());}
;
possiblyEmptyField
: classField
| s:SEMI {#s.setType(EMPTY_FIELD);}
;
class PdeLexer extends JavaLexer;
options {
importVocab=PdePartial;
exportVocab=Pde;
}
// We need to preserve whitespace and commentary instead of ignoring
// like the supergrammar does. Otherwise Jikes won't be able to give
// us error messages that point to the equivalent PDE code.
// WS, SL_COMMENT, ML_COMMENT are copies of the original productions,
// but with the SKIP assigment removed.
WS : ( ' '
| '\t'
| '\f'
// handle newlines
| ( options {generateAmbigWarnings=false;}
: "\r\n" // Evil DOS
| '\r' // Macintosh
| '\n' // Unix (the right way)
)
{ newline(); }
)+
;
// Single-line comments
SL_COMMENT
: "//"
(~('\n'|'\r'))* ('\n'|'\r'('\n')?)
{newline();}
;
// multiple-line comments
ML_COMMENT
: "/*"
( /* '\r' '\n' can be matched in one alternative or by matching
'\r' in one iteration and '\n' in another. I am trying to
handle any flavor of newline that comes in, but the language
that allows both "\r\n" and "\r" and "\n" to all be valid
newline is ambiguous. Consequently, the resulting grammar
must be ambiguous. I'm shutting this warning off.
*/
options {
generateAmbigWarnings=false;
}
:
{ LA(2)!='/' }? '*'
| '\r' '\n' {newline();}
| '\r' {newline();}
| '\n' {newline();}
| ~('*'|'\n'|'\r')
)*
"*/"
;
WEBCOLOR_LITERAL
: '#'! (HEX_DIGIT)+
;