comparison src/luan/interp/LuanParser.java @ 104:754e6030c029

remove parboiled and rewrite parser; add jline; git-svn-id: https://luan-java.googlecode.com/svn/trunk@105 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Mon, 12 May 2014 05:57:53 +0000
parents b19988270d74
children 1a29dd3888f6
comparison
equal deleted inserted replaced
103:c6c0aed1dbec 104:754e6030c029
4 import java.util.HashSet; 4 import java.util.HashSet;
5 import java.util.Arrays; 5 import java.util.Arrays;
6 import java.util.List; 6 import java.util.List;
7 import java.util.ArrayList; 7 import java.util.ArrayList;
8 import java.util.Scanner; 8 import java.util.Scanner;
9 import org.parboiled.BaseParser;
10 import org.parboiled.Parboiled;
11 import org.parboiled.Rule;
12 import org.parboiled.parserunners.ReportingParseRunner;
13 import org.parboiled.support.ParsingResult;
14 import org.parboiled.support.Var;
15 import org.parboiled.support.StringVar;
16 import org.parboiled.support.StringBuilderVar;
17 import org.parboiled.support.ValueStack;
18 import org.parboiled.errors.ErrorUtils;
19 import org.parboiled.annotations.Cached;
20 import luan.Luan; 9 import luan.Luan;
21 import luan.LuanState; 10 import luan.LuanState;
22 import luan.LuanSource; 11 import luan.LuanSource;
23 12 import luan.parser.Parser;
24 13 import luan.parser.ParseException;
25 class LuanParser extends BaseParser<Object> { 14
26 15
27 static final class Frame { 16 final class LuanParser {
17
18 static FnDef parse(LuanSource source,UpValue.Getter envGetter) throws ParseException {
19 return new LuanParser(source,envGetter).RequiredTarget();
20 }
21
22 private static final class Frame {
28 final Frame parent; 23 final Frame parent;
29 final List<String> symbols = new ArrayList<String>(); 24 final List<String> symbols = new ArrayList<String>();
30 int stackSize = 0; 25 int stackSize = 0;
31 int loops = 0; 26 int loops = 0;
32 boolean isVarArg = false; 27 boolean isVarArg = false;
74 upValueSymbols.add(name); 69 upValueSymbols.add(name);
75 return upValueSymbols.size() - 1; 70 return upValueSymbols.size() - 1;
76 } 71 }
77 } 72 }
78 73
79 static final String _ENV = "_ENV"; 74 private static final String _ENV = "_ENV";
80 static final UpValue.Getter[] NO_UP_VALUE_GETTERS = new UpValue.Getter[0]; 75 private static final UpValue.Getter[] NO_UP_VALUE_GETTERS = new UpValue.Getter[0];
81 76
82 // UpValue.Getter envGetter = new UpValue.EnvGetter(); 77 private final LuanSource source;
83 final LuanSource source; 78 private Frame frame;
84 Frame frame; 79 private final Parser parser;
85 int nEquals; 80
86 81 private LuanParser(LuanSource source,UpValue.Getter envGetter) {
87 LuanParser(LuanSource source,UpValue.Getter envGetter) {
88 this.source = source; 82 this.source = source;
89 this.frame = new Frame(envGetter); 83 this.frame = new Frame(envGetter);
90 } 84 this.parser = new Parser(source.text);
91 85 }
92 LuanSource.Element se(int start) { 86
93 return new LuanSource.Element(source,start,currentIndex()); 87 private LuanSource.Element se(int start) {
94 } 88 return new LuanSource.Element(source,start,parser.currentIndex());
95 89 }
96 boolean nEquals(int n) { 90
97 nEquals = n; 91 private List<String> symbols() {
98 return true;
99 }
100
101 List<String> symbols() {
102 return frame.symbols; 92 return frame.symbols;
103 } 93 }
104 94
105 int symbolsSize() { 95 private int symbolsSize() {
106 return frame.symbols.size(); 96 return frame.symbols.size();
107 } 97 }
108 98
109 boolean addSymbol(String name) { 99 private void addSymbol(String name) {
110 frame.symbols.add(name); 100 frame.symbols.add(name);
111 if( frame.stackSize < symbolsSize() ) 101 if( frame.stackSize < symbolsSize() )
112 frame.stackSize = symbolsSize(); 102 frame.stackSize = symbolsSize();
113 return true; 103 }
114 } 104
115 105 private void addSymbols(List<String> names) {
116 boolean addSymbols(List<String> names) {
117 frame.symbols.addAll(names); 106 frame.symbols.addAll(names);
118 if( frame.stackSize < symbolsSize() ) 107 if( frame.stackSize < symbolsSize() )
119 frame.stackSize = symbolsSize(); 108 frame.stackSize = symbolsSize();
120 return true; 109 }
121 } 110
122 111 private int stackIndex(String name) {
123 int stackIndex(String name) {
124 return frame.stackIndex(name); 112 return frame.stackIndex(name);
125 } 113 }
126 114
127 boolean popSymbols(int n) { 115 private void popSymbols(int n) {
128 List<String> symbols = frame.symbols; 116 List<String> symbols = frame.symbols;
129 while( n-- > 0 ) { 117 while( n-- > 0 ) {
130 symbols.remove(symbols.size()-1); 118 symbols.remove(symbols.size()-1);
131 } 119 }
132 return true; 120 }
133 } 121
134 122 private int upValueIndex(String name) {
135 int upValueIndex(String name) {
136 return frame.upValueIndex(name); 123 return frame.upValueIndex(name);
137 } 124 }
138 125
139 boolean incLoops() { 126 private void incLoops() {
140 frame.loops++; 127 frame.loops++;
141 return true; 128 }
142 } 129
143 130 private void decLoops() {
144 boolean decLoops() {
145 frame.loops--; 131 frame.loops--;
146 return true; 132 }
147 } 133
148 134 private <T> T required(T t) throws ParseException {
149 FnDef newFnDef(int start) { 135 if( t==null )
150 return new FnDef( se(start), (Stmt)pop(), frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) ); 136 throw parser.exception();
151 } 137 return t;
152 138 }
153 Rule Target() { 139
154 Var<Integer> start = new Var<Integer>(); 140 private <T> T required(T t,String msg) throws ParseException {
155 return Sequence( 141 if( t==null )
156 Spaces(false), 142 throw parser.exception(msg);
157 start.set(currentIndex()), 143 return t;
158 FirstOf( 144 }
159 Sequence( 145
160 ExpList(false), 146 private FnDef newFnDef(int start,Stmt stmt) {
161 push( new ReturnStmt( se(start.get()), (Expressions)pop() ) ), 147 return new FnDef( se(start), stmt, frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) );
162 push( newFnDef(start.get()) ), 148 }
163 EOI 149
164 ), 150 private FnDef RequiredTarget() throws ParseException {
165 Sequence( 151 Spaces();
166 action( frame.isVarArg = true ), 152 int start = parser.begin();
167 Block(), 153 Expressions exprs = ExpList();
168 push( newFnDef(start.get()) ), 154 if( exprs != null && parser.endOfInput() ) {
169 EOI 155 Stmt stmt = new ReturnStmt( se(start), exprs );
170 ) 156 return parser.success(newFnDef(start,stmt));
171 ) 157 }
172 ); 158 parser.rollback();
173 } 159 frame.isVarArg = true;
174 160 Stmt stmt = RequiredBlock();
175 Rule Block() { 161 if( parser.endOfInput() )
176 Var<List<Stmt>> stmts = new Var<List<Stmt>>(new ArrayList<Stmt>()); 162 return parser.success(newFnDef(start,stmt));
177 Var<Integer> stackStart = new Var<Integer>(symbolsSize()); 163 throw parser.exception();
178 return Sequence( 164 }
179 Optional( Stmt(stmts) ), 165
180 ZeroOrMore( 166 private Stmt RequiredBlock() throws ParseException {
181 StmtSep(stmts), 167 List<Stmt> stmts = new ArrayList<Stmt>();
182 Optional( Stmt(stmts) ) 168 int stackStart = symbolsSize();
183 ), 169 Stmt(stmts);
184 push( newBlock(stmts.get(),stackStart.get()) ) 170 while( StmtSep(stmts) ) {
185 ); 171 Spaces();
186 } 172 Stmt(stmts);
187 173 }
188 Stmt newBlock(List<Stmt> stmts,int stackStart) {
189 int stackEnd = symbolsSize(); 174 int stackEnd = symbolsSize();
190 popSymbols( stackEnd - stackStart ); 175 popSymbols( stackEnd - stackStart );
191 if( stmts.isEmpty() ) 176 if( stmts.isEmpty() )
192 return Stmt.EMPTY; 177 return Stmt.EMPTY;
193 if( stmts.size()==1 && stackStart==stackEnd ) 178 if( stmts.size()==1 && stackStart==stackEnd )
194 return stmts.get(0); 179 return stmts.get(0);
195 return new Block( stmts.toArray(new Stmt[0]), stackStart, stackEnd ); 180 return new Block( stmts.toArray(new Stmt[0]), stackStart, stackEnd );
196 } 181 }
197 182
198 Rule StmtSep(Var<List<Stmt>> stmts) { 183 private boolean StmtSep(List<Stmt> stmts) throws ParseException {
199 return Sequence( 184 parser.begin();
200 FirstOf( 185 if( parser.match( ';' ) )
201 ';', 186 return parser.success();
202 Sequence( 187 if( parser.match( "--" ) ) {
203 Optional( "--", ZeroOrMore(NoneOf("\r\n")) ), 188 while( parser.noneOf("\r\n") );
204 EndOfLine() 189 EndOfLine();
205 ), 190 return parser.success();
206 Sequence( 191 }
207 OutputStmt(), 192 if( EndOfLine() )
208 stmts.get().add( (Stmt)pop() ) 193 return parser.success();
209 ) 194 parser.rollback();
210 ), 195 Stmt stmt = OutputStmt();
211 Spaces(false) 196 if( stmt != null ) {
212 ); 197 stmts.add(stmt);
213 } 198 return parser.success();
214 199 }
215 Rule EndOfLine() { 200 return parser.failure();
216 return FirstOf("\r\n", '\r', '\n'); 201 }
217 } 202
218 203 private boolean EndOfLine() {
219 Rule Stmt(Var<List<Stmt>> stmts) { 204 return parser.match( "\r\n" ) || parser.match( '\r' ) || parser.match( '\n' );
220 return FirstOf( 205 }
221 LocalStmt(stmts), 206
222 Sequence( 207 private void Stmt(List<Stmt> stmts) throws ParseException {
223 FirstOf( 208 if( LocalStmt(stmts) )
224 ReturnStmt(), 209 return;
225 FunctionStmt(), 210 Stmt stmt;
226 LocalFunctionStmt(), 211 if( (stmt=ReturnStmt()) != null
227 BreakStmt(), 212 || (stmt=FunctionStmt()) != null
228 GenericForStmt(), 213 || (stmt=LocalFunctionStmt()) != null
229 NumericForStmt(), 214 || (stmt=BreakStmt()) != null
230 TryStmt(), 215 || (stmt=GenericForStmt()) != null
231 DoStmt(), 216 || (stmt=NumericForStmt()) != null
232 WhileStmt(), 217 || (stmt=TryStmt()) != null
233 RepeatStmt(), 218 || (stmt=DoStmt()) != null
234 IfStmt(), 219 || (stmt=WhileStmt()) != null
235 SetStmt(), 220 || (stmt=FunctionStmt()) != null
236 ExpressionsStmt() 221 || (stmt=RepeatStmt()) != null
237 ), 222 || (stmt=IfStmt()) != null
238 stmts.get().add( (Stmt)pop() ) 223 || (stmt=SetStmt()) != null
239 ) 224 || (stmt=ExpressionsStmt()) != null
240 ); 225 ) {
241 } 226 stmts.add(stmt);
242 227 }
243 Rule OutputStmt() { 228 }
244 Var<Integer> start = new Var<Integer>(); 229
245 Var<ExpList.Builder> builder = new Var<ExpList.Builder>(new ExpList.Builder()); 230 private Stmt OutputStmt() throws ParseException {
246 return Sequence( 231 int start = parser.begin();
247 start.set(currentIndex()), 232 if( !parser.match( "%>" ) )
248 "%>", Optional( EndOfLine() ), 233 return parser.failure(null);
249 ZeroOrMore( 234 EndOfLine();
250 FirstOf( 235 ExpList.Builder builder = new ExpList.Builder();
251 Sequence( 236 while(true) {
252 OneOrMore( 237 if( parser.match( "<%=" ) ) {
253 TestNot("<%"), 238 Spaces();
254 TestNot("%>"), 239 builder.add( RequiredExpr() );
255 ANY 240 RequiredMatch( "%>" );
256 ), 241 } else if( parser.match( "<%" ) ) {
257 addToExpList(builder.get(),new ConstExpr(match())) 242 Spaces();
258 ), 243 return parser.success(new OutputStmt( se(start), builder.build() ));
259 Sequence( 244 } else {
260 "<%=", Spaces(false), 245 int i = parser.currentIndex();
261 Expr(false), 246 do {
262 addToExpList(builder.get()), 247 if( parser.match( "%>" ) )
263 "%>" 248 throw parser.exception("'%>' unexpected");
264 ) 249 if( !parser.anyChar() )
265 ) 250 throw parser.exception("Unclosed output statement");
266 ), 251 } while( !parser.test( "<%" ) );
267 "<%", Spaces(false), 252 String match = parser.textFrom(i);
268 push( new OutputStmt( se(start.get()), builder.get().build() ) ) 253 builder.add( new ConstExpr(match) );
269 ); 254 }
270 } 255 }
271 256 }
272 Rule ReturnStmt() { 257
273 Var<Integer> start = new Var<Integer>(); 258 private Stmt ReturnStmt() throws ParseException {
274 return Sequence( 259 int start = parser.begin();
275 start.set(currentIndex()), 260 if( !Keyword("return") )
276 Keyword("return",false), Expressions(false), 261 return parser.failure(null);
277 push( new ReturnStmt( se(start.get()), (Expressions)pop() ) ) 262 Expressions exprs = ExpList();
278 ); 263 if( exprs==null )
279 } 264 exprs = ExpList.emptyExpList;
280 265 return parser.success( new ReturnStmt(se(start),exprs) );
281 Rule FunctionStmt() { 266 }
282 return Sequence( 267
283 Keyword("function",false), FnName(), Function(false), 268 private Stmt FunctionStmt() throws ParseException {
284 push( new SetStmt( (Settable)pop(1), expr(pop()) ) ) 269 parser.begin();
285 ); 270 if( !Keyword("function") )
286 } 271 return parser.failure(null);
287 272
288 Rule FnName() { 273 int start = parser.currentIndex();
289 Var<Integer> start = new Var<Integer>(); 274 Var var = nameVar(start,RequiredName());
290 return Sequence( 275 while( parser.match( '.' ) ) {
291 start.set(currentIndex()), 276 Spaces();
292 push(null), // marker 277 var = indexVar( start, var.expr(), NameExpr(false) );
293 Name(false), 278 }
294 ZeroOrMore( 279 Settable fnName = var.settable();
295 '.', Spaces(false), 280
296 makeVarExp(start.get()), 281 FnDef fnDef = RequiredFunction(false);
297 NameExpr(false) 282 return parser.success( new SetStmt(fnName,fnDef) );
298 ), 283 }
299 makeSettableVar(start.get()) 284
300 ); 285 private Stmt LocalFunctionStmt() throws ParseException {
301 } 286 parser.begin();
302 287 if( !(Keyword("local") && Keyword("function")) )
303 Rule LocalFunctionStmt() { 288 return parser.failure(null);
304 return Sequence( 289 String name = RequiredName();
305 Keyword("local",false), Keyword("function",false), 290 addSymbol( name );
306 Name(false), 291 FnDef fnDef = RequiredFunction(false);
307 addSymbol( (String)pop() ), 292 return parser.success( new SetStmt( new SetLocalVar(symbolsSize()-1), fnDef ) );
308 Function(false), 293 }
309 push( new SetStmt( new SetLocalVar(symbolsSize()-1), expr(pop()) ) ) 294
310 ); 295 private Stmt BreakStmt() throws ParseException {
311 } 296 parser.begin();
312 297 if( !Keyword("break") )
313 Rule BreakStmt() { 298 return parser.failure(null);
314 return Sequence( 299 if( frame.loops <= 0 )
315 Keyword("break",false), 300 throw parser.exception("'break' outside of loop");
316 frame.loops > 0, 301 return parser.success( new BreakStmt() );
317 push( new BreakStmt() ) 302 }
318 ); 303
319 } 304 private Stmt GenericForStmt() throws ParseException {
320 305 int start = parser.begin();
321 Rule GenericForStmt() {
322 Var<Integer> start = new Var<Integer>();
323 Var<Integer> stackStart = new Var<Integer>(symbolsSize());
324 Var<List<String>> names = new Var<List<String>>(new ArrayList<String>());
325 return Sequence(
326 start.set(currentIndex()),
327 Keyword("for",false), NameList(false,names), Keyword("in",false), Expr(false), Keyword("do",false),
328 addSymbols(names.get()),
329 LoopBlock(), Keyword("end",false),
330 push( new GenericForStmt( se(start.get()), stackStart.get(), symbolsSize() - stackStart.get(), expr(pop(1)), (Stmt)pop() ) ),
331 popSymbols( symbolsSize() - stackStart.get() )
332 );
333 }
334
335 Rule NumericForStmt() {
336 Var<Integer> start = new Var<Integer>();
337 return Sequence(
338 start.set(currentIndex()),
339 Keyword("for",false), Name(false), '=', Spaces(false), Expr(false), Keyword("to",false), Expr(false),
340 push( new ConstExpr(1) ), // default step
341 Optional(
342 Keyword("step",false),
343 drop(),
344 Expr(false)
345 ),
346 addSymbol( (String)pop(3) ), // add "for" var to symbols
347 Keyword("do",false), LoopBlock(), Keyword("end",false),
348 push( new NumericForStmt( se(start.get()), symbolsSize()-1, expr(pop(3)), expr(pop(2)), expr(pop(1)), (Stmt)pop() ) ),
349 popSymbols(1)
350 );
351 }
352
353 Rule TryStmt() {
354 return Sequence(
355 Keyword("try",false), Block(),
356 Keyword("catch",false), Name(false), addSymbol( (String)pop() ),
357 Keyword("do",false), Block(), Keyword("end",false),
358 push( new TryStmt( (Stmt)pop(1), symbolsSize()-1, (Stmt)pop() ) ),
359 popSymbols(1)
360 );
361 }
362
363 Rule DoStmt() {
364 return Sequence(
365 Keyword("do",false), Block(), Keyword("end",false)
366 );
367 }
368
369 Rule LocalStmt(Var<List<Stmt>> stmts) {
370 Var<List<String>> names = new Var<List<String>>(new ArrayList<String>());
371 return Sequence(
372 Keyword("local",false), NameList(false,names),
373 Optional(
374 '=', Spaces(false), ExpList(false),
375 stmts.get().add( newSetLocalStmt(names.get().size()) )
376 ),
377 addSymbols(names.get())
378 );
379 }
380
381 Rule NameList(boolean inParens,Var<List<String>> names) {
382 return Sequence(
383 Name(inParens),
384 names.get().add( (String)pop() ),
385 ZeroOrMore(
386 ',', Spaces(inParens), Name(inParens),
387 names.get().add( (String)pop() )
388 )
389 );
390 }
391
392 SetStmt newSetLocalStmt(int nVars) {
393 Expressions values = (Expressions)pop();
394 SetLocalVar[] vars = new SetLocalVar[nVars];
395 int stackStart = symbolsSize(); 306 int stackStart = symbolsSize();
396 for( int i=0; i<vars.length; i++ ) { 307 if( !Keyword("for") )
397 vars[i] = new SetLocalVar(stackStart+i); 308 return parser.failure(null);
398 } 309 List<String> names = RequiredNameList(false);
399 return new SetStmt( vars, values ); 310 if( !Keyword("in") )
400 } 311 return parser.failure(null);
401 312 Expr expr = RequiredExpr();
402 Rule WhileStmt() { 313 RequiredKeyword("do");
403 return Sequence( 314 addSymbols(names);
404 Keyword("while",false), Expr(false), Keyword("do",false), LoopBlock(), Keyword("end",false), 315 Stmt loop = RequiredLoopBlock();
405 push( new WhileStmt( expr(pop(1)), (Stmt)pop() ) ) 316 RequiredKeyword("end");
406 ); 317 Stmt stmt = new GenericForStmt( se(start), stackStart, symbolsSize() - stackStart, expr, loop );
407 } 318 popSymbols( symbolsSize() - stackStart );
408 319 return parser.success(stmt);
409 Rule RepeatStmt() { 320 }
410 return Sequence( 321
411 Keyword("repeat",false), LoopBlock(), Keyword("until",false), Expr(false), 322 private Stmt NumericForStmt() throws ParseException {
412 push( new RepeatStmt( (Stmt)pop(1), expr(pop()) ) ) 323 int start = parser.begin();
413 ); 324 if( !Keyword("for") )
414 } 325 return parser.failure(null);
415 326 String name = RequiredName();
416 Rule LoopBlock() { 327 RequiredMatch( "=" );
417 return Sequence( incLoops(), Block(), decLoops() ); 328 Spaces();
418 } 329 Expr from = RequiredExpr();
419 330 RequiredKeyword("to");
420 Rule IfStmt() { 331 Expr to = RequiredExpr();
421 Var<Integer> n = new Var<Integer>(1); 332 Expr step = Keyword("step") ? RequiredExpr() : new ConstExpr(1);
422 return Sequence( 333 addSymbol(name); // add "for" var to symbols
423 Keyword("if",false), Expr(false), Keyword("then",false), Block(), 334 RequiredKeyword("do");
424 push(Stmt.EMPTY), 335 Stmt loop = RequiredLoopBlock();
425 ZeroOrMore( 336 RequiredKeyword("end");
426 Keyword("elseif",false), drop(), Expr(false), Keyword("then",false), Block(), 337 Stmt stmt = new NumericForStmt( se(start), symbolsSize()-1, from, to, step, loop );
427 push(Stmt.EMPTY), 338 popSymbols(1);
428 n.set(n.get()+1) 339 return parser.success(stmt);
429 ), 340 }
430 Optional( 341
431 Keyword("else",false), drop(), Block() 342 private Stmt TryStmt() throws ParseException {
432 ), 343 parser.begin();
433 Keyword("end",false), 344 if( !Keyword("try") )
434 buildIfStmt(n.get()) 345 return parser.failure(null);
435 ); 346 Stmt tryBlock = RequiredBlock();
436 } 347 RequiredKeyword("catch");
437 348 String name = RequiredName();
438 boolean buildIfStmt(int n) { 349 addSymbol(name);
439 while( n-- > 0 ) { 350 RequiredKeyword("do");
440 Stmt elseStmt = (Stmt)pop(); 351 Stmt catchBlock = RequiredBlock();
441 Stmt thenStmt = (Stmt)pop(); 352 RequiredKeyword("end");
442 Expr cnd = expr(pop()); 353 Stmt stmt = new TryStmt( tryBlock, symbolsSize()-1, catchBlock );
443 push( new IfStmt(cnd,thenStmt,elseStmt) ); 354 popSymbols(1);
444 } 355 return parser.success(stmt);
356 }
357
358 private Stmt DoStmt() throws ParseException {
359 parser.begin();
360 if( !Keyword("do") )
361 return parser.failure(null);
362 Stmt stmt = RequiredBlock();
363 RequiredKeyword("end");
364 return parser.success(stmt);
365 }
366
367 private boolean LocalStmt(List<Stmt> stmts) throws ParseException {
368 parser.begin();
369 if( !Keyword("local") )
370 return parser.failure();
371 List<String> names = NameList(false);
372 if( names==null )
373 return parser.failure();
374 if( parser.match( '=' ) ) {
375 Spaces();
376 Expressions values = ExpList();
377 if( values==null )
378 throw parser.exception("Expressions expected");
379 SetLocalVar[] vars = new SetLocalVar[names.size()];
380 int stackStart = symbolsSize();
381 for( int i=0; i<vars.length; i++ ) {
382 vars[i] = new SetLocalVar(stackStart+i);
383 }
384 stmts.add( new SetStmt( vars, values ) );
385 }
386 addSymbols(names);
387 return parser.success();
388 }
389
390 private List<String> RequiredNameList(boolean inParens) throws ParseException {
391 parser.begin();
392 List<String> names = NameList(inParens);
393 if( names==null )
394 parser.exception("Name expected");
395 return parser.success(names);
396 }
397
398 private List<String> NameList(boolean inParens) throws ParseException {
399 String name = Name(inParens);
400 if( name==null )
401 return null;
402 List<String> names = new ArrayList<String>();
403 names.add(name);
404 while( parser.match( ',' ) ) {
405 Spaces(inParens);
406 names.add( RequiredName() );
407 }
408 return names;
409 }
410
411 private Stmt WhileStmt() throws ParseException {
412 parser.begin();
413 if( !Keyword("while") )
414 return parser.failure(null);
415 Expr cnd = RequiredExpr();
416 RequiredKeyword("do");
417 Stmt loop = RequiredLoopBlock();
418 RequiredKeyword("end");
419 return parser.success( new WhileStmt(cnd,loop) );
420 }
421
422 private Stmt RepeatStmt() throws ParseException {
423 parser.begin();
424 if( !Keyword("repeat") )
425 return parser.failure(null);
426 Stmt loop = RequiredLoopBlock();
427 RequiredKeyword("until");
428 Expr cnd = RequiredExpr();
429 return parser.success( new RepeatStmt(loop,cnd) );
430 }
431
432 private Stmt RequiredLoopBlock() throws ParseException {
433 incLoops();
434 Stmt stmt = RequiredBlock();
435 decLoops();
436 return stmt;
437 }
438
439 private Stmt IfStmt() throws ParseException {
440 parser.begin();
441 if( !Keyword("if") )
442 return parser.failure(null);
443 return parser.success( IfStmt2() );
444 }
445
446 private Stmt IfStmt2() throws ParseException {
447 Expr cnd = RequiredExpr();
448 RequiredKeyword("then");
449 Stmt thenBlock = RequiredBlock();
450 Stmt elseBlock;
451 if( Keyword("elseif") ) {
452 elseBlock = IfStmt2();
453 } else {
454 elseBlock = Keyword("else") ? RequiredBlock() : Stmt.EMPTY;
455 RequiredKeyword("end");
456 }
457 return new IfStmt(cnd,thenBlock,elseBlock);
458 }
459
460 private Stmt SetStmt() throws ParseException {
461 parser.begin();
462 List<Settable> vars = new ArrayList<Settable>();
463 Settable s = SettableVar();
464 if( s == null )
465 return parser.failure(null);
466 vars.add(s);
467 while( parser.match( ',' ) ) {
468 Spaces();
469 s = SettableVar();
470 if( s == null )
471 return parser.failure(null);
472 vars.add(s);
473 }
474 if( !parser.match( '=' ) )
475 return parser.failure(null);
476 Spaces();
477 Expressions values = ExpList();
478 if( values==null )
479 throw parser.exception("Expressions expected");
480 return parser.success( new SetStmt( vars.toArray(new Settable[0]), values ) );
481 }
482
483 private Stmt ExpressionsStmt() throws ParseException {
484 parser.begin();
485 Expressions exprs = ExpList();
486 if( exprs==null )
487 return parser.failure(null);
488 return parser.success( new ExpressionsStmt(exprs) );
489 }
490
491 private Settable SettableVar() throws ParseException {
492 int start = parser.begin();
493 Var var = VarZ(false);
494 if( var==null )
495 return null;
496 return var.settable();
497 }
498
499 private Expr RequiredExpr() throws ParseException {
500 return RequiredExpr(false);
501 }
502
503 private Expr Expr() throws ParseException {
504 return Expr(false);
505 }
506
507 private Expr RequiredExpr(boolean inParens) throws ParseException {
508 parser.begin();
509 return parser.success(required(Expr(inParens),"Bad expression"));
510 }
511
512 private Expr Expr(boolean inParens) throws ParseException {
513 parser.begin();
514 Expressions exps = VarArgs(inParens);
515 if( exps != null )
516 return parser.success( new ExpressionsExpr(exps) );
517 Expr exp = OrExpr(inParens);
518 if( exp==null )
519 return parser.failure(null);
520 return parser.success(exp);
521 }
522
523 private Expr OrExpr(boolean inParens) throws ParseException {
524 int start = parser.begin();
525 Expr exp = AndExpr(inParens);
526 if( exp==null )
527 return parser.failure(null);
528 while( Keyword("or",inParens) ) {
529 exp = new OrExpr( se(start), exp, required(AndExpr(inParens)) );
530 }
531 return parser.success(exp);
532 }
533
534 private Expr AndExpr(boolean inParens) throws ParseException {
535 int start = parser.begin();
536 Expr exp = RelExpr(inParens);
537 if( exp==null )
538 return parser.failure(null);
539 while( Keyword("and",inParens) ) {
540 exp = new AndExpr( se(start), exp, required(RelExpr(inParens)) );
541 }
542 return parser.success(exp);
543 }
544
545 private Expr RelExpr(boolean inParens) throws ParseException {
546 int start = parser.begin();
547 Expr exp = ConcatExpr(inParens);
548 if( exp==null )
549 return parser.failure(null);
550 while(true) {
551 if( parser.match("==") ) {
552 Spaces(inParens);
553 exp = new EqExpr( se(start), exp, required(ConcatExpr(inParens)) );
554 } else if( parser.match("~=") ) {
555 Spaces(inParens);
556 exp = new NotExpr( se(start), new EqExpr( se(start), exp, required(ConcatExpr(inParens)) ) );
557 } else if( parser.match("<=") ) {
558 Spaces(inParens);
559 exp = new LeExpr( se(start), exp, required(ConcatExpr(inParens)) );
560 } else if( parser.match(">=") ) {
561 Spaces(inParens);
562 exp = new LeExpr( se(start), required(ConcatExpr(inParens)), exp );
563 } else if( parser.match("<") ) {
564 Spaces(inParens);
565 exp = new LtExpr( se(start), exp, required(ConcatExpr(inParens)) );
566 } else if( parser.match(">") ) {
567 Spaces(inParens);
568 exp = new LtExpr( se(start), required(ConcatExpr(inParens)), exp );
569 } else
570 break;
571 }
572 return parser.success(exp);
573 }
574
575 private Expr ConcatExpr(boolean inParens) throws ParseException {
576 int start = parser.begin();
577 Expr exp = SumExpr(inParens);
578 if( exp==null )
579 return parser.failure(null);
580 if( parser.match("..") ) {
581 Spaces(inParens);
582 exp = new ConcatExpr( se(start), exp, required(ConcatExpr(inParens)) );
583 }
584 return parser.success(exp);
585 }
586
587 private Expr SumExpr(boolean inParens) throws ParseException {
588 int start = parser.begin();
589 Expr exp = TermExpr(inParens);
590 if( exp==null )
591 return parser.failure(null);
592 while(true) {
593 if( parser.match('+') ) {
594 Spaces(inParens);
595 exp = new AddExpr( se(start), exp, required(TermExpr(inParens)) );
596 } else if( Minus() ) {
597 Spaces(inParens);
598 exp = new SubExpr( se(start), exp, required(TermExpr(inParens)) );
599 } else
600 break;
601 }
602 return parser.success(exp);
603 }
604
605 private boolean Minus() {
606 parser.begin();
607 return parser.match('-') && !parser.match('-') ? parser.success() : parser.failure();
608 }
609
610 private Expr TermExpr(boolean inParens) throws ParseException {
611 int start = parser.begin();
612 Expr exp = UnaryExpr(inParens);
613 if( exp==null )
614 return parser.failure(null);
615 while(true) {
616 if( parser.match('*') ) {
617 Spaces(inParens);
618 exp = new MulExpr( se(start), exp, required(UnaryExpr(inParens)) );
619 } else if( parser.match('/') ) {
620 Spaces(inParens);
621 exp = new DivExpr( se(start), exp, required(UnaryExpr(inParens)) );
622 } else if( parser.match('%') ) {
623 Spaces(inParens);
624 exp = new ModExpr( se(start), exp, required(UnaryExpr(inParens)) );
625 } else
626 break;
627 }
628 return parser.success(exp);
629 }
630
631 private Expr UnaryExpr(boolean inParens) throws ParseException {
632 int start = parser.begin();
633 if( parser.match('#') ) {
634 Spaces(inParens);
635 return parser.success( new LenExpr( se(start), required(UnaryExpr(inParens)) ) );
636 }
637 if( Minus() ) {
638 Spaces(inParens);
639 return parser.success( new UnmExpr( se(start), required(UnaryExpr(inParens)) ) );
640 }
641 if( Keyword("not",inParens) ) {
642 Spaces(inParens);
643 return parser.success( new NotExpr( se(start), required(UnaryExpr(inParens)) ) );
644 }
645 Expr exp = PowExpr(inParens);
646 if( exp==null )
647 return parser.failure(null);
648 return parser.success(exp);
649 }
650
651 private Expr PowExpr(boolean inParens) throws ParseException {
652 int start = parser.begin();
653 Expr exp = SingleExpr(inParens);
654 if( exp==null )
655 return parser.failure(null);
656 if( parser.match('^') ) {
657 Spaces(inParens);
658 exp = new ConcatExpr( se(start), exp, required(PowExpr(inParens)) );
659 }
660 return parser.success(exp);
661 }
662
663 private Expr SingleExpr(boolean inParens) throws ParseException {
664 parser.begin();
665 Expr exp;
666 exp = FunctionExpr(inParens);
667 if( exp != null )
668 return parser.success(exp);
669 exp = TableExpr(inParens);
670 if( exp != null )
671 return parser.success(exp);
672 exp = VarExp(inParens);
673 if( exp != null )
674 return parser.success(exp);
675 exp = Literal(inParens);
676 if( exp != null )
677 return parser.success(exp);
678 return parser.failure(null);
679 }
680
681 private Expr FunctionExpr(boolean inParens) throws ParseException {
682 if( !Keyword("function",inParens) )
683 return null;
684 return RequiredFunction(inParens);
685 }
686
687 private FnDef RequiredFunction(boolean inParens) throws ParseException {
688 int start = parser.begin();
689 RequiredMatch('(');
690 Spaces(true);
691 frame = new Frame(frame);
692 List<String> names = NameList(false);
693 if( names != null ) {
694 addSymbols(names);
695 if( parser.match(',') ) {
696 Spaces(true);
697 if( !parser.match("...") )
698 throw parser.exception();
699 frame.isVarArg = true;
700 }
701 } else if( parser.match("...") ) {
702 Spaces(true);
703 frame.isVarArg = true;
704 }
705 RequiredMatch(')');
706 Spaces(inParens);
707 Stmt block = RequiredBlock();
708 RequiredKeyword("end",inParens);
709 FnDef fnDef = newFnDef(start,block);
710 frame = frame.parent;
711 return parser.success(fnDef);
712 }
713
714 private VarArgs VarArgs(boolean inParens) throws ParseException {
715 int start = parser.begin();
716 if( !frame.isVarArg || !parser.match("...") )
717 return parser.failure(null);
718 Spaces(inParens);
719 return parser.success( new VarArgs(se(start)) );
720 }
721
722 private Expr TableExpr(boolean inParens) throws ParseException {
723 int start = parser.begin();
724 if( !parser.match('{') )
725 return parser.failure(null);
726 Spaces(true);
727 List<TableExpr.Field> fields = new ArrayList<TableExpr.Field>();
728 ExpList.Builder builder = new ExpList.Builder();
729 while( Field(fields,builder) && FieldSep() );
730 RequiredMatch('}');
731 return parser.success( new TableExpr( se(start), fields.toArray(new TableExpr.Field[0]), builder.build() ) );
732 }
733
734 private boolean FieldSep() throws ParseException {
735 if( !parser.anyOf(",;") )
736 return false;
737 Spaces(true);
445 return true; 738 return true;
446 } 739 }
447 740
448 Rule SetStmt() { 741 private boolean Field(List<TableExpr.Field> fields,ExpList.Builder builder) throws ParseException {
449 return Sequence( 742 parser.begin();
450 VarList(), 743 Expr exp = SubExpr(true);
451 '=', Spaces(false), 744 if( exp==null )
452 ExpList(false), 745 exp = NameExpr(true);
453 push( newSetStmt() ) 746 if( exp!=null && parser.match('=') ) {
454 ); 747 fields.add( new TableExpr.Field( exp, required(Expr(true)) ) );
455 } 748 return parser.success();
456 749 }
457 Rule ExpressionsStmt() { 750 parser.rollback();
458 return Sequence( 751 exp = Expr(true);
459 ExpList(false), 752 if( exp != null ) {
460 push( new ExpressionsStmt((Expressions)pop()) ) 753 builder.add(exp);
461 ); 754 return parser.success();
462 } 755 }
463 756 return parser.failure();
464 SetStmt newSetStmt() { 757 }
465 Expressions values = (Expressions)pop(); 758
466 @SuppressWarnings("unchecked") 759 private Expr VarExp(boolean inParens) throws ParseException {
467 List<Settable> vars = (List<Settable>)pop(); 760 Var var = VarZ(inParens);
468 return new SetStmt( vars.toArray(new Settable[0]), values ); 761 return var==null ? null : var.expr();
469 } 762 }
470 763
471 Rule VarList() { 764 private Var VarZ(boolean inParens) throws ParseException {
472 Var<List<Settable>> vars = new Var<List<Settable>>(new ArrayList<Settable>()); 765 int start = parser.begin();
473 return Sequence( 766 Var var = VarStart(inParens);
474 SettableVar(), 767 if( var==null )
475 vars.get().add( (Settable)pop() ), 768 return parser.failure(null);
476 ZeroOrMore( 769 Var var2;
477 ',', Spaces(false), SettableVar(), 770 while( (var2=Var2(inParens,start,var.expr())) != null ) {
478 vars.get().add( (Settable)pop() ) 771 var = var2;
479 ), 772 }
480 push(vars.get()) 773 return parser.success(var);
481 ); 774 }
482 } 775
483 776 private Var Var2(boolean inParens,int start,Expr exp1) throws ParseException {
484 Rule SettableVar() { 777 Var var = VarExt(inParens,start,exp1);
485 Var<Integer> start = new Var<Integer>(); 778 if( var != null )
486 return Sequence( 779 return var;
487 start.set(currentIndex()), 780 if( parser.match("->") ) {
488 Var(false), 781 Spaces(inParens);
489 makeSettableVar(start.get()) 782 ExpList.Builder builder = new ExpList.Builder();
490 ); 783 builder.add(exp1);
491 } 784 Expr exp2 = RequiredVarExpB(inParens);
492 785 FnCall fnCall = required(Args( inParens, start, exp2, builder ));
493 boolean makeSettableVar(int start) { 786 return exprVar( new ExpressionsExpr(fnCall) );
494 Object obj2 = pop(); 787 }
495 if( obj2==null ) 788 FnCall fnCall = Args( inParens, start, exp1, new ExpList.Builder() );
496 return false; 789 if( fnCall != null )
497 Object obj1 = pop(); 790 return exprVar( new ExpressionsExpr(fnCall) );
498 if( obj1!=null ) { 791 return null;
499 Expr key = expr(obj2); 792 }
500 Expr table = expr(obj1); 793
501 return push( new SetTableEntry(se(start),table,key) ); 794 private Expr RequiredVarExpB(boolean inParens) throws ParseException {
502 } 795 int start = parser.begin();
503 String name = (String)obj2; 796 Var var = required(VarStart(inParens));
504 int index = stackIndex(name); 797 Var var2;
505 if( index != -1 ) 798 while( (var2=VarExt(inParens,start,var.expr())) != null ) {
506 return push( new SetLocalVar(index) ); 799 var = var2;
507 index = upValueIndex(name); 800 }
508 if( index != -1 ) 801 return parser.success(var.expr());
509 return push( new SetUpVar(index) ); 802 }
510 return push( new SetTableEntry( se(start), env(), new ConstExpr(name) ) ); 803
511 } 804 private Var VarExt(boolean inParens,int start,Expr exp1) throws ParseException {
512 805 parser.begin();
513 @Cached 806 Expr exp2 = SubExpr(inParens);
514 Rule Expr(boolean inParens) { 807 exp2 = SubExpr(inParens);
515 return FirstOf( 808 if( exp2 != null )
516 VarArgs(inParens), 809 return parser.success(indexVar(start,exp1,exp2));
517 OrExpr(inParens) 810 if( parser.match('.') ) {
518 ); 811 Spaces(inParens);
519 } 812 exp2 = NameExpr(inParens);
520 813 if( exp2!=null )
521 @Cached 814 return parser.success(indexVar(start,exp1,exp2));
522 Rule OrExpr(boolean inParens) { 815 }
523 Var<Integer> start = new Var<Integer>(); 816 return parser.failure(null);
524 return Sequence( 817 }
525 start.set(currentIndex()), 818
526 AndExpr(inParens), 819 private Var VarStart(boolean inParens) throws ParseException {
527 ZeroOrMore( Keyword("or",inParens), AndExpr(inParens), push( new OrExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ) 820 int start = parser.begin();
528 ); 821 if( parser.match('(') ) {
529 } 822 Spaces(true);
530 823 Expr exp = Expr(true);
531 @Cached 824 RequiredMatch(')');
532 Rule AndExpr(boolean inParens) { 825 Spaces(inParens);
533 Var<Integer> start = new Var<Integer>(); 826 return parser.success(exprVar(exp));
534 return Sequence( 827 }
535 start.set(currentIndex()), 828 String name = Name(inParens);
536 RelExpr(inParens), 829 if( name != null )
537 ZeroOrMore( Keyword("and",inParens), RelExpr(inParens), push( new AndExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ) 830 return parser.success(nameVar(start,name));
538 ); 831 return parser.failure(null);
539 } 832 }
540 833
541 @Cached 834 private Expr env() {
542 Rule RelExpr(boolean inParens) {
543 Var<Integer> start = new Var<Integer>();
544 return Sequence(
545 start.set(currentIndex()),
546 ConcatExpr(inParens),
547 ZeroOrMore(
548 FirstOf(
549 Sequence( "==", Spaces(inParens), ConcatExpr(inParens), push( new EqExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
550 Sequence( "~=", Spaces(inParens), ConcatExpr(inParens), push( new NotExpr(se(start.get()),new EqExpr(se(start.get()),expr(pop(1)),expr(pop()))) ) ),
551 Sequence( "<=", Spaces(inParens), ConcatExpr(inParens), push( new LeExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
552 Sequence( ">=", Spaces(inParens), ConcatExpr(inParens), push( new LeExpr(se(start.get()),expr(pop()),expr(pop())) ) ),
553 Sequence( "<", Spaces(inParens), ConcatExpr(inParens), push( new LtExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
554 Sequence( ">", Spaces(inParens), ConcatExpr(inParens), push( new LtExpr(se(start.get()),expr(pop()),expr(pop())) ) )
555 )
556 )
557 );
558 }
559
560 @Cached
561 Rule ConcatExpr(boolean inParens) {
562 Var<Integer> start = new Var<Integer>();
563 return Sequence(
564 start.set(currentIndex()),
565 SumExpr(inParens),
566 Optional( "..", Spaces(inParens), ConcatExpr(inParens), push( new ConcatExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
567 );
568 }
569
570 @Cached
571 Rule SumExpr(boolean inParens) {
572 Var<Integer> start = new Var<Integer>();
573 return Sequence(
574 start.set(currentIndex()),
575 TermExpr(inParens),
576 ZeroOrMore(
577 FirstOf(
578 Sequence( '+', Spaces(inParens), TermExpr(inParens), push( new AddExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
579 Sequence( '-', TestNot('-'), Spaces(inParens), TermExpr(inParens), push( new SubExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
580 )
581 )
582 );
583 }
584
585 @Cached
586 Rule TermExpr(boolean inParens) {
587 Var<Integer> start = new Var<Integer>();
588 return Sequence(
589 start.set(currentIndex()),
590 UnaryExpr(inParens),
591 ZeroOrMore(
592 FirstOf(
593 Sequence( '*', Spaces(inParens), UnaryExpr(inParens), push( new MulExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
594 Sequence( '/', Spaces(inParens), UnaryExpr(inParens), push( new DivExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
595 Sequence( '%', Spaces(inParens), UnaryExpr(inParens), push( new ModExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
596 )
597 )
598 );
599 }
600
601 @Cached
602 Rule UnaryExpr(boolean inParens) {
603 Var<Integer> start = new Var<Integer>();
604 return Sequence(
605 start.set(currentIndex()),
606 FirstOf(
607 Sequence( '#', Spaces(inParens), PowExpr(inParens), push( new LenExpr(se(start.get()),expr(pop())) ) ),
608 Sequence( '-', TestNot('-'), Spaces(inParens), PowExpr(inParens), push( new UnmExpr(se(start.get()),expr(pop())) ) ),
609 Sequence( Keyword("not",inParens), PowExpr(inParens), push( new NotExpr(se(start.get()),expr(pop())) ) ),
610 PowExpr(inParens)
611 )
612 );
613 }
614
615 @Cached
616 Rule PowExpr(boolean inParens) {
617 Var<Integer> start = new Var<Integer>();
618 return Sequence(
619 start.set(currentIndex()),
620 SingleExpr(inParens),
621 Optional( '^', Spaces(inParens), PowExpr(inParens), push( new PowExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
622 );
623 }
624
625 @Cached
626 Rule SingleExpr(boolean inParens) {
627 return FirstOf(
628 FunctionExpr(inParens),
629 TableExpr(inParens),
630 VarExp(inParens),
631 Literal(inParens)
632 );
633 }
634
635 @Cached
636 Rule FunctionExpr(boolean inParens) {
637 return Sequence( "function", Spaces(inParens), Function(inParens) );
638 }
639
640 @Cached
641 Rule Function(boolean inParens) {
642 Var<Integer> start = new Var<Integer>();
643 Var<List<String>> names = new Var<List<String>>(new ArrayList<String>());
644 return Sequence(
645 start.set(currentIndex()),
646 '(', Spaces(true),
647 action( frame = new Frame(frame) ),
648 Optional(
649 FirstOf(
650 Sequence(
651 NameList(true,names), addSymbols(names.get()),
652 Optional( ',', Spaces(true), VarArgName() )
653 ),
654 VarArgName()
655 )
656 ),
657 ')', Spaces(inParens), Block(), Keyword("end",inParens),
658 push( newFnDef(start.get()) ),
659 action( frame = frame.parent )
660 );
661 }
662
663 Rule VarArgName() {
664 return Sequence(
665 "...", Spaces(true),
666 action( frame.isVarArg = true )
667 );
668 }
669
670 @Cached
671 Rule VarArgs(boolean inParens) {
672 Var<Integer> start = new Var<Integer>();
673 return Sequence(
674 start.set(currentIndex()),
675 "...", Spaces(inParens),
676 frame.isVarArg,
677 push( new VarArgs(se(start.get())) )
678 );
679 }
680
681 @Cached
682 Rule TableExpr(boolean inParens) {
683 Var<Integer> start = new Var<Integer>();
684 Var<List<TableExpr.Field>> fields = new Var<List<TableExpr.Field>>(new ArrayList<TableExpr.Field>());
685 Var<ExpList.Builder> builder = new Var<ExpList.Builder>(new ExpList.Builder());
686 return Sequence(
687 start.set(currentIndex()),
688 '{', Spaces(true),
689 Optional(
690 Field(fields,builder),
691 ZeroOrMore(
692 FieldSep(),
693 Field(fields,builder)
694 ),
695 Optional( FieldSep() )
696 ),
697 '}',
698 Spaces(inParens),
699 push( new TableExpr( se(start.get()), fields.get().toArray(new TableExpr.Field[0]), builder.get().build() ) )
700 );
701 }
702
703 Rule FieldSep() {
704 return Sequence( AnyOf(",;"), Spaces(true) );
705 }
706
707 Rule Field(Var<List<TableExpr.Field>> fields,Var<ExpList.Builder> builder) {
708 return FirstOf(
709 Sequence(
710 FirstOf( SubExpr(true), NameExpr(true) ),
711 '=', Spaces(true), Expr(true),
712 fields.get().add( new TableExpr.Field( expr(pop(1)), expr(pop()) ) )
713 ),
714 Sequence(
715 Expr(true),
716 addToExpList(builder.get())
717 )
718 );
719 }
720
721 static Expr expr(Object obj) {
722 if( obj instanceof Expressions )
723 return new ExpressionsExpr((Expressions)obj);
724 return (Expr)obj;
725 }
726
727 @Cached
728 Rule VarExp(boolean inParens) {
729 Var<Integer> start = new Var<Integer>();
730 return Sequence(
731 start.set(currentIndex()),
732 Var(inParens),
733 makeVarExp(start.get())
734 );
735 }
736
737 @Cached
738 Rule Var(boolean inParens) {
739 Var<Integer> start = new Var<Integer>();
740 Var<ExpList.Builder> builder = new Var<ExpList.Builder>();
741 return Sequence(
742 start.set(currentIndex()),
743 VarStart(inParens),
744 ZeroOrMore(
745 makeVarExp(start.get()),
746 FirstOf(
747 VarExt(inParens),
748 Sequence(
749 builder.set(new ExpList.Builder()),
750 Args(inParens,start,builder)
751 ),
752 Sequence(
753 "->", Spaces(inParens),
754 builder.set(new ExpList.Builder()),
755 addToExpList(builder.get()),
756 VarExpB(inParens),
757 Args(inParens,start,builder)
758 )
759 )
760 )
761 );
762 }
763
764 @Cached
765 Rule VarExpB(boolean inParens) {
766 Var<Integer> start = new Var<Integer>();
767 return Sequence(
768 start.set(currentIndex()),
769 VarStart(inParens),
770 ZeroOrMore(
771 makeVarExp(start.get()),
772 VarExt(inParens)
773 ),
774 makeVarExp(start.get())
775 );
776 }
777
778 @Cached
779 Rule VarExt(boolean inParens) {
780 return FirstOf(
781 SubExpr(inParens),
782 Sequence( '.', Spaces(inParens), NameExpr(inParens) )
783 );
784 }
785
786 @Cached
787 Rule VarStart(boolean inParens) {
788 return FirstOf(
789 Sequence(
790 '(', Spaces(true), Expr(true), ')', Spaces(inParens),
791 push(expr(pop())),
792 push(null) // marker
793 ),
794 Sequence(
795 push(null), // marker
796 Name(inParens)
797 )
798 );
799 }
800
801 Expr env() {
802 int index = stackIndex(_ENV); 835 int index = stackIndex(_ENV);
803 if( index != -1 ) 836 if( index != -1 )
804 return new GetLocalVar(null,index); 837 return new GetLocalVar(null,index);
805 index = upValueIndex(_ENV); 838 index = upValueIndex(_ENV);
806 if( index != -1 ) 839 if( index != -1 )
807 return new GetUpVar(null,index); 840 return new GetUpVar(null,index);
808 throw new RuntimeException("_ENV not found"); 841 throw new RuntimeException("_ENV not found");
809 } 842 }
810 843
811 boolean makeVarExp(int start) { 844 private interface Var {
812 Object obj2 = pop(); 845 public Expr expr();
813 if( obj2==null ) 846 public Settable settable();
814 return true; 847 }
815 Object obj1 = pop(); 848
816 if( obj1 != null ) 849 private Var nameVar(final int start,final String name) {
817 return push( new IndexExpr( se(start), expr(obj1), expr(obj2) ) ); 850 return new Var() {
818 String name = (String)obj2; 851
819 int index = stackIndex(name); 852 public Expr expr() {
820 if( index != -1 ) 853 int index = stackIndex(name);
821 return push( new GetLocalVar(se(start),index) ); 854 if( index != -1 )
822 index = upValueIndex(name); 855 return new GetLocalVar(se(start),index);
823 if( index != -1 ) 856 index = upValueIndex(name);
824 return push( new GetUpVar(se(start),index) ); 857 if( index != -1 )
825 return push( new IndexExpr( se(start), env(), new ConstExpr(name) ) ); 858 return new GetUpVar(se(start),index);
826 } 859 return new IndexExpr( se(start), env(), new ConstExpr(name) );
827 860 }
828 // function should be on top of the stack 861
829 Rule Args(boolean inParens,Var<Integer> start,Var<ExpList.Builder> builder) { 862 public Settable settable() {
830 return Sequence( 863 int index = stackIndex(name);
831 FirstOf( 864 if( index != -1 )
832 Sequence( 865 return new SetLocalVar(index);
833 '(', Spaces(true), Optional(ExpList(true,builder)), ')', Spaces(inParens) 866 index = upValueIndex(name);
834 ), 867 if( index != -1 )
835 Sequence( 868 return new SetUpVar(index);
836 TableExpr(inParens), 869 return new SetTableEntry( se(start), env(), new ConstExpr(name) );
837 addToExpList(builder.get()) 870 }
838 ), 871 };
839 Sequence( 872 }
840 StringLiteral(inParens), 873
841 push(new ConstExpr(pop())), 874 private Var exprVar(final Expr expr) {
842 addToExpList(builder.get()) 875 return new Var() {
843 ) 876
844 ), 877 public Expr expr() {
845 push( new FnCall( se(start.get()), expr(pop()), builder.get().build() ) ), 878 return expr;
846 push(null) // marker 879 }
847 ); 880
848 } 881 public Settable settable() {
849 882 return null;
850 @Cached 883 }
851 Rule Expressions(boolean inParens) { 884 };
852 return FirstOf( 885 }
853 ExpList(inParens), 886
854 push( ExpList.emptyExpList ) 887 private Var indexVar(final int start,final Expr table,final Expr key) {
855 ); 888 return new Var() {
856 } 889
857 890 public Expr expr() {
858 @Cached 891 return new IndexExpr( se(start), table, key );
859 Rule ExpList(boolean inParens) { 892 }
860 Var<ExpList.Builder> builder = new Var<ExpList.Builder>(new ExpList.Builder()); 893
861 return Sequence( 894 public Settable settable() {
862 ExpList(inParens,builder), 895 return new SetTableEntry(se(start),table,key);
863 push( builder.get().build() ) 896 }
864 ); 897 };
865 } 898 }
866 899
867 Rule ExpList(boolean inParens,Var<ExpList.Builder> builder) { 900 private FnCall Args(boolean inParens,int start,Expr fn,ExpList.Builder builder) throws ParseException {
868 return Sequence( 901 parser.begin();
869 Expr(inParens), 902 if( parser.match('(') ) {
870 addToExpList(builder.get()), 903 Spaces(true);
871 ZeroOrMore( 904 ExpList(true,builder); // optional
872 ',', Spaces(inParens), Expr(inParens), 905 RequiredMatch(')');
873 addToExpList(builder.get()) 906 Spaces(inParens);
874 )
875 );
876 }
877
878 boolean addToExpList(ExpList.Builder bld) {
879 Object obj = pop();
880 if( obj instanceof Expressions ) {
881 bld.add( (Expressions)obj );
882 } else { 907 } else {
883 bld.add( (Expr)obj ); 908 Expr exp = TableExpr(inParens);
884 } 909 if( exp != null ) {
885 return true; 910 builder.add(exp);
886 } 911 } else {
887 912 String s = StringLiteral(inParens);
888 boolean addToExpList(ExpList.Builder bld, Expr expr) { 913 if( s != null ) {
889 bld.add(expr); 914 builder.add( new ConstExpr(s) );
890 return true; 915 } else {
891 } 916 return parser.failure(null);
892 917 }
893 @Cached 918 }
894 Rule SubExpr(boolean inParens) { 919 }
895 return Sequence( '[', Spaces(true), Expr(true), ']', Spaces(inParens) ); 920 return parser.success( new FnCall( se(start), fn, builder.build() ) );
896 } 921 }
897 922
898 @Cached 923 private Expressions ExpList() throws ParseException {
899 Rule NameExpr(boolean inParens) { 924 return ExpList(false);
900 return Sequence( 925 }
901 Name(inParens), 926
902 push( new ConstExpr((String)pop()) ) 927 private Expressions ExpList(boolean inParens) throws ParseException {
903 ); 928 ExpList.Builder builder = new ExpList.Builder();
904 } 929 return ExpList(inParens,builder) ? builder.build() : null;
905 930 }
906 @Cached 931
907 Rule Name(boolean inParens) { 932 private boolean ExpList(boolean inParens,ExpList.Builder builder) throws ParseException {
908 return Sequence( 933 parser.begin();
909 Sequence( 934 Expr exp = Expr(inParens);
910 NameFirstChar(), 935 if( exp==null )
911 ZeroOrMore( NameChar() ) 936 return parser.failure();
912 ), 937 builder.add(exp);
913 !keywords.contains(match()), 938 while( parser.match(',') ) {
914 push(match()), 939 Spaces(inParens);
915 Spaces(inParens) 940 builder.add( RequiredExpr(inParens) );
916 ); 941 }
917 } 942 return parser.success();
918 943 }
919 Rule NameChar() { 944
920 return FirstOf( NameFirstChar(), Digit() ); 945 private Expr SubExpr(boolean inParens) throws ParseException {
921 } 946 parser.begin();
922 947 if( !parser.match('[') )
923 Rule NameFirstChar() { 948 return parser.failure(null);
924 return FirstOf( 949 Spaces(true);
925 CharRange('a', 'z'), 950 Expr exp = RequiredExpr(true);
926 CharRange('A', 'Z'), 951 RequiredMatch(']');
927 '_' 952 Spaces(inParens);
928 ); 953 return parser.success(exp);
929 } 954 }
930 955
931 Rule Keyword(String keyword,boolean inParens) { 956 private Expr NameExpr(boolean inParens) throws ParseException {
932 return Sequence( 957 String name = Name(inParens);
933 keyword, 958 return name==null ? null : new ConstExpr(name);
934 TestNot( NameChar() ), 959 }
935 Spaces(inParens) 960
936 ); 961 private String RequiredName() throws ParseException {
937 } 962 parser.begin();
938 963 String name = Name();
939 static final Set<String> keywords = new HashSet<String>(Arrays.asList( 964 if( name==null )
965 parser.exception("Name expected");
966 return parser.success(name);
967 }
968
969 private String Name() throws ParseException {
970 return Name(false);
971 }
972
973 private String Name(boolean inParens) throws ParseException {
974 int start = parser.begin();
975 if( !NameFirstChar() )
976 return parser.failure(null);
977 while( NameChar() );
978 String match = parser.textFrom(start);
979 if( keywords.contains(match) )
980 return parser.failure(null);
981 Spaces(inParens);
982 return parser.success(match);
983 }
984
985 private boolean NameChar() {
986 return NameFirstChar() || Digit();
987 }
988
989 private boolean NameFirstChar() {
990 return parser.inCharRange('a', 'z') || parser.inCharRange('A', 'Z') || parser.match('_');
991 }
992
993 private void RequiredMatch(char c) throws ParseException {
994 if( !parser.match(c) )
995 throw parser.exception("'"+c+"' expected");
996 }
997
998 private void RequiredMatch(String s) throws ParseException {
999 if( !parser.match(s) )
1000 throw parser.exception("'"+s+"' expected");
1001 }
1002
1003 private void RequiredKeyword(String keyword) throws ParseException {
1004 RequiredKeyword(keyword,false);
1005 }
1006
1007 private boolean Keyword(String keyword) throws ParseException {
1008 return Keyword(keyword,false);
1009 }
1010
1011 private void RequiredKeyword(String keyword,boolean inParens) throws ParseException {
1012 if( !Keyword(keyword,inParens) )
1013 throw parser.exception("'"+keyword+"' expected");
1014 }
1015
1016 private boolean Keyword(String keyword,boolean inParens) throws ParseException {
1017 parser.begin();
1018 if( !parser.match(keyword) || NameChar() )
1019 return parser.failure();
1020 Spaces(inParens);
1021 return parser.success();
1022 }
1023
1024 private static final Set<String> keywords = new HashSet<String>(Arrays.asList(
940 "and", 1025 "and",
941 "break", 1026 "break",
942 "catch", 1027 "catch",
943 "do", 1028 "do",
944 "else", 1029 "else",
963 "try", 1048 "try",
964 "until", 1049 "until",
965 "while" 1050 "while"
966 )); 1051 ));
967 1052
968 @Cached 1053 private Expr Literal(boolean inParens) throws ParseException {
969 Rule Literal(boolean inParens) { 1054 if( NilLiteral(inParens) )
970 return Sequence( 1055 return new ConstExpr(null);
971 FirstOf( 1056 Boolean b = BooleanLiteral(inParens);
972 NilLiteral(inParens), 1057 if( b != null )
973 BooleanLiteral(inParens), 1058 return new ConstExpr(b);
974 NumberLiteral(inParens), 1059 Number n = NumberLiteral(inParens);
975 StringLiteral(inParens) 1060 if( n != null )
976 ), 1061 return new ConstExpr(n);
977 push(new ConstExpr(pop())) 1062 String s = StringLiteral(inParens);
978 ); 1063 if( s != null )
979 } 1064 return new ConstExpr(s);
980 1065 return null;
981 @Cached 1066 }
982 Rule NilLiteral(boolean inParens) { 1067
983 return Sequence( Keyword("nil",inParens), push(null) ); 1068 private boolean NilLiteral(boolean inParens) throws ParseException {
984 } 1069 return Keyword("nil",inParens);
985 1070 }
986 @Cached 1071
987 Rule BooleanLiteral(boolean inParens) { 1072 private Boolean BooleanLiteral(boolean inParens) throws ParseException {
988 return FirstOf( 1073 if( Keyword("true",inParens) )
989 Sequence( Keyword("true",inParens), push(true) ), 1074 return true;
990 Sequence( Keyword("false",inParens), push(false) ) 1075 if( Keyword("false",inParens) )
991 ); 1076 return false;
992 } 1077 return null;
993 1078 }
994 @Cached 1079
995 Rule NumberLiteral(boolean inParens) { 1080 private Number NumberLiteral(boolean inParens) throws ParseException {
996 return Sequence( 1081 parser.begin();
997 FirstOf( 1082 Number n;
998 Sequence( 1083 if( parser.matchIgnoreCase("0x") ) {
999 IgnoreCase("0x"), 1084 n = HexNumber();
1000 HexNumber() 1085 } else {
1001 ), 1086 n = DecNumber();
1002 Sequence( 1087 }
1003 DecNumber(), 1088 if( n==null || NameChar() )
1004 push(Double.valueOf(match())) 1089 return parser.failure(null);
1005 ) 1090 Spaces(inParens);
1006 ), 1091 return parser.success(n);
1007 TestNot( NameChar() ), 1092 }
1008 Spaces(inParens) 1093
1009 ); 1094 private Number DecNumber() {
1010 } 1095 int start = parser.begin();
1011 1096 if( Int() ) {
1012 Rule DecNumber() { 1097 if( parser.match('.') )
1013 return FirstOf( 1098 Int(); // optional
1014 Sequence( 1099 } else if( parser.match('.') && Int() ) {
1015 Int(), 1100 // ok
1016 Optional( '.', Optional(Int()) ), 1101 } else
1017 Exponent() 1102 return parser.failure(null);
1018 ), 1103 Exponent(); // optional
1019 Sequence( '.', Int(), Exponent() ) 1104 return parser.success(Double.valueOf(parser.textFrom(start)));
1020 ); 1105 }
1021 } 1106
1022 1107 private boolean Exponent() {
1023 Rule Exponent() { 1108 parser.begin();
1024 return Optional( 1109 if( !parser.matchIgnoreCase("e") )
1025 IgnoreCase('e'), 1110 return parser.failure();
1026 Optional(AnyOf("+-")), 1111 parser.anyOf("+-"); // optional
1027 Int() 1112 if( !Int() )
1028 ); 1113 return parser.failure();
1029 } 1114 return parser.success();
1030 1115 }
1031 Rule Int() { 1116
1032 return OneOrMore(Digit()); 1117 private boolean Int() {
1033 } 1118 if( !Digit() )
1034 1119 return false;
1035 Rule Digit() { 1120 while( Digit() );
1036 return CharRange('0', '9');
1037 }
1038
1039 Rule HexNumber() {
1040 return FirstOf(
1041 Sequence(
1042 HexInt(),
1043 push( (double)Long.parseLong(match(),16) ),
1044 Optional( '.', Optional(HexDec()) ),
1045 HexExponent()
1046 ),
1047 Sequence( push(0.0), '.', HexDec(), HexExponent() )
1048 );
1049 }
1050
1051 Rule HexDec() {
1052 return Sequence(
1053 HexInt(),
1054 push( (Double)pop() + (double)Long.parseLong(match(),16) / Math.pow(16,matchLength()) )
1055 );
1056 }
1057
1058 Rule HexExponent() {
1059 return Optional(
1060 IgnoreCase('p'),
1061 Sequence(
1062 Optional(AnyOf("+-")),
1063 HexInt()
1064 ),
1065 push( (Double)pop() * Math.pow(2,(double)Long.parseLong(match())) )
1066 );
1067 }
1068
1069 Rule HexInt() {
1070 return OneOrMore(Digit());
1071 }
1072
1073
1074 Rule HexDigit() {
1075 return FirstOf(
1076 Digit(),
1077 AnyOf("abcdefABCDEF")
1078 );
1079 }
1080
1081 @Cached
1082 Rule StringLiteral(boolean inParens) {
1083 return Sequence(
1084 FirstOf(
1085 QuotedString('"'),
1086 QuotedString('\''),
1087 LongString()
1088 ),
1089 Spaces(inParens)
1090 );
1091 }
1092
1093 Rule LongString() {
1094 return Sequence(
1095 '[',
1096 ZeroOrMore('='),
1097 nEquals(matchLength()),
1098 '[',
1099 ZeroOrMore(
1100 TestNot(LongBracketsEnd()),
1101 ANY
1102 ),
1103 push( match() ),
1104 LongBracketsEnd()
1105 );
1106 }
1107
1108 Rule QuotedString(char quote) {
1109 StringBuilderVar buf = new StringBuilderVar();
1110 return Sequence(
1111 quote,
1112 ZeroOrMore(
1113 FirstOf(
1114 Sequence(
1115 NoneOf("\\\n"+quote),
1116 buf.append(matchedChar())
1117 ),
1118 EscSeq(buf)
1119 )
1120 ),
1121 quote,
1122 push( buf.getString() )
1123 );
1124 }
1125
1126 Rule EscSeq(StringBuilderVar buf) {
1127 return Sequence(
1128 '\\',
1129 FirstOf(
1130 Sequence( 'a', buf.append('\u0007') ),
1131 Sequence( 'b', buf.append('\b') ),
1132 Sequence( 'f', buf.append('\f') ),
1133 Sequence( 'n', buf.append('\n') ),
1134 Sequence( 'r', buf.append('\r') ),
1135 Sequence( 't', buf.append('\t') ),
1136 Sequence( 'v', buf.append('\u000b') ),
1137 Sequence( '\\', buf.append('\\') ),
1138 Sequence( '"', buf.append('"') ),
1139 Sequence( '\'', buf.append('\'') ),
1140 Sequence(
1141 'x',
1142 Sequence( HexDigit(), HexDigit() ),
1143 buf.append( (char)Integer.parseInt(match(),16) )
1144 ),
1145 Sequence(
1146 Sequence(
1147 Digit(),
1148 Optional(
1149 Digit(),
1150 Optional(
1151 Digit()
1152 )
1153 )
1154 ),
1155 buf.append( (char)Integer.parseInt(match()) )
1156 )
1157 )
1158 );
1159 }
1160
1161 @Cached
1162 Rule Spaces(boolean inParens) {
1163 return ZeroOrMore(
1164 FirstOf(
1165 AnyOf(" \t"),
1166 Comment(),
1167 Sequence( '\\', EndOfLine() ),
1168 Sequence( inParens, AnyOf("\r\n"),
1169 Optional( "--", ZeroOrMore(NoneOf("\r\n")) )
1170 )
1171 )
1172 );
1173 }
1174
1175 Rule Comment() {
1176 return Sequence(
1177 "--[",
1178 ZeroOrMore('='),
1179 nEquals(matchLength()),
1180 '[',
1181 ZeroOrMore(
1182 TestNot(LongBracketsEnd()),
1183 ANY
1184 ),
1185 LongBracketsEnd()
1186 );
1187 }
1188
1189 Rule LongBracketsEnd() {
1190 return Sequence( ']', ZeroOrMore('='), nEquals==matchLength(), ']' );
1191 }
1192
1193 static boolean action(Object obj) {
1194 return true; 1121 return true;
1195 } 1122 }
1196 1123
1197 // for debugging 1124 private boolean Digit() {
1198 boolean print(Object o) { 1125 return parser.inCharRange('0', '9');
1199 System.out.println(o); 1126 }
1127
1128 private Number HexNumber() {
1129 int start = parser.begin();
1130 double n;
1131 if( HexInt() ) {
1132 n = (double)Long.parseLong(parser.textFrom(start),16);
1133 if( parser.match('.') ) {
1134 start = parser.currentIndex();
1135 if( HexInt() ) {
1136 String dec = parser.textFrom(start);
1137 n += (double)Long.parseLong(dec,16) / Math.pow(16,dec.length());
1138 }
1139 }
1140 } else if( parser.match('.') && HexInt() ) {
1141 String dec = parser.textFrom(start+1);
1142 n = (double)Long.parseLong(dec,16) / Math.pow(16,dec.length());
1143 } else {
1144 return parser.failure(null);
1145 }
1146 if( parser.matchIgnoreCase("p") ) {
1147 parser.anyOf("+-"); // optional
1148 start = parser.currentIndex();
1149 if( !HexInt() )
1150 return parser.failure(null);
1151 n *= Math.pow(2,(double)Long.parseLong(parser.textFrom(start)));
1152 }
1153 return parser.success(Double.valueOf(n));
1154 }
1155
1156 private boolean HexInt() {
1157 if( !HexDigit() )
1158 return false;
1159 while( HexDigit() );
1200 return true; 1160 return true;
1201 } 1161 }
1202 1162
1163
1164 private boolean HexDigit() {
1165 return Digit() || parser.anyOf("abcdefABCDEF");
1166 }
1167
1168 private String StringLiteral(boolean inParens) throws ParseException {
1169 String s;
1170 if( (s=QuotedString('"'))==null
1171 && (s=QuotedString('\''))==null
1172 && (s=LongString())==null
1173 )
1174 return null;
1175 Spaces(inParens);
1176 return s;
1177 }
1178
1179 private String LongString() throws ParseException {
1180 parser.begin();
1181 if( !parser.match('[') )
1182 return parser.failure(null);
1183 int start = parser.currentIndex();
1184 while( parser.match('=') );
1185 int nEquals = parser.currentIndex() - start;
1186 if( !parser.match('[') )
1187 return parser.failure(null);
1188 start = parser.currentIndex();
1189 while( !LongBracketsEnd(nEquals) ) {
1190 if( !parser.anyChar() )
1191 throw parser.exception("Unclosed long string");
1192 }
1193 String s = parser.text.substring( start, parser.currentIndex() - nEquals - 2 );
1194 return parser.success(s);
1195 }
1196
1197 private String QuotedString(char quote) throws ParseException {
1198 parser.begin();
1199 if( !parser.match(quote) )
1200 return parser.failure(null);
1201 StringBuilder buf = new StringBuilder();
1202 while( !parser.match(quote) ) {
1203 Character c = EscSeq();
1204 if( c != null ) {
1205 buf.append(c);
1206 } else {
1207 if( !parser.anyChar() )
1208 throw parser.exception("Unclosed string");
1209 buf.append(parser.lastChar());
1210 }
1211 }
1212 return parser.success(buf.toString());
1213 }
1214
1215 private Character EscSeq() {
1216 parser.begin();
1217 if( !parser.match('\\') )
1218 return parser.failure(null);
1219 if( parser.match('a') ) return '\u0007';
1220 if( parser.match('b') ) return '\b';
1221 if( parser.match('f') ) return '\f';
1222 if( parser.match('n') ) return '\n';
1223 if( parser.match('r') ) return '\r';
1224 if( parser.match('t') ) return '\t';
1225 if( parser.match('v') ) return '\u000b';
1226 if( parser.match('\\') ) return '\\';
1227 if( parser.match('"') ) return '"';
1228 if( parser.match('\'') ) return '\'';
1229 int start = parser.currentIndex();
1230 if( parser.match('x') && HexDigit() && HexDigit() )
1231 return (char)Integer.parseInt(parser.textFrom(start+1),16);
1232 if( Digit() ) {
1233 if( Digit() ) Digit(); // optional
1234 return (char)Integer.parseInt(parser.textFrom(start));
1235 }
1236 return parser.failure(null);
1237 }
1238
1239 private void Spaces() throws ParseException {
1240 Spaces(false);
1241 }
1242
1243 private void Spaces(boolean inParens) throws ParseException {
1244 while( parser.anyOf(" \t") || Comment() || ContinueOnNextLine() || inParens && NewLine() );
1245 }
1246
1247 private boolean ContinueOnNextLine() {
1248 parser.begin();
1249 return parser.match('\\') && EndOfLine() ? parser.success() : parser.failure();
1250 }
1251
1252 private boolean NewLine() {
1253 if( !EndOfLine() )
1254 return false;
1255 if( parser.match("--") ) {
1256 while( parser.noneOf("\r\n") );
1257 }
1258 return true;
1259 }
1260
1261 private boolean Comment() throws ParseException {
1262 parser.begin();
1263 if( !parser.match("--[") )
1264 return parser.failure();
1265 int start = parser.currentIndex();
1266 while( parser.match('=') );
1267 int nEquals = parser.currentIndex() - start;
1268 if( !parser.match('[') )
1269 return parser.failure();
1270 while( !LongBracketsEnd(nEquals) ) {
1271 if( !parser.anyChar() )
1272 throw parser.exception("Unclosed comment");
1273 }
1274 return parser.success();
1275 }
1276
1277 private boolean LongBracketsEnd(int nEquals) {
1278 parser.begin();
1279 if( !parser.match(']') )
1280 return parser.failure();
1281 while( nEquals-- > 0 ) {
1282 if( !parser.match('=') )
1283 return parser.failure();
1284 }
1285 if( !parser.match(']') )
1286 return parser.failure();
1287 return parser.success();
1288 }
1289
1203 } 1290 }