summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lcode.c36
-rw-r--r--lparser.c109
-rw-r--r--lparser.h13
-rw-r--r--manual/manual.of28
-rw-r--r--testes/constructs.lua61
-rw-r--r--testes/files.lua8
-rw-r--r--testes/math.lua6
7 files changed, 205 insertions, 56 deletions
diff --git a/lcode.c b/lcode.c
index 1e36e584..eccb8380 100644
--- a/lcode.c
+++ b/lcode.c
@@ -678,11 +678,12 @@ void luaK_setoneret (FuncState *fs, expdesc *e) {
678void luaK_dischargevars (FuncState *fs, expdesc *e) { 678void luaK_dischargevars (FuncState *fs, expdesc *e) {
679 switch (e->k) { 679 switch (e->k) {
680 case VLOCAL: { /* already in a register */ 680 case VLOCAL: { /* already in a register */
681 e->u.info = e->u.var.idx;
681 e->k = VNONRELOC; /* becomes a non-relocatable value */ 682 e->k = VNONRELOC; /* becomes a non-relocatable value */
682 break; 683 break;
683 } 684 }
684 case VUPVAL: { /* move value to some (pending) register */ 685 case VUPVAL: { /* move value to some (pending) register */
685 e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); 686 e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.var.idx, 0);
686 e->k = VRELOC; 687 e->k = VRELOC;
687 break; 688 break;
688 } 689 }
@@ -938,12 +939,12 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
938 switch (var->k) { 939 switch (var->k) {
939 case VLOCAL: { 940 case VLOCAL: {
940 freeexp(fs, ex); 941 freeexp(fs, ex);
941 exp2reg(fs, ex, var->u.info); /* compute 'ex' into proper place */ 942 exp2reg(fs, ex, var->u.var.idx); /* compute 'ex' into proper place */
942 return; 943 return;
943 } 944 }
944 case VUPVAL: { 945 case VUPVAL: {
945 int e = luaK_exp2anyreg(fs, ex); 946 int e = luaK_exp2anyreg(fs, ex);
946 luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); 947 luaK_codeABC(fs, OP_SETUPVAL, e, var->u.var.idx, 0);
947 break; 948 break;
948 } 949 }
949 case VINDEXUP: { 950 case VINDEXUP: {
@@ -1165,25 +1166,30 @@ static int isSCnumber (expdesc *e, lua_Integer *i, int *isfloat) {
1165** values in registers. 1166** values in registers.
1166*/ 1167*/
1167void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { 1168void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
1168 lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL)); 1169 lua_assert(!hasjumps(t) &&
1170 (t->k == VLOCAL || t->k == VNONRELOC || t->k == VUPVAL));
1169 if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non string? */ 1171 if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non string? */
1170 luaK_exp2anyreg(fs, t); /* put it in a register */ 1172 luaK_exp2anyreg(fs, t); /* put it in a register */
1171 t->u.ind.t = t->u.info; /* register or upvalue index */
1172 if (t->k == VUPVAL) { 1173 if (t->k == VUPVAL) {
1174 t->u.ind.t = t->u.var.idx; /* upvalue index */
1173 t->u.ind.idx = k->u.info; /* literal string */ 1175 t->u.ind.idx = k->u.info; /* literal string */
1174 t->k = VINDEXUP; 1176 t->k = VINDEXUP;
1175 } 1177 }
1176 else if (isKstr(fs, k)) {
1177 t->u.ind.idx = k->u.info; /* literal string */
1178 t->k = VINDEXSTR;
1179 }
1180 else if (isCint(k)) {
1181 t->u.ind.idx = cast_int(k->u.ival); /* integer constant in proper range */
1182 t->k = VINDEXI;
1183 }
1184 else { 1178 else {
1185 t->u.ind.idx = luaK_exp2anyreg(fs, k); /* register */ 1179 /* register index of the table */
1186 t->k = VINDEXED; 1180 t->u.ind.t = (t->k == VLOCAL) ? t->u.var.idx: t->u.info;
1181 if (isKstr(fs, k)) {
1182 t->u.ind.idx = k->u.info; /* literal string */
1183 t->k = VINDEXSTR;
1184 }
1185 else if (isCint(k)) {
1186 t->u.ind.idx = cast_int(k->u.ival); /* int. constant in proper range */
1187 t->k = VINDEXI;
1188 }
1189 else {
1190 t->u.ind.idx = luaK_exp2anyreg(fs, k); /* register */
1191 t->k = VINDEXED;
1192 }
1187 } 1193 }
1188} 1194}
1189 1195
diff --git a/lparser.c b/lparser.c
index 4e6c27fe..7c23710a 100644
--- a/lparser.c
+++ b/lparser.c
@@ -156,6 +156,13 @@ static void init_exp (expdesc *e, expkind k, int i) {
156} 156}
157 157
158 158
159static void init_var (expdesc *e, expkind k, int i) {
160 e->f = e->t = NO_JUMP;
161 e->k = k;
162 e->u.var.idx = i;
163}
164
165
159static void codestring (LexState *ls, expdesc *e, TString *s) { 166static void codestring (LexState *ls, expdesc *e, TString *s) {
160 init_exp(e, VK, luaK_stringK(ls->fs, s)); 167 init_exp(e, VK, luaK_stringK(ls->fs, s));
161} 168}
@@ -187,32 +194,83 @@ static int registerlocalvar (LexState *ls, TString *varname) {
187/* 194/*
188** Create a new local variable with the given 'name'. 195** Create a new local variable with the given 'name'.
189*/ 196*/
190static void new_localvar (LexState *ls, TString *name) { 197static Vardesc *new_localvar (LexState *ls, TString *name) {
191 FuncState *fs = ls->fs; 198 FuncState *fs = ls->fs;
192 Dyndata *dyd = ls->dyd; 199 Dyndata *dyd = ls->dyd;
200 Vardesc *var;
193 int reg = registerlocalvar(ls, name); 201 int reg = registerlocalvar(ls, name);
194 checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, 202 checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
195 MAXVARS, "local variables"); 203 MAXVARS, "local variables");
196 luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, 204 luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,
197 dyd->actvar.size, Vardesc, MAX_INT, "local variables"); 205 dyd->actvar.size, Vardesc, MAX_INT, "local variables");
198 dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg); 206 var = &dyd->actvar.arr[dyd->actvar.n++];
207 var->idx = cast(short, reg);
208 var->name = name;
209 var->ro = 0;
210 return var;
199} 211}
200 212
201#define new_localvarliteral(ls,v) \ 213#define new_localvarliteral(ls,v) \
202 new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1)); 214 new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1));
203 215
204 216
217
218/*
219** Return the "variable description" (Vardesc) of a given
220** variable
221*/
222static Vardesc *getlocalvardesc (FuncState *fs, int i) {
223 return &fs->ls->dyd->actvar.arr[fs->firstlocal + i];
224}
225
205/* 226/*
206** Get the debug-information entry for current variable 'i'. 227** Get the debug-information entry for current variable 'i'.
207*/ 228*/
208static LocVar *getlocvar (FuncState *fs, int i) { 229static LocVar *getlocvar (FuncState *fs, int i) {
209 int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; 230 int idx = getlocalvardesc(fs, i)->idx;
210 lua_assert(idx < fs->nlocvars); 231 lua_assert(idx < fs->nlocvars);
211 return &fs->f->locvars[idx]; 232 return &fs->f->locvars[idx];
212} 233}
213 234
214 235
215/* 236/*
237** Return the "variable description" (Vardesc) of a given
238** variable or upvalue
239*/
240static Vardesc *getvardesc (FuncState *fs, expdesc *e) {
241 if (e->k == VLOCAL)
242 return getlocalvardesc(fs, e->u.var.idx);
243 else if (e->k != VUPVAL)
244 return NULL; /* not a local variable */
245 else { /* upvalue: must go up all levels up to the original local */
246 int idx = e->u.var.idx;
247 for (;;) {
248 Upvaldesc *up = &fs->f->upvalues[idx];
249 fs = fs->prev; /* must look at the previous level */
250 idx = up->idx; /* at this index */
251 if (fs == NULL) { /* no more levels? (can happen only with _ENV) */
252 lua_assert(strcmp(getstr(up->name), LUA_ENV) == 0);
253 return NULL;
254 }
255 else if (up->instack) /* got to the original level? */
256 return getlocalvardesc(fs, idx);
257 /* else repeat for previous level */
258 }
259 }
260}
261
262
263static void check_readonly (LexState *ls, expdesc *e) {
264 Vardesc *vardesc = getvardesc(ls->fs, e);
265 if (vardesc && vardesc->ro) { /* is variable local and const? */
266 const char *msg = luaO_pushfstring(ls->L,
267 "assignment to const variable '%s'", getstr(vardesc->name));
268 luaK_semerror(ls, msg); /* error */
269 }
270}
271
272
273/*
216** Start the scope for the last 'nvars' created variables. 274** Start the scope for the last 'nvars' created variables.
217** (debug info.) 275** (debug info.)
218*/ 276*/
@@ -259,7 +317,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
259 while (oldsize < f->sizeupvalues) 317 while (oldsize < f->sizeupvalues)
260 f->upvalues[oldsize++].name = NULL; 318 f->upvalues[oldsize++].name = NULL;
261 f->upvalues[fs->nups].instack = (v->k == VLOCAL); 319 f->upvalues[fs->nups].instack = (v->k == VLOCAL);
262 f->upvalues[fs->nups].idx = cast_byte(v->u.info); 320 f->upvalues[fs->nups].idx = cast_byte(v->u.var.idx);
263 f->upvalues[fs->nups].name = name; 321 f->upvalues[fs->nups].name = name;
264 luaC_objbarrier(fs->ls->L, f, name); 322 luaC_objbarrier(fs->ls->L, f, name);
265 return fs->nups++; 323 return fs->nups++;
@@ -304,7 +362,7 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
304 else { 362 else {
305 int v = searchvar(fs, n); /* look up locals at current level */ 363 int v = searchvar(fs, n); /* look up locals at current level */
306 if (v >= 0) { /* found? */ 364 if (v >= 0) { /* found? */
307 init_exp(var, VLOCAL, v); /* variable is local */ 365 init_var(var, VLOCAL, v); /* variable is local */
308 if (!base) 366 if (!base)
309 markupval(fs, v); /* local will be used as an upval */ 367 markupval(fs, v); /* local will be used as an upval */
310 } 368 }
@@ -317,7 +375,7 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
317 /* else was LOCAL or UPVAL */ 375 /* else was LOCAL or UPVAL */
318 idx = newupvalue(fs, n, var); /* will be a new upvalue */ 376 idx = newupvalue(fs, n, var); /* will be a new upvalue */
319 } 377 }
320 init_exp(var, VUPVAL, idx); /* new or old upvalue */ 378 init_var(var, VUPVAL, idx); /* new or old upvalue */
321 } 379 }
322 } 380 }
323} 381}
@@ -1199,20 +1257,20 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
1199 for (; lh; lh = lh->prev) { /* check all previous assignments */ 1257 for (; lh; lh = lh->prev) { /* check all previous assignments */
1200 if (vkisindexed(lh->v.k)) { /* assignment to table field? */ 1258 if (vkisindexed(lh->v.k)) { /* assignment to table field? */
1201 if (lh->v.k == VINDEXUP) { /* is table an upvalue? */ 1259 if (lh->v.k == VINDEXUP) { /* is table an upvalue? */
1202 if (v->k == VUPVAL && lh->v.u.ind.t == v->u.info) { 1260 if (v->k == VUPVAL && lh->v.u.ind.t == v->u.var.idx) {
1203 conflict = 1; /* table is the upvalue being assigned now */ 1261 conflict = 1; /* table is the upvalue being assigned now */
1204 lh->v.k = VINDEXSTR; 1262 lh->v.k = VINDEXSTR;
1205 lh->v.u.ind.t = extra; /* assignment will use safe copy */ 1263 lh->v.u.ind.t = extra; /* assignment will use safe copy */
1206 } 1264 }
1207 } 1265 }
1208 else { /* table is a register */ 1266 else { /* table is a register */
1209 if (v->k == VLOCAL && lh->v.u.ind.t == v->u.info) { 1267 if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.idx) {
1210 conflict = 1; /* table is the local being assigned now */ 1268 conflict = 1; /* table is the local being assigned now */
1211 lh->v.u.ind.t = extra; /* assignment will use safe copy */ 1269 lh->v.u.ind.t = extra; /* assignment will use safe copy */
1212 } 1270 }
1213 /* is index the local being assigned? */ 1271 /* is index the local being assigned? */
1214 if (lh->v.k == VINDEXED && v->k == VLOCAL && 1272 if (lh->v.k == VINDEXED && v->k == VLOCAL &&
1215 lh->v.u.ind.idx == v->u.info) { 1273 lh->v.u.ind.idx == v->u.var.idx) {
1216 conflict = 1; 1274 conflict = 1;
1217 lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ 1275 lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */
1218 } 1276 }
@@ -1222,7 +1280,7 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
1222 if (conflict) { 1280 if (conflict) {
1223 /* copy upvalue/local value to a temporary (in position 'extra') */ 1281 /* copy upvalue/local value to a temporary (in position 'extra') */
1224 OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; 1282 OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
1225 luaK_codeABC(fs, op, extra, v->u.info, 0); 1283 luaK_codeABC(fs, op, extra, v->u.var.idx, 0);
1226 luaK_reserveregs(fs, 1); 1284 luaK_reserveregs(fs, 1);
1227 } 1285 }
1228} 1286}
@@ -1237,6 +1295,7 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
1237static void restassign (LexState *ls, struct LHS_assign *lh, int nvars) { 1295static void restassign (LexState *ls, struct LHS_assign *lh, int nvars) {
1238 expdesc e; 1296 expdesc e;
1239 check_condition(ls, vkisvar(lh->v.k), "syntax error"); 1297 check_condition(ls, vkisvar(lh->v.k), "syntax error");
1298 check_readonly(ls, &lh->v);
1240 if (testnext(ls, ',')) { /* restassign -> ',' suffixedexp restassign */ 1299 if (testnext(ls, ',')) { /* restassign -> ',' suffixedexp restassign */
1241 struct LHS_assign nv; 1300 struct LHS_assign nv;
1242 nv.prev = lh; 1301 nv.prev = lh;
@@ -1615,20 +1674,30 @@ static void commonlocalstat (LexState *ls) {
1615} 1674}
1616 1675
1617 1676
1618static void tocloselocalstat (LexState *ls) { 1677static void tocloselocalstat (LexState *ls, Vardesc *var) {
1619 FuncState *fs = ls->fs; 1678 FuncState *fs = ls->fs;
1679 var->ro = 1; /* to-be-closed variables are always read-only */
1680 markupval(fs, fs->nactvar);
1681 fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
1682 luaK_codeABC(fs, OP_TBC, fs->nactvar - 1, 0, 0);
1683}
1684
1685
1686static void attriblocalstat (LexState *ls) {
1687 Vardesc *var;
1620 TString *attr = str_checkname(ls); 1688 TString *attr = str_checkname(ls);
1621 if (strcmp(getstr(attr), "toclose") != 0)
1622 luaK_semerror(ls,
1623 luaO_pushfstring(ls->L, "unknown attribute '%s'", getstr(attr)));
1624 testnext(ls, '>'); 1689 testnext(ls, '>');
1625 new_localvar(ls, str_checkname(ls)); 1690 var = new_localvar(ls, str_checkname(ls));
1626 checknext(ls, '='); 1691 checknext(ls, '=');
1627 exp1(ls); 1692 exp1(ls);
1628 markupval(fs, fs->nactvar);
1629 fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
1630 adjustlocalvars(ls, 1); 1693 adjustlocalvars(ls, 1);
1631 luaK_codeABC(fs, OP_TBC, fs->nactvar - 1, 0, 0); 1694 if (strcmp(getstr(attr), "const") == 0)
1695 var->ro = 1; /* set variable as read-only */
1696 else if (strcmp(getstr(attr), "toclose") == 0)
1697 tocloselocalstat(ls, var);
1698 else
1699 luaK_semerror(ls,
1700 luaO_pushfstring(ls->L, "unknown attribute '%s'", getstr(attr)));
1632} 1701}
1633 1702
1634 1703
@@ -1636,7 +1705,7 @@ static void localstat (LexState *ls) {
1636 /* stat -> LOCAL NAME {',' NAME} ['=' explist] 1705 /* stat -> LOCAL NAME {',' NAME} ['=' explist]
1637 | LOCAL *toclose NAME '=' exp */ 1706 | LOCAL *toclose NAME '=' exp */
1638 if (testnext(ls, '<')) 1707 if (testnext(ls, '<'))
1639 tocloselocalstat(ls); 1708 attriblocalstat(ls);
1640 else 1709 else
1641 commonlocalstat(ls); 1710 commonlocalstat(ls);
1642} 1711}
@@ -1801,7 +1870,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
1801 expdesc v; 1870 expdesc v;
1802 open_func(ls, fs, &bl); 1871 open_func(ls, fs, &bl);
1803 setvararg(fs, 0); /* main function is always declared vararg */ 1872 setvararg(fs, 0); /* main function is always declared vararg */
1804 init_exp(&v, VLOCAL, 0); /* create and... */ 1873 init_var(&v, VLOCAL, 0); /* create and... */
1805 newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ 1874 newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
1806 luaX_next(ls); /* read first token */ 1875 luaX_next(ls); /* read first token */
1807 statlist(ls); /* parse main body */ 1876 statlist(ls); /* parse main body */
diff --git a/lparser.h b/lparser.h
index 3d6bd978..3b5d399f 100644
--- a/lparser.h
+++ b/lparser.h
@@ -33,8 +33,8 @@ typedef enum {
33 VKINT, /* integer constant; nval = numerical integer value */ 33 VKINT, /* integer constant; nval = numerical integer value */
34 VNONRELOC, /* expression has its value in a fixed register; 34 VNONRELOC, /* expression has its value in a fixed register;
35 info = result register */ 35 info = result register */
36 VLOCAL, /* local variable; info = local register */ 36 VLOCAL, /* local variable; var.idx = local register */
37 VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ 37 VUPVAL, /* upvalue variable; var.idx = index of upvalue in 'upvalues' */
38 VINDEXED, /* indexed variable; 38 VINDEXED, /* indexed variable;
39 ind.t = table register; 39 ind.t = table register;
40 ind.idx = key's R index */ 40 ind.idx = key's R index */
@@ -58,7 +58,7 @@ typedef enum {
58 58
59#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXSTR) 59#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXSTR)
60#define vkisindexed(k) (VINDEXED <= (k) && (k) <= VINDEXSTR) 60#define vkisindexed(k) (VINDEXED <= (k) && (k) <= VINDEXSTR)
61#define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL) 61
62 62
63typedef struct expdesc { 63typedef struct expdesc {
64 expkind k; 64 expkind k;
@@ -70,15 +70,20 @@ typedef struct expdesc {
70 short idx; /* index (R or "long" K) */ 70 short idx; /* index (R or "long" K) */
71 lu_byte t; /* table (register or upvalue) */ 71 lu_byte t; /* table (register or upvalue) */
72 } ind; 72 } ind;
73 struct { /* for local variables and upvalues */
74 lu_byte idx; /* index of the variable */
75 } var;
73 } u; 76 } u;
74 int t; /* patch list of 'exit when true' */ 77 int t; /* patch list of 'exit when true' */
75 int f; /* patch list of 'exit when false' */ 78 int f; /* patch list of 'exit when false' */
76} expdesc; 79} expdesc;
77 80
78 81
79/* description of active local variable */ 82/* description of an active local variable */
80typedef struct Vardesc { 83typedef struct Vardesc {
84 TString *name;
81 short idx; /* index of the variable in the Proto's 'locvars' array */ 85 short idx; /* index of the variable in the Proto's 'locvars' array */
86 lu_byte ro; /* true if variable is 'const' */
82} Vardesc; 87} Vardesc;
83 88
84 89
diff --git a/manual/manual.of b/manual/manual.of
index 54a07879..6cac8c6c 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -1488,13 +1488,24 @@ Function calls are explained in @See{functioncall}.
1488 1488
1489@sect3{localvar| @title{Local Declarations} 1489@sect3{localvar| @title{Local Declarations}
1490@x{Local variables} can be declared anywhere inside a block. 1490@x{Local variables} can be declared anywhere inside a block.
1491The declaration can include an initial assignment: 1491The declaration can include an initialization:
1492@Produc{ 1492@Produc{
1493@producname{stat}@producbody{@Rw{local} namelist @bnfopt{@bnfter{=} explist}} 1493@producname{stat}@producbody{@Rw{local} namelist @bnfopt{@bnfter{=} explist}}
1494} 1494@producname{stat}@producbody{
1495 @Rw{local} @bnfter{<} Name @bnfter{>} Name @bnfter{=} exp
1496}}
1495If present, an initial assignment has the same semantics 1497If present, an initial assignment has the same semantics
1496of a multiple assignment @see{assignment}. 1498of a multiple assignment @see{assignment}.
1497Otherwise, all variables are initialized with @nil. 1499Otherwise, all variables are initialized with @nil.
1500The second syntax declares a local with a given attribute,
1501which is the name between the angle brackets.
1502In this case, there must be an initialization.
1503There are two possible attributes:
1504@id{const}, which declares a @x{constant variable},
1505that is, a variable that cannot be assigned to
1506after its initialization;
1507and @id{toclose}, wich declares a to-be-closed variable @see{to-be-closed}.
1508
1498 1509
1499A chunk is also a block @see{chunks}, 1510A chunk is also a block @see{chunks},
1500and so local variables can be declared in a chunk outside any explicit block. 1511and so local variables can be declared in a chunk outside any explicit block.
@@ -1506,12 +1517,12 @@ The visibility rules for local variables are explained in @See{visibility}.
1506@sect3{to-be-closed| @title{To-be-closed Variables} 1517@sect3{to-be-closed| @title{To-be-closed Variables}
1507 1518
1508A local variable can be declared as a @def{to-be-closed} variable, 1519A local variable can be declared as a @def{to-be-closed} variable,
1509with the following syntax: 1520using the identifier @id{toclose} as its attribute:
1510@Produc{ 1521@Produc{
1511@producname{stat}@producbody{ 1522@producname{stat}@producbody{
1512 @Rw{local} @bnfter{<} @bnfter{toclose} @bnfter{>} Name @bnfter{=} exp 1523 @Rw{local} @bnfter{<} @id{toclose} @bnfter{>} Name @bnfter{=} exp
1513}} 1524}}
1514A to-be-closed variable behaves like a normal local variable, 1525A to-be-closed variable behaves like a constant local variable,
1515except that its value is @emph{closed} whenever the variable 1526except that its value is @emph{closed} whenever the variable
1516goes out of scope, including normal block termination, 1527goes out of scope, including normal block termination,
1517exiting its block by @Rw{break}/@Rw{goto}/@Rw{return}, 1528exiting its block by @Rw{break}/@Rw{goto}/@Rw{return},
@@ -7603,7 +7614,7 @@ or a float otherwise.
7603 7614
7604@LibEntry{math.abs (x)| 7615@LibEntry{math.abs (x)|
7605 7616
7606Returns the absolute value of @id{x}. (integer/float) 7617Returns the maximum value between @id{x} and @id{-x}. (integer/float)
7607 7618
7608} 7619}
7609 7620
@@ -8042,7 +8053,8 @@ following the lexical conventions of Lua.
8042This format always reads the longest input sequence that 8053This format always reads the longest input sequence that
8043is a valid prefix for a numeral; 8054is a valid prefix for a numeral;
8044if that prefix does not form a valid numeral 8055if that prefix does not form a valid numeral
8045(e.g., an empty string, @St{0x}, or @St{3.4e-}), 8056(e.g., an empty string, @St{0x}, or @St{3.4e-})
8057or it is too long (more than 200 characters),
8046it is discarded and the format returns @nil. 8058it is discarded and the format returns @nil.
8047} 8059}
8048 8060
@@ -8949,7 +8961,7 @@ and @bnfNter{LiteralString}, see @See{lexical}.)
8949@OrNL @Rw{function} funcname funcbody 8961@OrNL @Rw{function} funcname funcbody
8950@OrNL @Rw{local} @Rw{function} @bnfNter{Name} funcbody 8962@OrNL @Rw{local} @Rw{function} @bnfNter{Name} funcbody
8951@OrNL @Rw{local} namelist @bnfopt{@bnfter{=} explist} 8963@OrNL @Rw{local} namelist @bnfopt{@bnfter{=} explist}
8952@OrNL @Rw{local} @bnfter{<} @bnfter{toclose} @bnfter{>} Name @bnfter{=} exp 8964@OrNL @Rw{local} @bnfter{<} Name @bnfter{>} Name @bnfter{=} exp
8953} 8965}
8954 8966
8955@producname{retstat}@producbody{@Rw{return} 8967@producname{retstat}@producbody{@Rw{return}
diff --git a/testes/constructs.lua b/testes/constructs.lua
index a83df79e..b91e0979 100644
--- a/testes/constructs.lua
+++ b/testes/constructs.lua
@@ -59,6 +59,41 @@ assert((x>y) and x or y == 2);
59 59
60assert(1234567890 == tonumber('1234567890') and 1234567890+1 == 1234567891) 60assert(1234567890 == tonumber('1234567890') and 1234567890+1 == 1234567891)
61 61
62do -- testing operators with diffent kinds of constants
63 -- operands to consider:
64 -- * fit in register
65 -- * constant doesn't fit in register
66 -- * floats with integral values
67 local operand = {3, 100, 5.0, -10, -5.0, 10000, -10000}
68 local operator = {"+", "-", "*", "/", "//", "%", "^",
69 "&", "|", "^", "<<", ">>",
70 "==", "~=", "<", ">", "<=", ">=",}
71 for _, op in ipairs(operator) do
72 local f = assert(load(string.format([[return function (x,y)
73 return x %s y
74 end]], op)))();
75 for _, o1 in ipairs(operand) do
76 for _, o2 in ipairs(operand) do
77 local gab = f(o1, o2)
78
79 _ENV.XX = o1
80 code = string.format("return XX %s %s", op, o2)
81 res = assert(load(code))()
82 assert(res == gab)
83
84 _ENV.XX = o2
85 local code = string.format("return (%s) %s XX", o1, op)
86 local res = assert(load(code))()
87 assert(res == gab)
88
89 code = string.format("return (%s) %s %s", o1, op, o2)
90 res = assert(load(code))()
91 assert(res == gab)
92 end
93 end
94 end
95end
96
62 97
63-- silly loops 98-- silly loops
64repeat until 1; repeat until true; 99repeat until 1; repeat until true;
@@ -175,6 +210,28 @@ assert(a==1 and b==nil)
175 210
176print'+'; 211print'+';
177 212
213do -- testing constants
214 local <const> prog = [[local <XXX> x = 10]]
215 checkload(prog, "unknown attribute 'XXX'")
216
217 checkload([[local <const> xxx = 20; xxx = 10]],
218 ":1: assignment to const variable 'xxx'")
219
220 checkload([[
221 local xx;
222 local <const> xxx = 20;
223 local yyy;
224 local function foo ()
225 local abc = xx + yyy + xxx;
226 return function () return function () xxx = yyy end end
227 end
228 ]], ":6: assignment to const variable 'xxx'")
229
230 checkload([[
231 local <toclose> x = nil
232 x = io.open()
233 ]], ":2: assignment to const variable 'x'")
234end
178 235
179f = [[ 236f = [[
180return function ( a , b , c , d , e ) 237return function ( a , b , c , d , e )
@@ -245,12 +302,12 @@ print('testing short-circuit optimizations (' .. _ENV.GLOB1 .. ')')
245 302
246 303
247-- operators with their respective values 304-- operators with their respective values
248local binops = { 305local <const> binops = {
249 {" and ", function (a,b) if not a then return a else return b end end}, 306 {" and ", function (a,b) if not a then return a else return b end end},
250 {" or ", function (a,b) if a then return a else return b end end}, 307 {" or ", function (a,b) if a then return a else return b end end},
251} 308}
252 309
253local cases = {} 310local <const> cases = {}
254 311
255-- creates all combinations of '(cases[i] op cases[n-i])' plus 312-- creates all combinations of '(cases[i] op cases[n-i])' plus
256-- 'not(cases[i] op cases[n-i])' (syntax + value) 313-- 'not(cases[i] op cases[n-i])' (syntax + value)
diff --git a/testes/files.lua b/testes/files.lua
index eb100fe1..54931c14 100644
--- a/testes/files.lua
+++ b/testes/files.lua
@@ -144,7 +144,7 @@ do
144 f:write(string.format("0x%X\n", -maxint)) 144 f:write(string.format("0x%X\n", -maxint))
145 f:write("-0xABCp-3", '\n') 145 f:write("-0xABCp-3", '\n')
146 assert(f:close()) 146 assert(f:close())
147 f = assert(io.open(file, "r")) 147 local <toclose> f = assert(io.open(file, "r"))
148 assert(f:read("n") == maxint) 148 assert(f:read("n") == maxint)
149 assert(f:read("n") == maxint) 149 assert(f:read("n") == maxint)
150 assert(f:read("n") == 0xABCp-3) 150 assert(f:read("n") == 0xABCp-3)
@@ -170,18 +170,18 @@ three
170]] 170]]
171 local l1, l2, l3, l4, n1, n2, c, dummy 171 local l1, l2, l3, l4, n1, n2, c, dummy
172 assert(f:close()) 172 assert(f:close())
173 f = assert(io.open(file, "r")) 173 local <toclose> f = assert(io.open(file, "r"))
174 l1, l2, n1, n2, dummy = f:read("l", "L", "n", "n") 174 l1, l2, n1, n2, dummy = f:read("l", "L", "n", "n")
175 assert(l1 == "a line" and l2 == "another line\n" and 175 assert(l1 == "a line" and l2 == "another line\n" and
176 n1 == 1234 and n2 == 3.45 and dummy == nil) 176 n1 == 1234 and n2 == 3.45 and dummy == nil)
177 assert(f:close()) 177 assert(f:close())
178 f = assert(io.open(file, "r")) 178 local <toclose> f = assert(io.open(file, "r"))
179 l1, l2, n1, n2, c, l3, l4, dummy = f:read(7, "l", "n", "n", 1, "l", "l") 179 l1, l2, n1, n2, c, l3, l4, dummy = f:read(7, "l", "n", "n", 1, "l", "l")
180 assert(l1 == "a line\n" and l2 == "another line" and c == '\n' and 180 assert(l1 == "a line\n" and l2 == "another line" and c == '\n' and
181 n1 == 1234 and n2 == 3.45 and l3 == "one" and l4 == "two" 181 n1 == 1234 and n2 == 3.45 and l3 == "one" and l4 == "two"
182 and dummy == nil) 182 and dummy == nil)
183 assert(f:close()) 183 assert(f:close())
184 f = assert(io.open(file, "r")) 184 local <toclose> f = assert(io.open(file, "r"))
185 -- second item failing 185 -- second item failing
186 l1, n1, n2, dummy = f:read("l", "n", "n", "l") 186 l1, n1, n2, dummy = f:read("l", "n", "n", "l")
187 assert(l1 == "a line" and n1 == nil) 187 assert(l1 == "a line" and n1 == nil)
diff --git a/testes/math.lua b/testes/math.lua
index b010ff6c..c45a91ad 100644
--- a/testes/math.lua
+++ b/testes/math.lua
@@ -3,10 +3,10 @@
3 3
4print("testing numbers and math lib") 4print("testing numbers and math lib")
5 5
6local minint = math.mininteger 6local <const> minint = math.mininteger
7local maxint = math.maxinteger 7local <const> maxint = math.maxinteger
8 8
9local intbits = math.floor(math.log(maxint, 2) + 0.5) + 1 9local <const> intbits = math.floor(math.log(maxint, 2) + 0.5) + 1
10assert((1 << intbits) == 0) 10assert((1 << intbits) == 0)
11 11
12assert(minint == 1 << (intbits - 1)) 12assert(minint == 1 << (intbits - 1))