PageRenderTime 50ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/src/lang/parser/kahlua/KahluaParser.java

https://bitbucket.org/sylvanaar2/lua-for-idea/
Java | 1709 lines | 1144 code | 316 blank | 249 comment | 312 complexity | 65a835b462a649a6df3af444f56ba691 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright 2010 Jon S Akhtar (Sylvanaar)
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.sylvanaar.idea.Lua.lang.parser.kahlua;
  17. import com.intellij.lang.ASTNode;
  18. import com.intellij.lang.PsiBuilder;
  19. import com.intellij.lang.PsiParser;
  20. import com.intellij.openapi.diagnostic.Logger;
  21. import com.intellij.psi.tree.IElementType;
  22. import com.sylvanaar.idea.Lua.lang.parser.LuaElementTypes;
  23. import com.sylvanaar.idea.Lua.lang.parser.LuaPsiBuilder;
  24. import org.jetbrains.annotations.NotNull;
  25. import se.krka.kahlua.vm.Prototype;
  26. import java.io.IOException;
  27. import java.io.Reader;
  28. public class KahluaParser implements PsiParser, LuaElementTypes {
  29. public int nCcalls = 0;
  30. static Logger log = Logger.getInstance("#Lua.parser.KahluaParser");
  31. protected static final String RESERVED_LOCAL_VAR_FOR_CONTROL = "(for control)";
  32. protected static final String RESERVED_LOCAL_VAR_FOR_STATE = "(for state)";
  33. protected static final String RESERVED_LOCAL_VAR_FOR_GENERATOR = "(for generator)";
  34. protected static final String RESERVED_LOCAL_VAR_FOR_STEP = "(for step)";
  35. protected static final String RESERVED_LOCAL_VAR_FOR_LIMIT = "(for limit)";
  36. protected static final String RESERVED_LOCAL_VAR_FOR_INDEX = "(for index)";
  37. // // keywords array
  38. // protected static final String[] RESERVED_LOCAL_VAR_KEYWORDS = new String[]{
  39. // RESERVED_LOCAL_VAR_FOR_CONTROL,
  40. // RESERVED_LOCAL_VAR_FOR_GENERATOR,
  41. // RESERVED_LOCAL_VAR_FOR_INDEX,
  42. // RESERVED_LOCAL_VAR_FOR_LIMIT,
  43. // RESERVED_LOCAL_VAR_FOR_STATE,
  44. // RESERVED_LOCAL_VAR_FOR_STEP
  45. // };
  46. // private static final Hashtable<String, Boolean> RESERVED_LOCAL_VAR_KEYWORDS_TABLE =
  47. // new Hashtable<String, Boolean>();
  48. //
  49. // static {
  50. // int i = 0;
  51. // while (i < RESERVED_LOCAL_VAR_KEYWORDS.length) {
  52. // String RESERVED_LOCAL_VAR_KEYWORD = RESERVED_LOCAL_VAR_KEYWORDS[i];
  53. // RESERVED_LOCAL_VAR_KEYWORDS_TABLE.put(RESERVED_LOCAL_VAR_KEYWORD, Boolean.TRUE);
  54. // i++;
  55. // }
  56. // }
  57. private static final int EOZ = (-1);
  58. //private static final int MAXSRC = 80;
  59. private static final int MAX_INT = Integer.MAX_VALUE - 2;
  60. //private static final int UCHAR_MAX = 255; // TO DO, convert to unicode CHAR_MAX?
  61. private static final int LUAI_MAXCCALLS = 200;
  62. private LuaPsiBuilder builder = null;
  63. // public KahluaParser(Project project) {
  64. // }
  65. private static String LUA_QS(String s) {
  66. return "'" + s + "'";
  67. }
  68. private static String LUA_QL(Object o) {
  69. return LUA_QS(String.valueOf(o));
  70. }
  71. // public static boolean isReservedKeyword(String varName) {
  72. // return RESERVED_LOCAL_VAR_KEYWORDS_TABLE.containsKey(varName);
  73. // }
  74. /*
  75. ** Marks the end of a patch list. It is an invalid value both as an absolute
  76. ** address, and as a list link (would link an element to itself).
  77. */
  78. static final int NO_JUMP = (-1);
  79. /*
  80. ** grep "ORDER OPR" if you change these enums
  81. */
  82. static final int
  83. OPR_ADD = 0, OPR_SUB = 1, OPR_MUL = 2, OPR_DIV = 3, OPR_MOD = 4, OPR_POW = 5,
  84. OPR_CONCAT = 6,
  85. OPR_NE = 7, OPR_EQ = 8,
  86. OPR_LT = 9, OPR_LE = 10, OPR_GT = 11, OPR_GE = 12,
  87. OPR_AND = 13, OPR_OR = 14,
  88. OPR_NOBINOPR = 15;
  89. static final int
  90. OPR_MINUS = 0, OPR_NOT = 1, OPR_LEN = 2, OPR_NOUNOPR = 3;
  91. /* exp kind */
  92. static final int
  93. VVOID = 0, /* no value */
  94. VNIL = 1,
  95. VTRUE = 2,
  96. VFALSE = 3,
  97. VK = 4, /* info = index of constant in `k' */
  98. VKNUM = 5, /* nval = numerical value */
  99. VLOCAL = 6, /* info = local register */
  100. VUPVAL = 7, /* info = index of upvalue in `upvalues' */
  101. VGLOBAL = 8, /* info = index of table, aux = index of global name in `k' */
  102. VINDEXED = 9, /* info = table register, aux = index register (or `k') */
  103. VJMP = 10, /* info = instruction pc */
  104. VRELOCABLE = 11, /* info = instruction pc */
  105. VNONRELOC = 12, /* info = result register */
  106. VCALL = 13, /* info = instruction pc */
  107. VVARARG = 14; /* info = instruction pc */
  108. int current = 0; /* current character (charint) */
  109. int linenumber = 0; /* input line counter */
  110. int lastline = 0; /* line of last token `consumed' */
  111. IElementType t = null; /* current token */
  112. IElementType lookahead = null; /* look ahead token */
  113. FuncState fs = null; /* `FuncState' is private to the parser */
  114. Reader z = null; /* input stream */
  115. byte[] buff = null; /* buffer for tokens */
  116. int nbuff = 0; /* length of buffer */
  117. String source = null; /* current source name */
  118. public KahluaParser(Reader stream, int firstByte, String source) {
  119. this.z = stream;
  120. this.buff = new byte[32];
  121. this.lookahead = null; /* no look-ahead token */
  122. this.fs = null;
  123. this.linenumber = 1;
  124. this.lastline = 1;
  125. this.source = source;
  126. this.nbuff = 0; /* initialize buffer */
  127. this.current = firstByte; /* read first char */
  128. this.skipShebang();
  129. }
  130. public KahluaParser() {};
  131. void nextChar() {
  132. try {
  133. current = z.read();
  134. } catch (IOException e) {
  135. e.printStackTrace();
  136. current = EOZ;
  137. }
  138. }
  139. boolean currIsNewline() {
  140. return current == '\n' || current == '\r';
  141. }
  142. void lexerror(String msg, IElementType token) {
  143. String cid = source;
  144. String errorMessage;
  145. if (token != null) {
  146. errorMessage = /*cid + ":" + linenumber + ": " +*/ msg + " near `" + token + "`";
  147. } else {
  148. errorMessage = /*cid + ":" + linenumber + ": " +*/ msg;
  149. }
  150. builder.error(errorMessage);
  151. //throw new KahluaException(errorMessage);
  152. }
  153. // private static String trim(String s, int max) {
  154. // if (s.length() > max) {
  155. // return s.substring(0, max - 3) + "...";
  156. // }
  157. // return s;
  158. // }
  159. void syntaxerror(String msg) {
  160. lexerror(msg, t);
  161. }
  162. private void skipShebang() {
  163. if (current == '#')
  164. while (!currIsNewline() && current != EOZ)
  165. nextChar();
  166. }
  167. /*
  168. ** =======================================================
  169. ** LEXICAL ANALYZER
  170. ** =======================================================
  171. */
  172. void next() {
  173. lastline = linenumber;
  174. builder.advanceLexer();
  175. t = builder.getTokenType();
  176. // /*
  177. // if (lookahead != TK_EOS) { /* is there a look-ahead token? */
  178. // t.set( lookahead ); /* use this one */
  179. // lookahead = TK_EOS; /* and discharge it */
  180. // } else
  181. // t = llex(t); /* read next token */
  182. // */
  183. }
  184. void lookahead() {
  185. // FuncState._assert (lookahead == TK_EOS);
  186. PsiBuilder.Marker current = builder.mark();
  187. builder.advanceLexer();
  188. lookahead = builder.getTokenType();
  189. current.rollbackTo();
  190. }
  191. // =============================================================
  192. // from lcode.h
  193. // =============================================================
  194. // =============================================================
  195. // from lparser.c
  196. // =============================================================
  197. boolean hasmultret(int k) {
  198. return ((k) == VCALL || (k) == VVARARG);
  199. }
  200. /*----------------------------------------------------------------------
  201. name args description
  202. ------------------------------------------------------------------------*/
  203. /*
  204. * * prototypes for recursive non-terminal functions
  205. */
  206. void error_expected(IElementType token) {
  207. syntaxerror(token.toString() + " expected");
  208. }
  209. boolean testnext(IElementType c) {
  210. if (t == c) {
  211. next();
  212. return true;
  213. }
  214. return false;
  215. }
  216. void check(IElementType c) {
  217. if (t != c)
  218. error_expected(c);
  219. }
  220. void checknext(IElementType c) {
  221. check(c);
  222. next();
  223. }
  224. void check_condition(boolean c, String msg) {
  225. if (!(c))
  226. syntaxerror(msg);
  227. }
  228. void check_match(IElementType what, IElementType who, int where) {
  229. if (!testnext(what)) {
  230. if (where == linenumber)
  231. error_expected(what);
  232. else {
  233. syntaxerror(what
  234. + " expected " + "(to close " + who.toString()
  235. + " at line " + where + ")");
  236. }
  237. }
  238. }
  239. String str_checkname() {
  240. String ts;
  241. check(NAME);
  242. ts = builder.text();
  243. next();
  244. return ts;
  245. }
  246. void codestring(ExpDesc e, String s) {
  247. e.init(VK, fs.stringK(s));
  248. }
  249. void checkname(ExpDesc e) {
  250. codestring(e, str_checkname());
  251. }
  252. int registerlocalvar(String varname) {
  253. FuncState fs = this.fs;
  254. if (fs.locvars == null || fs.nlocvars + 1 > fs.locvars.length)
  255. fs.locvars = FuncState.realloc(fs.locvars, fs.nlocvars * 2 + 1);
  256. fs.locvars[fs.nlocvars] = varname;
  257. return fs.nlocvars++;
  258. }
  259. //
  260. // #define new_localvarliteral(ls,v,n) \
  261. // this.new_localvar(luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n)
  262. //
  263. void new_localvarliteral(String v, int n) {
  264. new_localvar(v, n);
  265. }
  266. void new_localvar(String name, int n) {
  267. FuncState fs = this.fs;
  268. fs.checklimit(fs.nactvar + n + 1, FuncState.LUAI_MAXVARS, "local variables");
  269. fs.actvar[fs.nactvar + n] = (short) registerlocalvar(name);
  270. }
  271. void adjustlocalvars(int nvars) {
  272. FuncState fs = this.fs;
  273. fs.nactvar = (fs.nactvar + nvars);
  274. }
  275. void removevars(int tolevel) {
  276. FuncState fs = this.fs;
  277. fs.nactvar = tolevel;
  278. }
  279. void singlevar(ExpDesc var) {
  280. PsiBuilder.Marker ref = builder.mark();
  281. PsiBuilder.Marker mark = builder.mark();
  282. String varname = this.str_checkname();
  283. FuncState fs = this.fs;
  284. if (fs.singlevaraux(varname, var, 1) == VGLOBAL) {
  285. var.info = fs.stringK(varname); /* info points to global name */
  286. mark.done(GLOBAL_NAME);
  287. } else {
  288. mark.done(LOCAL_NAME);
  289. }
  290. ref.done(REFERENCE);
  291. }
  292. void adjust_assign(int nvars, int nexps, ExpDesc e) {
  293. FuncState fs = this.fs;
  294. int extra = nvars - nexps;
  295. if (hasmultret(e.k)) {
  296. /* includes call itself */
  297. extra++;
  298. if (extra < 0)
  299. extra = 0;
  300. /* last exp. provides the difference */
  301. fs.setreturns(e, extra);
  302. if (extra > 1)
  303. fs.reserveregs(extra - 1);
  304. } else {
  305. /* close last expression */
  306. if (e.k != VVOID)
  307. fs.exp2nextreg(e);
  308. if (extra > 0) {
  309. int reg = fs.freereg;
  310. fs.reserveregs(extra);
  311. fs.nil(reg, extra);
  312. }
  313. }
  314. }
  315. void enterlevel() {
  316. if (++nCcalls > LUAI_MAXCCALLS)
  317. lexerror("chunk has too many syntax levels", EMPTY_INPUT);
  318. }
  319. void leavelevel() {
  320. nCcalls--;
  321. }
  322. void pushclosure(FuncState func, ExpDesc v) {
  323. FuncState fs = this.fs;
  324. Prototype f = fs.f;
  325. if (f.prototypes == null || fs.np + 1 > f.prototypes.length)
  326. f.prototypes = FuncState.realloc(f.prototypes, fs.np * 2 + 1);
  327. f.prototypes[fs.np++] = func.f;
  328. v.init(VRELOCABLE, fs.codeABx(FuncState.OP_CLOSURE, 0, fs.np - 1));
  329. for (int i = 0; i < func.f.numUpvalues; i++) {
  330. int o = (func.upvalues_k[i] == VLOCAL) ? FuncState.OP_MOVE
  331. : FuncState.OP_GETUPVAL;
  332. fs.codeABC(o, 0, func.upvalues_info[i], 0);
  333. }
  334. }
  335. void close_func() {
  336. FuncState fs = this.fs;
  337. Prototype f = fs.f;
  338. f.isVararg = fs.isVararg != 0;
  339. this.removevars(0);
  340. fs.ret(0, 0); /* final return */
  341. f.code = FuncState.realloc(f.code, fs.pc);
  342. f.lines = FuncState.realloc(f.lines, fs.pc);
  343. // f.sizelineinfo = fs.pc;
  344. f.constants = FuncState.realloc(f.constants, fs.nk);
  345. f.prototypes = FuncState.realloc(f.prototypes, fs.np);
  346. fs.locvars = FuncState.realloc(fs.locvars, fs.nlocvars);
  347. // f.sizelocvars = fs.nlocvars;
  348. fs.upvalues = FuncState.realloc(fs.upvalues, f.numUpvalues);
  349. // FuncState._assert (CheckCode.checkcode(f));
  350. FuncState._assert(fs.bl == null);
  351. this.fs = fs.prev;
  352. // L.top -= 2; /* remove table and prototype from the stack */
  353. // /* last token read was anchored in defunct function; must reanchor it
  354. // */
  355. // if (fs!=null) ls.anchor_token();
  356. }
  357. /*============================================================*/
  358. /* GRAMMAR RULES */
  359. /*============================================================*/
  360. void field(ExpDesc v) {
  361. /* field -> ['.' | ':'] NAME */
  362. FuncState fs = this.fs;
  363. ExpDesc key = new ExpDesc();
  364. fs.exp2anyreg(v);
  365. this.next(); /* skip the dot or colon */
  366. PsiBuilder.Marker mark = builder.mark();
  367. this.checkname(key);
  368. mark.done(FIELD_NAME);
  369. fs.indexed(v, key);
  370. }
  371. void yindex(ExpDesc v) {
  372. /* index -> '[' expr ']' */
  373. this.next(); /* skip the '[' */
  374. PsiBuilder.Marker mark = builder.mark();
  375. this.expr(v);
  376. mark.done(TABLE_INDEX);
  377. this.fs.exp2val(v);
  378. this.checknext(RBRACK);
  379. }
  380. /*
  381. ** {======================================================================
  382. ** Rules for Constructors
  383. ** =======================================================================
  384. */
  385. void recfield(ConsControl cc) {
  386. /* recfield -> (NAME | `['exp1`]') = exp1 */
  387. PsiBuilder.Marker mark = builder.mark();
  388. PsiBuilder.Marker field = builder.mark();
  389. FuncState fs = this.fs;
  390. int reg = this.fs.freereg;
  391. ExpDesc key = new ExpDesc();
  392. ExpDesc val = new ExpDesc();
  393. int rkkey;
  394. if (this.t == NAME) {
  395. fs.checklimit(cc.nh, MAX_INT, "items in a constructor");
  396. this.checkname(key);
  397. } else
  398. /* this.t == '[' */
  399. this.yindex(key);
  400. field.done(FIELD_NAME);
  401. cc.nh++;
  402. this.checknext(ASSIGN);
  403. rkkey = fs.exp2RK(key);
  404. this.expr(val);
  405. fs.codeABC(FuncState.OP_SETTABLE, cc.t.info, rkkey, fs.exp2RK(val));
  406. fs.freereg = reg; /* free registers */
  407. mark.done(KEY_ASSIGNMENT);
  408. }
  409. void listfield(ConsControl cc) {
  410. PsiBuilder.Marker mark = builder.mark();
  411. this.expr(cc.v);
  412. fs.checklimit(cc.na, MAX_INT, "items in a constructor");
  413. cc.na++;
  414. cc.tostore++;
  415. mark.done(IDX_ASSIGNMENT);
  416. }
  417. void constructor(ExpDesc t) {
  418. PsiBuilder.Marker mark = builder.mark();
  419. /* constructor -> ?? */
  420. FuncState fs = this.fs;
  421. int line = this.linenumber;
  422. int pc = fs.codeABC(FuncState.OP_NEWTABLE, 0, 0, 0);
  423. ConsControl cc = new ConsControl();
  424. cc.na = cc.nh = cc.tostore = 0;
  425. cc.t = t;
  426. t.init(VRELOCABLE, pc);
  427. cc.v.init(VVOID, 0); /* no value (yet) */
  428. fs.exp2nextreg(t); /* fix it at stack top (for gc) */
  429. this.checknext(LCURLY);
  430. do {
  431. FuncState._assert(cc.v.k == VVOID || cc.tostore > 0);
  432. if (this.t == RCURLY)
  433. break;
  434. fs.closelistfield(cc);
  435. if (this.t == NAME) {
  436. /* may be listfields or recfields */
  437. this.lookahead();
  438. if (this.lookahead != ASSIGN) /* expression? */
  439. this.listfield(cc);
  440. else
  441. this.recfield(cc);
  442. // break;
  443. } else if (this.t == LBRACK) { /* constructor_item -> recfield */
  444. this.recfield(cc);
  445. // break;
  446. } else { /* constructor_part -> listfield */
  447. this.listfield(cc);
  448. // break;
  449. }
  450. } while (this.testnext(COMMA) || this.testnext(SEMI));
  451. this.check_match(RCURLY, LCURLY, line);
  452. fs.lastlistfield(cc);
  453. InstructionPtr i = new InstructionPtr(fs.f.code, pc);
  454. FuncState.SETARG_B(i, luaO_int2fb(cc.na)); /* set initial array size */
  455. FuncState.SETARG_C(i, luaO_int2fb(cc.nh)); /* set initial table size */
  456. mark.done(TABLE_CONSTUCTOR);
  457. }
  458. /*
  459. ** converts an integer to a "floating point byte", represented as
  460. ** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
  461. ** eeeee != 0 and (xxx) otherwise.
  462. */
  463. static int luaO_int2fb(int x) {
  464. int e = 0; /* expoent */
  465. while (x >= 16) {
  466. x = (x + 1) >> 1;
  467. e++;
  468. }
  469. if (x < 8) return x;
  470. else return ((e + 1) << 3) | (x - 8);
  471. }
  472. /* }====================================================================== */
  473. void parlist() {
  474. //log.info(">>> parlist");
  475. /* parlist -> [ param { `,' param } ] */
  476. FuncState fs = this.fs;
  477. Prototype f = fs.f;
  478. int nparams = 0;
  479. fs.isVararg = 0;
  480. if (this.t != RPAREN) { /* is `parlist' not empty? */
  481. do {
  482. PsiBuilder.Marker parm = builder.mark();
  483. PsiBuilder.Marker mark = builder.mark();
  484. if (this.t == NAME) {
  485. /* param . NAME */
  486. String name = this.str_checkname();
  487. mark.done(LOCAL_NAME_DECL);
  488. this.new_localvar(name, nparams++);
  489. parm.done(PARAMETER);
  490. // break;
  491. } else if (this.t == ELLIPSIS) { /* param . `...' */
  492. mark.done(LOCAL_NAME_DECL);
  493. this.next();
  494. parm.done(PARAMETER);
  495. fs.isVararg |= FuncState.VARARG_ISVARARG;
  496. // break;
  497. } else {
  498. mark.drop();
  499. parm.drop();
  500. this.syntaxerror("<name> or " + LUA_QL("...") + " expected");
  501. }
  502. } while ((fs.isVararg == 0) && this.testnext(COMMA));
  503. }
  504. this.adjustlocalvars(nparams);
  505. f.numParams = (fs.nactvar - (fs.isVararg & FuncState.VARARG_HASARG));
  506. fs.reserveregs(fs.nactvar); /* reserve register for parameters */
  507. //log.info("<<< parlist");
  508. }
  509. void body(ExpDesc e, boolean needself, int line) {
  510. /* body -> `(' parlist `)' chunk END */
  511. FuncState new_fs = new FuncState(this);
  512. new_fs.linedefined = line;
  513. this.checknext(LPAREN);
  514. if (needself) {
  515. PsiBuilder.Marker self = builder.mark();
  516. new_localvarliteral("self", 0);
  517. adjustlocalvars(1);
  518. self.done(SELF_PARAMETER);
  519. }
  520. PsiBuilder.Marker mark = builder.mark();
  521. this.parlist();
  522. mark.done(LuaElementTypes.PARAMETER_LIST);
  523. this.checknext(RPAREN);
  524. mark = builder.mark();
  525. this.chunk();
  526. mark.done(BLOCK);
  527. new_fs.lastlinedefined = this.linenumber;
  528. this.check_match(END, FUNCTION, line);
  529. this.close_func();
  530. this.pushclosure(new_fs, e);
  531. }
  532. int explist1(ExpDesc v) {
  533. PsiBuilder.Marker mark = builder.mark();
  534. /* explist1 -> expr { `,' expr } */
  535. int n = 1; /* at least one expression */
  536. this.expr(v);
  537. while (this.testnext(COMMA)) {
  538. fs.exp2nextreg(v);
  539. this.expr(v);
  540. n++;
  541. }
  542. mark.done(EXPR_LIST);
  543. return n;
  544. }
  545. void funcargs(ExpDesc f) {
  546. PsiBuilder.Marker mark = builder.mark();
  547. FuncState fs = this.fs;
  548. ExpDesc args = new ExpDesc();
  549. int base, nparams;
  550. int line = this.linenumber;
  551. if (this.t == LPAREN) { /* funcargs -> `(' [ explist1 ] `)' */
  552. if (line != this.lastline)
  553. this.syntaxerror("ambiguous syntax (function call x new statement)");
  554. this.next();
  555. if (this.t == RPAREN) /* arg list is empty? */
  556. args.k = VVOID;
  557. else {
  558. this.explist1(args);
  559. fs.setmultret(args);
  560. }
  561. this.check_match(RPAREN, LPAREN, line);
  562. // break;
  563. } else if (this.t == LCURLY) {
  564. /* funcargs -> constructor */
  565. this.constructor(args);
  566. } else if (this.t == STRING || this.t == LONGSTRING) { /* funcargs -> STRING */
  567. this.codestring(args, builder.text());
  568. this.next(); /* must use `seminfo' before `next' */
  569. } else {
  570. this.syntaxerror("function arguments expected");
  571. }
  572. FuncState._assert(f.k == VNONRELOC);
  573. base = f.info; /* base register for call */
  574. if (hasmultret(args.k))
  575. nparams = FuncState.LUA_MULTRET; /* open call */
  576. else {
  577. if (args.k != VVOID)
  578. fs.exp2nextreg(args); /* close last argument */
  579. nparams = fs.freereg - (base + 1);
  580. }
  581. f.init(VCALL, fs.codeABC(FuncState.OP_CALL, base, nparams + 1, 2));
  582. fs.fixline(line);
  583. fs.freereg = base + 1; /* call remove function and arguments and leaves
  584. * (unless changed) one result */
  585. mark.done(FUNCTION_CALL_ARGS);
  586. }
  587. /*
  588. ** {======================================================================
  589. ** Expression parsing
  590. ** =======================================================================
  591. */
  592. void prefixexp(ExpDesc v) {
  593. /* prefixexp -> NAME | '(' expr ')' */
  594. if (this.t == LPAREN) {
  595. int line = this.linenumber;
  596. this.next();
  597. this.expr(v);
  598. this.check_match(RPAREN, LPAREN, line);
  599. fs.dischargevars(v);
  600. return;
  601. } else if (this.t == NAME) {
  602. this.singlevar(v);
  603. return;
  604. }
  605. this.syntaxerror("unexpected symbol in prefix expression");
  606. }
  607. void primaryexp(ExpDesc v) {
  608. /*
  609. * primaryexp -> prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs |
  610. * funcargs }
  611. */
  612. PsiBuilder.Marker mark = builder.mark();
  613. // PsiBuilder.Marker ref = builder.mark();
  614. // PsiBuilder.Marker tmp = ref;
  615. FuncState fs = this.fs;
  616. this.prefixexp(v);
  617. for (; ;) {
  618. if (this.t == DOT) { /* field */
  619. this.field(v);
  620. // if (tmp != null) {
  621. // ref = ref.precede();
  622. // tmp.done(REFERENCE);
  623. // tmp = ref;
  624. // }
  625. // break;
  626. } else if (this.t == LBRACK) { /* `[' exp1 `]' */
  627. ExpDesc key = new ExpDesc();
  628. fs.exp2anyreg(v);
  629. this.yindex(key);
  630. // if (tmp != null) {
  631. // ref = ref.precede();
  632. // tmp.done(REFERENCE);
  633. // tmp = ref;
  634. // }
  635. fs.indexed(v, key);
  636. // break;
  637. } else if (this.t == COLON) { /* `:' NAME funcargs */
  638. ExpDesc key = new ExpDesc();
  639. this.next();
  640. PsiBuilder.Marker func = builder.mark();
  641. this.checkname(key);
  642. func.done(FIELD_NAME);
  643. // // ref = ref.precede();
  644. // if (tmp != null)
  645. // tmp.done(REFERENCE);
  646. // tmp = null;
  647. // PsiBuilder.Marker call = null;
  648. // if (mark != null) {
  649. //
  650. // call = mark.precede();
  651. // //mark.done(FUNCTION_IDENTIFIER);
  652. // mark.drop();
  653. // mark = null;
  654. // }
  655. fs.self(v, key);
  656. this.funcargs(v);
  657. if (mark != null)
  658. mark.done(FUNCTION_CALL_EXPR);
  659. mark = null;
  660. // break;
  661. } else if (this.t == LPAREN
  662. || this.t == STRING || this.t == LONGSTRING
  663. || this.t == LCURLY) { /* funcargs */
  664. fs.exp2nextreg(v);
  665. // if (tmp != null) {
  666. // tmp.drop(); tmp = null;
  667. // }
  668. PsiBuilder.Marker call = null;
  669. // if (mark != null) {
  670. // call = mark.precede();
  671. // mark.done(FUNCTION_IDENTIFIER);
  672. // mark = null;
  673. // }
  674. this.funcargs(v);
  675. if (mark != null)
  676. mark.done(FUNCTION_CALL_EXPR);
  677. mark = null;
  678. // break;
  679. } else {
  680. // if (tmp != null)
  681. // tmp.drop();
  682. if (mark != null)
  683. mark.done(VARIABLE);
  684. return;
  685. }
  686. }
  687. }
  688. void simpleexp(ExpDesc v) {
  689. /*
  690. * simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor |
  691. * FUNCTION body | primaryexp
  692. */
  693. PsiBuilder.Marker mark = builder.mark();
  694. try {
  695. if (this.t == NUMBER) {
  696. v.init(VKNUM, 0);
  697. v.setNval(0); // TODO
  698. } else if (this.t == STRING || this.t == LONGSTRING) {
  699. this.codestring(v, builder.text()); //TODO
  700. } else if (this.t == NIL) {
  701. v.init(VNIL, 0);
  702. } else if (this.t == TRUE) {
  703. v.init(VTRUE, 0);
  704. } else if (this.t == FALSE) {
  705. v.init(VFALSE, 0);
  706. } else if (this.t == ELLIPSIS) { /* vararg */
  707. FuncState fs = this.fs;
  708. this.check_condition(fs.isVararg != 0, "cannot use " + LUA_QL("...")
  709. + " outside a vararg function");
  710. fs.isVararg &= ~FuncState.VARARG_NEEDSARG; /* don't need 'arg' */
  711. v.init(VVARARG, fs.codeABC(FuncState.OP_VARARG, 0, 1, 0));
  712. } else if (this.t == LCURLY) { /* constructor */
  713. this.constructor(v);
  714. return;
  715. } else if (this.t == FUNCTION) {
  716. this.next();
  717. PsiBuilder.Marker funcStmt = builder.mark();
  718. this.body(v, false, this.linenumber);
  719. funcStmt.done(ANONYMOUS_FUNCTION_EXPRESSION);
  720. return;
  721. } else {
  722. this.primaryexp(v);
  723. return;
  724. }
  725. this.next();
  726. mark.done(this.t == ELLIPSIS ? VARIABLE : LITERAL_EXPRESSION);
  727. mark = null;
  728. }
  729. finally {
  730. if (mark != null)
  731. mark.drop();
  732. }
  733. }
  734. int getunopr(IElementType op) {
  735. if (op == NOT)
  736. return OPR_NOT;
  737. if (op == MINUS)
  738. return OPR_MINUS;
  739. if (op == GETN)
  740. return OPR_LEN;
  741. return OPR_NOUNOPR;
  742. }
  743. int getbinopr(IElementType op) {
  744. if (op == PLUS)
  745. return OPR_ADD;
  746. if (op == MINUS)
  747. return OPR_SUB;
  748. if (op == MULT)
  749. return OPR_MUL;
  750. if (op == DIV)
  751. return OPR_DIV;
  752. if (op == MOD)
  753. return OPR_MOD;
  754. if (op == EXP)
  755. return OPR_POW;
  756. if (op == CONCAT)
  757. return OPR_CONCAT;
  758. if (op == NE)
  759. return OPR_NE;
  760. if (op == EQ)
  761. return OPR_EQ;
  762. if (op == LT)
  763. return OPR_LT;
  764. if (op == LE)
  765. return OPR_LE;
  766. if (op == GT)
  767. return OPR_GT;
  768. if (op == GE)
  769. return OPR_GE;
  770. if (op == AND)
  771. return OPR_AND;
  772. if (op == OR)
  773. return OPR_OR;
  774. return OPR_NOBINOPR;
  775. }
  776. static final int[] priorityLeft = {
  777. 6, 6, 7, 7, 7, /* `+' `-' `/' `%' */
  778. 10, 5, /* power and concat (right associative) */
  779. 3, 3, /* equality and inequality */
  780. 3, 3, 3, 3, /* order */
  781. 2, 1, /* logical (and/or) */
  782. };
  783. static final int[] priorityRight = { /* ORDER OPR */
  784. 6, 6, 7, 7, 7, /* `+' `-' `/' `%' */
  785. 9, 4, /* power and concat (right associative) */
  786. 3, 3, /* equality and inequality */
  787. 3, 3, 3, 3, /* order */
  788. 2, 1 /* logical (and/or) */
  789. };
  790. static final int UNARY_PRIORITY = 8; /* priority for unary operators */
  791. /*
  792. ** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
  793. ** where `binop' is any binary operator with a priority higher than `limit'
  794. */
  795. int subexpr(ExpDesc v, int limit) {
  796. int op;
  797. int uop;
  798. PsiBuilder.Marker mark = builder.mark();
  799. PsiBuilder.Marker oper;
  800. this.enterlevel();
  801. uop = getunopr(this.t);
  802. if (uop != OPR_NOUNOPR) {
  803. PsiBuilder.Marker mark2 = builder.mark();
  804. oper = builder.mark();
  805. this.next();
  806. oper.done(UNARY_OP);
  807. this.subexpr(v, UNARY_PRIORITY);
  808. mark2.done(UNARY_EXP);
  809. fs.prefix(uop, v);
  810. } else {
  811. this.simpleexp(v);
  812. }
  813. /* expand while operators have priorities higher than `limit' */
  814. op = getbinopr(this.t);
  815. while (op != OPR_NOBINOPR && priorityLeft[op] > limit) {
  816. ExpDesc v2 = new ExpDesc();
  817. int nextop;
  818. oper = builder.mark();
  819. this.next();
  820. oper.done(BINARY_OP);
  821. fs.infix(op, v);
  822. /* read sub-expression with higher priority */
  823. nextop = this.subexpr(v2, priorityRight[op]);
  824. fs.posfix(op, v, v2);
  825. op = nextop;
  826. mark.done(BINARY_EXP);
  827. mark = mark.precede();
  828. }
  829. mark.drop();
  830. this.leavelevel();
  831. return op; /* return first untreated operator */
  832. }
  833. void expr(ExpDesc v) {
  834. PsiBuilder.Marker mark = builder.mark();
  835. this.subexpr(v, 0);
  836. mark.done(EXPR);
  837. // next();
  838. }
  839. /* }==================================================================== */
  840. /*
  841. ** {======================================================================
  842. ** Rules for Statements
  843. ** =======================================================================
  844. */
  845. boolean block_follow(IElementType token) {
  846. return token == ELSE || token == ELSEIF ||
  847. token == END || token == UNTIL || token == null;
  848. }
  849. void block() {
  850. PsiBuilder.Marker mark = builder.mark();
  851. /* block -> chunk */
  852. FuncState fs = this.fs;
  853. BlockCnt bl = new BlockCnt();
  854. fs.enterblock(bl, false);
  855. this.chunk();
  856. FuncState._assert(bl.breaklist == NO_JUMP);
  857. fs.leaveblock();
  858. mark.done(BLOCK);
  859. }
  860. /*
  861. ** check whether, in an assignment to a local variable, the local variable
  862. ** is needed in a previous assignment (to a table). If so, save original
  863. ** local value in a safe place and use this safe copy in the previous
  864. ** assignment.
  865. */
  866. void check_conflict(LHS_assign lh, ExpDesc v) {
  867. FuncState fs = this.fs;
  868. int extra = fs.freereg; /* eventual position to save local variable */
  869. boolean conflict = false;
  870. for (; lh != null; lh = lh.prev) {
  871. if (lh.v.k == VINDEXED) {
  872. if (lh.v.info == v.info) { /* conflict? */
  873. conflict = true;
  874. lh.v.info = extra; /* previous assignment will use safe copy */
  875. }
  876. if (lh.v.aux == v.info) { /* conflict? */
  877. conflict = true;
  878. lh.v.aux = extra; /* previous assignment will use safe copy */
  879. }
  880. }
  881. }
  882. if (conflict) {
  883. fs.codeABC(FuncState.OP_MOVE, fs.freereg, v.info, 0); /* make copy */
  884. fs.reserveregs(1);
  885. }
  886. }
  887. void assignment(LHS_assign lh, int nvars, PsiBuilder.Marker expr) {
  888. // PsiBuilder.Marker mark = builder.mark();
  889. ExpDesc e = new ExpDesc();
  890. this.check_condition(VLOCAL <= lh.v.k && lh.v.k <= VINDEXED,
  891. "syntax error");
  892. if (this.testnext(COMMA)) { /* assignment -> `,' primaryexp assignment */
  893. LHS_assign nv = new LHS_assign();
  894. nv.prev = lh;
  895. PsiBuilder.Marker mark = builder.mark();
  896. this.primaryexp(nv.v);
  897. mark.done(VARIABLE);
  898. if (nv.v.k == VLOCAL)
  899. this.check_conflict(lh, nv.v);
  900. this.assignment(nv, nvars + 1, expr);
  901. } else { /* assignment . `=' explist1 */
  902. int nexps;
  903. expr.done(IDENTIFIER_LIST);
  904. this.checknext(ASSIGN);
  905. nexps = this.explist1(e);
  906. if (nexps != nvars) {
  907. this.adjust_assign(nvars, nexps, e);
  908. if (nexps > nvars)
  909. this.fs.freereg -= nexps - nvars; /* remove extra values */
  910. } else {
  911. fs.setoneret(e); /* close last expression */
  912. fs.storevar(lh.v, e);
  913. // mark.done(ASSIGN_STMT);
  914. return; /* avoid default */
  915. }
  916. }
  917. e.init(VNONRELOC, this.fs.freereg - 1); /* default assignment */
  918. fs.storevar(lh.v, e);
  919. // mark.done(ASSIGN_STMT);
  920. }
  921. int cond() {
  922. PsiBuilder.Marker mark = builder.mark();
  923. /* cond -> exp */
  924. ExpDesc v = new ExpDesc();
  925. /* read condition */
  926. this.expr(v);
  927. /* `falses' are all equal here */
  928. if (v.k == VNIL)
  929. v.k = VFALSE;
  930. fs.goiftrue(v);
  931. mark.done(CONDITIONAL_EXPR);
  932. return v.f;
  933. }
  934. void breakstat() {
  935. FuncState fs = this.fs;
  936. BlockCnt bl = fs.bl;
  937. boolean upval = false;
  938. while (bl != null && !bl.isbreakable) {
  939. upval |= bl.upval;
  940. bl = bl.previous;
  941. }
  942. if (bl == null) {
  943. this.syntaxerror("no loop to break");
  944. }
  945. else {
  946. if (upval)
  947. fs.codeABC(FuncState.OP_CLOSE, bl.nactvar, 0, 0);
  948. bl.breaklist = fs.concat(bl.breaklist, fs.jump());
  949. }
  950. }
  951. void whilestat(int line) {
  952. PsiBuilder.Marker mark = builder.mark();
  953. /* whilestat -> WHILE cond DO block END */
  954. FuncState fs = this.fs;
  955. int whileinit;
  956. int condexit;
  957. BlockCnt bl = new BlockCnt();
  958. this.next(); /* skip WHILE */
  959. whileinit = fs.getlabel();
  960. condexit = this.cond();
  961. fs.enterblock(bl, true);
  962. this.checknext(DO);
  963. this.block();
  964. fs.patchlist(fs.jump(), whileinit);
  965. this.check_match(END, WHILE, line);
  966. fs.leaveblock();
  967. fs.patchtohere(condexit); /* false conditions finish the loop */
  968. mark.done(WHILE_BLOCK);
  969. }
  970. void repeatstat(int line) {
  971. PsiBuilder.Marker mark = builder.mark();
  972. /* repeatstat -> REPEAT block UNTIL cond */
  973. int condexit;
  974. FuncState fs = this.fs;
  975. int repeat_init = fs.getlabel();
  976. BlockCnt bl1 = new BlockCnt();
  977. BlockCnt bl2 = new BlockCnt();
  978. fs.enterblock(bl1, true); /* loop block */
  979. fs.enterblock(bl2, false); /* scope block */
  980. this.next(); /* skip REPEAT */
  981. this.chunk();
  982. this.check_match(UNTIL, REPEAT, line);
  983. condexit = this.cond(); /* read condition (inside scope block) */
  984. if (!bl2.upval) { /* no upvalues? */
  985. fs.leaveblock(); /* finish scope */
  986. fs.patchlist(condexit, repeat_init); /* close the loop */
  987. } else { /* complete semantics when there are upvalues */
  988. this.breakstat(); /* if condition then break */
  989. fs.patchtohere(condexit); /* else... */
  990. fs.leaveblock(); /* finish scope... */
  991. fs.patchlist(fs.jump(), repeat_init); /* and repeat */
  992. }
  993. fs.leaveblock(); /* finish loop */
  994. mark.done(BLOCK);
  995. }
  996. int exp1() {
  997. ExpDesc e = new ExpDesc();
  998. int k;
  999. this.expr(e);
  1000. k = e.k;
  1001. fs.exp2nextreg(e);
  1002. return k;
  1003. }
  1004. void forbody(int base, int line, int nvars, boolean isnum) {
  1005. /* forbody -> DO block */
  1006. BlockCnt bl = new BlockCnt();
  1007. FuncState fs = this.fs;
  1008. int prep, endfor;
  1009. this.adjustlocalvars(3); /* control variables */
  1010. this.checknext(DO);
  1011. prep = isnum ? fs.codeAsBx(FuncState.OP_FORPREP, base, NO_JUMP) : fs.jump();
  1012. fs.enterblock(bl, false); /* scope for declared variables */
  1013. this.adjustlocalvars(nvars);
  1014. fs.reserveregs(nvars);
  1015. this.block();
  1016. fs.leaveblock(); /* end of scope for declared variables */
  1017. fs.patchtohere(prep);
  1018. endfor = (isnum) ? fs.codeAsBx(FuncState.OP_FORLOOP, base, NO_JUMP) : fs
  1019. .codeABC(FuncState.OP_TFORLOOP, base, 0, nvars);
  1020. fs.fixline(line); /* pretend that `Lua.OP_FOR' starts the loop */
  1021. fs.patchlist((isnum ? endfor : fs.jump()), prep + 1);
  1022. }
  1023. void fornum(String varname, int line) {
  1024. /* fornum -> NAME = exp1,exp1[,exp1] forbody */
  1025. FuncState fs = this.fs;
  1026. int base = fs.freereg;
  1027. this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_INDEX, 0);
  1028. this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_LIMIT, 1);
  1029. this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_STEP, 2);
  1030. this.new_localvar(varname, 3);
  1031. this.checknext(ASSIGN);
  1032. this.exp1(); /* initial value */
  1033. this.checknext(COMMA);
  1034. this.exp1(); /* limit */
  1035. if (this.testnext(COMMA))
  1036. this.exp1(); /* optional step */
  1037. else { /* default step = 1 */
  1038. fs.codeABx(FuncState.OP_LOADK, fs.freereg, fs.numberK(1));
  1039. fs.reserveregs(1);
  1040. }
  1041. this.forbody(base, line, 1, true);
  1042. }
  1043. void forlist(String indexname) {
  1044. /* forlist -> NAME {,NAME} IN explist1 forbody */
  1045. FuncState fs = this.fs;
  1046. ExpDesc e = new ExpDesc();
  1047. int nvars = 0;
  1048. int line;
  1049. int base = fs.freereg;
  1050. /* create control variables */
  1051. this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_GENERATOR, nvars++);
  1052. this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_STATE, nvars++);
  1053. this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_CONTROL, nvars++);
  1054. /* create declared variables */
  1055. this.new_localvar(indexname, nvars++);
  1056. // next();
  1057. while (this.testnext(COMMA)) {
  1058. PsiBuilder.Marker mark = builder.mark();
  1059. String name = this.str_checkname();
  1060. mark.done(LOCAL_NAME);
  1061. this.new_localvar(name, nvars++);
  1062. }
  1063. this.checknext(IN);
  1064. line = this.linenumber;
  1065. this.adjust_assign(3, this.explist1(e), e);
  1066. fs.checkstack(3); /* extra space to call generator */
  1067. this.forbody(base, line, nvars - 3, false);
  1068. }
  1069. void forstat(int line) {
  1070. /* forstat -> FOR (fornum | forlist) END */
  1071. FuncState fs = this.fs;
  1072. String varname;
  1073. BlockCnt bl = new BlockCnt();
  1074. fs.enterblock(bl, true); /* scope for loop and control variables */
  1075. PsiBuilder.Marker mark = builder.mark();
  1076. boolean numeric = false;
  1077. this.checknext(FOR); /* skip `for' */
  1078. PsiBuilder.Marker var_mark = builder.mark();
  1079. varname = this.str_checkname(); /* first variable name */
  1080. var_mark.done(LOCAL_NAME);
  1081. if (this.t == ASSIGN) {
  1082. numeric = true;
  1083. this.fornum(varname, line);
  1084. } else if (this.t == COMMA || this.t == IN) {
  1085. this.forlist(varname);
  1086. } else {
  1087. this.syntaxerror(LUA_QL("=") + " or " + LUA_QL("in") + " expected");
  1088. }
  1089. this.check_match(END, FOR, line);
  1090. mark.done(numeric ? NUMERIC_FOR_BLOCK : GENERIC_FOR_BLOCK);
  1091. fs.leaveblock(); /* loop scope (`break' jumps to this point) */
  1092. }
  1093. int test_then_block() {
  1094. /* test_then_block -> [IF | ELSEIF] cond THEN block */
  1095. int condexit;
  1096. this.next(); /* skip IF or ELSEIF */
  1097. condexit = this.cond();
  1098. this.checknext(THEN);
  1099. this.block(); /* `then' part */
  1100. return condexit;
  1101. }
  1102. void ifstat(int line) {
  1103. PsiBuilder.Marker mark = builder.mark();
  1104. /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block]
  1105. * END */
  1106. FuncState fs = this.fs;
  1107. int flist;
  1108. int escapelist = NO_JUMP;
  1109. flist = test_then_block(); /* IF cond THEN block */
  1110. while (this.t == ELSEIF) {
  1111. escapelist = fs.concat(escapelist, fs.jump());
  1112. fs.patchtohere(flist);
  1113. flist = test_then_block(); /* ELSEIF cond THEN block */
  1114. }
  1115. if (this.t == ELSE) {
  1116. escapelist = fs.concat(escapelist, fs.jump());
  1117. fs.patchtohere(flist);
  1118. this.next(); /* skip ELSE (after patch, for correct line info) */
  1119. this.block(); /* `else' part */
  1120. } else
  1121. escapelist = fs.concat(escapelist, flist);
  1122. fs.patchtohere(escapelist);
  1123. this.check_match(END, IF, line);
  1124. mark.done(IF_THEN_BLOCK);
  1125. }
  1126. void localfunc(PsiBuilder.Marker stat) {
  1127. ExpDesc v = new ExpDesc();
  1128. ExpDesc b = new ExpDesc();
  1129. FuncState fs = this.fs;
  1130. PsiBuilder.Marker funcStmt = stat;
  1131. next();
  1132. PsiBuilder.Marker funcName = builder.mark();
  1133. PsiBuilder.Marker mark = builder.mark();
  1134. String name = this.str_checkname();
  1135. mark.done(LOCAL_NAME_DECL);
  1136. funcName.done(FUNCTION_IDENTIFIER);
  1137. this.new_localvar(name, 0);
  1138. v.init(VLOCAL, fs.freereg);
  1139. fs.reserveregs(1);
  1140. this.adjustlocalvars(1);
  1141. this.body(b, false, this.linenumber);
  1142. funcStmt.done(LOCAL_FUNCTION);
  1143. fs.storevar(v, b);
  1144. /* debug information will only see the variable after this point! */
  1145. }
  1146. void localstat(PsiBuilder.Marker stat) {
  1147. // PsiBuilder.Marker mark = stat;
  1148. PsiBuilder.Marker names = builder.mark();
  1149. /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
  1150. int nvars = 0;
  1151. int nexps;
  1152. ExpDesc e = new ExpDesc();
  1153. do {
  1154. PsiBuilder.Marker mark = builder.mark();
  1155. String name = this.str_checkname();
  1156. mark.done(LOCAL_NAME_DECL);
  1157. this.new_localvar(name, nvars++);
  1158. } while (this.testnext(COMMA));
  1159. names.done(IDENTIFIER_LIST);
  1160. if (this.testnext(ASSIGN)) {
  1161. nexps = this.explist1(e);
  1162. stat.done(LOCAL_DECL_WITH_ASSIGNMENT);
  1163. }
  1164. else {
  1165. e.k = VVOID;
  1166. nexps = 0;
  1167. stat.done(LOCAL_DECL);
  1168. }
  1169. this.adjust_assign(nvars, nexps, e);
  1170. this.adjustlocalvars(nvars);
  1171. }
  1172. boolean funcname(ExpDesc v) {
  1173. //log.info(">>> funcname");
  1174. /* funcname -> NAME {field} [`:' NAME] */
  1175. boolean needself = false;
  1176. PsiBuilder.Marker ref = builder.mark();
  1177. PsiBuilder.Marker tmp = ref;
  1178. this.singlevar(v);
  1179. int lastPos = builder.getCurrentOffset();
  1180. while (this.t == DOT) {
  1181. this.field(v);
  1182. ref = ref.precede();
  1183. tmp.done(GETTABLE);
  1184. tmp = ref;
  1185. }
  1186. if (this.t == COLON) {
  1187. needself = true;
  1188. this.field(v);
  1189. // ref = ref.precede();
  1190. tmp.done(GETSELF);
  1191. tmp = null;
  1192. }
  1193. if (tmp != null)
  1194. // ref.done(REFERENCE);
  1195. // else
  1196. tmp.drop();
  1197. //log.info("<<< funcname");
  1198. return needself;
  1199. }
  1200. void funcstat(int line) {
  1201. //log.info(">>> funcstat");
  1202. PsiBuilder.Marker funcStmt = builder.mark();
  1203. /* funcstat -> FUNCTION funcname body */
  1204. boolean needself;
  1205. ExpDesc v = new ExpDesc();
  1206. ExpDesc b = new ExpDesc();
  1207. this.next(); /* skip FUNCTION */
  1208. PsiBuilder.Marker funcName = builder.mark();
  1209. needself = this.funcname(v);
  1210. // if (needself)
  1211. // funcName.done(FUNCTION_IDENTIFIER_NEEDSELF);
  1212. // else
  1213. funcName.done(FUNCTION_IDENTIFIER);
  1214. this.body(b, needself, line);
  1215. funcStmt.done(FUNCTION_DEFINITION);
  1216. fs.storevar(v, b);
  1217. fs.fixline(line); /* definition `happens' in the first line */
  1218. ///log.info("<<< funcstat");
  1219. }
  1220. void exprstat() {
  1221. /* stat -> func | assignment */
  1222. FuncState fs = this.fs;
  1223. LHS_assign v = new LHS_assign();
  1224. PsiBuilder.Marker mark = builder.mark();
  1225. this.primaryexp(v.v);
  1226. if (v.v.k == VCALL) /* stat -> func */ {
  1227. mark.done(FUNCTION_CALL);
  1228. FuncState.SETARG_C(fs.getcodePtr(v.v), 1); /* call statement uses no results */
  1229. }
  1230. else { /* stat -> assignment */
  1231. PsiBuilder.Marker expr = mark;
  1232. mark = expr.precede();
  1233. v.prev = null;
  1234. this.assignment(v, 1, expr);
  1235. mark.done(ASSIGN_STMT);
  1236. }
  1237. }
  1238. void retstat() {
  1239. PsiBuilder.Marker mark = builder.mark();
  1240. boolean tailCall = false;
  1241. /* stat -> RETURN explist */
  1242. FuncState fs = this.fs;
  1243. ExpDesc e = new ExpDesc();
  1244. int first, nret; /* registers with returned values */
  1245. this.next(); /* skip RETURN */
  1246. if (block_follow(this.t) || this.t == SEMI)
  1247. first = nret = 0; /* return no values */
  1248. else {
  1249. nret = this.explist1(e); /* optional return values */
  1250. if (hasmultret(e.k)) {
  1251. fs.setmultret(e);
  1252. if (e.k == VCALL && nret == 1) { /* tail call? */
  1253. tailCall = true;
  1254. FuncState.SET_OPCODE(fs.getcodePtr(e), FuncState.OP_TAILCALL);
  1255. FuncState._assert(FuncState.GETARG_A(fs.getcode(e)) == fs.nactvar);
  1256. }
  1257. first = fs.nactvar;
  1258. nret = FuncState.LUA_MULTRET; /* return all values */
  1259. } else {
  1260. if (nret == 1) /* only one single value? */
  1261. first = fs.exp2anyreg(e);
  1262. else {
  1263. fs.exp2nextreg(e); /* values must go to the `stack' */
  1264. first = fs.nactvar; /* return all `active' values */
  1265. FuncState._assert(nret == fs.freereg - first);
  1266. }
  1267. }
  1268. }
  1269. mark.done(tailCall?RETURN_STATEMENT_WITH_TAIL_CALL:RETURN_STATEMENT);
  1270. fs.ret(first, nret);
  1271. }
  1272. boolean statement() {
  1273. try {
  1274. //log.info(">>> statement");
  1275. int line = this.linenumber; /* may be needed for error messages */
  1276. if (this.t == IF) { /* stat -> ifstat */
  1277. this.ifstat(line);
  1278. return false;
  1279. }

Large files files are truncated, but you can click here to view the full file