Mercurial Hosting > luan
comparison src/luan/interp/LuanParser.java @ 129:486a0641bca4
add pickle client/server;
fix parser bugs;
git-svn-id: https://luan-java.googlecode.com/svn/trunk@130 21e917c8-12df-6dd8-5cb6-c86387c605b9
author | fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9> |
---|---|
date | Mon, 09 Jun 2014 09:16:16 +0000 |
parents | f0a4abe58593 |
children | 573ce091ae00 |
comparison
equal
deleted
inserted
replaced
128:f0a4abe58593 | 129:486a0641bca4 |
---|---|
70 upValueSymbols.add(name); | 70 upValueSymbols.add(name); |
71 upValueGetters.add(upValueGetter); | 71 upValueGetters.add(upValueGetter); |
72 } | 72 } |
73 } | 73 } |
74 | 74 |
75 private static class In { | |
76 static final In NOTHING = new In(false,false); | |
77 | |
78 final boolean parens; | |
79 final boolean jsp; | |
80 | |
81 private In(boolean parens,boolean jsp) { | |
82 this.parens = parens; | |
83 this.jsp = jsp; | |
84 } | |
85 | |
86 In parens() { | |
87 return parens ? this : new In(true,jsp); | |
88 } | |
89 | |
90 In jsp() { | |
91 return jsp ? this : new In(parens,true); | |
92 } | |
93 } | |
94 | |
75 private static final String _ENV = "_ENV"; | 95 private static final String _ENV = "_ENV"; |
76 private static final UpValue.Getter[] NO_UP_VALUE_GETTERS = new UpValue.Getter[0]; | 96 private static final UpValue.Getter[] NO_UP_VALUE_GETTERS = new UpValue.Getter[0]; |
77 | 97 |
78 final LuanSource source; | 98 final LuanSource source; |
79 private Frame frame; | 99 private Frame frame; |
159 private FnDef newFnDef(int start,Stmt stmt) { | 179 private FnDef newFnDef(int start,Stmt stmt) { |
160 return new FnDef( se(start), stmt, frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) ); | 180 return new FnDef( se(start), stmt, frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) ); |
161 } | 181 } |
162 | 182 |
163 FnDef Expressions() throws ParseException { | 183 FnDef Expressions() throws ParseException { |
164 Spaces(); | 184 Spaces(In.NOTHING); |
165 int start = parser.begin(); | 185 int start = parser.begin(); |
166 Expressions exprs = ExpList(); | 186 Expressions exprs = ExpList(In.NOTHING); |
167 if( exprs != null && parser.endOfInput() ) { | 187 if( exprs != null && parser.endOfInput() ) { |
168 Stmt stmt = new ReturnStmt( se(start), exprs ); | 188 Stmt stmt = new ReturnStmt( se(start), exprs ); |
169 return parser.success(newFnDef(start,stmt)); | 189 return parser.success(newFnDef(start,stmt)); |
170 } | 190 } |
171 return parser.failure(null); | 191 return parser.failure(null); |
172 } | 192 } |
173 | 193 |
174 FnDef RequiredModule() throws ParseException { | 194 FnDef RequiredModule() throws ParseException { |
175 Spaces(); | 195 Spaces(In.NOTHING); |
176 int start = parser.begin(); | 196 int start = parser.begin(); |
177 frame.isVarArg = true; | 197 frame.isVarArg = true; |
178 Stmt stmt = RequiredBlock(); | 198 Stmt stmt = RequiredBlock(); |
179 if( parser.endOfInput() ) | 199 if( parser.endOfInput() ) |
180 return parser.success(newFnDef(start,stmt)); | 200 return parser.success(newFnDef(start,stmt)); |
184 private Stmt RequiredBlock() throws ParseException { | 204 private Stmt RequiredBlock() throws ParseException { |
185 List<Stmt> stmts = new ArrayList<Stmt>(); | 205 List<Stmt> stmts = new ArrayList<Stmt>(); |
186 int stackStart = symbolsSize(); | 206 int stackStart = symbolsSize(); |
187 Stmt(stmts); | 207 Stmt(stmts); |
188 while( StmtSep(stmts) ) { | 208 while( StmtSep(stmts) ) { |
189 Spaces(); | 209 Spaces(In.NOTHING); |
190 Stmt(stmts); | 210 Stmt(stmts); |
191 } | 211 } |
192 int stackEnd = symbolsSize(); | 212 int stackEnd = symbolsSize(); |
193 popSymbols( stackEnd - stackStart ); | 213 popSymbols( stackEnd - stackStart ); |
194 if( stmts.isEmpty() ) | 214 if( stmts.isEmpty() ) |
233 ) { | 253 ) { |
234 stmts.add(stmt); | 254 stmts.add(stmt); |
235 } | 255 } |
236 } | 256 } |
237 | 257 |
238 private Expressions JspExpressions() throws ParseException { | 258 private Expressions JspExpressions(In in) throws ParseException { |
259 if( in.jsp ) | |
260 return null; | |
239 int start = parser.begin(); | 261 int start = parser.begin(); |
240 if( !parser.match( "%>" ) ) | 262 if( !parser.match( "%>" ) ) |
241 return parser.failure(null); | 263 return parser.failure(null); |
242 EndOfLine(); | 264 EndOfLine(); |
265 In inJsp = in.jsp(); | |
243 ExpList.Builder builder = new ExpList.Builder(); | 266 ExpList.Builder builder = new ExpList.Builder(); |
244 while(true) { | 267 while(true) { |
245 if( parser.match( "<%=" ) ) { | 268 if( parser.match( "<%=" ) ) { |
246 Spaces(); | 269 Spaces(inJsp); |
247 builder.add( RequiredExpr() ); | 270 builder.add( RequiredExpr(inJsp) ); |
248 RequiredMatch( "%>" ); | 271 RequiredMatch( "%>" ); |
249 } else if( parser.match( "<%" ) ) { | 272 } else if( parser.match( "<%" ) ) { |
250 Spaces(); | 273 Spaces(inJsp); |
251 return parser.success(builder.build()); | 274 return parser.success(builder.build()); |
252 } else { | 275 } else { |
253 int i = parser.currentIndex(); | 276 int i = parser.currentIndex(); |
254 do { | 277 do { |
255 if( parser.match( "%>" ) ) | 278 if( parser.match( "%>" ) ) |
263 } | 286 } |
264 } | 287 } |
265 | 288 |
266 private Stmt ReturnStmt() throws ParseException { | 289 private Stmt ReturnStmt() throws ParseException { |
267 int start = parser.begin(); | 290 int start = parser.begin(); |
268 if( !Keyword("return") ) | 291 if( !Keyword("return",In.NOTHING) ) |
269 return parser.failure(null); | 292 return parser.failure(null); |
270 Expressions exprs = ExpList(); | 293 Expressions exprs = ExpList(In.NOTHING); |
271 if( exprs==null ) | 294 if( exprs==null ) |
272 exprs = ExpList.emptyExpList; | 295 exprs = ExpList.emptyExpList; |
273 return parser.success( new ReturnStmt(se(start),exprs) ); | 296 return parser.success( new ReturnStmt(se(start),exprs) ); |
274 } | 297 } |
275 | 298 |
276 private Stmt FunctionStmt() throws ParseException { | 299 private Stmt FunctionStmt() throws ParseException { |
277 parser.begin(); | 300 parser.begin(); |
278 if( !Keyword("function") ) | 301 if( !Keyword("function",In.NOTHING) ) |
279 return parser.failure(null); | 302 return parser.failure(null); |
280 | 303 |
281 int start = parser.currentIndex(); | 304 int start = parser.currentIndex(); |
282 Var var = nameVar(start,RequiredName()); | 305 Var var = nameVar(start,RequiredName(In.NOTHING)); |
283 while( parser.match( '.' ) ) { | 306 while( parser.match( '.' ) ) { |
284 Spaces(); | 307 Spaces(In.NOTHING); |
285 var = indexVar( start, expr(var.expr()), NameExpr(false) ); | 308 var = indexVar( start, expr(var.expr()), NameExpr(In.NOTHING) ); |
286 } | 309 } |
287 Settable fnName = var.settable(); | 310 Settable fnName = var.settable(); |
288 | 311 |
289 FnDef fnDef = RequiredFunction(false); | 312 FnDef fnDef = RequiredFunction(In.NOTHING); |
290 return parser.success( new SetStmt(fnName,fnDef) ); | 313 return parser.success( new SetStmt(fnName,fnDef) ); |
291 } | 314 } |
292 | 315 |
293 private Stmt LocalFunctionStmt() throws ParseException { | 316 private Stmt LocalFunctionStmt() throws ParseException { |
294 parser.begin(); | 317 parser.begin(); |
295 if( !(Keyword("local") && Keyword("function")) ) | 318 if( !(Keyword("local",In.NOTHING) && Keyword("function",In.NOTHING)) ) |
296 return parser.failure(null); | 319 return parser.failure(null); |
297 String name = RequiredName(); | 320 String name = RequiredName(In.NOTHING); |
298 addSymbol( name ); | 321 addSymbol( name ); |
299 FnDef fnDef = RequiredFunction(false); | 322 FnDef fnDef = RequiredFunction(In.NOTHING); |
300 return parser.success( new SetStmt( new SetLocalVar(symbolsSize()-1), fnDef ) ); | 323 return parser.success( new SetStmt( new SetLocalVar(symbolsSize()-1), fnDef ) ); |
301 } | 324 } |
302 | 325 |
303 private Stmt ImportStmt() throws ParseException { | 326 private Stmt ImportStmt() throws ParseException { |
304 int start = parser.begin(); | 327 int start = parser.begin(); |
305 if( !Keyword("import") ) | 328 if( !Keyword("import",In.NOTHING) ) |
306 return parser.failure(null); | 329 return parser.failure(null); |
307 Expr importExpr = (Expr)nameVar(start,"require").expr(); | 330 Expr importExpr = (Expr)nameVar(start,"require").expr(); |
308 String modName = StringLiteral(false); | 331 String modName = StringLiteral(In.NOTHING); |
309 if( modName==null ) | 332 if( modName==null ) |
310 return parser.failure(null); | 333 return parser.failure(null); |
311 String varName = modName.substring(modName.lastIndexOf('.')+1); | 334 String varName = modName.substring(modName.lastIndexOf('.')+1); |
312 LuanSource.Element se = se(start); | 335 LuanSource.Element se = se(start); |
313 FnCall require = new FnCall( se, importExpr, new ExpList.SingleExpList(new ConstExpr(modName)) ); | 336 FnCall require = new FnCall( se, importExpr, new ExpList.SingleExpList(new ConstExpr(modName)) ); |
321 return parser.success( new SetStmt( settable, expr(require) ) ); | 344 return parser.success( new SetStmt( settable, expr(require) ) ); |
322 } | 345 } |
323 | 346 |
324 private Stmt BreakStmt() throws ParseException { | 347 private Stmt BreakStmt() throws ParseException { |
325 parser.begin(); | 348 parser.begin(); |
326 if( !Keyword("break") ) | 349 if( !Keyword("break",In.NOTHING) ) |
327 return parser.failure(null); | 350 return parser.failure(null); |
328 if( frame.loops <= 0 ) | 351 if( frame.loops <= 0 ) |
329 throw parser.exception("'break' outside of loop"); | 352 throw parser.exception("'break' outside of loop"); |
330 return parser.success( new BreakStmt() ); | 353 return parser.success( new BreakStmt() ); |
331 } | 354 } |
332 | 355 |
333 private Stmt ForStmt() throws ParseException { | 356 private Stmt ForStmt() throws ParseException { |
334 int start = parser.begin(); | 357 int start = parser.begin(); |
335 int stackStart = symbolsSize(); | 358 int stackStart = symbolsSize(); |
336 if( !Keyword("for") ) | 359 if( !Keyword("for",In.NOTHING) ) |
337 return parser.failure(null); | 360 return parser.failure(null); |
338 List<String> names = RequiredNameList(false); | 361 List<String> names = RequiredNameList(In.NOTHING); |
339 if( !Keyword("in") ) | 362 if( !Keyword("in",In.NOTHING) ) |
340 return parser.failure(null); | 363 return parser.failure(null); |
341 Expr expr = expr(RequiredExpr()); | 364 Expr expr = expr(RequiredExpr(In.NOTHING)); |
342 RequiredKeyword("do"); | 365 RequiredKeyword("do",In.NOTHING); |
343 addSymbols(names); | 366 addSymbols(names); |
344 Stmt loop = RequiredLoopBlock(); | 367 Stmt loop = RequiredLoopBlock(); |
345 RequiredKeyword("end"); | 368 RequiredKeyword("end",In.NOTHING); |
346 Stmt stmt = new ForStmt( se(start), stackStart, symbolsSize() - stackStart, expr, loop ); | 369 Stmt stmt = new ForStmt( se(start), stackStart, symbolsSize() - stackStart, expr, loop ); |
347 popSymbols( symbolsSize() - stackStart ); | 370 popSymbols( symbolsSize() - stackStart ); |
348 return parser.success(stmt); | 371 return parser.success(stmt); |
349 } | 372 } |
350 | 373 |
351 private Stmt TryStmt() throws ParseException { | 374 private Stmt TryStmt() throws ParseException { |
352 parser.begin(); | 375 parser.begin(); |
353 if( !Keyword("try") ) | 376 if( !Keyword("try",In.NOTHING) ) |
354 return parser.failure(null); | 377 return parser.failure(null); |
355 Stmt tryBlock = RequiredBlock(); | 378 Stmt tryBlock = RequiredBlock(); |
356 RequiredKeyword("catch"); | 379 RequiredKeyword("catch",In.NOTHING); |
357 String name = RequiredName(); | 380 String name = RequiredName(In.NOTHING); |
358 addSymbol(name); | 381 addSymbol(name); |
359 RequiredKeyword("do"); | 382 RequiredKeyword("do",In.NOTHING); |
360 Stmt catchBlock = RequiredBlock(); | 383 Stmt catchBlock = RequiredBlock(); |
361 RequiredKeyword("end"); | 384 RequiredKeyword("end",In.NOTHING); |
362 Stmt stmt = new TryStmt( tryBlock, symbolsSize()-1, catchBlock ); | 385 Stmt stmt = new TryStmt( tryBlock, symbolsSize()-1, catchBlock ); |
363 popSymbols(1); | 386 popSymbols(1); |
364 return parser.success(stmt); | 387 return parser.success(stmt); |
365 } | 388 } |
366 | 389 |
367 private Stmt DoStmt() throws ParseException { | 390 private Stmt DoStmt() throws ParseException { |
368 parser.begin(); | 391 parser.begin(); |
369 if( !Keyword("do") ) | 392 if( !Keyword("do",In.NOTHING) ) |
370 return parser.failure(null); | 393 return parser.failure(null); |
371 Stmt stmt = RequiredBlock(); | 394 Stmt stmt = RequiredBlock(); |
372 RequiredKeyword("end"); | 395 RequiredKeyword("end",In.NOTHING); |
373 return parser.success(stmt); | 396 return parser.success(stmt); |
374 } | 397 } |
375 | 398 |
376 private boolean LocalStmt(List<Stmt> stmts) throws ParseException { | 399 private boolean LocalStmt(List<Stmt> stmts) throws ParseException { |
377 parser.begin(); | 400 parser.begin(); |
378 if( !Keyword("local") ) | 401 if( !Keyword("local",In.NOTHING) ) |
379 return parser.failure(); | 402 return parser.failure(); |
380 List<String> names = NameList(false); | 403 List<String> names = NameList(In.NOTHING); |
381 if( names==null ) | 404 if( names==null ) |
382 return parser.failure(); | 405 return parser.failure(); |
383 if( parser.match( '=' ) ) { | 406 if( parser.match( '=' ) ) { |
384 Spaces(); | 407 Spaces(In.NOTHING); |
385 Expressions values = ExpList(); | 408 Expressions values = ExpList(In.NOTHING); |
386 if( values==null ) | 409 if( values==null ) |
387 throw parser.exception("Expressions expected"); | 410 throw parser.exception("Expressions expected"); |
388 SetLocalVar[] vars = new SetLocalVar[names.size()]; | 411 SetLocalVar[] vars = new SetLocalVar[names.size()]; |
389 int stackStart = symbolsSize(); | 412 int stackStart = symbolsSize(); |
390 for( int i=0; i<vars.length; i++ ) { | 413 for( int i=0; i<vars.length; i++ ) { |
394 } | 417 } |
395 addSymbols(names); | 418 addSymbols(names); |
396 return parser.success(); | 419 return parser.success(); |
397 } | 420 } |
398 | 421 |
399 private List<String> RequiredNameList(boolean inParens) throws ParseException { | 422 private List<String> RequiredNameList(In in) throws ParseException { |
400 parser.begin(); | 423 parser.begin(); |
401 List<String> names = NameList(inParens); | 424 List<String> names = NameList(in); |
402 if( names==null ) | 425 if( names==null ) |
403 parser.exception("Name expected"); | 426 parser.exception("Name expected"); |
404 return parser.success(names); | 427 return parser.success(names); |
405 } | 428 } |
406 | 429 |
407 private List<String> NameList(boolean inParens) throws ParseException { | 430 private List<String> NameList(In in) throws ParseException { |
408 String name = Name(inParens); | 431 String name = Name(in); |
409 if( name==null ) | 432 if( name==null ) |
410 return null; | 433 return null; |
411 List<String> names = new ArrayList<String>(); | 434 List<String> names = new ArrayList<String>(); |
412 names.add(name); | 435 names.add(name); |
413 while( parser.match( ',' ) ) { | 436 while( parser.match( ',' ) ) { |
414 Spaces(inParens); | 437 Spaces(in); |
415 names.add( RequiredName() ); | 438 names.add( RequiredName(in) ); |
416 } | 439 } |
417 return names; | 440 return names; |
418 } | 441 } |
419 | 442 |
420 private Stmt WhileStmt() throws ParseException { | 443 private Stmt WhileStmt() throws ParseException { |
421 parser.begin(); | 444 parser.begin(); |
422 if( !Keyword("while") ) | 445 if( !Keyword("while",In.NOTHING) ) |
423 return parser.failure(null); | 446 return parser.failure(null); |
424 Expr cnd = expr(RequiredExpr()); | 447 Expr cnd = expr(RequiredExpr(In.NOTHING)); |
425 RequiredKeyword("do"); | 448 RequiredKeyword("do",In.NOTHING); |
426 Stmt loop = RequiredLoopBlock(); | 449 Stmt loop = RequiredLoopBlock(); |
427 RequiredKeyword("end"); | 450 RequiredKeyword("end",In.NOTHING); |
428 return parser.success( new WhileStmt(cnd,loop) ); | 451 return parser.success( new WhileStmt(cnd,loop) ); |
429 } | 452 } |
430 | 453 |
431 private Stmt RepeatStmt() throws ParseException { | 454 private Stmt RepeatStmt() throws ParseException { |
432 parser.begin(); | 455 parser.begin(); |
433 if( !Keyword("repeat") ) | 456 if( !Keyword("repeat",In.NOTHING) ) |
434 return parser.failure(null); | 457 return parser.failure(null); |
435 Stmt loop = RequiredLoopBlock(); | 458 Stmt loop = RequiredLoopBlock(); |
436 RequiredKeyword("until"); | 459 RequiredKeyword("until",In.NOTHING); |
437 Expr cnd = expr(RequiredExpr()); | 460 Expr cnd = expr(RequiredExpr(In.NOTHING)); |
438 return parser.success( new RepeatStmt(loop,cnd) ); | 461 return parser.success( new RepeatStmt(loop,cnd) ); |
439 } | 462 } |
440 | 463 |
441 private Stmt RequiredLoopBlock() throws ParseException { | 464 private Stmt RequiredLoopBlock() throws ParseException { |
442 incLoops(); | 465 incLoops(); |
445 return stmt; | 468 return stmt; |
446 } | 469 } |
447 | 470 |
448 private Stmt IfStmt() throws ParseException { | 471 private Stmt IfStmt() throws ParseException { |
449 parser.begin(); | 472 parser.begin(); |
450 if( !Keyword("if") ) | 473 if( !Keyword("if",In.NOTHING) ) |
451 return parser.failure(null); | 474 return parser.failure(null); |
452 return parser.success( IfStmt2() ); | 475 return parser.success( IfStmt2() ); |
453 } | 476 } |
454 | 477 |
455 private Stmt IfStmt2() throws ParseException { | 478 private Stmt IfStmt2() throws ParseException { |
456 Expr cnd = expr(RequiredExpr()); | 479 Expr cnd = expr(RequiredExpr(In.NOTHING)); |
457 RequiredKeyword("then"); | 480 RequiredKeyword("then",In.NOTHING); |
458 Stmt thenBlock = RequiredBlock(); | 481 Stmt thenBlock = RequiredBlock(); |
459 Stmt elseBlock; | 482 Stmt elseBlock; |
460 if( Keyword("elseif") ) { | 483 if( Keyword("elseif",In.NOTHING) ) { |
461 elseBlock = IfStmt2(); | 484 elseBlock = IfStmt2(); |
462 } else { | 485 } else { |
463 elseBlock = Keyword("else") ? RequiredBlock() : Stmt.EMPTY; | 486 elseBlock = Keyword("else",In.NOTHING) ? RequiredBlock() : Stmt.EMPTY; |
464 RequiredKeyword("end"); | 487 RequiredKeyword("end",In.NOTHING); |
465 } | 488 } |
466 return new IfStmt(cnd,thenBlock,elseBlock); | 489 return new IfStmt(cnd,thenBlock,elseBlock); |
467 } | 490 } |
468 | 491 |
469 private Stmt SetStmt() throws ParseException { | 492 private Stmt SetStmt() throws ParseException { |
472 Settable s = SettableVar(); | 495 Settable s = SettableVar(); |
473 if( s == null ) | 496 if( s == null ) |
474 return parser.failure(null); | 497 return parser.failure(null); |
475 vars.add(s); | 498 vars.add(s); |
476 while( parser.match( ',' ) ) { | 499 while( parser.match( ',' ) ) { |
477 Spaces(); | 500 Spaces(In.NOTHING); |
478 s = SettableVar(); | 501 s = SettableVar(); |
479 if( s == null ) | 502 if( s == null ) |
480 return parser.failure(null); | 503 return parser.failure(null); |
481 vars.add(s); | 504 vars.add(s); |
482 } | 505 } |
483 if( !parser.match( '=' ) ) | 506 if( !parser.match( '=' ) ) |
484 return parser.failure(null); | 507 return parser.failure(null); |
485 Spaces(); | 508 Spaces(In.NOTHING); |
486 Expressions values = ExpList(); | 509 Expressions values = ExpList(In.NOTHING); |
487 if( values==null ) | 510 if( values==null ) |
488 throw parser.exception("Expressions expected"); | 511 throw parser.exception("Expressions expected"); |
489 return parser.success( new SetStmt( vars.toArray(new Settable[0]), values ) ); | 512 return parser.success( new SetStmt( vars.toArray(new Settable[0]), values ) ); |
490 } | 513 } |
491 | 514 |
492 private Stmt ExpressionsStmt() throws ParseException { | 515 private Stmt ExpressionsStmt() throws ParseException { |
493 parser.begin(); | 516 parser.begin(); |
494 Expressions exprs = ExpList(); | 517 Expressions exprs = ExpList(In.NOTHING); |
495 if( exprs==null ) | 518 if( exprs==null ) |
496 return parser.failure(null); | 519 return parser.failure(null); |
497 return parser.success( new ExpressionsStmt(exprs) ); | 520 return parser.success( new ExpressionsStmt(exprs) ); |
498 } | 521 } |
499 | 522 |
500 private Settable SettableVar() throws ParseException { | 523 private Settable SettableVar() throws ParseException { |
501 int start = parser.begin(); | 524 int start = parser.begin(); |
502 Var var = VarZ(false); | 525 Var var = VarZ(In.NOTHING); |
503 if( var==null ) | 526 if( var==null ) |
504 return null; | 527 return null; |
505 return var.settable(); | 528 return var.settable(); |
506 } | 529 } |
507 | 530 |
508 private Code RequiredExpr() throws ParseException { | 531 private Code RequiredExpr(In in) throws ParseException { |
509 return RequiredExpr(false); | 532 parser.begin(); |
510 } | 533 return parser.success(required(Expr(in),"Bad expression")); |
511 | 534 } |
512 private Code Expr() throws ParseException { | 535 |
513 return Expr(false); | 536 private Code Expr(In in) throws ParseException { |
514 } | |
515 | |
516 private Code RequiredExpr(boolean inParens) throws ParseException { | |
517 parser.begin(); | |
518 return parser.success(required(Expr(inParens),"Bad expression")); | |
519 } | |
520 | |
521 private Code Expr(boolean inParens) throws ParseException { | |
522 parser.begin(); | 537 parser.begin(); |
523 Code exp; | 538 Code exp; |
524 return (exp = VarArgs(inParens)) != null | 539 return (exp = VarArgs(in)) != null |
525 || (exp = JspExpressions()) != null | 540 || (exp = JspExpressions(in)) != null |
526 || (exp = OrExpr(inParens)) != null | 541 || (exp = OrExpr(in)) != null |
527 ? parser.success(exp) | 542 ? parser.success(exp) |
528 : parser.failure((Code)null) | 543 : parser.failure((Code)null) |
529 ; | 544 ; |
530 } | 545 } |
531 | 546 |
532 private Code OrExpr(boolean inParens) throws ParseException { | 547 private Code OrExpr(In in) throws ParseException { |
533 int start = parser.begin(); | 548 int start = parser.begin(); |
534 Code exp = AndExpr(inParens); | 549 Code exp = AndExpr(in); |
535 if( exp==null ) | 550 if( exp==null ) |
536 return parser.failure(null); | 551 return parser.failure(null); |
537 while( Keyword("or",inParens) ) { | 552 while( Keyword("or",in) ) { |
538 exp = new OrExpr( se(start), expr(exp), required(expr(AndExpr(inParens))) ); | 553 exp = new OrExpr( se(start), expr(exp), required(expr(AndExpr(in))) ); |
539 } | 554 } |
540 return parser.success(exp); | 555 return parser.success(exp); |
541 } | 556 } |
542 | 557 |
543 private Code AndExpr(boolean inParens) throws ParseException { | 558 private Code AndExpr(In in) throws ParseException { |
544 int start = parser.begin(); | 559 int start = parser.begin(); |
545 Code exp = RelExpr(inParens); | 560 Code exp = RelExpr(in); |
546 if( exp==null ) | 561 if( exp==null ) |
547 return parser.failure(null); | 562 return parser.failure(null); |
548 while( Keyword("and",inParens) ) { | 563 while( Keyword("and",in) ) { |
549 exp = new AndExpr( se(start), expr(exp), required(expr(RelExpr(inParens))) ); | 564 exp = new AndExpr( se(start), expr(exp), required(expr(RelExpr(in))) ); |
550 } | 565 } |
551 return parser.success(exp); | 566 return parser.success(exp); |
552 } | 567 } |
553 | 568 |
554 private Code RelExpr(boolean inParens) throws ParseException { | 569 private Code RelExpr(In in) throws ParseException { |
555 int start = parser.begin(); | 570 int start = parser.begin(); |
556 Code exp = ConcatExpr(inParens); | 571 Code exp = ConcatExpr(in); |
557 if( exp==null ) | 572 if( exp==null ) |
558 return parser.failure(null); | 573 return parser.failure(null); |
559 while(true) { | 574 while(true) { |
560 if( parser.match("==") ) { | 575 if( parser.match("==") ) { |
561 Spaces(inParens); | 576 Spaces(in); |
562 exp = new EqExpr( se(start), expr(exp), required(expr(ConcatExpr(inParens))) ); | 577 exp = new EqExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ); |
563 } else if( parser.match("~=") ) { | 578 } else if( parser.match("~=") ) { |
564 Spaces(inParens); | 579 Spaces(in); |
565 exp = new NotExpr( se(start), new EqExpr( se(start), expr(exp), required(expr(ConcatExpr(inParens))) ) ); | 580 exp = new NotExpr( se(start), new EqExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ) ); |
566 } else if( parser.match("<=") ) { | 581 } else if( parser.match("<=") ) { |
567 Spaces(inParens); | 582 Spaces(in); |
568 exp = new LeExpr( se(start), expr(exp), required(expr(ConcatExpr(inParens))) ); | 583 exp = new LeExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ); |
569 } else if( parser.match(">=") ) { | 584 } else if( parser.match(">=") ) { |
570 Spaces(inParens); | 585 Spaces(in); |
571 exp = new LeExpr( se(start), required(expr(ConcatExpr(inParens))), expr(exp) ); | 586 exp = new LeExpr( se(start), required(expr(ConcatExpr(in))), expr(exp) ); |
572 } else if( parser.match("<") ) { | 587 } else if( parser.match("<") ) { |
573 Spaces(inParens); | 588 Spaces(in); |
574 exp = new LtExpr( se(start), expr(exp), required(expr(ConcatExpr(inParens))) ); | 589 exp = new LtExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ); |
575 } else if( parser.match(">") ) { | 590 } else if( parser.match(">") ) { |
576 Spaces(inParens); | 591 Spaces(in); |
577 exp = new LtExpr( se(start), required(expr(ConcatExpr(inParens))), expr(exp) ); | 592 exp = new LtExpr( se(start), required(expr(ConcatExpr(in))), expr(exp) ); |
578 } else | 593 } else |
579 break; | 594 break; |
580 } | 595 } |
581 return parser.success(exp); | 596 return parser.success(exp); |
582 } | 597 } |
583 | 598 |
584 private Code ConcatExpr(boolean inParens) throws ParseException { | 599 private Code ConcatExpr(In in) throws ParseException { |
585 int start = parser.begin(); | 600 int start = parser.begin(); |
586 Code exp = SumExpr(inParens); | 601 Code exp = SumExpr(in); |
587 if( exp==null ) | 602 if( exp==null ) |
588 return parser.failure(null); | 603 return parser.failure(null); |
589 if( parser.match("..") ) { | 604 if( parser.match("..") ) { |
590 Spaces(inParens); | 605 Spaces(in); |
591 exp = new ConcatExpr( se(start), expr(exp), required(expr(ConcatExpr(inParens))) ); | 606 exp = new ConcatExpr( se(start), expr(exp), required(expr(ConcatExpr(in))) ); |
592 } | 607 } |
593 return parser.success(exp); | 608 return parser.success(exp); |
594 } | 609 } |
595 | 610 |
596 private Code SumExpr(boolean inParens) throws ParseException { | 611 private Code SumExpr(In in) throws ParseException { |
597 int start = parser.begin(); | 612 int start = parser.begin(); |
598 Code exp = TermExpr(inParens); | 613 Code exp = TermExpr(in); |
599 if( exp==null ) | 614 if( exp==null ) |
600 return parser.failure(null); | 615 return parser.failure(null); |
601 while(true) { | 616 while(true) { |
602 if( parser.match('+') ) { | 617 if( parser.match('+') ) { |
603 Spaces(inParens); | 618 Spaces(in); |
604 exp = new AddExpr( se(start), expr(exp), required(expr(TermExpr(inParens))) ); | 619 exp = new AddExpr( se(start), expr(exp), required(expr(TermExpr(in))) ); |
605 } else if( Minus() ) { | 620 } else if( Minus() ) { |
606 Spaces(inParens); | 621 Spaces(in); |
607 exp = new SubExpr( se(start), expr(exp), required(expr(TermExpr(inParens))) ); | 622 exp = new SubExpr( se(start), expr(exp), required(expr(TermExpr(in))) ); |
608 } else | 623 } else |
609 break; | 624 break; |
610 } | 625 } |
611 return parser.success(exp); | 626 return parser.success(exp); |
612 } | 627 } |
614 private boolean Minus() { | 629 private boolean Minus() { |
615 parser.begin(); | 630 parser.begin(); |
616 return parser.match('-') && !parser.match('-') ? parser.success() : parser.failure(); | 631 return parser.match('-') && !parser.match('-') ? parser.success() : parser.failure(); |
617 } | 632 } |
618 | 633 |
619 private Code TermExpr(boolean inParens) throws ParseException { | 634 private Code TermExpr(In in) throws ParseException { |
620 int start = parser.begin(); | 635 int start = parser.begin(); |
621 Code exp = UnaryExpr(inParens); | 636 Code exp = UnaryExpr(in); |
622 if( exp==null ) | 637 if( exp==null ) |
623 return parser.failure(null); | 638 return parser.failure(null); |
624 while(true) { | 639 while(true) { |
625 if( parser.match('*') ) { | 640 if( parser.match('*') ) { |
626 Spaces(inParens); | 641 Spaces(in); |
627 exp = new MulExpr( se(start), expr(exp), required(expr(UnaryExpr(inParens))) ); | 642 exp = new MulExpr( se(start), expr(exp), required(expr(UnaryExpr(in))) ); |
628 } else if( parser.match('/') ) { | 643 } else if( parser.match('/') ) { |
629 Spaces(inParens); | 644 Spaces(in); |
630 exp = new DivExpr( se(start), expr(exp), required(expr(UnaryExpr(inParens))) ); | 645 exp = new DivExpr( se(start), expr(exp), required(expr(UnaryExpr(in))) ); |
631 } else if( Mod() ) { | 646 } else if( Mod() ) { |
632 Spaces(inParens); | 647 Spaces(in); |
633 exp = new ModExpr( se(start), expr(exp), required(expr(UnaryExpr(inParens))) ); | 648 exp = new ModExpr( se(start), expr(exp), required(expr(UnaryExpr(in))) ); |
634 } else | 649 } else |
635 break; | 650 break; |
636 } | 651 } |
637 return parser.success(exp); | 652 return parser.success(exp); |
638 } | 653 } |
640 private boolean Mod() { | 655 private boolean Mod() { |
641 parser.begin(); | 656 parser.begin(); |
642 return parser.match('%') && !parser.match('>') ? parser.success() : parser.failure(); | 657 return parser.match('%') && !parser.match('>') ? parser.success() : parser.failure(); |
643 } | 658 } |
644 | 659 |
645 private Code UnaryExpr(boolean inParens) throws ParseException { | 660 private Code UnaryExpr(In in) throws ParseException { |
646 int start = parser.begin(); | 661 int start = parser.begin(); |
647 if( parser.match('#') ) { | 662 if( parser.match('#') ) { |
648 Spaces(inParens); | 663 Spaces(in); |
649 return parser.success( new LenExpr( se(start), required(expr(UnaryExpr(inParens))) ) ); | 664 return parser.success( new LenExpr( se(start), required(expr(UnaryExpr(in))) ) ); |
650 } | 665 } |
651 if( Minus() ) { | 666 if( Minus() ) { |
652 Spaces(inParens); | 667 Spaces(in); |
653 return parser.success( new UnmExpr( se(start), required(expr(UnaryExpr(inParens))) ) ); | 668 return parser.success( new UnmExpr( se(start), required(expr(UnaryExpr(in))) ) ); |
654 } | 669 } |
655 if( Keyword("not",inParens) ) { | 670 if( Keyword("not",in) ) { |
656 Spaces(inParens); | 671 Spaces(in); |
657 return parser.success( new NotExpr( se(start), required(expr(UnaryExpr(inParens))) ) ); | 672 return parser.success( new NotExpr( se(start), required(expr(UnaryExpr(in))) ) ); |
658 } | 673 } |
659 Code exp = PowExpr(inParens); | 674 Code exp = PowExpr(in); |
660 if( exp==null ) | 675 if( exp==null ) |
661 return parser.failure(null); | 676 return parser.failure(null); |
662 return parser.success(exp); | 677 return parser.success(exp); |
663 } | 678 } |
664 | 679 |
665 private Code PowExpr(boolean inParens) throws ParseException { | 680 private Code PowExpr(In in) throws ParseException { |
666 int start = parser.begin(); | 681 int start = parser.begin(); |
667 Code exp = SingleExpr(inParens); | 682 Code exp = SingleExpr(in); |
668 if( exp==null ) | 683 if( exp==null ) |
669 return parser.failure(null); | 684 return parser.failure(null); |
670 if( parser.match('^') ) { | 685 if( parser.match('^') ) { |
671 Spaces(inParens); | 686 Spaces(in); |
672 exp = new ConcatExpr( se(start), expr(exp), required(expr(PowExpr(inParens))) ); | 687 exp = new ConcatExpr( se(start), expr(exp), required(expr(PowExpr(in))) ); |
673 } | 688 } |
674 return parser.success(exp); | 689 return parser.success(exp); |
675 } | 690 } |
676 | 691 |
677 private Code SingleExpr(boolean inParens) throws ParseException { | 692 private Code SingleExpr(In in) throws ParseException { |
678 parser.begin(); | 693 parser.begin(); |
679 Code exp; | 694 Code exp; |
680 exp = FunctionExpr(inParens); | 695 exp = FunctionExpr(in); |
681 if( exp != null ) | 696 if( exp != null ) |
682 return parser.success(exp); | 697 return parser.success(exp); |
683 exp = TableExpr(inParens); | 698 exp = TableExpr(in); |
684 if( exp != null ) | 699 if( exp != null ) |
685 return parser.success(exp); | 700 return parser.success(exp); |
686 exp = VarExp(inParens); | 701 exp = VarExp(in); |
687 if( exp != null ) | 702 if( exp != null ) |
688 return parser.success(exp); | 703 return parser.success(exp); |
689 exp = Literal(inParens); | 704 exp = Literal(in); |
690 if( exp != null ) | 705 if( exp != null ) |
691 return parser.success(exp); | 706 return parser.success(exp); |
692 return parser.failure(null); | 707 return parser.failure(null); |
693 } | 708 } |
694 | 709 |
695 private Expr FunctionExpr(boolean inParens) throws ParseException { | 710 private Expr FunctionExpr(In in) throws ParseException { |
696 if( !Keyword("function",inParens) ) | 711 if( !Keyword("function",in) ) |
697 return null; | 712 return null; |
698 return RequiredFunction(inParens); | 713 return RequiredFunction(in); |
699 } | 714 } |
700 | 715 |
701 private FnDef RequiredFunction(boolean inParens) throws ParseException { | 716 private FnDef RequiredFunction(In in) throws ParseException { |
702 int start = parser.begin(); | 717 int start = parser.begin(); |
703 RequiredMatch('('); | 718 RequiredMatch('('); |
704 Spaces(true); | 719 In inParens = in.parens(); |
720 Spaces(inParens); | |
705 frame = new Frame(frame); | 721 frame = new Frame(frame); |
706 List<String> names = NameList(false); | 722 List<String> names = NameList(in); |
707 if( names != null ) { | 723 if( names != null ) { |
708 addSymbols(names); | 724 addSymbols(names); |
709 if( parser.match(',') ) { | 725 if( parser.match(',') ) { |
710 Spaces(true); | 726 Spaces(inParens); |
711 if( !parser.match("...") ) | 727 if( !parser.match("...") ) |
712 throw parser.exception(); | 728 throw parser.exception(); |
713 frame.isVarArg = true; | 729 frame.isVarArg = true; |
714 } | 730 } |
715 } else if( parser.match("...") ) { | 731 } else if( parser.match("...") ) { |
716 Spaces(true); | 732 Spaces(inParens); |
717 frame.isVarArg = true; | 733 frame.isVarArg = true; |
718 } | 734 } |
719 RequiredMatch(')'); | 735 RequiredMatch(')'); |
720 Spaces(inParens); | 736 Spaces(in); |
721 Stmt block = RequiredBlock(); | 737 Stmt block = RequiredBlock(); |
722 RequiredKeyword("end",inParens); | 738 RequiredKeyword("end",in); |
723 FnDef fnDef = newFnDef(start,block); | 739 FnDef fnDef = newFnDef(start,block); |
724 frame = frame.parent; | 740 frame = frame.parent; |
725 return parser.success(fnDef); | 741 return parser.success(fnDef); |
726 } | 742 } |
727 | 743 |
728 private VarArgs VarArgs(boolean inParens) throws ParseException { | 744 private VarArgs VarArgs(In in) throws ParseException { |
729 int start = parser.begin(); | 745 int start = parser.begin(); |
730 if( !frame.isVarArg || !parser.match("...") ) | 746 if( !frame.isVarArg || !parser.match("...") ) |
731 return parser.failure(null); | 747 return parser.failure(null); |
748 Spaces(in); | |
749 return parser.success( new VarArgs(se(start)) ); | |
750 } | |
751 | |
752 private Expr TableExpr(In in) throws ParseException { | |
753 int start = parser.begin(); | |
754 if( !parser.match('{') ) | |
755 return parser.failure(null); | |
756 In inParens = in.parens(); | |
732 Spaces(inParens); | 757 Spaces(inParens); |
733 return parser.success( new VarArgs(se(start)) ); | |
734 } | |
735 | |
736 private Expr TableExpr(boolean inParens) throws ParseException { | |
737 int start = parser.begin(); | |
738 if( !parser.match('{') ) | |
739 return parser.failure(null); | |
740 Spaces(true); | |
741 List<TableExpr.Field> fields = new ArrayList<TableExpr.Field>(); | 758 List<TableExpr.Field> fields = new ArrayList<TableExpr.Field>(); |
742 ExpList.Builder builder = new ExpList.Builder(); | 759 ExpList.Builder builder = new ExpList.Builder(); |
743 while( Field(fields,builder) && FieldSep() ); | 760 while( Field(fields,builder,in) && FieldSep(inParens) ); |
744 if( !parser.match('}') ) | 761 if( !parser.match('}') ) |
745 throw parser.exception("Expected table element or '}'"); | 762 throw parser.exception("Expected table element or '}'"); |
746 return parser.success( new TableExpr( se(start), fields.toArray(new TableExpr.Field[0]), builder.build() ) ); | 763 return parser.success( new TableExpr( se(start), fields.toArray(new TableExpr.Field[0]), builder.build() ) ); |
747 } | 764 } |
748 | 765 |
749 private boolean FieldSep() throws ParseException { | 766 private boolean FieldSep(In in) throws ParseException { |
750 if( !parser.anyOf(",;") ) | 767 if( !parser.anyOf(",;") ) |
751 return false; | 768 return false; |
752 Spaces(true); | 769 Spaces(in); |
753 return true; | 770 return true; |
754 } | 771 } |
755 | 772 |
756 private boolean Field(List<TableExpr.Field> fields,ExpList.Builder builder) throws ParseException { | 773 private boolean Field(List<TableExpr.Field> fields,ExpList.Builder builder,In in) throws ParseException { |
757 parser.begin(); | 774 parser.begin(); |
758 Expr exp = SubExpr(true); | 775 Expr exp = SubExpr(in); |
759 if( exp==null ) | 776 if( exp==null ) |
760 exp = NameExpr(true); | 777 exp = NameExpr(in); |
761 if( exp!=null && parser.match('=') ) { | 778 if( exp!=null && parser.match('=') ) { |
762 fields.add( new TableExpr.Field( exp, required(expr(Expr(true))) ) ); | 779 fields.add( new TableExpr.Field( exp, required(expr(Expr(in))) ) ); |
763 return parser.success(); | 780 return parser.success(); |
764 } | 781 } |
765 parser.rollback(); | 782 parser.rollback(); |
766 Code code = Expr(true); | 783 Code code = Expr(in); |
767 if( code != null ) { | 784 if( code != null ) { |
768 builder.add(code); | 785 builder.add(code); |
769 return parser.success(); | 786 return parser.success(); |
770 } | 787 } |
771 return parser.failure(); | 788 return parser.failure(); |
772 } | 789 } |
773 | 790 |
774 private Code VarExp(boolean inParens) throws ParseException { | 791 private Code VarExp(In in) throws ParseException { |
775 Var var = VarZ(inParens); | 792 Var var = VarZ(in); |
776 return var==null ? null : var.expr(); | 793 return var==null ? null : var.expr(); |
777 } | 794 } |
778 | 795 |
779 private Var VarZ(boolean inParens) throws ParseException { | 796 private Var VarZ(In in) throws ParseException { |
780 int start = parser.begin(); | 797 int start = parser.begin(); |
781 Var var = VarStart(inParens); | 798 Var var = VarStart(in); |
782 if( var==null ) | 799 if( var==null ) |
783 return parser.failure(null); | 800 return parser.failure(null); |
784 Var var2; | 801 Var var2; |
785 while( (var2=Var2(inParens,start,var.expr())) != null ) { | 802 while( (var2=Var2(in,start,var.expr())) != null ) { |
786 var = var2; | 803 var = var2; |
787 } | 804 } |
788 return parser.success(var); | 805 return parser.success(var); |
789 } | 806 } |
790 | 807 |
791 private Var Var2(boolean inParens,int start,Code exp1) throws ParseException { | 808 private Var Var2(In in,int start,Code exp1) throws ParseException { |
792 Var var = VarExt(inParens,start,exp1); | 809 Var var = VarExt(in,start,exp1); |
793 if( var != null ) | 810 if( var != null ) |
794 return var; | 811 return var; |
795 if( parser.match("->") ) { | 812 if( parser.match("->") ) { |
796 Spaces(inParens); | 813 Spaces(in); |
797 ExpList.Builder builder = new ExpList.Builder(); | 814 ExpList.Builder builder = new ExpList.Builder(); |
798 builder.add(exp1); | 815 builder.add(exp1); |
799 Expr exp2 = expr(RequiredVarExpB(inParens)); | 816 Expr exp2 = expr(RequiredVarExpB(in)); |
800 FnCall fnCall = required(Args( inParens, start, exp2, builder )); | 817 FnCall fnCall = required(Args( in, start, exp2, builder )); |
801 return exprVar(fnCall); | 818 return exprVar(fnCall); |
802 } | 819 } |
803 FnCall fnCall = Args( inParens, start, expr(exp1), new ExpList.Builder() ); | 820 FnCall fnCall = Args( in, start, expr(exp1), new ExpList.Builder() ); |
804 if( fnCall != null ) | 821 if( fnCall != null ) |
805 return exprVar(fnCall); | 822 return exprVar(fnCall); |
806 return null; | 823 return null; |
807 } | 824 } |
808 | 825 |
809 private Code RequiredVarExpB(boolean inParens) throws ParseException { | 826 private Code RequiredVarExpB(In in) throws ParseException { |
810 int start = parser.begin(); | 827 int start = parser.begin(); |
811 Var var = required(VarStart(inParens)); | 828 Var var = required(VarStart(in)); |
812 Var var2; | 829 Var var2; |
813 while( (var2=VarExt(inParens,start,var.expr())) != null ) { | 830 while( (var2=VarExt(in,start,var.expr())) != null ) { |
814 var = var2; | 831 var = var2; |
815 } | 832 } |
816 return parser.success(var.expr()); | 833 return parser.success(var.expr()); |
817 } | 834 } |
818 | 835 |
819 private Var VarExt(boolean inParens,int start,Code exp1) throws ParseException { | 836 private Var VarExt(In in,int start,Code exp1) throws ParseException { |
820 parser.begin(); | 837 parser.begin(); |
821 Expr exp2 = SubExpr(inParens); | 838 Expr exp2 = SubExpr(in); |
822 if( exp2 != null ) | 839 if( exp2 != null ) |
823 return parser.success(indexVar(start,expr(exp1),exp2)); | 840 return parser.success(indexVar(start,expr(exp1),exp2)); |
824 if( parser.match('.') ) { | 841 if( parser.match('.') ) { |
825 Spaces(inParens); | 842 Spaces(in); |
826 exp2 = NameExpr(inParens); | 843 exp2 = NameExpr(in); |
827 if( exp2!=null ) | 844 if( exp2!=null ) |
828 return parser.success(indexVar(start,expr(exp1),exp2)); | 845 return parser.success(indexVar(start,expr(exp1),exp2)); |
829 } | 846 } |
830 return parser.failure(null); | 847 return parser.failure(null); |
831 } | 848 } |
832 | 849 |
833 private Var VarStart(boolean inParens) throws ParseException { | 850 private Var VarStart(In in) throws ParseException { |
834 int start = parser.begin(); | 851 int start = parser.begin(); |
835 if( parser.match('(') ) { | 852 if( parser.match('(') ) { |
836 Spaces(true); | 853 In inParens = in.parens(); |
837 Expr exp = expr(Expr(true)); | 854 Spaces(inParens); |
855 Expr exp = expr(Expr(inParens)); | |
838 RequiredMatch(')'); | 856 RequiredMatch(')'); |
839 Spaces(inParens); | 857 Spaces(in); |
840 return parser.success(exprVar(exp)); | 858 return parser.success(exprVar(exp)); |
841 } | 859 } |
842 String name = Name(inParens); | 860 String name = Name(in); |
843 if( name != null ) | 861 if( name != null ) |
844 return parser.success(nameVar(start,name)); | 862 return parser.success(nameVar(start,name)); |
845 return parser.failure(null); | 863 return parser.failure(null); |
846 } | 864 } |
847 | 865 |
909 return new SetTableEntry(se(start),table,key); | 927 return new SetTableEntry(se(start),table,key); |
910 } | 928 } |
911 }; | 929 }; |
912 } | 930 } |
913 | 931 |
914 private FnCall Args(boolean inParens,int start,Expr fn,ExpList.Builder builder) throws ParseException { | 932 private FnCall Args(In in,int start,Expr fn,ExpList.Builder builder) throws ParseException { |
915 parser.begin(); | 933 parser.begin(); |
916 return args(inParens,builder) | 934 return args(in,builder) |
917 ? parser.success( new FnCall( se(start), fn, builder.build() ) ) | 935 ? parser.success( new FnCall( se(start), fn, builder.build() ) ) |
918 : parser.failure((FnCall)null); | 936 : parser.failure((FnCall)null); |
919 } | 937 } |
920 | 938 |
921 private boolean args(boolean inParens,ExpList.Builder builder) throws ParseException { | 939 private boolean args(In in,ExpList.Builder builder) throws ParseException { |
922 if( parser.match('(') ) { | 940 if( parser.match('(') ) { |
923 Spaces(true); | 941 In inParens = in.parens(); |
924 ExpList(true,builder); // optional | 942 Spaces(inParens); |
943 ExpList(inParens,builder); // optional | |
925 if( !parser.match(')') ) | 944 if( !parser.match(')') ) |
926 throw parser.exception("Expression or ')' expected"); | 945 throw parser.exception("Expression or ')' expected"); |
927 Spaces(inParens); | 946 Spaces(in); |
928 return true; | 947 return true; |
929 } | 948 } |
930 Expr exp = TableExpr(inParens); | 949 Expr exp = TableExpr(in); |
931 if( exp != null ) { | 950 if( exp != null ) { |
932 builder.add(exp); | 951 builder.add(exp); |
933 return true; | 952 return true; |
934 } | 953 } |
935 String s = StringLiteral(inParens); | 954 String s = StringLiteral(in); |
936 if( s != null ) { | 955 if( s != null ) { |
937 builder.add( new ConstExpr(s) ); | 956 builder.add( new ConstExpr(s) ); |
938 return true; | 957 return true; |
939 } | 958 } |
940 Expressions exps = JspExpressions(); | 959 Expressions exps = JspExpressions(in); |
941 if( exps != null ) { | 960 if( exps != null ) { |
942 builder.add(exps); | 961 builder.add(exps); |
943 return true; | 962 return true; |
944 } | 963 } |
945 return false; | 964 return false; |
946 } | 965 } |
947 | 966 |
948 private Expressions ExpList() throws ParseException { | 967 private Expressions ExpList(In in) throws ParseException { |
949 return ExpList(false); | |
950 } | |
951 | |
952 private Expressions ExpList(boolean inParens) throws ParseException { | |
953 ExpList.Builder builder = new ExpList.Builder(); | 968 ExpList.Builder builder = new ExpList.Builder(); |
954 return ExpList(inParens,builder) ? builder.build() : null; | 969 return ExpList(in,builder) ? builder.build() : null; |
955 } | 970 } |
956 | 971 |
957 private boolean ExpList(boolean inParens,ExpList.Builder builder) throws ParseException { | 972 private boolean ExpList(In in,ExpList.Builder builder) throws ParseException { |
958 parser.begin(); | 973 parser.begin(); |
959 Code exp = Expr(inParens); | 974 Code exp = Expr(in); |
960 if( exp==null ) | 975 if( exp==null ) |
961 return parser.failure(); | 976 return parser.failure(); |
962 builder.add(exp); | 977 builder.add(exp); |
963 while( parser.match(',') ) { | 978 while( parser.match(',') ) { |
964 Spaces(inParens); | 979 Spaces(in); |
965 builder.add( RequiredExpr(inParens) ); | 980 builder.add( RequiredExpr(in) ); |
966 } | 981 } |
967 return parser.success(); | 982 return parser.success(); |
968 } | 983 } |
969 | 984 |
970 private Expr SubExpr(boolean inParens) throws ParseException { | 985 private Expr SubExpr(In in) throws ParseException { |
971 parser.begin(); | 986 parser.begin(); |
972 if( !parser.match('[') ) | 987 if( !parser.match('[') ) |
973 return parser.failure(null); | 988 return parser.failure(null); |
974 Spaces(true); | 989 In inParens = in.parens(); |
975 Expr exp = expr(RequiredExpr(true)); | 990 Spaces(inParens); |
991 Expr exp = expr(RequiredExpr(inParens)); | |
976 RequiredMatch(']'); | 992 RequiredMatch(']'); |
977 Spaces(inParens); | 993 Spaces(in); |
978 return parser.success(exp); | 994 return parser.success(exp); |
979 } | 995 } |
980 | 996 |
981 private Expr NameExpr(boolean inParens) throws ParseException { | 997 private Expr NameExpr(In in) throws ParseException { |
982 String name = Name(inParens); | 998 String name = Name(in); |
983 return name==null ? null : new ConstExpr(name); | 999 return name==null ? null : new ConstExpr(name); |
984 } | 1000 } |
985 | 1001 |
986 private String RequiredName() throws ParseException { | 1002 private String RequiredName(In in) throws ParseException { |
987 parser.begin(); | 1003 parser.begin(); |
988 String name = Name(); | 1004 String name = Name(in); |
989 if( name==null ) | 1005 if( name==null ) |
990 parser.exception("Name expected"); | 1006 parser.exception("Name expected"); |
991 return parser.success(name); | 1007 return parser.success(name); |
992 } | 1008 } |
993 | 1009 |
994 private String Name() throws ParseException { | 1010 private String Name(In in) throws ParseException { |
995 return Name(false); | |
996 } | |
997 | |
998 private String Name(boolean inParens) throws ParseException { | |
999 int start = parser.begin(); | 1011 int start = parser.begin(); |
1000 if( !NameFirstChar() ) | 1012 if( !NameFirstChar() ) |
1001 return parser.failure(null); | 1013 return parser.failure(null); |
1002 while( NameChar() ); | 1014 while( NameChar() ); |
1003 String match = parser.textFrom(start); | 1015 String match = parser.textFrom(start); |
1004 if( keywords.contains(match) ) | 1016 if( keywords.contains(match) ) |
1005 return parser.failure(null); | 1017 return parser.failure(null); |
1006 Spaces(inParens); | 1018 Spaces(in); |
1007 return parser.success(match); | 1019 return parser.success(match); |
1008 } | 1020 } |
1009 | 1021 |
1010 private boolean NameChar() { | 1022 private boolean NameChar() { |
1011 return NameFirstChar() || Digit(); | 1023 return NameFirstChar() || Digit(); |
1023 private void RequiredMatch(String s) throws ParseException { | 1035 private void RequiredMatch(String s) throws ParseException { |
1024 if( !parser.match(s) ) | 1036 if( !parser.match(s) ) |
1025 throw parser.exception("'"+s+"' expected"); | 1037 throw parser.exception("'"+s+"' expected"); |
1026 } | 1038 } |
1027 | 1039 |
1028 private void RequiredKeyword(String keyword) throws ParseException { | 1040 private void RequiredKeyword(String keyword,In in) throws ParseException { |
1029 RequiredKeyword(keyword,false); | 1041 if( !Keyword(keyword,in) ) |
1030 } | |
1031 | |
1032 private boolean Keyword(String keyword) throws ParseException { | |
1033 return Keyword(keyword,false); | |
1034 } | |
1035 | |
1036 private void RequiredKeyword(String keyword,boolean inParens) throws ParseException { | |
1037 if( !Keyword(keyword,inParens) ) | |
1038 throw parser.exception("'"+keyword+"' expected"); | 1042 throw parser.exception("'"+keyword+"' expected"); |
1039 } | 1043 } |
1040 | 1044 |
1041 private boolean Keyword(String keyword,boolean inParens) throws ParseException { | 1045 private boolean Keyword(String keyword,In in) throws ParseException { |
1042 parser.begin(); | 1046 parser.begin(); |
1043 if( !parser.match(keyword) || NameChar() ) | 1047 if( !parser.match(keyword) || NameChar() ) |
1044 return parser.failure(); | 1048 return parser.failure(); |
1045 Spaces(inParens); | 1049 Spaces(in); |
1046 return parser.success(); | 1050 return parser.success(); |
1047 } | 1051 } |
1048 | 1052 |
1049 private static final Set<String> keywords = new HashSet<String>(Arrays.asList( | 1053 private static final Set<String> keywords = new HashSet<String>(Arrays.asList( |
1050 "and", | 1054 "and", |
1072 "try", | 1076 "try", |
1073 "until", | 1077 "until", |
1074 "while" | 1078 "while" |
1075 )); | 1079 )); |
1076 | 1080 |
1077 private Expr Literal(boolean inParens) throws ParseException { | 1081 private Expr Literal(In in) throws ParseException { |
1078 if( NilLiteral(inParens) ) | 1082 if( NilLiteral(in) ) |
1079 return new ConstExpr(null); | 1083 return new ConstExpr(null); |
1080 Boolean b = BooleanLiteral(inParens); | 1084 Boolean b = BooleanLiteral(in); |
1081 if( b != null ) | 1085 if( b != null ) |
1082 return new ConstExpr(b); | 1086 return new ConstExpr(b); |
1083 Number n = NumberLiteral(inParens); | 1087 Number n = NumberLiteral(in); |
1084 if( n != null ) | 1088 if( n != null ) |
1085 return new ConstExpr(n); | 1089 return new ConstExpr(n); |
1086 String s = StringLiteral(inParens); | 1090 String s = StringLiteral(in); |
1087 if( s != null ) | 1091 if( s != null ) |
1088 return new ConstExpr(s); | 1092 return new ConstExpr(s); |
1089 return null; | 1093 return null; |
1090 } | 1094 } |
1091 | 1095 |
1092 private boolean NilLiteral(boolean inParens) throws ParseException { | 1096 private boolean NilLiteral(In in) throws ParseException { |
1093 return Keyword("nil",inParens); | 1097 return Keyword("nil",in); |
1094 } | 1098 } |
1095 | 1099 |
1096 private Boolean BooleanLiteral(boolean inParens) throws ParseException { | 1100 private Boolean BooleanLiteral(In in) throws ParseException { |
1097 if( Keyword("true",inParens) ) | 1101 if( Keyword("true",in) ) |
1098 return true; | 1102 return true; |
1099 if( Keyword("false",inParens) ) | 1103 if( Keyword("false",in) ) |
1100 return false; | 1104 return false; |
1101 return null; | 1105 return null; |
1102 } | 1106 } |
1103 | 1107 |
1104 private Number NumberLiteral(boolean inParens) throws ParseException { | 1108 private Number NumberLiteral(In in) throws ParseException { |
1105 parser.begin(); | 1109 parser.begin(); |
1106 Number n; | 1110 Number n; |
1107 if( parser.matchIgnoreCase("0x") ) { | 1111 if( parser.matchIgnoreCase("0x") ) { |
1108 n = HexNumber(); | 1112 n = HexNumber(); |
1109 } else { | 1113 } else { |
1110 n = DecNumber(); | 1114 n = DecNumber(); |
1111 } | 1115 } |
1112 if( n==null || NameChar() ) | 1116 if( n==null || NameChar() ) |
1113 return parser.failure(null); | 1117 return parser.failure(null); |
1114 Spaces(inParens); | 1118 Spaces(in); |
1115 return parser.success(n); | 1119 return parser.success(n); |
1116 } | 1120 } |
1117 | 1121 |
1118 private Number DecNumber() { | 1122 private Number DecNumber() { |
1119 int start = parser.begin(); | 1123 int start = parser.begin(); |
1187 | 1191 |
1188 private boolean HexDigit() { | 1192 private boolean HexDigit() { |
1189 return Digit() || parser.anyOf("abcdefABCDEF"); | 1193 return Digit() || parser.anyOf("abcdefABCDEF"); |
1190 } | 1194 } |
1191 | 1195 |
1192 private String StringLiteral(boolean inParens) throws ParseException { | 1196 private String StringLiteral(In in) throws ParseException { |
1193 String s; | 1197 String s; |
1194 if( (s=QuotedString('"'))==null | 1198 if( (s=QuotedString('"'))==null |
1195 && (s=QuotedString('\''))==null | 1199 && (s=QuotedString('\''))==null |
1196 && (s=LongString())==null | 1200 && (s=LongString())==null |
1197 ) | 1201 ) |
1198 return null; | 1202 return null; |
1199 Spaces(inParens); | 1203 Spaces(in); |
1200 return s; | 1204 return s; |
1201 } | 1205 } |
1202 | 1206 |
1203 private String LongString() throws ParseException { | 1207 private String LongString() throws ParseException { |
1204 parser.begin(); | 1208 parser.begin(); |
1259 return (char)Integer.parseInt(parser.textFrom(start)); | 1263 return (char)Integer.parseInt(parser.textFrom(start)); |
1260 } | 1264 } |
1261 return parser.failure(null); | 1265 return parser.failure(null); |
1262 } | 1266 } |
1263 | 1267 |
1264 private void Spaces() throws ParseException { | 1268 private void Spaces(In in) throws ParseException { |
1265 Spaces(false); | 1269 while( parser.anyOf(" \t") || Comment() || ContinueOnNextLine() || in.parens && NewLine() ); |
1266 } | |
1267 | |
1268 private void Spaces(boolean inParens) throws ParseException { | |
1269 while( parser.anyOf(" \t") || Comment() || ContinueOnNextLine() || inParens && NewLine() ); | |
1270 } | 1270 } |
1271 | 1271 |
1272 private boolean ContinueOnNextLine() { | 1272 private boolean ContinueOnNextLine() { |
1273 parser.begin(); | 1273 parser.begin(); |
1274 return parser.match('\\') && EndOfLine() ? parser.success() : parser.failure(); | 1274 return parser.match('\\') && EndOfLine() ? parser.success() : parser.failure(); |