Add support for author nicknames
[jpcrr.git] / mnj / lua / Syntax.java
blob5b5e3538f8966a5a23878fb70c5a7080a7dcf676
1 /* $Header: //info.ravenbrook.com/project/jili/version/1.1/code/mnj/lua/Syntax.java#1 $
2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
3 * All rights reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject
11 * to the following conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 package mnj.lua;
27 import java.io.IOException;
28 import java.io.Reader;
29 import java.util.Hashtable;
32 /**
33 * Syntax analyser. Lexing, parsing, code generation.
35 final class Syntax
37 /** End of File, must be -1 as that is what read() returns. */
38 private static final int EOZ = -1;
40 private static final int FIRST_RESERVED = 257;
42 // WARNING: if you change the order of this enumeration,
43 // grep "ORDER RESERVED"
44 private static final int TK_AND = FIRST_RESERVED + 0;
45 private static final int TK_BREAK = FIRST_RESERVED + 1;
46 private static final int TK_DO = FIRST_RESERVED + 2;
47 private static final int TK_ELSE = FIRST_RESERVED + 3;
48 private static final int TK_ELSEIF = FIRST_RESERVED + 4;
49 private static final int TK_END = FIRST_RESERVED + 5;
50 private static final int TK_FALSE = FIRST_RESERVED + 6;
51 private static final int TK_FOR = FIRST_RESERVED + 7;
52 private static final int TK_FUNCTION = FIRST_RESERVED + 8;
53 private static final int TK_IF = FIRST_RESERVED + 9;
54 private static final int TK_IN = FIRST_RESERVED + 10;
55 private static final int TK_LOCAL = FIRST_RESERVED + 11;
56 private static final int TK_NIL = FIRST_RESERVED + 12;
57 private static final int TK_NOT = FIRST_RESERVED + 13;
58 private static final int TK_OR = FIRST_RESERVED + 14;
59 private static final int TK_REPEAT = FIRST_RESERVED + 15;
60 private static final int TK_RETURN = FIRST_RESERVED + 16;
61 private static final int TK_THEN = FIRST_RESERVED + 17;
62 private static final int TK_TRUE = FIRST_RESERVED + 18;
63 private static final int TK_UNTIL = FIRST_RESERVED + 19;
64 private static final int TK_WHILE = FIRST_RESERVED + 20;
65 private static final int TK_CONCAT = FIRST_RESERVED + 21;
66 private static final int TK_DOTS = FIRST_RESERVED + 22;
67 private static final int TK_EQ = FIRST_RESERVED + 23;
68 private static final int TK_GE = FIRST_RESERVED + 24;
69 private static final int TK_LE = FIRST_RESERVED + 25;
70 private static final int TK_NE = FIRST_RESERVED + 26;
71 private static final int TK_NUMBER = FIRST_RESERVED + 27;
72 private static final int TK_NAME = FIRST_RESERVED + 28;
73 private static final int TK_STRING = FIRST_RESERVED + 29;
74 private static final int TK_EOS = FIRST_RESERVED + 30;
76 private static final int NUM_RESERVED = TK_WHILE - FIRST_RESERVED + 1;
78 /** Equivalent to luaX_tokens. ORDER RESERVED */
79 static String[] tokens = new String[]
81 "and", "break", "do", "else", "elseif",
82 "end", "false", "for", "function", "if",
83 "in", "local", "nil", "not", "or", "repeat",
84 "return", "then", "true", "until", "while",
85 "..", "...", "==", ">=", "<=", "~=",
86 "<number>", "<name>", "<string>", "<eof>"
89 static Hashtable<Object, Object> reserved = new Hashtable<Object, Object>();
90 static
92 for (int i=0; i < NUM_RESERVED; ++i)
94 reserved.put(tokens[i], new Integer(FIRST_RESERVED+i));
98 // From struct LexState
100 /** current character */
101 int current;
102 /** input line counter */
103 int linenumber = 1;
104 /** line of last token 'consumed' */
105 int lastline = 1;
107 * The token value. For "punctuation" tokens this is the ASCII value
108 * for the character for the token; for other tokens a member of the
109 * enum (all of which are > 255).
111 int token;
112 /** Semantic info for token; a number. */
113 double tokenR;
114 /** Semantic info for token; a string. */
115 String tokenS;
117 /** Lookahead token value. */
118 int lookahead = TK_EOS;
119 /** Semantic info for lookahead; a number. */
120 double lookaheadR;
121 /** Semantic info for lookahead; a string. */
122 String lookaheadS;
124 /** Semantic info for return value from {@link #llex}; a number. */
125 double semR;
126 /** As {@link #semR}, for string. */
127 String semS;
129 /** FuncState for current (innermost) function being parsed. */
130 FuncState fs;
131 Lua L;
133 /** input stream */
134 private Reader z;
136 /** Buffer for tokens. */
137 StringBuffer buff = new StringBuffer();
139 /** current source name */
140 String source;
142 private Syntax(Lua L, Reader z, String source) throws IOException
144 this.L = L;
145 this.z = z;
146 this.source = source;
147 next();
150 int lastline()
152 return lastline;
156 // From <ctype.h>
158 // Implementations of functions from <ctype.h> are only correct copies
159 // to the extent that Lua requires them.
160 // Generally they have default access so that StringLib can see them.
161 // Unlike C's these version are not locale dependent, they use the
162 // ISO-Latin-1 definitions from CLDC 1.1 Character class.
164 static boolean isalnum(int c)
166 char ch = (char)c;
167 return Character.isUpperCase(ch) ||
168 Character.isLowerCase(ch) ||
169 Character.isDigit(ch);
172 static boolean isalpha(int c)
174 char ch = (char)c;
175 return Character.isUpperCase(ch) ||
176 Character.isLowerCase(ch);
179 /** True if and only if the char (when converted from the int) is a
180 * control character.
182 static boolean iscntrl(int c)
184 return (char)c < 0x20 || c == 0x7f;
187 static boolean isdigit(int c)
189 return Character.isDigit((char)c);
192 static boolean islower(int c)
194 return Character.isLowerCase((char)c);
198 * A character is punctuation if not cntrl, not alnum, and not space.
200 static boolean ispunct(int c)
202 return !isalnum(c) && !iscntrl(c) && !isspace(c);
205 static boolean isspace(int c)
207 return c == ' ' ||
208 c == '\f' ||
209 c == '\n' ||
210 c == '\r' ||
211 c == '\t';
214 static boolean isupper(int c)
216 return Character.isUpperCase((char)c);
219 static boolean isxdigit(int c)
221 return Character.isDigit((char)c) ||
222 ('a' <= c && c <= 'f') ||
223 ('A' <= c && c <= 'F');
226 // From llex.c
228 private boolean check_next(String set) throws IOException
230 if (set.indexOf(current) < 0)
232 return false;
234 save_and_next();
235 return true;
238 private boolean currIsNewline()
240 return current == '\n' || current == '\r';
243 private void inclinenumber() throws IOException
245 int old = current;
246 //# assert currIsNewline()
247 next(); // skip '\n' or '\r'
248 if (currIsNewline() && current != old)
250 next(); // skip '\n\r' or '\r\n'
252 if (++linenumber < 0) // overflow
254 xSyntaxerror("chunk has too many lines");
258 private int skip_sep() throws IOException
260 int count = 0;
261 int s = current;
262 //# assert s == '[' || s == ']'
263 save_and_next();
264 while (current == '=')
266 save_and_next();
267 count++;
269 return (current == s) ? count : (-count) - 1;
272 private void read_long_string(boolean isString, int sep) throws IOException
274 save_and_next(); /* skip 2nd `[' */
275 if (currIsNewline()) /* string starts with a newline? */
276 inclinenumber(); /* skip it */
277 loop:
278 while (true)
280 switch (current)
282 case EOZ:
283 xLexerror(isString ? "unfinished long string" :
284 "unfinished long comment",
285 TK_EOS);
286 break; /* to avoid warnings */
287 case ']':
288 if (skip_sep() == sep)
290 save_and_next(); /* skip 2nd `]' */
291 break loop;
293 break;
295 case '\n':
296 case '\r':
297 save('\n');
298 inclinenumber();
299 if (!isString)
300 buff.setLength(0) ; /* avoid wasting space */
301 break;
303 default:
304 if (isString) save_and_next();
305 else next();
307 } /* loop */
308 if (isString)
310 String rawtoken = buff.toString();
311 int trim_by = 2+sep ;
312 semS = rawtoken.substring(trim_by, rawtoken.length()-trim_by) ;
317 /** Lex a token and return it. The semantic info for the token is
318 * stored in <code>this.semR</code> or <code>this.semS</code> as
319 * appropriate.
321 private int llex() throws IOException
323 buff.setLength(0);
324 while (true)
326 switch (current)
328 case '\n':
329 case '\r':
330 inclinenumber();
331 continue;
332 case '-':
333 next();
334 if (current != '-')
335 return '-';
336 /* else is a comment */
337 next();
338 if (current == '[')
340 int sep = skip_sep();
341 buff.setLength(0) ; /* `skip_sep' may dirty the buffer */
342 if (sep >= 0)
344 read_long_string(false, sep); /* long comment */
345 buff.setLength(0) ;
346 continue;
349 /* else short comment */
350 while (!currIsNewline() && current != EOZ)
351 next();
352 continue;
354 case '[':
355 int sep = skip_sep();
356 if (sep >= 0)
358 read_long_string(true, sep);
359 return TK_STRING;
361 else if (sep == -1)
362 return '[';
363 else
364 xLexerror("invalid long string delimiter", TK_STRING);
365 continue; // avoids Checkstyle warning.
367 case '=':
368 next() ;
369 if (current != '=')
370 { return '=' ; }
371 else
373 next() ;
374 return TK_EQ ;
376 case '<':
377 next() ;
378 if (current != '=')
379 { return '<' ; }
380 else
382 next() ;
383 return TK_LE ;
385 case '>':
386 next() ;
387 if (current != '=')
388 { return '>' ; }
389 else
391 next() ;
392 return TK_GE ;
394 case '~':
395 next();
396 if (current != '=')
397 { return '~'; }
398 else
400 next();
401 return TK_NE;
403 case '"':
404 case '\'':
405 read_string(current);
406 return TK_STRING;
407 case '.':
408 save_and_next();
409 if (check_next("."))
411 if (check_next("."))
413 return TK_DOTS;
415 else
417 return TK_CONCAT ;
420 else if (!isdigit(current))
422 return '.';
424 else
426 read_numeral();
427 return TK_NUMBER;
429 case EOZ:
430 return TK_EOS;
431 default:
432 if (isspace(current))
434 // assert !currIsNewline();
435 next();
436 continue;
438 else if (isdigit(current))
440 read_numeral();
441 return TK_NUMBER;
443 else if (isalpha(current) || current == '_')
445 // identifier or reserved word
448 save_and_next();
449 } while (isalnum(current) || current == '_');
450 String s = buff.toString();
451 Object t = reserved.get(s);
452 if (t == null)
454 semS = s;
455 return TK_NAME;
457 else
459 return ((Integer)t).intValue();
462 else
464 int c = current;
465 next();
466 return c; // single-char tokens
472 private void next() throws IOException
474 current = z.read();
477 private static final int hexCharValue(char x) throws NumberFormatException
479 switch(x)
481 case '0': return 0;
482 case '1': return 1;
483 case '2': return 2;
484 case '3': return 3;
485 case '4': return 4;
486 case '5': return 5;
487 case '6': return 6;
488 case '7': return 7;
489 case '8': return 8;
490 case '9': return 9;
491 case 'A': return 10;
492 case 'B': return 11;
493 case 'C': return 12;
494 case 'D': return 13;
495 case 'E': return 14;
496 case 'F': return 15;
497 case 'a': return 10;
498 case 'b': return 11;
499 case 'c': return 12;
500 case 'd': return 13;
501 case 'e': return 14;
502 case 'f': return 15;
503 default: throw new NumberFormatException("Bad hexadecimal digit");
507 /** Reads number. Writes to semR. */
508 private void read_numeral() throws IOException
510 // assert isdigit(current);
513 save_and_next();
514 } while (isdigit(current) || current == '.');
515 if (check_next("Ee")) // 'E' ?
517 check_next("+-"); // optional exponent sign
519 while (isalnum(current) || current == '_')
521 save_and_next();
523 // :todo: consider doing PUC-Rio's decimal point tricks.
526 String n = buff.toString();
527 if(n.length() > 2 && n.charAt(0) == '0' && n.charAt(1) == 'x')
529 //Hexadecimal constant.
530 double value = 0;
531 for(int i = 2; i < n.length(); i++)
532 value = value * 16 + hexCharValue(n.charAt(i));
533 semR = value;
534 return;
536 semR = Double.parseDouble(n);
537 return;
539 catch (NumberFormatException e)
541 xLexerror("malformed number", TK_NUMBER);
545 /** Reads string. Writes to semS. */
546 private void read_string(int del) throws IOException
548 save_and_next();
549 while (current != del)
551 switch (current)
553 case EOZ:
554 xLexerror("unfinished string", TK_EOS);
555 continue; // avoid compiler warning
556 case '\n':
557 case '\r':
558 xLexerror("unfinished string", TK_STRING);
559 continue; // avoid compiler warning
560 case '\\':
562 int c;
563 next(); // do not save the '\'
564 switch (current)
566 case 'a': c = 7; break; // no '\a' in Java.
567 case 'b': c = '\b'; break;
568 case 'f': c = '\f'; break;
569 case 'n': c = '\n'; break;
570 case 'r': c = '\r'; break;
571 case 't': c = '\t'; break;
572 case 'v': c = 11; break; // no '\v' in Java.
573 case '\n': case '\r':
574 save('\n');
575 inclinenumber();
576 continue;
577 case EOZ:
578 continue; // will raise an error next loop
579 default:
580 if (!isdigit(current))
582 save_and_next(); // handles \\, \", \', \?
584 else // \xxx
586 int i = 0;
587 c = 0;
590 c = 10*c + (current - '0');
591 next();
592 } while (++i<3 && isdigit(current));
593 // In unicode, there are no bounds on a 3-digit decimal.
594 save(c);
596 continue;
598 save(c);
599 next();
600 continue;
602 default:
603 save_and_next();
606 save_and_next(); // skip delimiter
607 String rawtoken = buff.toString() ;
608 semS = rawtoken.substring(1, rawtoken.length()-1) ;
611 private void save()
613 buff.append((char)current);
616 private void save(int c)
618 buff.append((char)c);
621 private void save_and_next() throws IOException
623 save();
624 next();
627 /** Getter for source. */
628 String source()
630 return source;
633 private String txtToken(int tok)
635 switch (tok)
637 case TK_NAME:
638 case TK_STRING:
639 case TK_NUMBER:
640 return buff.toString();
641 default:
642 return xToken2str(tok);
646 /** Equivalent to <code>luaX_lexerror</code>. */
647 private void xLexerror(String msg, int tok)
649 msg = source + ":" + linenumber + ": " + msg;
650 if (tok != 0)
652 msg = msg + " near '" + txtToken(tok) + "'";
654 L.pushString(msg);
655 L.dThrow(Lua.ERRSYNTAX);
658 /** Equivalent to <code>luaX_next</code>. */
659 private void xNext() throws IOException
661 lastline = linenumber;
662 if (lookahead != TK_EOS) // is there a look-ahead token?
664 token = lookahead; // Use this one,
665 tokenR = lookaheadR;
666 tokenS = lookaheadS;
667 lookahead = TK_EOS; // and discharge it.
669 else
671 token = llex();
672 tokenR = semR;
673 tokenS = semS;
677 /** Equivalent to <code>luaX_syntaxerror</code>. */
678 void xSyntaxerror(String msg)
680 xLexerror(msg, token);
683 private static String xToken2str(int token)
685 if (token < FIRST_RESERVED)
687 // assert token == (char)token;
688 if (iscntrl(token))
690 return "char(" + token + ")";
692 return (new Character((char)token)).toString();
694 return tokens[token-FIRST_RESERVED];
697 // From lparser.c
699 private static boolean block_follow(int token)
701 switch (token)
703 case TK_ELSE: case TK_ELSEIF: case TK_END:
704 case TK_UNTIL: case TK_EOS:
705 return true;
706 default:
707 return false;
711 private void check(int c)
713 if (token != c)
715 error_expected(c);
720 * @param what the token that is intended to end the match.
721 * @param who the token that begins the match.
722 * @param where the line number of <var>what</var>.
724 private void check_match(int what, int who, int where)
725 throws IOException
727 if (!testnext(what))
729 if (where == linenumber)
731 error_expected(what);
733 else
735 xSyntaxerror("'" + xToken2str(what) + "' expected (to close '" +
736 xToken2str(who) + "' at line " + where + ")");
741 private void close_func()
743 removevars(0);
744 fs.kRet(0, 0); // final return;
745 fs.close();
746 // :todo: check this is a valid assertion to make
747 //# assert fs != fs.prev
748 fs = fs.prev;
752 static String opcode_name(int op)
754 switch (op)
756 case Lua.OP_MOVE: return "MOVE";
757 case Lua.OP_LOADK: return "LOADK";
758 case Lua.OP_LOADBOOL: return "LOADBOOL";
759 case Lua.OP_LOADNIL: return "LOADNIL";
760 case Lua.OP_GETUPVAL: return "GETUPVAL";
761 case Lua.OP_GETGLOBAL: return "GETGLOBAL";
762 case Lua.OP_GETTABLE: return "GETTABLE";
763 case Lua.OP_SETGLOBAL: return "SETGLOBAL";
764 case Lua.OP_SETUPVAL: return "SETUPVAL";
765 case Lua.OP_SETTABLE: return "SETTABLE";
766 case Lua.OP_NEWTABLE: return "NEWTABLE";
767 case Lua.OP_SELF: return "SELF";
768 case Lua.OP_ADD: return "ADD";
769 case Lua.OP_SUB: return "SUB";
770 case Lua.OP_MUL: return "MUL";
771 case Lua.OP_DIV: return "DIV";
772 case Lua.OP_MOD: return "MOD";
773 case Lua.OP_POW: return "POW";
774 case Lua.OP_UNM: return "UNM";
775 case Lua.OP_NOT: return "NOT";
776 case Lua.OP_LEN: return "LEN";
777 case Lua.OP_CONCAT: return "CONCAT";
778 case Lua.OP_JMP: return "JMP";
779 case Lua.OP_EQ: return "EQ";
780 case Lua.OP_LT: return "LT";
781 case Lua.OP_LE: return "LE";
782 case Lua.OP_TEST: return "TEST";
783 case Lua.OP_TESTSET: return "TESTSET";
784 case Lua.OP_CALL: return "CALL";
785 case Lua.OP_TAILCALL: return "TAILCALL";
786 case Lua.OP_RETURN: return "RETURN";
787 case Lua.OP_FORLOOP: return "FORLOOP";
788 case Lua.OP_FORPREP: return "FORPREP";
789 case Lua.OP_TFORLOOP: return "TFORLOOP";
790 case Lua.OP_SETLIST: return "SETLIST";
791 case Lua.OP_CLOSE: return "CLOSE";
792 case Lua.OP_CLOSURE: return "CLOSURE";
793 case Lua.OP_VARARG: return "VARARG";
794 default: return "??"+op;
798 private void codestring(Expdesc e, String s)
800 e.init(Expdesc.VK, fs.kStringK(s));
803 private void checkname(Expdesc e) throws IOException
805 codestring(e, str_checkname());
808 private void enterlevel()
810 L.nCcalls++ ;
813 private void error_expected(int tok)
815 xSyntaxerror("'" + xToken2str(tok) + "' expected");
818 private void leavelevel()
820 L.nCcalls-- ;
824 /** Equivalent to luaY_parser. */
825 static Proto parser(Lua L, Reader in, String name)
826 throws IOException
828 Syntax ls = new Syntax(L, in, name);
829 FuncState fs = new FuncState(ls);
830 ls.open_func(fs);
831 fs.f.setIsVararg();
832 ls.xNext();
833 ls.chunk();
834 ls.check(TK_EOS);
835 ls.close_func();
836 //# assert fs.prev == null
837 //# assert fs.f.nups == 0
838 //# assert ls.fs == null
839 return fs.f;
842 private void removevars(int tolevel)
844 // :todo: consider making a method in FuncState.
845 while (fs.nactvar > tolevel)
847 fs.getlocvar(--fs.nactvar).endpc = fs.pc;
851 private void singlevar(Expdesc var) throws IOException
853 String varname = str_checkname();
854 if (singlevaraux(fs, varname, var, true) == Expdesc.VGLOBAL)
856 var.setInfo(fs.kStringK(varname));
860 private int singlevaraux(FuncState f,
861 String n,
862 Expdesc var,
863 boolean base)
865 if (f == null) // no more levels?
867 var.init(Expdesc.VGLOBAL, Lua.NO_REG); // default is global variable
868 return Expdesc.VGLOBAL;
870 else
872 int v = f.searchvar(n);
873 if (v >= 0)
875 var.init(Expdesc.VLOCAL, v);
876 if (!base)
878 f.markupval(v); // local will be used as an upval
880 return Expdesc.VLOCAL;
882 else // not found at current level; try upper one
884 if (singlevaraux(f.prev, n, var, false) == Expdesc.VGLOBAL)
886 return Expdesc.VGLOBAL;
888 var.upval(indexupvalue(f, n, var)); // else was LOCAL or UPVAL
889 return Expdesc.VUPVAL;
894 private String str_checkname() throws IOException
896 check(TK_NAME);
897 String s = tokenS;
898 xNext();
899 return s;
902 private boolean testnext(int c) throws IOException
904 if (token == c)
906 xNext();
907 return true;
909 return false;
913 // GRAMMAR RULES
915 private void chunk() throws IOException
917 // chunk -> { stat [';'] }
918 boolean islast = false;
919 enterlevel();
920 while (!islast && !block_follow(token))
922 islast = statement();
923 testnext(';');
924 //# assert fs.f.maxstacksize >= fs.freereg && fs.freereg >= fs.nactvar
925 fs.freereg = fs.nactvar;
927 leavelevel();
930 private void constructor(Expdesc t) throws IOException
932 // constructor -> ??
933 int line = linenumber;
934 int pc = fs.kCodeABC(Lua.OP_NEWTABLE, 0, 0, 0);
935 ConsControl cc = new ConsControl(t) ;
936 t.init(Expdesc.VRELOCABLE, pc);
937 cc.v.init(Expdesc.VVOID, 0); /* no value (yet) */
938 fs.kExp2nextreg(t); /* fix it at stack top (for gc) */
939 checknext('{');
942 //# assert cc.v.k == Expdesc.VVOID || cc.tostore > 0
943 if (token == '}')
944 break;
945 closelistfield(cc);
946 switch(token)
948 case TK_NAME: /* may be listfields or recfields */
949 xLookahead();
950 if (lookahead != '=') /* expression? */
951 listfield(cc);
952 else
953 recfield(cc);
954 break;
956 case '[': /* constructor_item -> recfield */
957 recfield(cc);
958 break;
960 default: /* constructor_part -> listfield */
961 listfield(cc);
962 break;
964 } while (testnext(',') || testnext(';'));
965 check_match('}', '{', line);
966 lastlistfield(cc);
967 int [] code = fs.f.code ;
968 code[pc] = Lua.SETARG_B(code[pc], oInt2fb(cc.na)); /* set initial array size */
969 code[pc] = Lua.SETARG_C(code[pc], oInt2fb(cc.nh)); /* set initial table size */
972 private static int oInt2fb(int x)
974 int e = 0; /* exponent */
975 while (x < 0 || x >= 16)
977 x = (x+1) >>> 1;
978 e++;
980 return (x < 8) ? x : (((e+1) << 3) | (x - 8));
983 private void recfield(ConsControl cc) throws IOException
985 /* recfield -> (NAME | `['exp1`]') = exp1 */
986 int reg = fs.freereg;
987 Expdesc key = new Expdesc() ;
988 Expdesc val = new Expdesc() ;
989 if (token == TK_NAME)
991 // yChecklimit(fs, cc.nh, MAX_INT, "items in a constructor");
992 checkname(key);
994 else /* token == '[' */
995 yindex(key);
996 cc.nh++;
997 checknext('=');
998 fs.kExp2RK(key);
999 expr(val);
1000 fs.kCodeABC(Lua.OP_SETTABLE, cc.t.info, fs.kExp2RK(key), fs.kExp2RK(val));
1001 fs.freereg = reg; /* free registers */
1004 private void lastlistfield(ConsControl cc)
1006 if (cc.tostore == 0)
1007 return;
1008 if (hasmultret(cc.v.k))
1010 fs.kSetmultret(cc.v);
1011 fs.kSetlist(cc.t.info, cc.na, Lua.MULTRET);
1012 cc.na--; /* do not count last expression (unknown number of elements) */
1014 else
1016 if (cc.v.k != Expdesc.VVOID)
1017 fs.kExp2nextreg(cc.v);
1018 fs.kSetlist(cc.t.info, cc.na, cc.tostore);
1022 private void closelistfield(ConsControl cc)
1024 if (cc.v.k == Expdesc.VVOID)
1025 return; /* there is no list item */
1026 fs.kExp2nextreg(cc.v);
1027 cc.v.k = Expdesc.VVOID;
1028 if (cc.tostore == Lua.LFIELDS_PER_FLUSH)
1030 fs.kSetlist(cc.t.info, cc.na, cc.tostore); /* flush */
1031 cc.tostore = 0; /* no more items pending */
1035 private void expr(Expdesc v) throws IOException
1037 subexpr(v, 0);
1040 /** @return number of expressions in expression list. */
1041 private int explist1(Expdesc v) throws IOException
1043 // explist1 -> expr { ',' expr }
1044 int n = 1; // at least one expression
1045 expr(v);
1046 while (testnext(','))
1048 fs.kExp2nextreg(v);
1049 expr(v);
1050 ++n;
1052 return n;
1055 private void exprstat() throws IOException
1057 // stat -> func | assignment
1058 LHSAssign v = new LHSAssign() ;
1059 primaryexp(v.v);
1060 if (v.v.k == Expdesc.VCALL) // stat -> func
1062 fs.setargc(v.v, 1); // call statement uses no results
1064 else // stat -> assignment
1066 v.prev = null;
1067 assignment(v, 1);
1072 ** check whether, in an assignment to a local variable, the local variable
1073 ** is needed in a previous assignment (to a table). If so, save original
1074 ** local value in a safe place and use this safe copy in the previous
1075 ** assignment.
1077 private void check_conflict(LHSAssign lh, Expdesc v)
1079 int extra = fs.freereg; /* eventual position to save local variable */
1080 boolean conflict = false ;
1081 for (; lh != null; lh = lh.prev)
1083 if (lh.v.k == Expdesc.VINDEXED)
1085 if (lh.v.info == v.info) /* conflict? */
1087 conflict = true;
1088 lh.v.info = extra; /* previous assignment will use safe copy */
1090 if (lh.v.aux == v.info) /* conflict? */
1092 conflict = true;
1093 lh.v.aux = extra; /* previous assignment will use safe copy */
1097 if (conflict)
1099 fs.kCodeABC(Lua.OP_MOVE, fs.freereg, v.info, 0); /* make copy */
1100 fs.kReserveregs(1);
1104 private void assignment(LHSAssign lh, int nvars) throws IOException
1106 Expdesc e = new Expdesc() ;
1107 int kind = lh.v.k ;
1108 if (!(Expdesc.VLOCAL <= kind && kind <= Expdesc.VINDEXED))
1109 xSyntaxerror("syntax error");
1110 if (testnext(',')) /* assignment -> `,' primaryexp assignment */
1112 LHSAssign nv = new LHSAssign(lh) ;
1113 primaryexp(nv.v);
1114 if (nv.v.k == Expdesc.VLOCAL)
1115 check_conflict(lh, nv.v);
1116 assignment(nv, nvars+1);
1118 else /* assignment -> `=' explist1 */
1120 int nexps;
1121 checknext('=');
1122 nexps = explist1(e);
1123 if (nexps != nvars)
1125 adjust_assign(nvars, nexps, e);
1126 if (nexps > nvars)
1127 fs.freereg -= nexps - nvars; /* remove extra values */
1129 else
1131 fs.kSetoneret(e); /* close last expression */
1132 fs.kStorevar(lh.v, e);
1133 return; /* avoid default */
1136 e.init(Expdesc.VNONRELOC, fs.freereg-1); /* default assignment */
1137 fs.kStorevar(lh.v, e);
1141 private void funcargs(Expdesc f) throws IOException
1143 Expdesc args = new Expdesc();
1144 int line = linenumber;
1145 switch (token)
1147 case '(': // funcargs -> '(' [ explist1 ] ')'
1148 if (line != lastline)
1150 xSyntaxerror("ambiguous syntax (function call x new statement)");
1152 xNext();
1153 if (token == ')') // arg list is empty?
1155 args.setKind(Expdesc.VVOID);
1157 else
1159 explist1(args);
1160 fs.kSetmultret(args);
1162 check_match(')', '(', line);
1163 break;
1165 case '{': // funcargs -> constructor
1166 constructor(args);
1167 break;
1169 case TK_STRING: // funcargs -> STRING
1170 codestring(args, tokenS);
1171 xNext(); // must use tokenS before 'next'
1172 break;
1174 default:
1175 xSyntaxerror("function arguments expected");
1176 return;
1178 // assert (f.kind() == VNONRELOC);
1179 int nparams;
1180 int base = f.info(); // base register for call
1181 if (args.hasmultret())
1183 nparams = Lua.MULTRET; // open call
1185 else
1187 if (args.kind() != Expdesc.VVOID)
1189 fs.kExp2nextreg(args); // close last argument
1191 nparams = fs.freereg - (base+1);
1193 f.init(Expdesc.VCALL, fs.kCodeABC(Lua.OP_CALL, base, nparams+1, 2));
1194 fs.kFixline(line);
1195 fs.freereg = base+1; // call removes functions and arguments
1196 // and leaves (unless changed) one result.
1199 private void prefixexp(Expdesc v) throws IOException
1201 // prefixexp -> NAME | '(' expr ')'
1202 switch (token)
1204 case '(':
1206 int line = linenumber;
1207 xNext();
1208 expr(v);
1209 check_match(')', '(', line);
1210 fs.kDischargevars(v);
1211 return;
1213 case TK_NAME:
1214 singlevar(v);
1215 return;
1216 default:
1217 xSyntaxerror("unexpected symbol");
1218 return;
1222 private void primaryexp(Expdesc v) throws IOException
1224 // primaryexp ->
1225 // prefixexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs }
1226 prefixexp(v);
1227 while (true)
1229 switch (token)
1231 case '.': /* field */
1232 field(v);
1233 break;
1235 case '[': /* `[' exp1 `]' */
1237 Expdesc key = new Expdesc();
1238 fs.kExp2anyreg(v);
1239 yindex(key);
1240 fs.kIndexed(v, key);
1242 break;
1244 case ':': /* `:' NAME funcargs */
1246 Expdesc key = new Expdesc() ;
1247 xNext();
1248 checkname(key);
1249 fs.kSelf(v, key);
1250 funcargs(v);
1252 break;
1254 case '(':
1255 case TK_STRING:
1256 case '{': // funcargs
1257 fs.kExp2nextreg(v);
1258 funcargs(v);
1259 break;
1261 default:
1262 return;
1267 private void retstat() throws IOException
1269 // stat -> RETURN explist
1270 xNext(); // skip RETURN
1271 // registers with returned values (first, nret)
1272 int first = 0;
1273 int nret;
1274 if (block_follow(token) || token == ';')
1276 // return no values
1277 first = 0;
1278 nret = 0;
1280 else
1282 Expdesc e = new Expdesc();
1283 nret = explist1(e);
1284 if (hasmultret(e.k))
1286 fs.kSetmultret(e);
1287 if (e.k == Expdesc.VCALL && nret == 1) /* tail call? */
1289 fs.setcode(e, Lua.SET_OPCODE(fs.getcode(e), Lua.OP_TAILCALL));
1290 //# assert Lua.ARGA(fs.getcode(e)) == fs.nactvar
1292 first = fs.nactvar;
1293 nret = Lua.MULTRET; /* return all values */
1295 else
1297 if (nret == 1) // only one single value?
1299 first = fs.kExp2anyreg(e);
1301 else
1303 fs.kExp2nextreg(e); /* values must go to the `stack' */
1304 first = fs.nactvar; /* return all `active' values */
1305 //# assert nret == fs.freereg - first
1309 fs.kRet(first, nret);
1312 private void simpleexp(Expdesc v) throws IOException
1314 // simpleexp -> NUMBER | STRING | NIL | true | false | ... |
1315 // constructor | FUNCTION body | primaryexp
1316 switch (token)
1318 case TK_NUMBER:
1319 v.init(Expdesc.VKNUM, 0);
1320 v.nval = tokenR;
1321 break;
1323 case TK_STRING:
1324 codestring(v, tokenS);
1325 break;
1327 case TK_NIL:
1328 v.init(Expdesc.VNIL, 0);
1329 break;
1331 case TK_TRUE:
1332 v.init(Expdesc.VTRUE, 0);
1333 break;
1335 case TK_FALSE:
1336 v.init(Expdesc.VFALSE, 0);
1337 break;
1339 case TK_DOTS: /* vararg */
1340 if (!fs.f.isVararg())
1341 xSyntaxerror("cannot use \"...\" outside a vararg function");
1342 v.init(Expdesc.VVARARG, fs.kCodeABC(Lua.OP_VARARG, 0, 1, 0));
1343 break;
1345 case '{': /* constructor */
1346 constructor(v);
1347 return;
1349 case TK_FUNCTION:
1350 xNext();
1351 body(v, false, linenumber);
1352 return;
1354 default:
1355 primaryexp(v);
1356 return;
1358 xNext();
1361 private boolean statement() throws IOException
1363 int line = linenumber;
1364 switch (token)
1366 case TK_IF: // stat -> ifstat
1367 ifstat(line);
1368 return false;
1370 case TK_WHILE: // stat -> whilestat
1371 whilestat(line);
1372 return false;
1374 case TK_DO: // stat -> DO block END
1375 xNext(); // skip DO
1376 block();
1377 check_match(TK_END, TK_DO, line);
1378 return false;
1380 case TK_FOR: // stat -> forstat
1381 forstat(line);
1382 return false;
1384 case TK_REPEAT: // stat -> repeatstat
1385 repeatstat(line);
1386 return false;
1388 case TK_FUNCTION:
1389 funcstat(line); // stat -> funcstat
1390 return false;
1392 case TK_LOCAL: // stat -> localstat
1393 xNext(); // skip LOCAL
1394 if (testnext(TK_FUNCTION)) // local function?
1395 localfunc();
1396 else
1397 localstat();
1398 return false;
1400 case TK_RETURN:
1401 retstat();
1402 return true; // must be last statement
1404 case TK_BREAK: // stat -> breakstat
1405 xNext(); // skip BREAK
1406 breakstat();
1407 return true; // must be last statement
1409 default:
1410 exprstat();
1411 return false;
1415 // grep "ORDER OPR" if you change these enums.
1416 // default access so that FuncState can access them.
1417 static final int OPR_ADD = 0;
1418 static final int OPR_SUB = 1;
1419 static final int OPR_MUL = 2;
1420 static final int OPR_DIV = 3;
1421 static final int OPR_MOD = 4;
1422 static final int OPR_POW = 5;
1423 static final int OPR_CONCAT = 6;
1424 static final int OPR_NE = 7;
1425 static final int OPR_EQ = 8;
1426 static final int OPR_LT = 9;
1427 static final int OPR_LE = 10;
1428 static final int OPR_GT = 11;
1429 static final int OPR_GE = 12;
1430 static final int OPR_AND = 13;
1431 static final int OPR_OR = 14;
1432 static final int OPR_NOBINOPR = 15;
1434 static final int OPR_MINUS = 0;
1435 static final int OPR_NOT = 1;
1436 static final int OPR_LEN = 2;
1437 static final int OPR_NOUNOPR = 3;
1439 /** Converts token into binary operator. */
1440 private static int getbinopr(int op)
1442 switch (op)
1444 case '+': return OPR_ADD;
1445 case '-': return OPR_SUB;
1446 case '*': return OPR_MUL;
1447 case '/': return OPR_DIV;
1448 case '%': return OPR_MOD;
1449 case '^': return OPR_POW;
1450 case TK_CONCAT: return OPR_CONCAT;
1451 case TK_NE: return OPR_NE;
1452 case TK_EQ: return OPR_EQ;
1453 case '<': return OPR_LT;
1454 case TK_LE: return OPR_LE;
1455 case '>': return OPR_GT;
1456 case TK_GE: return OPR_GE;
1457 case TK_AND: return OPR_AND;
1458 case TK_OR: return OPR_OR;
1459 default: return OPR_NOBINOPR;
1463 private static int getunopr(int op)
1465 switch (op)
1467 case TK_NOT: return OPR_NOT;
1468 case '-': return OPR_MINUS;
1469 case '#': return OPR_LEN;
1470 default: return OPR_NOUNOPR;
1475 // ORDER OPR
1477 * Priority table. left-priority of an operator is
1478 * <code>priority[op][0]</code>, its right priority is
1479 * <code>priority[op][1]</code>. Please do not modify this table.
1481 private static final int[][] PRIORITY = new int[][]
1483 {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, // + - * / %
1484 {10, 9}, {5, 4}, // power and concat (right associative)
1485 {3, 3}, {3, 3}, // equality and inequality
1486 {3, 3}, {3, 3}, {3, 3}, {3, 3}, // order
1487 {2, 2}, {1, 1} // logical (and/or)
1490 /** Priority for unary operators. */
1491 private static final int UNARY_PRIORITY = 8;
1494 * Operator precedence parser.
1495 * <code>subexpr -> (simpleexp) | unop subexpr) { binop subexpr }</code>
1496 * where <var>binop</var> is any binary operator with a priority
1497 * higher than <var>limit</var>.
1499 private int subexpr(Expdesc v, int limit) throws IOException
1501 enterlevel();
1502 int uop = getunopr(token);
1503 if (uop != OPR_NOUNOPR)
1505 xNext();
1506 subexpr(v, UNARY_PRIORITY);
1507 fs.kPrefix(uop, v);
1509 else
1511 simpleexp(v);
1513 // expand while operators have priorities higher than 'limit'
1514 int op = getbinopr(token);
1515 while (op != OPR_NOBINOPR && PRIORITY[op][0] > limit)
1517 Expdesc v2 = new Expdesc();
1518 xNext();
1519 fs.kInfix(op, v);
1520 // read sub-expression with higher priority
1521 int nextop = subexpr(v2, PRIORITY[op][1]);
1522 fs.kPosfix(op, v, v2);
1523 op = nextop;
1525 leavelevel();
1526 return op;
1529 private void enterblock(FuncState f, BlockCnt bl, boolean isbreakable)
1531 bl.breaklist = FuncState.NO_JUMP ;
1532 bl.isbreakable = isbreakable ;
1533 bl.nactvar = f.nactvar ;
1534 bl.upval = false ;
1535 bl.previous = f.bl;
1536 f.bl = bl;
1537 //# assert f.freereg == f.nactvar
1540 private void leaveblock(FuncState f)
1542 BlockCnt bl = f.bl;
1543 f.bl = bl.previous;
1544 removevars(bl.nactvar);
1545 if (bl.upval)
1546 f.kCodeABC(Lua.OP_CLOSE, bl.nactvar, 0, 0);
1547 /* loops have no body */
1548 //# assert (!bl.isbreakable) || (!bl.upval)
1549 //# assert bl.nactvar == f.nactvar
1550 f.freereg = f.nactvar; /* free registers */
1551 f.kPatchtohere(bl.breaklist);
1556 ** {======================================================================
1557 ** Rules for Statements
1558 ** =======================================================================
1562 private void block() throws IOException
1564 /* block -> chunk */
1565 BlockCnt bl = new BlockCnt() ;
1566 enterblock(fs, bl, false);
1567 chunk();
1568 //# assert bl.breaklist == FuncState.NO_JUMP
1569 leaveblock(fs);
1572 private void breakstat()
1574 BlockCnt bl = fs.bl;
1575 boolean upval = false;
1576 while (bl != null && !bl.isbreakable)
1578 upval |= bl.upval;
1579 bl = bl.previous;
1581 if (bl == null)
1582 xSyntaxerror("no loop to break");
1583 if (upval)
1584 fs.kCodeABC(Lua.OP_CLOSE, bl.nactvar, 0, 0);
1585 bl.breaklist = fs.kConcat(bl.breaklist, fs.kJump());
1588 private void funcstat(int line) throws IOException
1590 /* funcstat -> FUNCTION funcname body */
1591 Expdesc b = new Expdesc() ;
1592 Expdesc v = new Expdesc() ;
1593 xNext(); /* skip FUNCTION */
1594 boolean needself = funcname(v);
1595 body(b, needself, line);
1596 fs.kStorevar(v, b);
1597 fs.kFixline(line); /* definition `happens' in the first line */
1600 private void checknext(int c) throws IOException
1602 check(c);
1603 xNext();
1606 private void parlist() throws IOException
1608 /* parlist -> [ param { `,' param } ] */
1609 Proto f = fs.f;
1610 int nparams = 0;
1611 if (token != ')') /* is `parlist' not empty? */
1615 switch (token)
1617 case TK_NAME: /* param -> NAME */
1619 new_localvar(str_checkname(), nparams++);
1620 break;
1622 case TK_DOTS: /* param -> `...' */
1624 xNext();
1625 f.setIsVararg();
1626 break;
1628 default: xSyntaxerror("<name> or '...' expected");
1630 } while ((!f.isVararg()) && testnext(','));
1632 adjustlocalvars(nparams);
1633 f.numparams = fs.nactvar ; /* VARARG_HASARG not now used */
1634 fs.kReserveregs(fs.nactvar); /* reserve register for parameters */
1638 private LocVar getlocvar(int i)
1640 FuncState fstate = fs ;
1641 return fstate.f.locvars [fstate.actvar[i]] ;
1644 private void adjustlocalvars(int nvars)
1646 fs.nactvar += nvars;
1647 for (; nvars != 0; nvars--)
1649 getlocvar(fs.nactvar - nvars).startpc = fs.pc;
1653 private void new_localvarliteral(String v, int n)
1655 new_localvar(v, n) ;
1658 private void errorlimit(int limit, String what)
1660 String msg = fs.f.linedefined == 0 ?
1661 "main function has more than "+limit+" "+what :
1662 "function at line "+fs.f.linedefined+" has more than "+limit+" "+what ;
1663 xLexerror(msg, 0);
1667 private void yChecklimit(int v, int l, String m)
1669 if (v > l)
1670 errorlimit(l,m);
1673 private void new_localvar(String name, int n)
1675 yChecklimit(fs.nactvar+n+1, Lua.MAXVARS, "local variables");
1676 fs.actvar[fs.nactvar+n] = (short)registerlocalvar(name);
1679 private int registerlocalvar(String varname)
1681 Proto f = fs.f;
1682 f.ensureLocvars(L, fs.nlocvars, Short.MAX_VALUE) ;
1683 f.locvars[fs.nlocvars].varname = varname;
1684 return fs.nlocvars++;
1688 private void body(Expdesc e, boolean needself, int line) throws IOException
1690 /* body -> `(' parlist `)' chunk END */
1691 FuncState new_fs = new FuncState(this);
1692 open_func(new_fs);
1693 new_fs.f.linedefined = line;
1694 checknext('(');
1695 if (needself)
1697 new_localvarliteral("self", 0);
1698 adjustlocalvars(1);
1700 parlist();
1701 checknext(')');
1702 chunk();
1703 new_fs.f.lastlinedefined = linenumber;
1704 check_match(TK_END, TK_FUNCTION, line);
1705 close_func();
1706 pushclosure(new_fs, e);
1709 private int UPVAL_K(int upvaldesc)
1711 return (upvaldesc >>> 8) & 0xFF ;
1713 private int UPVAL_INFO(int upvaldesc)
1715 return upvaldesc & 0xFF ;
1717 private int UPVAL_ENCODE(int k, int info)
1719 //# assert (k & 0xFF) == k && (info & 0xFF) == info
1720 return ((k & 0xFF) << 8) | (info & 0xFF) ;
1724 private void pushclosure(FuncState func, Expdesc v)
1726 Proto f = fs.f;
1727 f.ensureProtos(L, fs.np) ;
1728 Proto ff = func.f ;
1729 f.p[fs.np++] = ff;
1730 v.init(Expdesc.VRELOCABLE, fs.kCodeABx(Lua.OP_CLOSURE, 0, fs.np-1));
1731 for (int i=0; i < ff.nups; i++)
1733 int upvalue = func.upvalues[i] ;
1734 int o = (UPVAL_K(upvalue) == Expdesc.VLOCAL) ? Lua.OP_MOVE :
1735 Lua.OP_GETUPVAL;
1736 fs.kCodeABC(o, 0, UPVAL_INFO(upvalue), 0);
1740 private boolean funcname(Expdesc v) throws IOException
1742 /* funcname -> NAME {field} [`:' NAME] */
1743 boolean needself = false;
1744 singlevar(v);
1745 while (token == '.')
1746 field(v);
1747 if (token == ':')
1749 needself = true;
1750 field(v);
1752 return needself;
1755 private void field(Expdesc v) throws IOException
1757 /* field -> ['.' | ':'] NAME */
1758 Expdesc key = new Expdesc() ;
1759 fs.kExp2anyreg(v);
1760 xNext(); /* skip the dot or colon */
1761 checkname(key);
1762 fs.kIndexed(v, key);
1765 private void repeatstat(int line) throws IOException
1767 /* repeatstat -> REPEAT block UNTIL cond */
1768 int repeat_init = fs.kGetlabel();
1769 BlockCnt bl1 = new BlockCnt();
1770 BlockCnt bl2 = new BlockCnt();
1771 enterblock(fs, bl1, true); /* loop block */
1772 enterblock(fs, bl2, false); /* scope block */
1773 xNext(); /* skip REPEAT */
1774 chunk();
1775 check_match(TK_UNTIL, TK_REPEAT, line);
1776 int condexit = cond(); /* read condition (inside scope block) */
1777 if (!bl2.upval) /* no upvalues? */
1779 leaveblock(fs); /* finish scope */
1780 fs.kPatchlist(condexit, repeat_init); /* close the loop */
1782 else /* complete semantics when there are upvalues */
1784 breakstat(); /* if condition then break */
1785 fs.kPatchtohere(condexit); /* else... */
1786 leaveblock(fs); /* finish scope... */
1787 fs.kPatchlist(fs.kJump(), repeat_init); /* and repeat */
1789 leaveblock(fs); /* finish loop */
1792 private int cond() throws IOException
1794 /* cond -> exp */
1795 Expdesc v = new Expdesc() ;
1796 expr(v); /* read condition */
1797 if (v.k == Expdesc.VNIL)
1798 v.k = Expdesc.VFALSE; /* `falses' are all equal here */
1799 fs.kGoiftrue(v);
1800 return v.f;
1803 private void open_func(FuncState funcstate)
1805 Proto f = new Proto(source, 2); /* registers 0/1 are always valid */
1806 funcstate.f = f;
1807 funcstate.ls = this;
1808 funcstate.L = L;
1810 funcstate.prev = this.fs; /* linked list of funcstates */
1811 this.fs = funcstate;
1814 private void localstat() throws IOException
1816 /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
1817 int nvars = 0;
1818 int nexps;
1819 Expdesc e = new Expdesc();
1822 new_localvar(str_checkname(), nvars++);
1823 } while (testnext(','));
1824 if (testnext('='))
1826 nexps = explist1(e);
1828 else
1830 e.k = Expdesc.VVOID;
1831 nexps = 0;
1833 adjust_assign(nvars, nexps, e);
1834 adjustlocalvars(nvars);
1837 private void forstat(int line) throws IOException
1839 /* forstat -> FOR (fornum | forlist) END */
1840 BlockCnt bl = new BlockCnt() ;
1841 enterblock(fs, bl, true); /* scope for loop and control variables */
1842 xNext(); /* skip `for' */
1843 String varname = str_checkname(); /* first variable name */
1844 switch (token)
1846 case '=':
1847 fornum(varname, line);
1848 break;
1849 case ',':
1850 case TK_IN:
1851 forlist(varname);
1852 break;
1853 default:
1854 xSyntaxerror("\"=\" or \"in\" expected");
1856 check_match(TK_END, TK_FOR, line);
1857 leaveblock(fs); /* loop scope (`break' jumps to this point) */
1860 private void fornum(String varname, int line) throws IOException
1862 /* fornum -> NAME = exp1,exp1[,exp1] forbody */
1863 int base = fs.freereg;
1864 new_localvarliteral("(for index)", 0);
1865 new_localvarliteral("(for limit)", 1);
1866 new_localvarliteral("(for step)", 2);
1867 new_localvar(varname, 3);
1868 checknext('=');
1869 exp1(); /* initial value */
1870 checknext(',');
1871 exp1(); /* limit */
1872 if (testnext(','))
1873 exp1(); /* optional step */
1874 else /* default step = 1 */
1876 fs.kCodeABx(Lua.OP_LOADK, fs.freereg, fs.kNumberK(1));
1877 fs.kReserveregs(1);
1879 forbody(base, line, 1, true);
1882 private int exp1() throws IOException
1884 Expdesc e = new Expdesc();
1885 expr(e);
1886 int k = e.k;
1887 fs.kExp2nextreg(e);
1888 return k;
1892 private void forlist(String indexname) throws IOException
1894 /* forlist -> NAME {,NAME} IN explist1 forbody */
1895 Expdesc e = new Expdesc() ;
1896 int nvars = 0;
1897 int base = fs.freereg;
1898 /* create control variables */
1899 new_localvarliteral("(for generator)", nvars++);
1900 new_localvarliteral("(for state)", nvars++);
1901 new_localvarliteral("(for control)", nvars++);
1902 /* create declared variables */
1903 new_localvar(indexname, nvars++);
1904 while (testnext(','))
1905 new_localvar(str_checkname(), nvars++);
1906 checknext(TK_IN);
1907 int line = linenumber;
1908 adjust_assign(3, explist1(e), e);
1909 fs.kCheckstack(3); /* extra space to call generator */
1910 forbody(base, line, nvars - 3, false);
1913 private void forbody(int base, int line, int nvars, boolean isnum)
1914 throws IOException
1916 /* forbody -> DO block */
1917 BlockCnt bl = new BlockCnt() ;
1918 adjustlocalvars(3); /* control variables */
1919 checknext(TK_DO);
1920 int prep = isnum ? fs.kCodeAsBx(Lua.OP_FORPREP, base, FuncState.NO_JUMP) : fs.kJump();
1921 enterblock(fs, bl, false); /* scope for declared variables */
1922 adjustlocalvars(nvars);
1923 fs.kReserveregs(nvars);
1924 block();
1925 leaveblock(fs); /* end of scope for declared variables */
1926 fs.kPatchtohere(prep);
1927 int endfor = isnum ?
1928 fs.kCodeAsBx(Lua.OP_FORLOOP, base, FuncState.NO_JUMP) :
1929 fs.kCodeABC(Lua.OP_TFORLOOP, base, 0, nvars);
1930 fs.kFixline(line); /* pretend that `OP_FOR' starts the loop */
1931 fs.kPatchlist((isnum ? endfor : fs.kJump()), prep + 1);
1934 private void ifstat(int line) throws IOException
1936 /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
1937 int escapelist = FuncState.NO_JUMP;
1938 int flist = test_then_block(); /* IF cond THEN block */
1939 while (token == TK_ELSEIF)
1941 escapelist = fs.kConcat(escapelist, fs.kJump());
1942 fs.kPatchtohere(flist);
1943 flist = test_then_block(); /* ELSEIF cond THEN block */
1945 if (token == TK_ELSE)
1947 escapelist = fs.kConcat(escapelist, fs.kJump());
1948 fs.kPatchtohere(flist);
1949 xNext(); /* skip ELSE (after patch, for correct line info) */
1950 block(); /* `else' part */
1952 else
1953 escapelist = fs.kConcat(escapelist, flist);
1955 fs.kPatchtohere(escapelist);
1956 check_match(TK_END, TK_IF, line);
1959 private int test_then_block() throws IOException
1961 /* test_then_block -> [IF | ELSEIF] cond THEN block */
1962 xNext(); /* skip IF or ELSEIF */
1963 int condexit = cond();
1964 checknext(TK_THEN);
1965 block(); /* `then' part */
1966 return condexit;
1969 private void whilestat(int line) throws IOException
1971 /* whilestat -> WHILE cond DO block END */
1972 BlockCnt bl = new BlockCnt() ;
1973 xNext(); /* skip WHILE */
1974 int whileinit = fs.kGetlabel();
1975 int condexit = cond();
1976 enterblock(fs, bl, true);
1977 checknext(TK_DO);
1978 block();
1979 fs.kPatchlist(fs.kJump(), whileinit);
1980 check_match(TK_END, TK_WHILE, line);
1981 leaveblock(fs);
1982 fs.kPatchtohere(condexit); /* false conditions finish the loop */
1985 private static boolean hasmultret(int k)
1987 return k == Expdesc.VCALL || k == Expdesc.VVARARG ;
1990 private void adjust_assign(int nvars, int nexps, Expdesc e)
1992 int extra = nvars - nexps;
1993 if (hasmultret(e.k))
1995 extra++; /* includes call itself */
1996 if (extra < 0)
1997 extra = 0;
1998 fs.kSetreturns(e, extra); /* last exp. provides the difference */
1999 if (extra > 1)
2000 fs.kReserveregs(extra-1);
2002 else
2004 if (e.k != Expdesc.VVOID)
2005 fs.kExp2nextreg(e); /* close last expression */
2006 if (extra > 0)
2008 int reg = fs.freereg;
2009 fs.kReserveregs(extra);
2010 fs.kNil(reg, extra);
2015 private void localfunc() throws IOException
2017 Expdesc b = new Expdesc();
2018 new_localvar(str_checkname(), 0);
2019 Expdesc v = new Expdesc(Expdesc.VLOCAL, fs.freereg);
2020 fs.kReserveregs(1);
2021 adjustlocalvars(1);
2022 body(b, false, linenumber);
2023 fs.kStorevar(v, b);
2024 /* debug information will only see the variable after this point! */
2025 fs.getlocvar(fs.nactvar - 1).startpc = fs.pc;
2028 private void yindex(Expdesc v) throws IOException
2030 /* index -> '[' expr ']' */
2031 xNext(); /* skip the '[' */
2032 expr(v);
2033 fs.kExp2val(v);
2034 checknext(']');
2037 void xLookahead() throws IOException
2039 //# assert lookahead == TK_EOS
2040 lookahead = llex();
2041 lookaheadR = semR ;
2042 lookaheadS = semS ;
2045 private void listfield(ConsControl cc) throws IOException
2047 expr(cc.v);
2048 yChecklimit(cc.na, Lua.MAXARG_Bx, "items in a constructor");
2049 cc.na++;
2050 cc.tostore++;
2053 private int indexupvalue(FuncState funcstate, String name, Expdesc v)
2055 Proto f = funcstate.f;
2056 for (int i=0; i<f.nups; i++)
2058 int entry = funcstate.upvalues[i] ;
2059 if (UPVAL_K(entry) == v.k && UPVAL_INFO(entry) == v.info)
2061 //# assert name.equals(f.upvalues[i])
2062 return i;
2065 /* new one */
2066 yChecklimit(f.nups + 1, Lua.MAXUPVALUES, "upvalues");
2067 f.ensureUpvals(L, f.nups) ;
2068 f.upvalues[f.nups] = name;
2069 //# assert v.k == Expdesc.VLOCAL || v.k == Expdesc.VUPVAL
2070 funcstate.upvalues[f.nups] = UPVAL_ENCODE(v.k, v.info) ;
2071 return f.nups++;
2075 final class LHSAssign
2077 LHSAssign prev ;
2078 Expdesc v = new Expdesc() ;
2080 LHSAssign()
2083 LHSAssign(LHSAssign prev)
2085 this.prev = prev ;
2089 final class ConsControl
2091 Expdesc v = new Expdesc() ; /* last list item read */
2092 Expdesc t; /* table descriptor */
2093 int nh; /* total number of `record' elements */
2094 int na; /* total number of array elements */
2095 int tostore; /* number of array elements pending to be stored */
2097 ConsControl(Expdesc t)
2099 this.t = t ;