lua/lparser.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 18 Jun 2017 19:50:43 -0400
changeset 57 4974e5368a29
parent 0 d7ee4e2ed49d
permissions -rw-r--r--
Minor type cleanup ("unsigned char" -> "uint8_t").
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     1
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     2
** $Id: lparser.c,v 2.130.1.1 2013/04/12 18:48:47 roberto Exp $
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     3
** Lua Parser
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     4
** See Copyright Notice in lua.h
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     5
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     6
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     7
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     8
#include <string.h>
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     9
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    10
#define lparser_c
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    11
#define LUA_CORE
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    12
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    13
#include "lua.h"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    14
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    15
#include "lcode.h"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    16
#include "ldebug.h"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    17
#include "ldo.h"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    18
#include "lfunc.h"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    19
#include "llex.h"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    20
#include "lmem.h"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    21
#include "lobject.h"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    22
#include "lopcodes.h"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    23
#include "lparser.h"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    24
#include "lstate.h"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    25
#include "lstring.h"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    26
#include "ltable.h"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    27
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    28
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    29
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    30
/* maximum number of local variables per function (must be smaller
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    31
   than 250, due to the bytecode format) */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    32
#define MAXVARS		200
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    33
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    34
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    35
#define hasmultret(k)		((k) == VCALL || (k) == VVARARG)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    36
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    37
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    38
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    39
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    40
** nodes for block list (list of active blocks)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    41
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    42
typedef struct BlockCnt {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    43
  struct BlockCnt *previous;  /* chain */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    44
  short firstlabel;  /* index of first label in this block */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    45
  short firstgoto;  /* index of first pending goto in this block */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    46
  lu_byte nactvar;  /* # active locals outside the block */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    47
  lu_byte upval;  /* true if some variable in the block is an upvalue */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    48
  lu_byte isloop;  /* true if `block' is a loop */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    49
} BlockCnt;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    50
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    51
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    52
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    53
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    54
** prototypes for recursive non-terminal functions
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    55
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    56
static void statement (LexState *ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    57
static void expr (LexState *ls, expdesc *v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    58
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    59
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    60
static void anchor_token (LexState *ls) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    61
  /* last token from outer function must be EOS */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    62
  lua_assert(ls->fs != NULL || ls->t.token == TK_EOS);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    63
  if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    64
    TString *ts = ls->t.seminfo.ts;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    65
    luaX_newstring(ls, getstr(ts), ts->tsv.len);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    66
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    67
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    68
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    69
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    70
/* semantic error */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    71
static l_noret semerror (LexState *ls, const char *msg) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    72
  ls->t.token = 0;  /* remove 'near to' from final message */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    73
  luaX_syntaxerror(ls, msg);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    74
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    75
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    76
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    77
static l_noret error_expected (LexState *ls, int token) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    78
  luaX_syntaxerror(ls,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    79
      luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token)));
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    80
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    81
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    82
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    83
static l_noret errorlimit (FuncState *fs, int limit, const char *what) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    84
  lua_State *L = fs->ls->L;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    85
  const char *msg;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    86
  int line = fs->f->linedefined;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    87
  const char *where = (line == 0)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    88
                      ? "main function"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    89
                      : luaO_pushfstring(L, "function at line %d", line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    90
  msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s",
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    91
                             what, limit, where);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    92
  luaX_syntaxerror(fs->ls, msg);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    93
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    94
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    95
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    96
static void checklimit (FuncState *fs, int v, int l, const char *what) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    97
  if (v > l) errorlimit(fs, l, what);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    98
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    99
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   100
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   101
static int testnext (LexState *ls, int c) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   102
  if (ls->t.token == c) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   103
    luaX_next(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   104
    return 1;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   105
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   106
  else return 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   107
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   108
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   109
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   110
static void check (LexState *ls, int c) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   111
  if (ls->t.token != c)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   112
    error_expected(ls, c);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   113
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   114
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   115
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   116
static void checknext (LexState *ls, int c) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   117
  check(ls, c);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   118
  luaX_next(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   119
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   120
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   121
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   122
#define check_condition(ls,c,msg)	{ if (!(c)) luaX_syntaxerror(ls, msg); }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   123
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   124
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   125
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   126
static void check_match (LexState *ls, int what, int who, int where) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   127
  if (!testnext(ls, what)) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   128
    if (where == ls->linenumber)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   129
      error_expected(ls, what);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   130
    else {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   131
      luaX_syntaxerror(ls, luaO_pushfstring(ls->L,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   132
             "%s expected (to close %s at line %d)",
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   133
              luaX_token2str(ls, what), luaX_token2str(ls, who), where));
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   134
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   135
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   136
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   137
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   138
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   139
static TString *str_checkname (LexState *ls) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   140
  TString *ts;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   141
  check(ls, TK_NAME);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   142
  ts = ls->t.seminfo.ts;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   143
  luaX_next(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   144
  return ts;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   145
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   146
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   147
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   148
static void init_exp (expdesc *e, expkind k, int i) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   149
  e->f = e->t = NO_JUMP;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   150
  e->k = k;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   151
  e->u.info = i;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   152
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   153
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   154
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   155
static void codestring (LexState *ls, expdesc *e, TString *s) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   156
  init_exp(e, VK, luaK_stringK(ls->fs, s));
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   157
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   158
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   159
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   160
static void checkname (LexState *ls, expdesc *e) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   161
  codestring(ls, e, str_checkname(ls));
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   162
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   163
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   164
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   165
static int registerlocalvar (LexState *ls, TString *varname) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   166
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   167
  Proto *f = fs->f;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   168
  int oldsize = f->sizelocvars;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   169
  luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   170
                  LocVar, SHRT_MAX, "local variables");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   171
  while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   172
  f->locvars[fs->nlocvars].varname = varname;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   173
  luaC_objbarrier(ls->L, f, varname);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   174
  return fs->nlocvars++;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   175
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   176
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   177
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   178
static void new_localvar (LexState *ls, TString *name) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   179
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   180
  Dyndata *dyd = ls->dyd;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   181
  int reg = registerlocalvar(ls, name);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   182
  checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   183
                  MAXVARS, "local variables");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   184
  luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   185
                  dyd->actvar.size, Vardesc, MAX_INT, "local variables");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   186
  dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   187
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   188
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   189
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   190
static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   191
  new_localvar(ls, luaX_newstring(ls, name, sz));
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   192
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   193
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   194
#define new_localvarliteral(ls,v) \
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   195
	new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   196
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   197
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   198
static LocVar *getlocvar (FuncState *fs, int i) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   199
  int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   200
  lua_assert(idx < fs->nlocvars);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   201
  return &fs->f->locvars[idx];
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   202
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   203
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   204
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   205
static void adjustlocalvars (LexState *ls, int nvars) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   206
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   207
  fs->nactvar = cast_byte(fs->nactvar + nvars);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   208
  for (; nvars; nvars--) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   209
    getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   210
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   211
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   212
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   213
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   214
static void removevars (FuncState *fs, int tolevel) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   215
  fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   216
  while (fs->nactvar > tolevel)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   217
    getlocvar(fs, --fs->nactvar)->endpc = fs->pc;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   218
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   219
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   220
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   221
static int searchupvalue (FuncState *fs, TString *name) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   222
  int i;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   223
  Upvaldesc *up = fs->f->upvalues;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   224
  for (i = 0; i < fs->nups; i++) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   225
    if (luaS_eqstr(up[i].name, name)) return i;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   226
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   227
  return -1;  /* not found */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   228
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   229
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   230
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   231
static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   232
  Proto *f = fs->f;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   233
  int oldsize = f->sizeupvalues;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   234
  checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   235
  luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   236
                  Upvaldesc, MAXUPVAL, "upvalues");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   237
  while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   238
  f->upvalues[fs->nups].instack = (v->k == VLOCAL);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   239
  f->upvalues[fs->nups].idx = cast_byte(v->u.info);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   240
  f->upvalues[fs->nups].name = name;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   241
  luaC_objbarrier(fs->ls->L, f, name);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   242
  return fs->nups++;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   243
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   244
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   245
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   246
static int searchvar (FuncState *fs, TString *n) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   247
  int i;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   248
  for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   249
    if (luaS_eqstr(n, getlocvar(fs, i)->varname))
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   250
      return i;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   251
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   252
  return -1;  /* not found */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   253
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   254
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   255
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   256
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   257
  Mark block where variable at given level was defined
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   258
  (to emit close instructions later).
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   259
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   260
static void markupval (FuncState *fs, int level) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   261
  BlockCnt *bl = fs->bl;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   262
  while (bl->nactvar > level) bl = bl->previous;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   263
  bl->upval = 1;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   264
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   265
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   266
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   267
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   268
  Find variable with given name 'n'. If it is an upvalue, add this
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   269
  upvalue into all intermediate functions.
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   270
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   271
static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   272
  if (fs == NULL)  /* no more levels? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   273
    return VVOID;  /* default is global */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   274
  else {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   275
    int v = searchvar(fs, n);  /* look up locals at current level */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   276
    if (v >= 0) {  /* found? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   277
      init_exp(var, VLOCAL, v);  /* variable is local */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   278
      if (!base)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   279
        markupval(fs, v);  /* local will be used as an upval */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   280
      return VLOCAL;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   281
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   282
    else {  /* not found as local at current level; try upvalues */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   283
      int idx = searchupvalue(fs, n);  /* try existing upvalues */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   284
      if (idx < 0) {  /* not found? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   285
        if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   286
          return VVOID;  /* not found; is a global */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   287
        /* else was LOCAL or UPVAL */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   288
        idx  = newupvalue(fs, n, var);  /* will be a new upvalue */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   289
      }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   290
      init_exp(var, VUPVAL, idx);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   291
      return VUPVAL;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   292
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   293
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   294
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   295
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   296
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   297
static void singlevar (LexState *ls, expdesc *var) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   298
  TString *varname = str_checkname(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   299
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   300
  if (singlevaraux(fs, varname, var, 1) == VVOID) {  /* global name? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   301
    expdesc key;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   302
    singlevaraux(fs, ls->envn, var, 1);  /* get environment variable */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   303
    lua_assert(var->k == VLOCAL || var->k == VUPVAL);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   304
    codestring(ls, &key, varname);  /* key is variable name */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   305
    luaK_indexed(fs, var, &key);  /* env[varname] */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   306
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   307
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   308
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   309
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   310
static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   311
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   312
  int extra = nvars - nexps;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   313
  if (hasmultret(e->k)) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   314
    extra++;  /* includes call itself */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   315
    if (extra < 0) extra = 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   316
    luaK_setreturns(fs, e, extra);  /* last exp. provides the difference */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   317
    if (extra > 1) luaK_reserveregs(fs, extra-1);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   318
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   319
  else {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   320
    if (e->k != VVOID) luaK_exp2nextreg(fs, e);  /* close last expression */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   321
    if (extra > 0) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   322
      int reg = fs->freereg;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   323
      luaK_reserveregs(fs, extra);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   324
      luaK_nil(fs, reg, extra);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   325
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   326
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   327
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   328
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   329
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   330
static void enterlevel (LexState *ls) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   331
  lua_State *L = ls->L;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   332
  ++L->nCcalls;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   333
  checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   334
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   335
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   336
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   337
#define leavelevel(ls)	((ls)->L->nCcalls--)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   338
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   339
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   340
static void closegoto (LexState *ls, int g, Labeldesc *label) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   341
  int i;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   342
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   343
  Labellist *gl = &ls->dyd->gt;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   344
  Labeldesc *gt = &gl->arr[g];
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   345
  lua_assert(luaS_eqstr(gt->name, label->name));
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   346
  if (gt->nactvar < label->nactvar) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   347
    TString *vname = getlocvar(fs, gt->nactvar)->varname;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   348
    const char *msg = luaO_pushfstring(ls->L,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   349
      "<goto %s> at line %d jumps into the scope of local " LUA_QS,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   350
      getstr(gt->name), gt->line, getstr(vname));
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   351
    semerror(ls, msg);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   352
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   353
  luaK_patchlist(fs, gt->pc, label->pc);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   354
  /* remove goto from pending list */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   355
  for (i = g; i < gl->n - 1; i++)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   356
    gl->arr[i] = gl->arr[i + 1];
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   357
  gl->n--;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   358
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   359
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   360
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   361
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   362
** try to close a goto with existing labels; this solves backward jumps
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   363
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   364
static int findlabel (LexState *ls, int g) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   365
  int i;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   366
  BlockCnt *bl = ls->fs->bl;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   367
  Dyndata *dyd = ls->dyd;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   368
  Labeldesc *gt = &dyd->gt.arr[g];
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   369
  /* check labels in current block for a match */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   370
  for (i = bl->firstlabel; i < dyd->label.n; i++) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   371
    Labeldesc *lb = &dyd->label.arr[i];
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   372
    if (luaS_eqstr(lb->name, gt->name)) {  /* correct label? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   373
      if (gt->nactvar > lb->nactvar &&
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   374
          (bl->upval || dyd->label.n > bl->firstlabel))
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   375
        luaK_patchclose(ls->fs, gt->pc, lb->nactvar);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   376
      closegoto(ls, g, lb);  /* close it */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   377
      return 1;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   378
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   379
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   380
  return 0;  /* label not found; cannot close goto */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   381
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   382
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   383
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   384
static int newlabelentry (LexState *ls, Labellist *l, TString *name,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   385
                          int line, int pc) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   386
  int n = l->n;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   387
  luaM_growvector(ls->L, l->arr, n, l->size,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   388
                  Labeldesc, SHRT_MAX, "labels/gotos");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   389
  l->arr[n].name = name;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   390
  l->arr[n].line = line;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   391
  l->arr[n].nactvar = ls->fs->nactvar;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   392
  l->arr[n].pc = pc;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   393
  l->n++;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   394
  return n;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   395
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   396
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   397
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   398
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   399
** check whether new label 'lb' matches any pending gotos in current
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   400
** block; solves forward jumps
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   401
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   402
static void findgotos (LexState *ls, Labeldesc *lb) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   403
  Labellist *gl = &ls->dyd->gt;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   404
  int i = ls->fs->bl->firstgoto;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   405
  while (i < gl->n) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   406
    if (luaS_eqstr(gl->arr[i].name, lb->name))
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   407
      closegoto(ls, i, lb);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   408
    else
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   409
      i++;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   410
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   411
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   412
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   413
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   414
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   415
** "export" pending gotos to outer level, to check them against
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   416
** outer labels; if the block being exited has upvalues, and
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   417
** the goto exits the scope of any variable (which can be the
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   418
** upvalue), close those variables being exited.
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   419
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   420
static void movegotosout (FuncState *fs, BlockCnt *bl) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   421
  int i = bl->firstgoto;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   422
  Labellist *gl = &fs->ls->dyd->gt;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   423
  /* correct pending gotos to current block and try to close it
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   424
     with visible labels */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   425
  while (i < gl->n) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   426
    Labeldesc *gt = &gl->arr[i];
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   427
    if (gt->nactvar > bl->nactvar) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   428
      if (bl->upval)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   429
        luaK_patchclose(fs, gt->pc, bl->nactvar);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   430
      gt->nactvar = bl->nactvar;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   431
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   432
    if (!findlabel(fs->ls, i))
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   433
      i++;  /* move to next one */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   434
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   435
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   436
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   437
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   438
static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   439
  bl->isloop = isloop;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   440
  bl->nactvar = fs->nactvar;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   441
  bl->firstlabel = fs->ls->dyd->label.n;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   442
  bl->firstgoto = fs->ls->dyd->gt.n;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   443
  bl->upval = 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   444
  bl->previous = fs->bl;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   445
  fs->bl = bl;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   446
  lua_assert(fs->freereg == fs->nactvar);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   447
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   448
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   449
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   450
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   451
** create a label named "break" to resolve break statements
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   452
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   453
static void breaklabel (LexState *ls) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   454
  TString *n = luaS_new(ls->L, "break");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   455
  int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   456
  findgotos(ls, &ls->dyd->label.arr[l]);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   457
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   458
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   459
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   460
** generates an error for an undefined 'goto'; choose appropriate
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   461
** message when label name is a reserved word (which can only be 'break')
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   462
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   463
static l_noret undefgoto (LexState *ls, Labeldesc *gt) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   464
  const char *msg = isreserved(gt->name)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   465
                    ? "<%s> at line %d not inside a loop"
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   466
                    : "no visible label " LUA_QS " for <goto> at line %d";
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   467
  msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   468
  semerror(ls, msg);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   469
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   470
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   471
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   472
static void leaveblock (FuncState *fs) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   473
  BlockCnt *bl = fs->bl;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   474
  LexState *ls = fs->ls;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   475
  if (bl->previous && bl->upval) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   476
    /* create a 'jump to here' to close upvalues */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   477
    int j = luaK_jump(fs);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   478
    luaK_patchclose(fs, j, bl->nactvar);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   479
    luaK_patchtohere(fs, j);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   480
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   481
  if (bl->isloop)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   482
    breaklabel(ls);  /* close pending breaks */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   483
  fs->bl = bl->previous;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   484
  removevars(fs, bl->nactvar);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   485
  lua_assert(bl->nactvar == fs->nactvar);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   486
  fs->freereg = fs->nactvar;  /* free registers */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   487
  ls->dyd->label.n = bl->firstlabel;  /* remove local labels */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   488
  if (bl->previous)  /* inner block? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   489
    movegotosout(fs, bl);  /* update pending gotos to outer block */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   490
  else if (bl->firstgoto < ls->dyd->gt.n)  /* pending gotos in outer block? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   491
    undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]);  /* error */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   492
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   493
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   494
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   495
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   496
** adds a new prototype into list of prototypes
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   497
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   498
static Proto *addprototype (LexState *ls) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   499
  Proto *clp;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   500
  lua_State *L = ls->L;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   501
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   502
  Proto *f = fs->f;  /* prototype of current function */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   503
  if (fs->np >= f->sizep) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   504
    int oldsize = f->sizep;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   505
    luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   506
    while (oldsize < f->sizep) f->p[oldsize++] = NULL;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   507
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   508
  f->p[fs->np++] = clp = luaF_newproto(L);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   509
  luaC_objbarrier(L, f, clp);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   510
  return clp;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   511
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   512
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   513
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   514
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   515
** codes instruction to create new closure in parent function.
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   516
** The OP_CLOSURE instruction must use the last available register,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   517
** so that, if it invokes the GC, the GC knows which registers
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   518
** are in use at that time.
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   519
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   520
static void codeclosure (LexState *ls, expdesc *v) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   521
  FuncState *fs = ls->fs->prev;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   522
  init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1));
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   523
  luaK_exp2nextreg(fs, v);  /* fix it at the last register */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   524
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   525
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   526
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   527
static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   528
  lua_State *L = ls->L;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   529
  Proto *f;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   530
  fs->prev = ls->fs;  /* linked list of funcstates */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   531
  fs->ls = ls;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   532
  ls->fs = fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   533
  fs->pc = 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   534
  fs->lasttarget = 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   535
  fs->jpc = NO_JUMP;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   536
  fs->freereg = 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   537
  fs->nk = 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   538
  fs->np = 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   539
  fs->nups = 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   540
  fs->nlocvars = 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   541
  fs->nactvar = 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   542
  fs->firstlocal = ls->dyd->actvar.n;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   543
  fs->bl = NULL;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   544
  f = fs->f;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   545
  f->source = ls->source;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   546
  f->maxstacksize = 2;  /* registers 0/1 are always valid */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   547
  fs->h = luaH_new(L);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   548
  /* anchor table of constants (to avoid being collected) */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   549
  sethvalue2s(L, L->top, fs->h);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   550
  incr_top(L);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   551
  enterblock(fs, bl, 0);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   552
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   553
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   554
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   555
static void close_func (LexState *ls) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   556
  lua_State *L = ls->L;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   557
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   558
  Proto *f = fs->f;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   559
  luaK_ret(fs, 0, 0);  /* final return */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   560
  leaveblock(fs);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   561
  luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   562
  f->sizecode = fs->pc;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   563
  luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   564
  f->sizelineinfo = fs->pc;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   565
  luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   566
  f->sizek = fs->nk;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   567
  luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   568
  f->sizep = fs->np;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   569
  luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   570
  f->sizelocvars = fs->nlocvars;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   571
  luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   572
  f->sizeupvalues = fs->nups;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   573
  lua_assert(fs->bl == NULL);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   574
  ls->fs = fs->prev;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   575
  /* last token read was anchored in defunct function; must re-anchor it */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   576
  anchor_token(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   577
  L->top--;  /* pop table of constants */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   578
  luaC_checkGC(L);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   579
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   580
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   581
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   582
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   583
/*============================================================*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   584
/* GRAMMAR RULES */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   585
/*============================================================*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   586
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   587
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   588
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   589
** check whether current token is in the follow set of a block.
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   590
** 'until' closes syntactical blocks, but do not close scope,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   591
** so it handled in separate.
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   592
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   593
static int block_follow (LexState *ls, int withuntil) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   594
  switch (ls->t.token) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   595
    case TK_ELSE: case TK_ELSEIF:
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   596
    case TK_END: case TK_EOS:
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   597
      return 1;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   598
    case TK_UNTIL: return withuntil;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   599
    default: return 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   600
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   601
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   602
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   603
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   604
static void statlist (LexState *ls) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   605
  /* statlist -> { stat [`;'] } */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   606
  while (!block_follow(ls, 1)) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   607
    if (ls->t.token == TK_RETURN) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   608
      statement(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   609
      return;  /* 'return' must be last statement */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   610
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   611
    statement(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   612
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   613
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   614
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   615
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   616
static void fieldsel (LexState *ls, expdesc *v) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   617
  /* fieldsel -> ['.' | ':'] NAME */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   618
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   619
  expdesc key;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   620
  luaK_exp2anyregup(fs, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   621
  luaX_next(ls);  /* skip the dot or colon */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   622
  checkname(ls, &key);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   623
  luaK_indexed(fs, v, &key);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   624
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   625
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   626
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   627
static void yindex (LexState *ls, expdesc *v) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   628
  /* index -> '[' expr ']' */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   629
  luaX_next(ls);  /* skip the '[' */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   630
  expr(ls, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   631
  luaK_exp2val(ls->fs, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   632
  checknext(ls, ']');
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   633
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   634
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   635
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   636
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   637
** {======================================================================
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   638
** Rules for Constructors
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   639
** =======================================================================
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   640
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   641
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   642
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   643
struct ConsControl {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   644
  expdesc v;  /* last list item read */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   645
  expdesc *t;  /* table descriptor */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   646
  int nh;  /* total number of `record' elements */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   647
  int na;  /* total number of array elements */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   648
  int tostore;  /* number of array elements pending to be stored */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   649
};
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   650
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   651
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   652
static void recfield (LexState *ls, struct ConsControl *cc) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   653
  /* recfield -> (NAME | `['exp1`]') = exp1 */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   654
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   655
  int reg = ls->fs->freereg;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   656
  expdesc key, val;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   657
  int rkkey;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   658
  if (ls->t.token == TK_NAME) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   659
    checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   660
    checkname(ls, &key);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   661
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   662
  else  /* ls->t.token == '[' */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   663
    yindex(ls, &key);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   664
  cc->nh++;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   665
  checknext(ls, '=');
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   666
  rkkey = luaK_exp2RK(fs, &key);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   667
  expr(ls, &val);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   668
  luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val));
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   669
  fs->freereg = reg;  /* free registers */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   670
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   671
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   672
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   673
static void closelistfield (FuncState *fs, struct ConsControl *cc) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   674
  if (cc->v.k == VVOID) return;  /* there is no list item */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   675
  luaK_exp2nextreg(fs, &cc->v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   676
  cc->v.k = VVOID;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   677
  if (cc->tostore == LFIELDS_PER_FLUSH) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   678
    luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore);  /* flush */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   679
    cc->tostore = 0;  /* no more items pending */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   680
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   681
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   682
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   683
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   684
static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   685
  if (cc->tostore == 0) return;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   686
  if (hasmultret(cc->v.k)) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   687
    luaK_setmultret(fs, &cc->v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   688
    luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   689
    cc->na--;  /* do not count last expression (unknown number of elements) */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   690
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   691
  else {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   692
    if (cc->v.k != VVOID)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   693
      luaK_exp2nextreg(fs, &cc->v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   694
    luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   695
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   696
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   697
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   698
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   699
static void listfield (LexState *ls, struct ConsControl *cc) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   700
  /* listfield -> exp */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   701
  expr(ls, &cc->v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   702
  checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   703
  cc->na++;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   704
  cc->tostore++;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   705
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   706
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   707
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   708
static void field (LexState *ls, struct ConsControl *cc) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   709
  /* field -> listfield | recfield */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   710
  switch(ls->t.token) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   711
    case TK_NAME: {  /* may be 'listfield' or 'recfield' */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   712
      if (luaX_lookahead(ls) != '=')  /* expression? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   713
        listfield(ls, cc);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   714
      else
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   715
        recfield(ls, cc);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   716
      break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   717
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   718
    case '[': {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   719
      recfield(ls, cc);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   720
      break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   721
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   722
    default: {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   723
      listfield(ls, cc);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   724
      break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   725
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   726
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   727
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   728
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   729
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   730
static void constructor (LexState *ls, expdesc *t) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   731
  /* constructor -> '{' [ field { sep field } [sep] ] '}'
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   732
     sep -> ',' | ';' */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   733
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   734
  int line = ls->linenumber;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   735
  int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   736
  struct ConsControl cc;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   737
  cc.na = cc.nh = cc.tostore = 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   738
  cc.t = t;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   739
  init_exp(t, VRELOCABLE, pc);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   740
  init_exp(&cc.v, VVOID, 0);  /* no value (yet) */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   741
  luaK_exp2nextreg(ls->fs, t);  /* fix it at stack top */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   742
  checknext(ls, '{');
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   743
  do {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   744
    lua_assert(cc.v.k == VVOID || cc.tostore > 0);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   745
    if (ls->t.token == '}') break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   746
    closelistfield(fs, &cc);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   747
    field(ls, &cc);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   748
  } while (testnext(ls, ',') || testnext(ls, ';'));
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   749
  check_match(ls, '}', '{', line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   750
  lastlistfield(fs, &cc);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   751
  SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   752
  SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh));  /* set initial table size */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   753
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   754
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   755
/* }====================================================================== */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   756
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   757
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   758
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   759
static void parlist (LexState *ls) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   760
  /* parlist -> [ param { `,' param } ] */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   761
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   762
  Proto *f = fs->f;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   763
  int nparams = 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   764
  f->is_vararg = 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   765
  if (ls->t.token != ')') {  /* is `parlist' not empty? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   766
    do {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   767
      switch (ls->t.token) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   768
        case TK_NAME: {  /* param -> NAME */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   769
          new_localvar(ls, str_checkname(ls));
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   770
          nparams++;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   771
          break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   772
        }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   773
        case TK_DOTS: {  /* param -> `...' */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   774
          luaX_next(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   775
          f->is_vararg = 1;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   776
          break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   777
        }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   778
        default: luaX_syntaxerror(ls, "<name> or " LUA_QL("...") " expected");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   779
      }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   780
    } while (!f->is_vararg && testnext(ls, ','));
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   781
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   782
  adjustlocalvars(ls, nparams);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   783
  f->numparams = cast_byte(fs->nactvar);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   784
  luaK_reserveregs(fs, fs->nactvar);  /* reserve register for parameters */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   785
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   786
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   787
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   788
static void body (LexState *ls, expdesc *e, int ismethod, int line) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   789
  /* body ->  `(' parlist `)' block END */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   790
  FuncState new_fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   791
  BlockCnt bl;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   792
  new_fs.f = addprototype(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   793
  new_fs.f->linedefined = line;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   794
  open_func(ls, &new_fs, &bl);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   795
  checknext(ls, '(');
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   796
  if (ismethod) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   797
    new_localvarliteral(ls, "self");  /* create 'self' parameter */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   798
    adjustlocalvars(ls, 1);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   799
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   800
  parlist(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   801
  checknext(ls, ')');
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   802
  statlist(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   803
  new_fs.f->lastlinedefined = ls->linenumber;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   804
  check_match(ls, TK_END, TK_FUNCTION, line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   805
  codeclosure(ls, e);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   806
  close_func(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   807
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   808
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   809
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   810
static int explist (LexState *ls, expdesc *v) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   811
  /* explist -> expr { `,' expr } */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   812
  int n = 1;  /* at least one expression */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   813
  expr(ls, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   814
  while (testnext(ls, ',')) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   815
    luaK_exp2nextreg(ls->fs, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   816
    expr(ls, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   817
    n++;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   818
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   819
  return n;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   820
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   821
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   822
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   823
static void funcargs (LexState *ls, expdesc *f, int line) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   824
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   825
  expdesc args;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   826
  int base, nparams;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   827
  switch (ls->t.token) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   828
    case '(': {  /* funcargs -> `(' [ explist ] `)' */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   829
      luaX_next(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   830
      if (ls->t.token == ')')  /* arg list is empty? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   831
        args.k = VVOID;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   832
      else {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   833
        explist(ls, &args);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   834
        luaK_setmultret(fs, &args);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   835
      }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   836
      check_match(ls, ')', '(', line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   837
      break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   838
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   839
    case '{': {  /* funcargs -> constructor */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   840
      constructor(ls, &args);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   841
      break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   842
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   843
    case TK_STRING: {  /* funcargs -> STRING */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   844
      codestring(ls, &args, ls->t.seminfo.ts);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   845
      luaX_next(ls);  /* must use `seminfo' before `next' */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   846
      break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   847
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   848
    default: {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   849
      luaX_syntaxerror(ls, "function arguments expected");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   850
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   851
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   852
  lua_assert(f->k == VNONRELOC);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   853
  base = f->u.info;  /* base register for call */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   854
  if (hasmultret(args.k))
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   855
    nparams = LUA_MULTRET;  /* open call */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   856
  else {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   857
    if (args.k != VVOID)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   858
      luaK_exp2nextreg(fs, &args);  /* close last argument */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   859
    nparams = fs->freereg - (base+1);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   860
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   861
  init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   862
  luaK_fixline(fs, line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   863
  fs->freereg = base+1;  /* call remove function and arguments and leaves
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   864
                            (unless changed) one result */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   865
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   866
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   867
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   868
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   869
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   870
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   871
** {======================================================================
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   872
** Expression parsing
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   873
** =======================================================================
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   874
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   875
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   876
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   877
static void primaryexp (LexState *ls, expdesc *v) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   878
  /* primaryexp -> NAME | '(' expr ')' */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   879
  switch (ls->t.token) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   880
    case '(': {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   881
      int line = ls->linenumber;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   882
      luaX_next(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   883
      expr(ls, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   884
      check_match(ls, ')', '(', line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   885
      luaK_dischargevars(ls->fs, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   886
      return;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   887
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   888
    case TK_NAME: {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   889
      singlevar(ls, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   890
      return;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   891
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   892
    default: {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   893
      luaX_syntaxerror(ls, "unexpected symbol");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   894
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   895
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   896
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   897
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   898
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   899
static void suffixedexp (LexState *ls, expdesc *v) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   900
  /* suffixedexp ->
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   901
       primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   902
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   903
  int line = ls->linenumber;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   904
  primaryexp(ls, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   905
  for (;;) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   906
    switch (ls->t.token) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   907
      case '.': {  /* fieldsel */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   908
        fieldsel(ls, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   909
        break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   910
      }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   911
      case '[': {  /* `[' exp1 `]' */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   912
        expdesc key;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   913
        luaK_exp2anyregup(fs, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   914
        yindex(ls, &key);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   915
        luaK_indexed(fs, v, &key);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   916
        break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   917
      }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   918
      case ':': {  /* `:' NAME funcargs */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   919
        expdesc key;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   920
        luaX_next(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   921
        checkname(ls, &key);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   922
        luaK_self(fs, v, &key);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   923
        funcargs(ls, v, line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   924
        break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   925
      }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   926
      case '(': case TK_STRING: case '{': {  /* funcargs */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   927
        luaK_exp2nextreg(fs, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   928
        funcargs(ls, v, line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   929
        break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   930
      }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   931
      default: return;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   932
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   933
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   934
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   935
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   936
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   937
static void simpleexp (LexState *ls, expdesc *v) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   938
  /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... |
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   939
                  constructor | FUNCTION body | suffixedexp */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   940
  switch (ls->t.token) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   941
    case TK_NUMBER: {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   942
      init_exp(v, VKNUM, 0);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   943
      v->u.nval = ls->t.seminfo.r;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   944
      break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   945
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   946
    case TK_STRING: {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   947
      codestring(ls, v, ls->t.seminfo.ts);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   948
      break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   949
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   950
    case TK_NIL: {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   951
      init_exp(v, VNIL, 0);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   952
      break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   953
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   954
    case TK_TRUE: {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   955
      init_exp(v, VTRUE, 0);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   956
      break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   957
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   958
    case TK_FALSE: {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   959
      init_exp(v, VFALSE, 0);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   960
      break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   961
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   962
    case TK_DOTS: {  /* vararg */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   963
      FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   964
      check_condition(ls, fs->f->is_vararg,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   965
                      "cannot use " LUA_QL("...") " outside a vararg function");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   966
      init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   967
      break;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   968
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   969
    case '{': {  /* constructor */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   970
      constructor(ls, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   971
      return;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   972
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   973
    case TK_FUNCTION: {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   974
      luaX_next(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   975
      body(ls, v, 0, ls->linenumber);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   976
      return;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   977
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   978
    default: {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   979
      suffixedexp(ls, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   980
      return;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   981
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   982
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   983
  luaX_next(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   984
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   985
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   986
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   987
static UnOpr getunopr (int op) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   988
  switch (op) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   989
    case TK_NOT: return OPR_NOT;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   990
    case '-': return OPR_MINUS;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   991
    case '#': return OPR_LEN;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   992
    default: return OPR_NOUNOPR;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   993
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   994
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   995
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   996
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   997
static BinOpr getbinopr (int op) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   998
  switch (op) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   999
    case '+': return OPR_ADD;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1000
    case '-': return OPR_SUB;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1001
    case '*': return OPR_MUL;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1002
    case '/': return OPR_DIV;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1003
    case '%': return OPR_MOD;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1004
    case '^': return OPR_POW;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1005
    case TK_CONCAT: return OPR_CONCAT;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1006
    case TK_NE: return OPR_NE;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1007
    case TK_EQ: return OPR_EQ;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1008
    case '<': return OPR_LT;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1009
    case TK_LE: return OPR_LE;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1010
    case '>': return OPR_GT;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1011
    case TK_GE: return OPR_GE;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1012
    case TK_AND: return OPR_AND;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1013
    case TK_OR: return OPR_OR;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1014
    default: return OPR_NOBINOPR;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1015
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1016
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1017
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1018
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1019
static const struct {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1020
  lu_byte left;  /* left priority for each binary operator */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1021
  lu_byte right; /* right priority */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1022
} priority[] = {  /* ORDER OPR */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1023
   {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7},  /* `+' `-' `*' `/' `%' */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1024
   {10, 9}, {5, 4},                 /* ^, .. (right associative) */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1025
   {3, 3}, {3, 3}, {3, 3},          /* ==, <, <= */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1026
   {3, 3}, {3, 3}, {3, 3},          /* ~=, >, >= */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1027
   {2, 2}, {1, 1}                   /* and, or */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1028
};
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1029
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1030
#define UNARY_PRIORITY	8  /* priority for unary operators */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1031
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1032
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1033
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1034
** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1035
** where `binop' is any binary operator with a priority higher than `limit'
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1036
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1037
static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1038
  BinOpr op;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1039
  UnOpr uop;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1040
  enterlevel(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1041
  uop = getunopr(ls->t.token);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1042
  if (uop != OPR_NOUNOPR) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1043
    int line = ls->linenumber;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1044
    luaX_next(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1045
    subexpr(ls, v, UNARY_PRIORITY);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1046
    luaK_prefix(ls->fs, uop, v, line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1047
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1048
  else simpleexp(ls, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1049
  /* expand while operators have priorities higher than `limit' */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1050
  op = getbinopr(ls->t.token);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1051
  while (op != OPR_NOBINOPR && priority[op].left > limit) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1052
    expdesc v2;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1053
    BinOpr nextop;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1054
    int line = ls->linenumber;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1055
    luaX_next(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1056
    luaK_infix(ls->fs, op, v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1057
    /* read sub-expression with higher priority */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1058
    nextop = subexpr(ls, &v2, priority[op].right);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1059
    luaK_posfix(ls->fs, op, v, &v2, line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1060
    op = nextop;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1061
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1062
  leavelevel(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1063
  return op;  /* return first untreated operator */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1064
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1065
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1066
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1067
static void expr (LexState *ls, expdesc *v) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1068
  subexpr(ls, v, 0);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1069
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1070
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1071
/* }==================================================================== */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1072
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1073
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1074
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1075
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1076
** {======================================================================
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1077
** Rules for Statements
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1078
** =======================================================================
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1079
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1080
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1081
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1082
static void block (LexState *ls) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1083
  /* block -> statlist */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1084
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1085
  BlockCnt bl;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1086
  enterblock(fs, &bl, 0);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1087
  statlist(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1088
  leaveblock(fs);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1089
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1090
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1091
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1092
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1093
** structure to chain all variables in the left-hand side of an
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1094
** assignment
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1095
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1096
struct LHS_assign {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1097
  struct LHS_assign *prev;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1098
  expdesc v;  /* variable (global, local, upvalue, or indexed) */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1099
};
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1100
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1101
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1102
/*
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1103
** check whether, in an assignment to an upvalue/local variable, the
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1104
** upvalue/local variable is begin used in a previous assignment to a
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1105
** table. If so, save original upvalue/local value in a safe place and
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1106
** use this safe copy in the previous assignment.
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1107
*/
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1108
static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1109
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1110
  int extra = fs->freereg;  /* eventual position to save local variable */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1111
  int conflict = 0;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1112
  for (; lh; lh = lh->prev) {  /* check all previous assignments */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1113
    if (lh->v.k == VINDEXED) {  /* assigning to a table? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1114
      /* table is the upvalue/local being assigned now? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1115
      if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1116
        conflict = 1;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1117
        lh->v.u.ind.vt = VLOCAL;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1118
        lh->v.u.ind.t = extra;  /* previous assignment will use safe copy */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1119
      }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1120
      /* index is the local being assigned? (index cannot be upvalue) */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1121
      if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1122
        conflict = 1;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1123
        lh->v.u.ind.idx = extra;  /* previous assignment will use safe copy */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1124
      }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1125
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1126
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1127
  if (conflict) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1128
    /* copy upvalue/local value to a temporary (in position 'extra') */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1129
    OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1130
    luaK_codeABC(fs, op, extra, v->u.info, 0);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1131
    luaK_reserveregs(fs, 1);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1132
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1133
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1134
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1135
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1136
static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1137
  expdesc e;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1138
  check_condition(ls, vkisvar(lh->v.k), "syntax error");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1139
  if (testnext(ls, ',')) {  /* assignment -> ',' suffixedexp assignment */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1140
    struct LHS_assign nv;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1141
    nv.prev = lh;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1142
    suffixedexp(ls, &nv.v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1143
    if (nv.v.k != VINDEXED)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1144
      check_conflict(ls, lh, &nv.v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1145
    checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1146
                    "C levels");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1147
    assignment(ls, &nv, nvars+1);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1148
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1149
  else {  /* assignment -> `=' explist */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1150
    int nexps;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1151
    checknext(ls, '=');
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1152
    nexps = explist(ls, &e);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1153
    if (nexps != nvars) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1154
      adjust_assign(ls, nvars, nexps, &e);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1155
      if (nexps > nvars)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1156
        ls->fs->freereg -= nexps - nvars;  /* remove extra values */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1157
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1158
    else {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1159
      luaK_setoneret(ls->fs, &e);  /* close last expression */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1160
      luaK_storevar(ls->fs, &lh->v, &e);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1161
      return;  /* avoid default */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1162
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1163
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1164
  init_exp(&e, VNONRELOC, ls->fs->freereg-1);  /* default assignment */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1165
  luaK_storevar(ls->fs, &lh->v, &e);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1166
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1167
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1168
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1169
static int cond (LexState *ls) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1170
  /* cond -> exp */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1171
  expdesc v;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1172
  expr(ls, &v);  /* read condition */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1173
  if (v.k == VNIL) v.k = VFALSE;  /* `falses' are all equal here */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1174
  luaK_goiftrue(ls->fs, &v);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1175
  return v.f;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1176
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1177
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1178
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1179
static void gotostat (LexState *ls, int pc) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1180
  int line = ls->linenumber;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1181
  TString *label;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1182
  int g;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1183
  if (testnext(ls, TK_GOTO))
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1184
    label = str_checkname(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1185
  else {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1186
    luaX_next(ls);  /* skip break */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1187
    label = luaS_new(ls->L, "break");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1188
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1189
  g = newlabelentry(ls, &ls->dyd->gt, label, line, pc);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1190
  findlabel(ls, g);  /* close it if label already defined */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1191
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1192
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1193
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1194
/* check for repeated labels on the same block */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1195
static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1196
  int i;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1197
  for (i = fs->bl->firstlabel; i < ll->n; i++) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1198
    if (luaS_eqstr(label, ll->arr[i].name)) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1199
      const char *msg = luaO_pushfstring(fs->ls->L,
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1200
                          "label " LUA_QS " already defined on line %d",
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1201
                          getstr(label), ll->arr[i].line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1202
      semerror(fs->ls, msg);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1203
    }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1204
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1205
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1206
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1207
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1208
/* skip no-op statements */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1209
static void skipnoopstat (LexState *ls) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1210
  while (ls->t.token == ';' || ls->t.token == TK_DBCOLON)
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1211
    statement(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1212
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1213
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1214
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1215
static void labelstat (LexState *ls, TString *label, int line) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1216
  /* label -> '::' NAME '::' */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1217
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1218
  Labellist *ll = &ls->dyd->label;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1219
  int l;  /* index of new label being created */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1220
  checkrepeated(fs, ll, label);  /* check for repeated labels */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1221
  checknext(ls, TK_DBCOLON);  /* skip double colon */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1222
  /* create new entry for this label */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1223
  l = newlabelentry(ls, ll, label, line, fs->pc);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1224
  skipnoopstat(ls);  /* skip other no-op statements */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1225
  if (block_follow(ls, 0)) {  /* label is last no-op statement in the block? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1226
    /* assume that locals are already out of scope */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1227
    ll->arr[l].nactvar = fs->bl->nactvar;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1228
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1229
  findgotos(ls, &ll->arr[l]);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1230
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1231
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1232
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1233
static void whilestat (LexState *ls, int line) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1234
  /* whilestat -> WHILE cond DO block END */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1235
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1236
  int whileinit;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1237
  int condexit;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1238
  BlockCnt bl;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1239
  luaX_next(ls);  /* skip WHILE */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1240
  whileinit = luaK_getlabel(fs);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1241
  condexit = cond(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1242
  enterblock(fs, &bl, 1);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1243
  checknext(ls, TK_DO);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1244
  block(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1245
  luaK_jumpto(fs, whileinit);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1246
  check_match(ls, TK_END, TK_WHILE, line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1247
  leaveblock(fs);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1248
  luaK_patchtohere(fs, condexit);  /* false conditions finish the loop */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1249
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1250
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1251
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1252
static void repeatstat (LexState *ls, int line) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1253
  /* repeatstat -> REPEAT block UNTIL cond */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1254
  int condexit;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1255
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1256
  int repeat_init = luaK_getlabel(fs);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1257
  BlockCnt bl1, bl2;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1258
  enterblock(fs, &bl1, 1);  /* loop block */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1259
  enterblock(fs, &bl2, 0);  /* scope block */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1260
  luaX_next(ls);  /* skip REPEAT */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1261
  statlist(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1262
  check_match(ls, TK_UNTIL, TK_REPEAT, line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1263
  condexit = cond(ls);  /* read condition (inside scope block) */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1264
  if (bl2.upval)  /* upvalues? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1265
    luaK_patchclose(fs, condexit, bl2.nactvar);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1266
  leaveblock(fs);  /* finish scope */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1267
  luaK_patchlist(fs, condexit, repeat_init);  /* close the loop */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1268
  leaveblock(fs);  /* finish loop */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1269
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1270
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1271
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1272
static int exp1 (LexState *ls) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1273
  expdesc e;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1274
  int reg;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1275
  expr(ls, &e);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1276
  luaK_exp2nextreg(ls->fs, &e);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1277
  lua_assert(e.k == VNONRELOC);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1278
  reg = e.u.info;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1279
  return reg;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1280
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1281
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1282
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1283
static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1284
  /* forbody -> DO block */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1285
  BlockCnt bl;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1286
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1287
  int prep, endfor;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1288
  adjustlocalvars(ls, 3);  /* control variables */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1289
  checknext(ls, TK_DO);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1290
  prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1291
  enterblock(fs, &bl, 0);  /* scope for declared variables */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1292
  adjustlocalvars(ls, nvars);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1293
  luaK_reserveregs(fs, nvars);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1294
  block(ls);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1295
  leaveblock(fs);  /* end of scope for declared variables */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1296
  luaK_patchtohere(fs, prep);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1297
  if (isnum)  /* numeric for? */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1298
    endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1299
  else {  /* generic for */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1300
    luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1301
    luaK_fixline(fs, line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1302
    endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1303
  }
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1304
  luaK_patchlist(fs, endfor, prep + 1);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1305
  luaK_fixline(fs, line);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1306
}
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1307
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1308
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1309
static void fornum (LexState *ls, TString *varname, int line) {
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1310
  /* fornum -> NAME = exp1,exp1[,exp1] forbody */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1311
  FuncState *fs = ls->fs;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1312
  int base = fs->freereg;
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1313
  new_localvarliteral(ls, "(for index)");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1314
  new_localvarliteral(ls, "(for limit)");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1315
  new_localvarliteral(ls, "(for step)");
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1316
  new_localvar(ls, varname);
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1317
  checknext(ls, '=');
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1318
  exp1(ls);  /* initial value */
d7ee4e2ed49d Initial work.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
  1319
  checknext(ls, ',');