@@ -156,6 +156,13 @@ static void init_exp (expdesc *e, expkind k, int i) {
156156}
157157
158158
159+ static 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+
159166static void codestring (LexState * ls , expdesc * e , TString * s ) {
160167 init_exp (e , VK , luaK_stringK (ls -> fs , s ));
161168}
@@ -187,31 +194,82 @@ static int registerlocalvar (LexState *ls, TString *varname) {
187194/*
188195** Create a new local variable with the given 'name'.
189196*/
190- static void new_localvar (LexState * ls , TString * name ) {
197+ static Vardesc * new_localvar (LexState * ls , TString * name ) {
191198 FuncState * fs = ls -> fs ;
192199 Dyndata * dyd = ls -> dyd ;
200+ Vardesc * var ;
193201 int reg = registerlocalvar (ls , name );
194202 checklimit (fs , dyd -> actvar .n + 1 - fs -> firstlocal ,
195203 MAXVARS , "local variables" );
196204 luaM_growvector (ls -> L , dyd -> actvar .arr , dyd -> actvar .n + 1 ,
197205 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 ;
199211}
200212
201213#define new_localvarliteral (ls ,v ) \
202214 new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1));
203215
204216
217+
218+ /*
219+ ** Return the "variable description" (Vardesc) of a given
220+ ** variable
221+ */
222+ static Vardesc * getlocalvardesc (FuncState * fs , int i ) {
223+ return & fs -> ls -> dyd -> actvar .arr [fs -> firstlocal + i ];
224+ }
225+
205226/*
206227** Get the debug-information entry for current variable 'i'.
207228*/
208229static 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 ;
210231 lua_assert (idx < fs -> nlocvars );
211232 return & fs -> f -> locvars [idx ];
212233}
213234
214235
236+ /*
237+ ** Return the "variable description" (Vardesc) of a given
238+ ** variable or upvalue
239+ */
240+ static 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+
263+ static 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+
215273/*
216274** Start the scope for the last 'nvars' created variables.
217275** (debug info.)
@@ -259,7 +317,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
259317 while (oldsize < f -> sizeupvalues )
260318 f -> upvalues [oldsize ++ ].name = NULL ;
261319 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 );
263321 f -> upvalues [fs -> nups ].name = name ;
264322 luaC_objbarrier (fs -> ls -> L , f , name );
265323 return fs -> nups ++ ;
@@ -304,7 +362,7 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
304362 else {
305363 int v = searchvar (fs , n ); /* look up locals at current level */
306364 if (v >= 0 ) { /* found? */
307- init_exp (var , VLOCAL , v ); /* variable is local */
365+ init_var (var , VLOCAL , v ); /* variable is local */
308366 if (!base )
309367 markupval (fs , v ); /* local will be used as an upval */
310368 }
@@ -317,7 +375,7 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
317375 /* else was LOCAL or UPVAL */
318376 idx = newupvalue (fs , n , var ); /* will be a new upvalue */
319377 }
320- init_exp (var , VUPVAL , idx ); /* new or old upvalue */
378+ init_var (var , VUPVAL , idx ); /* new or old upvalue */
321379 }
322380 }
323381}
@@ -1199,20 +1257,20 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
11991257 for (; lh ; lh = lh -> prev ) { /* check all previous assignments */
12001258 if (vkisindexed (lh -> v .k )) { /* assignment to table field? */
12011259 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 ) {
12031261 conflict = 1 ; /* table is the upvalue being assigned now */
12041262 lh -> v .k = VINDEXSTR ;
12051263 lh -> v .u .ind .t = extra ; /* assignment will use safe copy */
12061264 }
12071265 }
12081266 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 ) {
12101268 conflict = 1 ; /* table is the local being assigned now */
12111269 lh -> v .u .ind .t = extra ; /* assignment will use safe copy */
12121270 }
12131271 /* is index the local being assigned? */
12141272 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 ) {
12161274 conflict = 1 ;
12171275 lh -> v .u .ind .idx = extra ; /* previous assignment will use safe copy */
12181276 }
@@ -1222,7 +1280,7 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
12221280 if (conflict ) {
12231281 /* copy upvalue/local value to a temporary (in position 'extra') */
12241282 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 );
12261284 luaK_reserveregs (fs , 1 );
12271285 }
12281286}
@@ -1237,6 +1295,7 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
12371295static void restassign (LexState * ls , struct LHS_assign * lh , int nvars ) {
12381296 expdesc e ;
12391297 check_condition (ls , vkisvar (lh -> v .k ), "syntax error" );
1298+ check_readonly (ls , & lh -> v );
12401299 if (testnext (ls , ',' )) { /* restassign -> ',' suffixedexp restassign */
12411300 struct LHS_assign nv ;
12421301 nv .prev = lh ;
@@ -1615,28 +1674,38 @@ static void commonlocalstat (LexState *ls) {
16151674}
16161675
16171676
1618- static void tocloselocalstat (LexState * ls ) {
1677+ static void tocloselocalstat (LexState * ls , Vardesc * var ) {
16191678 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+
1686+ static void attriblocalstat (LexState * ls ) {
1687+ Vardesc * var ;
16201688 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 )));
16241689 testnext (ls , '>' );
1625- new_localvar (ls , str_checkname (ls ));
1690+ var = new_localvar (ls , str_checkname (ls ));
16261691 checknext (ls , '=' );
16271692 exp1 (ls );
1628- markupval (fs , fs -> nactvar );
1629- fs -> bl -> insidetbc = 1 ; /* in the scope of a to-be-closed variable */
16301693 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 )));
16321701}
16331702
16341703
16351704static void localstat (LexState * ls ) {
16361705 /* stat -> LOCAL NAME {',' NAME} ['=' explist]
16371706 | LOCAL *toclose NAME '=' exp */
16381707 if (testnext (ls , '<' ))
1639- tocloselocalstat (ls );
1708+ attriblocalstat (ls );
16401709 else
16411710 commonlocalstat (ls );
16421711}
@@ -1801,7 +1870,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
18011870 expdesc v ;
18021871 open_func (ls , fs , & bl );
18031872 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... */
18051874 newupvalue (fs , ls -> envn , & v ); /* ...set environment upvalue */
18061875 luaX_next (ls ); /* read first token */
18071876 statlist (ls ); /* parse main body */
0 commit comments