diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-17 14:26:56 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-17 14:26:56 -0300 |
commit | d6af81084df569bc8e3bd0949ad6fc0b40c8468d (patch) | |
tree | 103b92a3fd9b1164763500054f7979f51f9aa4b4 | |
parent | 4846f7e3bb1397142ab0de808ae59c08db9832a6 (diff) | |
download | lua-d6af81084df569bc8e3bd0949ad6fc0b40c8468d.tar.gz lua-d6af81084df569bc8e3bd0949ad6fc0b40c8468d.tar.bz2 lua-d6af81084df569bc8e3bd0949ad6fc0b40c8468d.zip |
New kind of expression VKSTR
String literal expressions have their own kind VKSTR, instead of the
generic VK. This allows strings to "cross" functions without entering
their constant tables (e.g., if they are used only by some nested
function).
-rw-r--r-- | lcode.c | 35 | ||||
-rw-r--r-- | lcode.h | 1 | ||||
-rw-r--r-- | lparser.c | 14 | ||||
-rw-r--r-- | lparser.h | 5 | ||||
-rw-r--r-- | testes/code.lua | 17 |
5 files changed, 54 insertions, 18 deletions
@@ -81,9 +81,8 @@ int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v) { | |||
81 | case VNIL: | 81 | case VNIL: |
82 | setnilvalue(v); | 82 | setnilvalue(v); |
83 | return 1; | 83 | return 1; |
84 | case VK: { | 84 | case VKSTR: { |
85 | TValue *k = &fs->f->k[e->u.info]; | 85 | setsvalue(fs->ls->L, v, e->u.strval); |
86 | setobj(fs->ls->L, v, k); | ||
87 | return 1; | 86 | return 1; |
88 | } | 87 | } |
89 | default: return tonumeral(e, v); | 88 | default: return tonumeral(e, v); |
@@ -561,7 +560,7 @@ static int addk (FuncState *fs, TValue *key, TValue *v) { | |||
561 | /* | 560 | /* |
562 | ** Add a string to list of constants and return its index. | 561 | ** Add a string to list of constants and return its index. |
563 | */ | 562 | */ |
564 | int luaK_stringK (FuncState *fs, TString *s) { | 563 | static int stringK (FuncState *fs, TString *s) { |
565 | TValue o; | 564 | TValue o; |
566 | setsvalue(fs->ls->L, &o, s); | 565 | setsvalue(fs->ls->L, &o, s); |
567 | return addk(fs, &o, &o); /* use string itself as key */ | 566 | return addk(fs, &o, &o); /* use string itself as key */ |
@@ -656,7 +655,7 @@ static void luaK_float (FuncState *fs, int reg, lua_Number f) { | |||
656 | /* | 655 | /* |
657 | ** Convert a constant in 'v' into an expression description 'e' | 656 | ** Convert a constant in 'v' into an expression description 'e' |
658 | */ | 657 | */ |
659 | static void const2exp (FuncState *fs, TValue *v, expdesc *e) { | 658 | static void const2exp (TValue *v, expdesc *e) { |
660 | switch (ttypetag(v)) { | 659 | switch (ttypetag(v)) { |
661 | case LUA_TNUMINT: | 660 | case LUA_TNUMINT: |
662 | e->k = VKINT; e->u.ival = ivalue(v); | 661 | e->k = VKINT; e->u.ival = ivalue(v); |
@@ -671,7 +670,7 @@ static void const2exp (FuncState *fs, TValue *v, expdesc *e) { | |||
671 | e->k = VNIL; | 670 | e->k = VNIL; |
672 | break; | 671 | break; |
673 | case LUA_TSHRSTR: case LUA_TLNGSTR: | 672 | case LUA_TSHRSTR: case LUA_TLNGSTR: |
674 | e->k = VK; e->u.info = luaK_stringK(fs, tsvalue(v)); | 673 | e->k = VKSTR; e->u.strval = tsvalue(v); |
675 | break; | 674 | break; |
676 | default: lua_assert(0); | 675 | default: lua_assert(0); |
677 | } | 676 | } |
@@ -697,6 +696,16 @@ void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { | |||
697 | 696 | ||
698 | 697 | ||
699 | /* | 698 | /* |
699 | ** Convert a VKSTR to a VK | ||
700 | */ | ||
701 | static void str2K (FuncState *fs, expdesc *e) { | ||
702 | lua_assert(e->k == VKSTR); | ||
703 | e->u.info = stringK(fs, e->u.strval); | ||
704 | e->k = VK; | ||
705 | } | ||
706 | |||
707 | |||
708 | /* | ||
700 | ** Fix an expression to return one result. | 709 | ** Fix an expression to return one result. |
701 | ** If expression is not a multi-ret expression (function call or | 710 | ** If expression is not a multi-ret expression (function call or |
702 | ** vararg), it already returns one result, so nothing needs to be done. | 711 | ** vararg), it already returns one result, so nothing needs to be done. |
@@ -728,7 +737,7 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { | |||
728 | switch (e->k) { | 737 | switch (e->k) { |
729 | case VCONST: { | 738 | case VCONST: { |
730 | TValue *val = &fs->ls->dyd->actvar.arr[e->u.info].k; | 739 | TValue *val = &fs->ls->dyd->actvar.arr[e->u.info].k; |
731 | const2exp(fs, val, e); | 740 | const2exp(val, e); |
732 | break; | 741 | break; |
733 | } | 742 | } |
734 | case VLOCAL: { /* already in a register */ | 743 | case VLOCAL: { /* already in a register */ |
@@ -789,6 +798,9 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { | |||
789 | luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); | 798 | luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); |
790 | break; | 799 | break; |
791 | } | 800 | } |
801 | case VKSTR: { | ||
802 | str2K(fs, e); | ||
803 | } /* FALLTHROUGH */ | ||
792 | case VK: { | 804 | case VK: { |
793 | luaK_codek(fs, reg, e->u.info); | 805 | luaK_codek(fs, reg, e->u.info); |
794 | break; | 806 | break; |
@@ -949,6 +961,7 @@ static int luaK_exp2K (FuncState *fs, expdesc *e) { | |||
949 | case VNIL: info = nilK(fs); break; | 961 | case VNIL: info = nilK(fs); break; |
950 | case VKINT: info = luaK_intK(fs, e->u.ival); break; | 962 | case VKINT: info = luaK_intK(fs, e->u.ival); break; |
951 | case VKFLT: info = luaK_numberK(fs, e->u.nval); break; | 963 | case VKFLT: info = luaK_numberK(fs, e->u.nval); break; |
964 | case VKSTR: info = stringK(fs, e->u.strval); break; | ||
952 | case VK: info = e->u.info; break; | 965 | case VK: info = e->u.info; break; |
953 | default: return 0; /* not a constant */ | 966 | default: return 0; /* not a constant */ |
954 | } | 967 | } |
@@ -1083,7 +1096,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { | |||
1083 | pc = e->u.info; /* save jump position */ | 1096 | pc = e->u.info; /* save jump position */ |
1084 | break; | 1097 | break; |
1085 | } | 1098 | } |
1086 | case VK: case VKFLT: case VKINT: case VTRUE: { | 1099 | case VK: case VKFLT: case VKINT: case VKSTR: case VTRUE: { |
1087 | pc = NO_JUMP; /* always true; do nothing */ | 1100 | pc = NO_JUMP; /* always true; do nothing */ |
1088 | break; | 1101 | break; |
1089 | } | 1102 | } |
@@ -1133,7 +1146,7 @@ static void codenot (FuncState *fs, expdesc *e) { | |||
1133 | e->k = VTRUE; /* true == not nil == not false */ | 1146 | e->k = VTRUE; /* true == not nil == not false */ |
1134 | break; | 1147 | break; |
1135 | } | 1148 | } |
1136 | case VK: case VKFLT: case VKINT: case VTRUE: { | 1149 | case VK: case VKFLT: case VKINT: case VKSTR: case VTRUE: { |
1137 | e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */ | 1150 | e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */ |
1138 | break; | 1151 | break; |
1139 | } | 1152 | } |
@@ -1219,9 +1232,11 @@ static int isSCnumber (expdesc *e, lua_Integer *i, int *isfloat) { | |||
1219 | ** values in registers. | 1232 | ** values in registers. |
1220 | */ | 1233 | */ |
1221 | void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { | 1234 | void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { |
1235 | if (k->k == VKSTR) | ||
1236 | str2K(fs, k); | ||
1222 | lua_assert(!hasjumps(t) && | 1237 | lua_assert(!hasjumps(t) && |
1223 | (t->k == VLOCAL || t->k == VNONRELOC || t->k == VUPVAL)); | 1238 | (t->k == VLOCAL || t->k == VNONRELOC || t->k == VUPVAL)); |
1224 | if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non string? */ | 1239 | if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */ |
1225 | luaK_exp2anyreg(fs, t); /* put it in a register */ | 1240 | luaK_exp2anyreg(fs, t); /* put it in a register */ |
1226 | if (t->k == VUPVAL) { | 1241 | if (t->k == VUPVAL) { |
1227 | t->u.ind.t = t->u.info; /* upvalue index */ | 1242 | t->u.ind.t = t->u.info; /* upvalue index */ |
@@ -62,7 +62,6 @@ LUAI_FUNC void luaK_fixline (FuncState *fs, int line); | |||
62 | LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); | 62 | LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); |
63 | LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); | 63 | LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); |
64 | LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); | 64 | LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); |
65 | LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); | ||
66 | LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n); | 65 | LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n); |
67 | LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); | 66 | LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); |
68 | LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); | 67 | LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); |
@@ -156,13 +156,15 @@ static void init_exp (expdesc *e, expkind k, int i) { | |||
156 | } | 156 | } |
157 | 157 | ||
158 | 158 | ||
159 | static void codestring (LexState *ls, expdesc *e, TString *s) { | 159 | static void codestring (expdesc *e, TString *s) { |
160 | init_exp(e, VK, luaK_stringK(ls->fs, s)); | 160 | e->f = e->t = NO_JUMP; |
161 | e->k = VKSTR; | ||
162 | e->u.strval = s; | ||
161 | } | 163 | } |
162 | 164 | ||
163 | 165 | ||
164 | static void codename (LexState *ls, expdesc *e) { | 166 | static void codename (LexState *ls, expdesc *e) { |
165 | codestring(ls, e, str_checkname(ls)); | 167 | codestring(e, str_checkname(ls)); |
166 | } | 168 | } |
167 | 169 | ||
168 | 170 | ||
@@ -445,7 +447,7 @@ static void singlevar (LexState *ls, expdesc *var) { | |||
445 | expdesc key; | 447 | expdesc key; |
446 | singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ | 448 | singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ |
447 | lua_assert(var->k != VVOID); /* this one must exist */ | 449 | lua_assert(var->k != VVOID); /* this one must exist */ |
448 | codestring(ls, &key, varname); /* key is variable name */ | 450 | codestring(&key, varname); /* key is variable name */ |
449 | luaK_indexed(fs, var, &key); /* env[varname] */ | 451 | luaK_indexed(fs, var, &key); /* env[varname] */ |
450 | } | 452 | } |
451 | } | 453 | } |
@@ -1019,7 +1021,7 @@ static void funcargs (LexState *ls, expdesc *f, int line) { | |||
1019 | break; | 1021 | break; |
1020 | } | 1022 | } |
1021 | case TK_STRING: { /* funcargs -> STRING */ | 1023 | case TK_STRING: { /* funcargs -> STRING */ |
1022 | codestring(ls, &args, ls->t.seminfo.ts); | 1024 | codestring(&args, ls->t.seminfo.ts); |
1023 | luaX_next(ls); /* must use 'seminfo' before 'next' */ | 1025 | luaX_next(ls); /* must use 'seminfo' before 'next' */ |
1024 | break; | 1026 | break; |
1025 | } | 1027 | } |
@@ -1127,7 +1129,7 @@ static void simpleexp (LexState *ls, expdesc *v) { | |||
1127 | break; | 1129 | break; |
1128 | } | 1130 | } |
1129 | case TK_STRING: { | 1131 | case TK_STRING: { |
1130 | codestring(ls, v, ls->t.seminfo.ts); | 1132 | codestring(v, ls->t.seminfo.ts); |
1131 | break; | 1133 | break; |
1132 | } | 1134 | } |
1133 | case TK_NIL: { | 1135 | case TK_NIL: { |
@@ -30,7 +30,9 @@ typedef enum { | |||
30 | VFALSE, /* constant false */ | 30 | VFALSE, /* constant false */ |
31 | VK, /* constant in 'k'; info = index of constant in 'k' */ | 31 | VK, /* constant in 'k'; info = index of constant in 'k' */ |
32 | VKFLT, /* floating constant; nval = numerical float value */ | 32 | VKFLT, /* floating constant; nval = numerical float value */ |
33 | VKINT, /* integer constant; nval = numerical integer value */ | 33 | VKINT, /* integer constant; ival = numerical integer value */ |
34 | VKSTR, /* string constant; strval = TString address; | ||
35 | (string is fixed by the lexer) */ | ||
34 | VNONRELOC, /* expression has its value in a fixed register; | 36 | VNONRELOC, /* expression has its value in a fixed register; |
35 | info = result register */ | 37 | info = result register */ |
36 | VLOCAL, /* local variable; var.ridx = local register; | 38 | VLOCAL, /* local variable; var.ridx = local register; |
@@ -67,6 +69,7 @@ typedef struct expdesc { | |||
67 | union { | 69 | union { |
68 | lua_Integer ival; /* for VKINT */ | 70 | lua_Integer ival; /* for VKINT */ |
69 | lua_Number nval; /* for VKFLT */ | 71 | lua_Number nval; /* for VKFLT */ |
72 | TString *strval; /* for VKSTR */ | ||
70 | int info; /* for generic use */ | 73 | int info; /* for generic use */ |
71 | struct { /* for indexed variables */ | 74 | struct { /* for indexed variables */ |
72 | short idx; /* index (R or "long" K) */ | 75 | short idx; /* index (R or "long" K) */ |
diff --git a/testes/code.lua b/testes/code.lua index b2702c61..b5091458 100644 --- a/testes/code.lua +++ b/testes/code.lua | |||
@@ -409,5 +409,22 @@ checkequal(function () return 6 and true or nil end, | |||
409 | function () return k6 and kTrue or kNil end) | 409 | function () return k6 and kTrue or kNil end) |
410 | 410 | ||
411 | 411 | ||
412 | do -- string constants | ||
413 | local function f1 () | ||
414 | local <const> k = "00000000000000000000000000000000000000000000000000" | ||
415 | return function () | ||
416 | return function () return k end | ||
417 | end | ||
418 | end | ||
419 | |||
420 | local f2 = f1() | ||
421 | local f3 = f2() | ||
422 | assert(f3() == string.rep("0", 50)) | ||
423 | checkK(f3, f3()) | ||
424 | -- string is not needed by other functions | ||
425 | assert(T.listk(f1)[1] == nil) | ||
426 | assert(T.listk(f2)[1] == nil) | ||
427 | end | ||
428 | |||
412 | print 'OK' | 429 | print 'OK' |
413 | 430 | ||