diff options
Diffstat (limited to 'src/lj_parse.c')
-rw-r--r-- | src/lj_parse.c | 172 |
1 files changed, 86 insertions, 86 deletions
diff --git a/src/lj_parse.c b/src/lj_parse.c index 96136280..d949698f 100644 --- a/src/lj_parse.c +++ b/src/lj_parse.c | |||
@@ -88,11 +88,15 @@ typedef struct FuncScope { | |||
88 | uint8_t isbreakable; /* Scope is a loop and allows a break. */ | 88 | uint8_t isbreakable; /* Scope is a loop and allows a break. */ |
89 | } FuncScope; | 89 | } FuncScope; |
90 | 90 | ||
91 | /* Upvalue type and location. */ | 91 | /* Index into variable stack. */ |
92 | typedef struct UVLoc { | 92 | typedef uint16_t VarIndex; |
93 | uint8_t k; /* Upvalue type (ExpKind). */ | 93 | #define LJ_MAX_VSTACK 65536 |
94 | uint8_t info; /* Upvalue location (BCReg or uvidx). */ | 94 | |
95 | } UVLoc; | 95 | /* Upvalue map. */ |
96 | typedef struct UVMap { | ||
97 | VarIndex vidx; /* Varinfo index. */ | ||
98 | uint16_t slot; /* Slot or parent upvalue index. */ | ||
99 | } UVMap; | ||
96 | 100 | ||
97 | /* Per-function state. */ | 101 | /* Per-function state. */ |
98 | typedef struct FuncState { | 102 | typedef struct FuncState { |
@@ -108,13 +112,13 @@ typedef struct FuncState { | |||
108 | BCReg freereg; /* First free register. */ | 112 | BCReg freereg; /* First free register. */ |
109 | BCReg nkn, nkgc; /* Number of lua_Number/GCobj constants */ | 113 | BCReg nkn, nkgc; /* Number of lua_Number/GCobj constants */ |
110 | BCLine linedefined; /* First line of the function definition. */ | 114 | BCLine linedefined; /* First line of the function definition. */ |
111 | MSize nvarinfo; /* Number of entries in varinfo. */ | 115 | MSize vbase; /* Base of variable stack for this function. */ |
112 | uint8_t nactvar; /* Number of active local variables. */ | 116 | uint8_t nactvar; /* Number of active local variables. */ |
113 | uint8_t flags; /* Prototype flags. */ | 117 | uint8_t flags; /* Prototype flags. */ |
114 | uint8_t framesize; /* Fixed frame size. */ | 118 | uint8_t framesize; /* Fixed frame size. */ |
115 | uint8_t nuv; /* Number of upvalues */ | 119 | uint8_t nuv; /* Number of upvalues */ |
116 | uint16_t varmap[LJ_MAX_LOCVAR]; /* Map from register to varinfo index. */ | 120 | VarIndex varmap[LJ_MAX_LOCVAR]; /* Map from register to variable idx. */ |
117 | UVLoc uvloc[LJ_MAX_UPVAL]; /* Upvalue type and location. */ | 121 | UVMap uvloc[LJ_MAX_UPVAL]; /* Map from upvalue to variable idx and slot. */ |
118 | } FuncState; | 122 | } FuncState; |
119 | 123 | ||
120 | /* Binary and unary operators. ORDER OPR */ | 124 | /* Binary and unary operators. ORDER OPR */ |
@@ -924,28 +928,27 @@ static GCstr *lex_str(LexState *ls) | |||
924 | 928 | ||
925 | /* -- Variable handling --------------------------------------------------- */ | 929 | /* -- Variable handling --------------------------------------------------- */ |
926 | 930 | ||
927 | #define var_get(fs, i) (proto_varinfo((fs)->pt)[(fs)->varmap[(i)]]) | 931 | #define var_get(ls, fs, i) ((ls)->vstack[(fs)->varmap[(i)]]) |
928 | 932 | ||
929 | /* Define a new local variable. */ | 933 | /* Define a new local variable. */ |
930 | static void var_new(LexState *ls, BCReg n, GCstr *name) | 934 | static void var_new(LexState *ls, BCReg n, GCstr *name) |
931 | { | 935 | { |
932 | FuncState *fs = ls->fs; | 936 | FuncState *fs = ls->fs; |
933 | GCproto *pt = fs->pt; | 937 | MSize vtop = ls->vtop; |
934 | VarInfo *varinfo = proto_varinfo(pt); | ||
935 | checklimit(fs, fs->nactvar+n, LJ_MAX_LOCVAR, "local variables"); | 938 | checklimit(fs, fs->nactvar+n, LJ_MAX_LOCVAR, "local variables"); |
936 | if (LJ_UNLIKELY(fs->nvarinfo >= pt->sizevarinfo)) { | 939 | if (LJ_UNLIKELY(vtop >= ls->sizevstack)) { |
937 | MSize oldsize = pt->sizevarinfo; | 940 | if (ls->sizevstack >= LJ_MAX_VSTACK) |
938 | checklimit(fs, fs->nvarinfo, 32767, "local variables"); | 941 | lj_lex_error(ls, 0, LJ_ERR_XLIMC, LJ_MAX_VSTACK); |
939 | lj_mem_growvec(fs->L, varinfo, pt->sizevarinfo, 32767, VarInfo); | 942 | lj_mem_growvec(ls->L, ls->vstack, ls->sizevstack, LJ_MAX_VSTACK, VarInfo); |
940 | setmref(pt->varinfo, varinfo); | ||
941 | while (oldsize < pt->sizevarinfo) setgcrefnull(varinfo[oldsize++].name); | ||
942 | } | 943 | } |
943 | setgcref(varinfo[fs->nvarinfo].name, obj2gco(name)); | 944 | lua_assert(lj_tab_getstr(fs->kt, name) != NULL); |
944 | lj_gc_objbarrier(ls->L, pt, name); | 945 | /* NOBARRIER: name is anchored in fs->kt and ls->vstack is not a GCobj. */ |
945 | fs->varmap[fs->nactvar+n] = (uint16_t)(fs->nvarinfo++); | 946 | setgcref(ls->vstack[vtop].name, obj2gco(name)); |
947 | fs->varmap[fs->nactvar+n] = (uint16_t)vtop; | ||
948 | ls->vtop = vtop+1; | ||
946 | } | 949 | } |
947 | 950 | ||
948 | #define var_new_lit(ls, v, n) \ | 951 | #define var_new_lit(ls, n, v) \ |
949 | var_new(ls, (n), lj_parse_keepstr(ls, "" v, sizeof(v)-1)) | 952 | var_new(ls, (n), lj_parse_keepstr(ls, "" v, sizeof(v)-1)) |
950 | 953 | ||
951 | /* Add local variables. */ | 954 | /* Add local variables. */ |
@@ -954,7 +957,7 @@ static void var_add(LexState *ls, BCReg nvars) | |||
954 | FuncState *fs = ls->fs; | 957 | FuncState *fs = ls->fs; |
955 | fs->nactvar = cast_byte(fs->nactvar + nvars); | 958 | fs->nactvar = cast_byte(fs->nactvar + nvars); |
956 | for (; nvars; nvars--) | 959 | for (; nvars; nvars--) |
957 | var_get(fs, fs->nactvar - nvars).startpc = fs->pc; | 960 | var_get(ls, fs, fs->nactvar - nvars).startpc = fs->pc; |
958 | } | 961 | } |
959 | 962 | ||
960 | /* Remove local variables. */ | 963 | /* Remove local variables. */ |
@@ -962,7 +965,7 @@ static void var_remove(LexState *ls, BCReg tolevel) | |||
962 | { | 965 | { |
963 | FuncState *fs = ls->fs; | 966 | FuncState *fs = ls->fs; |
964 | while (fs->nactvar > tolevel) | 967 | while (fs->nactvar > tolevel) |
965 | var_get(fs, --fs->nactvar).endpc = fs->pc; | 968 | var_get(ls, fs, --fs->nactvar).endpc = fs->pc; |
966 | } | 969 | } |
967 | 970 | ||
968 | /* Lookup local variable name. */ | 971 | /* Lookup local variable name. */ |
@@ -970,46 +973,33 @@ static BCReg var_lookup_local(FuncState *fs, GCstr *n) | |||
970 | { | 973 | { |
971 | int i; | 974 | int i; |
972 | for (i = fs->nactvar-1; i >= 0; i--) { | 975 | for (i = fs->nactvar-1; i >= 0; i--) { |
973 | if (n == gco2str(gcref(var_get(fs, i).name))) | 976 | if (n == gco2str(gcref(var_get(fs->ls, fs, i).name))) |
974 | return (BCReg)i; | 977 | return (BCReg)i; |
975 | } | 978 | } |
976 | return (BCReg)-1; /* Not found. */ | 979 | return (BCReg)-1; /* Not found. */ |
977 | } | 980 | } |
978 | 981 | ||
979 | /* Lookup upvalue name. */ | 982 | /* Lookup or add upvalue index. */ |
980 | static uint32_t var_lookup_uv(FuncState *fs, GCstr *name, ExpDesc *v) | 983 | static MSize var_lookup_uv(FuncState *fs, MSize vidx, ExpDesc *e) |
981 | { | 984 | { |
982 | uint32_t i; | 985 | MSize i, n = fs->nuv; |
983 | GCproto *pt = fs->pt; | 986 | for (i = 0; i < n; i++) |
984 | GCRef *uvname; | 987 | if (fs->uvloc[i].vidx == vidx) |
985 | for (i = 0; i < fs->nuv; i++) { | 988 | return i; /* Already exists. */ |
986 | if (fs->uvloc[i].info == v->u.s.info && fs->uvloc[i].k == v->k) { | 989 | /* Otherwise create a new one. */ |
987 | lua_assert(gco2str(proto_uvname(pt, i)) == name); | 990 | checklimit(fs, fs->nuv, LJ_MAX_UPVAL, "upvalues"); |
988 | return i; | 991 | lua_assert(e->k == VLOCAL || e->k == VUPVAL); |
989 | } | 992 | fs->uvloc[n].vidx = (uint16_t)vidx; |
990 | } | 993 | fs->uvloc[n].slot = (uint16_t)(e->u.s.info | (e->k == VLOCAL ? 0x8000 : 0)); |
991 | /* Not found, create a new upvalue for this name. */ | 994 | fs->nuv = n+1; |
992 | uvname = mref(pt->uvname, GCRef); | 995 | return n; |
993 | if (LJ_UNLIKELY(fs->nuv >= pt->sizeuvname)) { | ||
994 | MSize oldsize = pt->sizeuvname; | ||
995 | checklimit(fs, fs->nuv, LJ_MAX_UPVAL, "upvalues"); | ||
996 | lj_mem_growvec(fs->L, uvname, pt->sizeuvname, LJ_MAX_UPVAL, GCRef); | ||
997 | setmref(pt->uvname, uvname); | ||
998 | while (oldsize < pt->sizeuvname) setgcrefnull(uvname[oldsize++]); | ||
999 | } | ||
1000 | setgcref(uvname[fs->nuv], obj2gco(name)); | ||
1001 | lj_gc_objbarrier(fs->L, pt, name); | ||
1002 | lua_assert(v->k == VLOCAL || v->k == VUPVAL); | ||
1003 | fs->uvloc[fs->nuv].k = cast_byte(v->k); | ||
1004 | fs->uvloc[fs->nuv].info = cast_byte(v->u.s.info); | ||
1005 | return fs->nuv++; | ||
1006 | } | 996 | } |
1007 | 997 | ||
1008 | /* Forward declaration. */ | 998 | /* Forward declaration. */ |
1009 | static void scope_uvmark(FuncState *fs, BCReg level); | 999 | static void scope_uvmark(FuncState *fs, BCReg level); |
1010 | 1000 | ||
1011 | /* Recursively lookup variables in enclosing functions. */ | 1001 | /* Recursively lookup variables in enclosing functions. */ |
1012 | static int var_lookup_(FuncState *fs, GCstr *name, ExpDesc *e, int first) | 1002 | static MSize var_lookup_(FuncState *fs, GCstr *name, ExpDesc *e, int first) |
1013 | { | 1003 | { |
1014 | if (fs) { | 1004 | if (fs) { |
1015 | BCReg reg = var_lookup_local(fs, name); | 1005 | BCReg reg = var_lookup_local(fs, name); |
@@ -1017,17 +1007,20 @@ static int var_lookup_(FuncState *fs, GCstr *name, ExpDesc *e, int first) | |||
1017 | expr_init(e, VLOCAL, reg); | 1007 | expr_init(e, VLOCAL, reg); |
1018 | if (!first) | 1008 | if (!first) |
1019 | scope_uvmark(fs, reg); /* Scope now has an upvalue. */ | 1009 | scope_uvmark(fs, reg); /* Scope now has an upvalue. */ |
1020 | return 1; | 1010 | return (MSize)fs->varmap[reg]; |
1021 | } else if (var_lookup_(fs->prev, name, e, 0)) { /* In outer function? */ | 1011 | } else { |
1022 | e->u.s.info = var_lookup_uv(fs, name, e); /* Make it an upvalue here. */ | 1012 | MSize vidx = var_lookup_(fs->prev, name, e, 0); /* Var in outer func? */ |
1023 | e->k = VUPVAL; | 1013 | if ((int32_t)vidx >= 0) { /* Yes, make it an upvalue here. */ |
1024 | return 1; | 1014 | e->u.s.info = (uint8_t)var_lookup_uv(fs, vidx, e); |
1015 | e->k = VUPVAL; | ||
1016 | return vidx; | ||
1017 | } | ||
1025 | } | 1018 | } |
1026 | } else { /* Not found in any function, must be a global. */ | 1019 | } else { /* Not found in any function, must be a global. */ |
1027 | expr_init(e, VGLOBAL, 0); | 1020 | expr_init(e, VGLOBAL, 0); |
1028 | e->u.sval = name; | 1021 | e->u.sval = name; |
1029 | } | 1022 | } |
1030 | return 0; /* Global. */ | 1023 | return (MSize)-1; /* Global. */ |
1031 | } | 1024 | } |
1032 | 1025 | ||
1033 | /* Lookup variable name. */ | 1026 | /* Lookup variable name. */ |
@@ -1080,15 +1073,12 @@ static void fs_fixup_k(FuncState *fs, GCproto *pt) | |||
1080 | /* Fixup upvalues for prototype. */ | 1073 | /* Fixup upvalues for prototype. */ |
1081 | static void fs_fixup_uv(FuncState *fs, GCproto *pt) | 1074 | static void fs_fixup_uv(FuncState *fs, GCproto *pt) |
1082 | { | 1075 | { |
1083 | uint32_t i; | 1076 | MSize i, n = fs->nuv; |
1084 | uint16_t *uv = lj_mem_newvec(fs->L, fs->nuv, uint16_t); | 1077 | uint16_t *uv = lj_mem_newvec(fs->L, n, uint16_t); |
1085 | setmref(pt->uv, uv); | 1078 | setmref(pt->uv, uv); |
1086 | pt->sizeuv = fs->nuv; | 1079 | pt->sizeuv = n; |
1087 | for (i = 0; i < pt->sizeuv; i++) { | 1080 | for (i = 0; i < n; i++) |
1088 | uint32_t v = fs->uvloc[i].info; | 1081 | uv[i] = fs->uvloc[i].slot; |
1089 | if (fs->uvloc[i].k == VLOCAL) v |= 0x8000; | ||
1090 | uv[i] = (uint16_t)v; | ||
1091 | } | ||
1092 | } | 1082 | } |
1093 | 1083 | ||
1094 | /* Check if bytecode op returns. */ | 1084 | /* Check if bytecode op returns. */ |
@@ -1143,9 +1133,7 @@ static GCproto *fs_finish(LexState *ls, BCLine line) | |||
1143 | FuncState *fs = ls->fs; | 1133 | FuncState *fs = ls->fs; |
1144 | GCproto *pt = fs->pt; | 1134 | GCproto *pt = fs->pt; |
1145 | BCIns *bc; | 1135 | BCIns *bc; |
1146 | GCRef *uvname; | ||
1147 | BCLine *lineinfo; | 1136 | BCLine *lineinfo; |
1148 | VarInfo *varinfo; | ||
1149 | 1137 | ||
1150 | /* Apply final fixups. */ | 1138 | /* Apply final fixups. */ |
1151 | var_remove(ls, 0); | 1139 | var_remove(ls, 0); |
@@ -1156,21 +1144,31 @@ static GCproto *fs_finish(LexState *ls, BCLine line) | |||
1156 | lj_mem_reallocvec(L, bc, pt->sizebc, fs->pc, BCIns); | 1144 | lj_mem_reallocvec(L, bc, pt->sizebc, fs->pc, BCIns); |
1157 | setmref(pt->bc, bc); | 1145 | setmref(pt->bc, bc); |
1158 | pt->sizebc = fs->pc; | 1146 | pt->sizebc = fs->pc; |
1147 | |||
1159 | fs_fixup_k(fs, pt); | 1148 | fs_fixup_k(fs, pt); |
1160 | fs_fixup_uv(fs, pt); | 1149 | fs_fixup_uv(fs, pt); |
1150 | |||
1161 | lineinfo = proto_lineinfo(pt); | 1151 | lineinfo = proto_lineinfo(pt); |
1162 | lj_mem_reallocvec(L, lineinfo, pt->sizelineinfo, fs->pc, BCLine); | 1152 | lj_mem_reallocvec(L, lineinfo, pt->sizelineinfo, fs->pc, BCLine); |
1163 | setmref(pt->lineinfo, lineinfo); | 1153 | setmref(pt->lineinfo, lineinfo); |
1164 | pt->sizelineinfo = fs->pc; | 1154 | pt->sizelineinfo = fs->pc; |
1165 | varinfo = proto_varinfo(pt); | 1155 | |
1166 | lj_mem_reallocvec(L, varinfo, pt->sizevarinfo, fs->nvarinfo, VarInfo); | 1156 | { |
1167 | setmref(pt->varinfo, varinfo); | 1157 | MSize n = ls->vtop - fs->vbase; |
1168 | pt->sizevarinfo = fs->nvarinfo; | 1158 | VarInfo *vi = lj_mem_newvec(L, n, VarInfo); |
1169 | uvname = mref(pt->uvname, GCRef); | 1159 | memcpy(vi, &ls->vstack[fs->vbase], n*sizeof(VarInfo)); |
1170 | lj_mem_reallocvec(L, uvname, pt->sizeuvname, fs->nuv, GCRef); | 1160 | setmref(pt->varinfo, vi); |
1171 | setmref(pt->uvname, uvname); | 1161 | pt->sizevarinfo = n; |
1172 | pt->sizeuvname = fs->nuv; | 1162 | } |
1173 | lua_assert(fs->bl == NULL); | 1163 | |
1164 | { | ||
1165 | MSize i, n = fs->nuv; | ||
1166 | GCRef *uvname = lj_mem_newvec(L, n, GCRef); | ||
1167 | for (i = 0; i < n; i++) | ||
1168 | setgcref(uvname[i], gcref(ls->vstack[fs->uvloc[i].vidx].name)); | ||
1169 | setmref(pt->uvname, uvname); | ||
1170 | pt->sizeuvname = n; | ||
1171 | } | ||
1174 | 1172 | ||
1175 | /* Initialize prototype fields. */ | 1173 | /* Initialize prototype fields. */ |
1176 | pt->flags = fs->flags; | 1174 | pt->flags = fs->flags; |
@@ -1182,7 +1180,9 @@ static GCproto *fs_finish(LexState *ls, BCLine line) | |||
1182 | setprotoV(L, L->top++, pt); | 1180 | setprotoV(L, L->top++, pt); |
1183 | ); | 1181 | ); |
1184 | 1182 | ||
1185 | /* Remove FuncState from list. Pop const table and prototype. */ | 1183 | /* Remove VarInfo and FuncState. Pop const table and prototype. */ |
1184 | lua_assert(fs->bl == NULL); | ||
1185 | ls->vtop = fs->vbase; | ||
1186 | ls->fs = fs->prev; | 1186 | ls->fs = fs->prev; |
1187 | L->top -= 2; | 1187 | L->top -= 2; |
1188 | lua_assert(ls->fs != NULL || ls->token == TK_eof); | 1188 | lua_assert(ls->fs != NULL || ls->token == TK_eof); |
@@ -1202,6 +1202,7 @@ static void fs_init(LexState *ls, FuncState *fs, BCLine line) | |||
1202 | fs->pt = pt; | 1202 | fs->pt = pt; |
1203 | fs->prev = ls->fs; ls->fs = fs; /* Append to list. */ | 1203 | fs->prev = ls->fs; ls->fs = fs; /* Append to list. */ |
1204 | fs->ls = ls; | 1204 | fs->ls = ls; |
1205 | fs->vbase = ls->vtop; | ||
1205 | fs->L = L; | 1206 | fs->L = L; |
1206 | fs->pc = 0; | 1207 | fs->pc = 0; |
1207 | fs->lasttarget = 0; | 1208 | fs->lasttarget = 0; |
@@ -1209,7 +1210,6 @@ static void fs_init(LexState *ls, FuncState *fs, BCLine line) | |||
1209 | fs->freereg = 0; | 1210 | fs->freereg = 0; |
1210 | fs->nkgc = 0; | 1211 | fs->nkgc = 0; |
1211 | fs->nkn = 0; | 1212 | fs->nkn = 0; |
1212 | fs->nvarinfo = 0; | ||
1213 | fs->nactvar = 0; | 1213 | fs->nactvar = 0; |
1214 | fs->nuv = 0; | 1214 | fs->nuv = 0; |
1215 | fs->bl = NULL; | 1215 | fs->bl = NULL; |
@@ -1382,7 +1382,7 @@ static void parse_params(LexState *ls, int needself) | |||
1382 | BCReg nparams = 0; | 1382 | BCReg nparams = 0; |
1383 | lex_check(ls, '('); | 1383 | lex_check(ls, '('); |
1384 | if (needself) { | 1384 | if (needself) { |
1385 | var_new_lit(ls, "self", 0); | 1385 | var_new_lit(ls, 0, "self"); |
1386 | var_add(ls, 1); | 1386 | var_add(ls, 1); |
1387 | } | 1387 | } |
1388 | if (ls->token != ')') { | 1388 | if (ls->token != ')') { |
@@ -1921,7 +1921,7 @@ static void parse_local(LexState *ls) | |||
1921 | parse_body(ls, &b, 0, ls->linenumber); | 1921 | parse_body(ls, &b, 0, ls->linenumber); |
1922 | bcemit_store(fs, &v, &b); | 1922 | bcemit_store(fs, &v, &b); |
1923 | /* The upvalue is in scope, but the local is only valid after the store. */ | 1923 | /* The upvalue is in scope, but the local is only valid after the store. */ |
1924 | var_get(fs, fs->nactvar - 1).startpc = fs->pc; | 1924 | var_get(ls, fs, fs->nactvar - 1).startpc = fs->pc; |
1925 | } else { /* Local variable declaration. */ | 1925 | } else { /* Local variable declaration. */ |
1926 | ExpDesc e; | 1926 | ExpDesc e; |
1927 | BCReg nexps, nvars = 0; | 1927 | BCReg nexps, nvars = 0; |
@@ -2045,9 +2045,9 @@ static void parse_for_num(LexState *ls, GCstr *varname, BCLine line) | |||
2045 | FuncState *fs = ls->fs; | 2045 | FuncState *fs = ls->fs; |
2046 | BCReg base = fs->freereg; | 2046 | BCReg base = fs->freereg; |
2047 | /* Hidden control variables. */ | 2047 | /* Hidden control variables. */ |
2048 | var_new_lit(ls, "(for index)", FORL_IDX); | 2048 | var_new_lit(ls, FORL_IDX, "(for index)"); |
2049 | var_new_lit(ls, "(for limit)", FORL_STOP); | 2049 | var_new_lit(ls, FORL_STOP, "(for limit)"); |
2050 | var_new_lit(ls, "(for step)", FORL_STEP); | 2050 | var_new_lit(ls, FORL_STEP, "(for step)"); |
2051 | /* Visible copy of index variable. */ | 2051 | /* Visible copy of index variable. */ |
2052 | var_new(ls, FORL_EXT, varname); | 2052 | var_new(ls, FORL_EXT, varname); |
2053 | lex_check(ls, '='); | 2053 | lex_check(ls, '='); |
@@ -2072,9 +2072,9 @@ static void parse_for_iter(LexState *ls, GCstr *indexname) | |||
2072 | BCLine line; | 2072 | BCLine line; |
2073 | BCReg base = fs->freereg; | 2073 | BCReg base = fs->freereg; |
2074 | /* Hidden control variables. */ | 2074 | /* Hidden control variables. */ |
2075 | var_new_lit(ls, "(for generator)", nvars++); | 2075 | var_new_lit(ls, nvars++, "(for generator)"); |
2076 | var_new_lit(ls, "(for state)", nvars++); | 2076 | var_new_lit(ls, nvars++, "(for state)"); |
2077 | var_new_lit(ls, "(for control)", nvars++); | 2077 | var_new_lit(ls, nvars++, "(for control)"); |
2078 | /* Visible variables returned from iterator. */ | 2078 | /* Visible variables returned from iterator. */ |
2079 | var_new(ls, nvars++, indexname); | 2079 | var_new(ls, nvars++, indexname); |
2080 | while (lex_opt(ls, ',')) | 2080 | while (lex_opt(ls, ',')) |