Compare commits

...

88 Commits

Author SHA1 Message Date
Roberto Ierusalimschy
e354c6355e small updates 2017-01-31 19:17:47 -02:00
Roberto Ierusalimschy
94c1b3a8ee Handling of LUA_PATH/LUA_CPATH moved back to 'package' library
to avoid incompatibilites with previous releases
2017-01-12 15:14:26 -02:00
Roberto Ierusalimschy
08199ade4a release 5.3.4 (year 2017) 2016-12-22 13:51:20 -02:00
Roberto Ierusalimschy
2a235312f0 detail (removing spaces at end of lines) 2016-12-22 11:08:50 -02:00
Roberto Ierusalimschy
9903dd52a3 Using LUAI_UAC* types more consistently on vararg calls 2016-12-20 16:37:00 -02:00
Roberto Ierusalimschy
24f6e236a3 'moveresults' and 'luaD_poscall' moved up in the file 2016-12-13 13:52:21 -02:00
Roberto Ierusalimschy
9f594ca6f5 LUA_PATHSUFFIX -> LUA_VERSUFFIX + LUA_VERSUFFIX used in the
definition of LUA_INITVARVERSION, too.
2016-12-13 13:50:58 -02:00
Roberto Ierusalimschy
4df4560bf5 detail (wrong comment) 2016-12-06 12:54:31 -02:00
Roberto Ierusalimschy
b2aa2ba046 using constants for "_LOADED" and "PRELOAD" 2016-12-04 18:17:24 -02:00
Roberto Ierusalimschy
beec5af201 'luaL_tolstring' uses metatable's "__name" when available 2016-12-04 18:09:45 -02:00
Roberto Ierusalimschy
7b1fba69b7 using 'lastfree == NULL' to signal that table is using the dummy
node for its hash part + new macro 'allocsizenode'
2016-11-07 10:38:35 -02:00
Roberto Ierusalimschy
697593d8d5 bug: When a coroutine tries to resume a non-suspended coroutine,
it can do some mess (and break C assertions) before detecting the error.
2016-10-19 10:34:27 -02:00
Roberto Ierusalimschy
e2dc807c6e check whether function is finalizer when finding a name for it +
comments + some instructions can call functions in unespected ways
(e.g., finalizers)
2016-10-19 10:32:10 -02:00
Roberto Ierusalimschy
138d00176c new flag in 'CallInfo.callstatus' to tell whether function is running
as a finalizer
2016-10-19 10:31:42 -02:00
Roberto Ierusalimschy
8edbf57fb8 detail (ANSI C does not accept empty arguments to macros) 2016-09-20 13:37:45 -03:00
Roberto Ierusalimschy
7fe1a4cff3 cleaner and more correct code for 'luaD_shrinkstack' (the old
test "inuse <= LUAI_MAXSTACK" for stack overflow is not correct,
as the real maximum usable size is "LUAI_MAXSTACK - EXTRA_STACK")
2016-09-08 13:36:26 -03:00
Roberto Ierusalimschy
dbb6f11e8e bug (with compat on): 'ipairs' can work with any type that provides
an __index; so, 'pairsmeta' should not check for tables. ('pairs'
already checks for tables through 'next'.)
2016-09-05 16:06:34 -03:00
Roberto Ierusalimschy
aeb4c6fff1 comments + removed unused variable 2016-09-05 15:53:02 -03:00
Roberto Ierusalimschy
3b91b07fd9 detail (macro 'l_checkmode' reimplemented as function) 2016-09-01 13:14:56 -03:00
Roberto Ierusalimschy
349badabc1 wrong test in '#if' for floating-point type 2016-08-22 14:21:12 -03:00
Roberto Ierusalimschy
e4a9e6fcca do not eliminate varargs from functions that do not use varargs
(confuses the debug lib and gains very little in performance)
2016-08-01 16:51:24 -03:00
Roberto Ierusalimschy
9de2bb0d62 bug: When a coroutine tries to resume a non-suspended coroutine,
it coud do some mess (and break C assertions) before detecting the error.
Now it tests for those errors before anything else.
2016-07-29 14:12:44 -03:00
Roberto Ierusalimschy
d55fd3455b redefine MAXINDEXRK (for debugging, to force most values to
go through registers)
2016-07-19 14:13:00 -03:00
Roberto Ierusalimschy
0d1c6f4188 MAXINDEXRK can be redefined (for debugging, to force most values to
go through registers)
2016-07-19 14:12:21 -03:00
Roberto Ierusalimschy
fc6b32bcaa bug: Lua can generate wrong code in functions with too many constants 2016-07-19 14:12:07 -03:00
Roberto Ierusalimschy
de96e26afc bug: 'checkoption' could read past end of string + 'os.date' can
handle embedded zeros
2016-07-18 14:58:58 -03:00
Roberto Ierusalimschy
de3fd8ab83 Handling of LUA_PATH/LUA_CPATH moved from package library to stand
alone interpreter (so that 'lua.c' concentrates all handling of
environment variables)
2016-07-18 14:55:59 -03:00
Roberto Ierusalimschy
788109a3de new bug: Checking a format for 'os.date' may read pass the format string 2016-07-15 14:24:09 -03:00
Roberto Ierusalimschy
09c9fa36ea small corrections for C++ compliance 2016-06-27 10:15:08 -03:00
Roberto Ierusalimschy
dcb2998aa6 bug: expression list with four or more expressions in
a 'for' loop can crash the interpreter. ('adjust_assign' must
remove extra expresssions from its registers.)
2016-06-22 12:48:25 -03:00
Roberto Ierusalimschy
fac00ca023 bug: expression list with four or more expressions in
a 'for' loop can crash the interpreter.
2016-06-21 14:22:34 -03:00
Roberto Ierusalimschy
6487fb11fc all 'static' variables should be 'const' 2016-06-20 16:12:46 -03:00
Roberto Ierusalimschy
644799537f allow more bits in 'callstatus' (use no extra space due to alignments) 2016-06-16 10:36:09 -03:00
Roberto Ierusalimschy
aa66ca76ce 'lua_pushglobaltable' returns 'void' 2016-05-30 12:53:28 -03:00
Roberto Ierusalimschy
707b0ba6e2 'string.format("%q")' writes 'math.mininteger' in hexa, to ensure
it is read back as an integer
2016-05-20 11:13:21 -03:00
Roberto Ierusalimschy
10b0b09555 do not convert decimal constants with overflow to integers.
(Therefore, they will be converted as floats)
2016-05-20 11:07:48 -03:00
Roberto Ierusalimschy
4d5ab9baa6 'string.pack("cn")' does not accept strings longer than 'n' 2016-05-18 15:19:51 -03:00
Roberto Ierusalimschy
b65252b39b 'singlevaraux' returns result only in 'var->k' 2016-05-13 16:10:16 -03:00
Roberto Ierusalimschy
fbd8614bdb comment (FALLTHROUGH) 2016-05-13 16:09:46 -03:00
Roberto Ierusalimschy
f3b52a6061 'io.read("n")' accepts both a dot and the locale point as its
radix character + 'MAXRN' -> 'L_MAXLENNUM' + small detail in
'test2'
2016-05-02 11:03:19 -03:00
Roberto Ierusalimschy
0232fbffbe now that 'luaO_str2num' always accepts a dot as a radix character,
the lexer does not need to bother with this issue.
2016-05-02 11:02:12 -03:00
Roberto Ierusalimschy
ed110f66c5 'luaO_str2num' (and, therefore, 'lua_stringtonumber', 'number',
and coercions) accepts both the locale point and a dot as its
radix character
2016-05-02 11:00:32 -03:00
Roberto Ierusalimschy
22093f9c6e 'string.format("%q", number)' ensures a dot as decimal point 2016-05-02 10:58:01 -03:00
Roberto Ierusalimschy
792ffaccf2 detail (macro should "use" all its arguments) 2016-05-01 17:06:09 -03:00
Roberto Ierusalimschy
57cdb60429 no more time limits to pattern matching (at least for now) 2016-04-22 13:36:30 -03:00
Roberto Ierusalimschy
89c09c8e40 match time limit defined by variable 'string.pattlimit' 2016-04-19 09:34:08 -03:00
Roberto Ierusalimschy
48baa5e89c 'os.time(t)' normalizes 't' fields 2016-04-18 10:06:55 -03:00
Roberto Ierusalimschy
fdd7209688 error handling in 'wrap' does not coerce numbers into string messages 2016-04-11 16:19:55 -03:00
Roberto Ierusalimschy
82a8e06524 details ('error' does not coerce numbers to strings + comments) 2016-04-11 16:18:40 -03:00
Roberto Ierusalimschy
c258870c59 diff for last bug was against wrong version 2016-04-11 12:34:21 -03:00
Roberto Ierusalimschy
e8e39a277f 'string.format"%q"' now works for all basic types (nil, boolean,
numbers, and strings)
2016-04-08 18:15:02 -03:00
Roberto Ierusalimschy
fff7d42a69 LUA_PACKPADBYTE -> LUAL_PACKPADBYTE (it is an internal library
name, not something to be usually configured)
2016-04-07 12:40:07 -03:00
Roberto Ierusalimschy
783aa8a9da new way to avoid infinite loops in empty matches: "Python rule"
("Empty matches for the pattern are replaced only when not
adjacent to a previous match")
2016-03-31 16:07:42 -03:00
Roberto Ierusalimschy
8d4feb504f do not try to ensure that 'sweepgc' points to a live object
when entering sweep phase ('entersweep'); that may be too
expensive to be done still inside the atomic step. Walking
one single object more often than not will work.
2016-03-31 16:02:03 -03:00
Roberto Ierusalimschy
d77a7a8c26 detail (comment) 2016-03-31 16:01:21 -03:00
Roberto Ierusalimschy
e747491b96 comments 2016-03-23 15:08:26 -03:00
Roberto Ierusalimschy
acff3ad88d bug: 'gmatch' iterator fails when called from a coroutine different
from the one that created it
2016-03-23 14:12:17 -03:00
Roberto Ierusalimschy
e7b2e01d43 bug: label between local definitions can mix-up their initializations 2016-03-07 16:25:39 -03:00
Roberto Ierusalimschy
03ca6385dc call 'checkGC' *after* creating new objects (this is how 'execute'
does it)
(It increases the changes that 'allgc' start with a non-white
object, which helps 'entersweep')
2016-02-29 11:27:14 -03:00
Roberto Ierusalimschy
7777b412de When available, use metafield '__name' in error messages 2016-02-26 16:20:15 -03:00
Roberto Ierusalimschy
c3e9b14d24 '\0' is a control character, no need to check it explicitly 2016-02-25 16:42:55 -03:00
Roberto Ierusalimschy
7d6b78ee79 in 'table.move', destination table can be source table even if
given as an explicit extra argument
2016-02-25 16:41:54 -03:00
Roberto Ierusalimschy
5f3ad5731e simpler yet definition for 'checkoption' 2016-02-09 10:16:11 -02:00
Roberto Ierusalimschy
494e9ba0f4 simpler code for 'checkoption' + added conversion specifiers specific
to Windows
2016-02-08 12:42:46 -02:00
Roberto Ierusalimschy
f79b4568ae details (removed silly use of 'luaL_opt' + better error messages
in cases of "table expected")
2016-02-08 10:55:19 -02:00
Roberto Ierusalimschy
fd51651684 new macro 'vmfetch' to help changing code to computed goto's (macro
abstracts the code to run before each instruction)
2016-02-05 17:59:14 -02:00
Roberto Ierusalimschy
994374c4df new release number + new year 2016-01-13 15:55:19 -02:00
Roberto Ierusalimschy
62f6652d53 no more extra space in 'luaL_checkstack'. (It was already useless
for the first call, and function works ok without that space
anyway (just error message misses the 'msg' component)
2016-01-08 13:33:09 -02:00
Roberto Ierusalimschy
9945253d57 details (comments + text of error messages) 2016-01-06 11:43:05 -02:00
Roberto Ierusalimschy
1f259be52a 'getcode' -> 'getinstruction' 2016-01-05 14:22:37 -02:00
Roberto Ierusalimschy
1a44e82200 'luaV_fastget' only treats the real fast case (table with a non-nil
value at given key, so that it does not need to check metamethods)
2016-01-05 14:07:21 -02:00
Roberto Ierusalimschy
a272fa66f0 bug: Metatable may access its own dealocated field when
it has a self reference in __newindex + some refactoring
2016-01-04 14:44:50 -02:00
Roberto Ierusalimschy
b12b635a90 more refactoring 2016-01-04 11:40:57 -02:00
Roberto Ierusalimschy
7cd7c2e0a1 Metatable may access its own dealocated field when
it has a self reference in __newindex.
2016-01-04 11:35:56 -02:00
Roberto Ierusalimschy
07cf8415e3 more comments + reordeing of union inside 'expdesc' to allow
static initialization of a VKINT value
2015-12-30 16:16:13 -02:00
Roberto Ierusalimschy
c0836dda74 avoid empty macro arguments (invalid in C89) 2015-12-21 11:02:14 -02:00
Roberto Ierusalimschy
384d1b47b0 comments (*lots* of them) + asserts 2015-12-18 11:53:36 -02:00
Roberto Ierusalimschy
19770b03a9 comments. (More explanation about kinds of expressions.) 2015-12-17 13:44:50 -02:00
Roberto Ierusalimschy
a01eba657e reordering of some functions + 'code_label' renamed to 'code_loadbool' 2015-12-17 13:02:44 -02:00
Roberto Ierusalimschy
b7446ea88d detail ('while' -> 'for') in 'luaK_patchclose' 2015-12-17 12:52:53 -02:00
Roberto Ierusalimschy
a051b3323e comments (about hooks vs signals) 2015-12-16 14:40:07 -02:00
Roberto Ierusalimschy
c4e01c568a make 'hook' volatile (as it may be changed in signal handling) 2015-12-16 14:39:38 -02:00
Roberto Ierusalimschy
bda090b961 comments + small code changes around stack usage when 'luaL_checkstack'
raises an error (and needs the stack to create the error message...)
2015-12-14 09:59:27 -02:00
Roberto Ierusalimschy
e383941652 in 'table.sort': 'typedef' for type of indices + removed stack check
(recursion is in the C stack, not in the Lua stack!)
2015-12-14 09:57:38 -02:00
Roberto Ierusalimschy
656b3cea1b using 'sig_atomic_t' for 'hookmask' (as it can be changed inside
a signal)
2015-12-14 09:54:49 -02:00
Roberto Ierusalimschy
2d1d57bc18 comments 2015-12-14 09:53:27 -02:00
Roberto Ierusalimschy
03412af06e detail (removed fixed argument to function 'callallpendingfinalizers') 2015-12-10 16:12:30 -02:00
Roberto Ierusalimschy
542dbd4c65 detail (moving bodies of 'while' to a separate line) 2015-12-09 13:21:28 -02:00
42 changed files with 1613 additions and 915 deletions

221
bugs
View File

@@ -3465,7 +3465,7 @@ patch = [[
Bug{ Bug{
what = [['io.lines' does not check maximum number of options]], what = [['io.lines' does not check maximum number of options]],
report = [[Patrick Donnell, 2015/07/10]], report = [[Patrick Donnell, 2015/07/10]],
since = [[3.0]], since = [[5.3.0]],
fix = nil, fix = nil,
example = [[ example = [[
-- can segfault in some machines -- can segfault in some machines
@@ -3495,6 +3495,225 @@ patch = [[
} }
-----------------------------------------------------------------
-- Lua 5.3.2
Bug{
what = [[Metatable may access its own dealocated field when
it has a self reference in __newindex]],
report = [[actboy168@gmail.com, 2016/01/01]],
since = [[5.3.2]],
fix = nil,
example = [[
local mt = {}
mt.__newindex = mt
local t = setmetatable({}, mt)
t[1] = 1 -- will segfault on some machines
]],
patch = [[
--- lvm.c 2015/11/23 11:30:45 2.265
+++ lvm.c 2016/01/01 14:34:12
@@ -190,18 +190,19 @@
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (oldval != NULL) {
- lua_assert(ttistable(t) && ttisnil(oldval));
+ Table *h = hvalue(t); /* save 't' table */
+ lua_assert(ttisnil(oldval));
/* must check the metamethod */
- if ((tm = fasttm(L, hvalue(t)->metatable, TM_NEWINDEX)) == NULL &&
+ if ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL &&
/* no metamethod; is there a previous entry in the table? */
(oldval != luaO_nilobject ||
/* no previous entry; must create one. (The next test is
always true; we only need the assignment.) */
- (oldval = luaH_newkey(L, hvalue(t), key), 1))) {
+ (oldval = luaH_newkey(L, h, key), 1))) {
/* no metamethod and (now) there is an entry with given key */
setobj2t(L, cast(TValue *, oldval), val);
- invalidateTMcache(hvalue(t));
- luaC_barrierback(L, hvalue(t), val);
+ invalidateTMcache(h);
+ luaC_barrierback(L, h, val);
return;
}
/* else will try the metamethod */
]]
}
Bug{
what = [[label between local definitions can mix-up their initializations]],
report = [[Karel Tuma, 2016/03/01]],
since = [[5.2]],
fix = nil,
example = [[
do
local k = 0
local x
::foo::
local y -- should be reset to nil after goto, but it is not
assert(not y)
y = true
k = k + 1
if k < 2 then goto foo end
end
]],
patch = [[
--- lparser.c 2015/11/02 16:09:30 2.149
+++ lparser.c 2016/03/03 12:03:37
@@ -1226,7 +1226,7 @@
checkrepeated(fs, ll, label); /* check for repeated labels */
checknext(ls, TK_DBCOLON); /* skip double colon */
/* create new entry for this label */
- l = newlabelentry(ls, ll, label, line, fs->pc);
+ l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));
skipnoopstat(ls); /* skip other no-op statements */
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */
]]
}
Bug{
what = [['gmatch' iterator fails when called from a coroutine different
from the one that created it]],
report = [[Nagaev Boris, 2016/03/18]],
since = [[5.3.2]],
fix = nil,
example = [[
local f = string.gmatch("1 2 3 4 5", "%d+")
print(f()) --> 1
co = coroutine.wrap(f)
print(co()) --> ??? (should be 2)
]],
patch = [[
--- lstrlib.c 2015/11/25 16:28:17 1.239
+++ lstrlib.c 2016/04/11 15:29:41
@@ -688,6 +688,7 @@
static int gmatch_aux (lua_State *L) {
GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3));
const char *src;
+ gm->ms.L = L;
for (src = gm->src; src <= gm->ms.src_end; src++) {
const char *e;
reprepstate(&gm->ms);
]]
}
-----------------------------------------------------------------
-- Lua 5.3.3
Bug{
what = [[expression list with four or more expressions in
a 'for' loop can crash the interpreter]],
report = [[Marco Schöpl, 2016/06/17]],
since = [[5.2]],
fix = nil,
example = [[
-- the next loop will probably crash the interpreter
repeat until load "for _ in _,_,_,_ do local function _() end"
]],
patch = [[
--- lparser.c 2016/05/13 19:10:16 2.153
+++ lparser.c 2016/06/17 19:52:48
@@ -323,6 +323,8 @@
luaK_nil(fs, reg, extra);
}
}
+ if (nexps > nvars)
+ ls->fs->freereg -= nexps - nvars; /* remove extra values */
}
@@ -1160,11 +1162,8 @@
int nexps;
checknext(ls, '=');
nexps = explist(ls, &e);
- if (nexps != nvars) {
+ if (nexps != nvars)
adjust_assign(ls, nvars, nexps, &e);
- if (nexps > nvars)
- ls->fs->freereg -= nexps - nvars; /* remove extra values */
- }
else {
luaK_setoneret(ls->fs, &e); /* close last expression */
luaK_storevar(ls->fs, &lh->v, &e);
]]
}
Bug{
what = [[Checking a format for 'os.date' may read pass the format string]],
report = [[Nagaev Boris, 2016/07/10]],
since = [[5.3.3]],
fix = nil,
example = [[
This bug does not seem to happen with regular compilers.
It needs an "interceptor" 'memcmp' function that continues
reading memory after a difference is found.]],
patch = [[
2c2
< ** $Id: bugs,v 1.150 2016/07/19 17:10:45 roberto Exp roberto $
---
> ** $Id: bugs,v 1.150 2016/07/19 17:10:45 roberto Exp roberto $
263c263,264
< for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) {
---
> int convlen = (int)strlen(conv);
> for (option = LUA_STRFTIMEOPTIONS; *option != '\0' && oplen <= convlen; option += oplen) {
]]
}
Bug{
what = [[Lua can generate wrong code in functions with too many constants]],
report = [[Marco Schöpl, 2016/07/17]],
since = [[5.3.3]],
fix = nil,
example = [[See http://lua-users.org/lists/lua-l/2016-07/msg00303.html]],
patch = [[
--- lcode.c 2016/06/20 19:12:46 2.110
+++ lcode.c 2016/07/18 15:43:41
@@ -1018,8 +1018,8 @@
*/
static void codebinexpval (FuncState *fs, OpCode op,
expdesc *e1, expdesc *e2, int line) {
- int rk1 = luaK_exp2RK(fs, e1); /* both operands are "RK" */
- int rk2 = luaK_exp2RK(fs, e2);
+ int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */
+ int rk1 = luaK_exp2RK(fs, e1);
freeexps(fs, e1, e2);
e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */
e1->k = VRELOCABLE; /* all those operations are relocatable */
]]
}
Bug{
what = [[When a coroutine tries to resume a non-suspended coroutine,
it can do some mess (and break C assertions) before detecting the error]],
report = [[Marco Schöpl, 2016/07/20]],
since = [[ ]],
fix = nil,
example = [[
-- with C assertions on
A = coroutine.running()
B = coroutine.create(function() coroutine.resume(A) end)
coroutine.resume(B)
-- or
A = coroutine.wrap(function() pcall(A, _) end)
A()
]],
patch = [[
]]
}
]=]
--[=[ --[=[
Bug{ Bug{
what = [[ ]], what = [[ ]],

48
lapi.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lapi.c,v 2.256 2015/10/06 16:10:22 roberto Exp roberto $ ** $Id: lapi.c,v 2.258 2016/01/05 16:07:21 roberto Exp roberto $
** Lua API ** Lua API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -378,9 +378,9 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
return NULL; return NULL;
} }
lua_lock(L); /* 'luaO_tostring' may create a new string */ lua_lock(L); /* 'luaO_tostring' may create a new string */
luaO_tostring(L, o);
luaC_checkGC(L); luaC_checkGC(L);
o = index2addr(L, idx); /* previous call may reallocate the stack */ o = index2addr(L, idx); /* previous call may reallocate the stack */
luaO_tostring(L, o);
lua_unlock(L); lua_unlock(L);
} }
if (len != NULL) if (len != NULL)
@@ -479,10 +479,10 @@ LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts; TString *ts;
lua_lock(L); lua_lock(L);
luaC_checkGC(L);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top, ts);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
return getstr(ts); return getstr(ts);
} }
@@ -494,12 +494,12 @@ LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
setnilvalue(L->top); setnilvalue(L->top);
else { else {
TString *ts; TString *ts;
luaC_checkGC(L);
ts = luaS_new(L, s); ts = luaS_new(L, s);
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top, ts);
s = getstr(ts); /* internal copy's address */ s = getstr(ts); /* internal copy's address */
} }
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
return s; return s;
} }
@@ -509,8 +509,8 @@ LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,
va_list argp) { va_list argp) {
const char *ret; const char *ret;
lua_lock(L); lua_lock(L);
luaC_checkGC(L);
ret = luaO_pushvfstring(L, fmt, argp); ret = luaO_pushvfstring(L, fmt, argp);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
return ret; return ret;
} }
@@ -520,10 +520,10 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
const char *ret; const char *ret;
va_list argp; va_list argp;
lua_lock(L); lua_lock(L);
luaC_checkGC(L);
va_start(argp, fmt); va_start(argp, fmt);
ret = luaO_pushvfstring(L, fmt, argp); ret = luaO_pushvfstring(L, fmt, argp);
va_end(argp); va_end(argp);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
return ret; return ret;
} }
@@ -538,7 +538,6 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
CClosure *cl; CClosure *cl;
api_checknelems(L, n); api_checknelems(L, n);
api_check(L, n <= MAXUPVAL, "upvalue index too large"); api_check(L, n <= MAXUPVAL, "upvalue index too large");
luaC_checkGC(L);
cl = luaF_newCclosure(L, n); cl = luaF_newCclosure(L, n);
cl->f = fn; cl->f = fn;
L->top -= n; L->top -= n;
@@ -549,6 +548,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
setclCvalue(L, L->top, cl); setclCvalue(L, L->top, cl);
} }
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
} }
@@ -585,16 +585,16 @@ LUA_API int lua_pushthread (lua_State *L) {
static int auxgetstr (lua_State *L, const TValue *t, const char *k) { static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *aux; const TValue *slot;
TString *str = luaS_new(L, k); TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, aux, luaH_getstr)) { if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
setobj2s(L, L->top, aux); setobj2s(L, L->top, slot);
api_incr_top(L); api_incr_top(L);
} }
else { else {
setsvalue2s(L, L->top, str); setsvalue2s(L, L->top, str);
api_incr_top(L); api_incr_top(L);
luaV_finishget(L, t, L->top - 1, L->top - 1, aux); luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
} }
lua_unlock(L); lua_unlock(L);
return ttnov(L->top - 1); return ttnov(L->top - 1);
@@ -626,17 +626,17 @@ LUA_API int lua_getfield (lua_State *L, int idx, const char *k) {
LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
StkId t; StkId t;
const TValue *aux; const TValue *slot;
lua_lock(L); lua_lock(L);
t = index2addr(L, idx); t = index2addr(L, idx);
if (luaV_fastget(L, t, n, aux, luaH_getint)) { if (luaV_fastget(L, t, n, slot, luaH_getint)) {
setobj2s(L, L->top, aux); setobj2s(L, L->top, slot);
api_incr_top(L); api_incr_top(L);
} }
else { else {
setivalue(L->top, n); setivalue(L->top, n);
api_incr_top(L); api_incr_top(L);
luaV_finishget(L, t, L->top - 1, L->top - 1, aux); luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
} }
lua_unlock(L); lua_unlock(L);
return ttnov(L->top - 1); return ttnov(L->top - 1);
@@ -683,12 +683,12 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t; Table *t;
lua_lock(L); lua_lock(L);
luaC_checkGC(L);
t = luaH_new(L); t = luaH_new(L);
sethvalue(L, L->top, t); sethvalue(L, L->top, t);
api_incr_top(L); api_incr_top(L);
if (narray > 0 || nrec > 0) if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec); luaH_resize(L, t, narray, nrec);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
} }
@@ -740,15 +740,15 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) {
** t[k] = value at the top of the stack (where 'k' is a string) ** t[k] = value at the top of the stack (where 'k' is a string)
*/ */
static void auxsetstr (lua_State *L, const TValue *t, const char *k) { static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *aux; const TValue *slot;
TString *str = luaS_new(L, k); TString *str = luaS_new(L, k);
api_checknelems(L, 1); api_checknelems(L, 1);
if (luaV_fastset(L, t, str, aux, luaH_getstr, L->top - 1)) if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1))
L->top--; /* pop value */ L->top--; /* pop value */
else { else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
api_incr_top(L); api_incr_top(L);
luaV_finishset(L, t, L->top - 1, L->top - 2, aux); luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
L->top -= 2; /* pop value and key */ L->top -= 2; /* pop value and key */
} }
lua_unlock(L); /* lock done by caller */ lua_unlock(L); /* lock done by caller */
@@ -781,16 +781,16 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
StkId t; StkId t;
const TValue *aux; const TValue *slot;
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = index2addr(L, idx); t = index2addr(L, idx);
if (luaV_fastset(L, t, n, aux, luaH_getint, L->top - 1)) if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1))
L->top--; /* pop value */ L->top--; /* pop value */
else { else {
setivalue(L->top, n); setivalue(L->top, n);
api_incr_top(L); api_incr_top(L);
luaV_finishset(L, t, L->top - 1, L->top - 2, aux); luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
L->top -= 2; /* pop value and key */ L->top -= 2; /* pop value and key */
} }
lua_unlock(L); lua_unlock(L);
@@ -1140,7 +1140,6 @@ LUA_API void lua_concat (lua_State *L, int n) {
lua_lock(L); lua_lock(L);
api_checknelems(L, n); api_checknelems(L, n);
if (n >= 2) { if (n >= 2) {
luaC_checkGC(L);
luaV_concat(L, n); luaV_concat(L, n);
} }
else if (n == 0) { /* push empty string */ else if (n == 0) { /* push empty string */
@@ -1148,6 +1147,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
api_incr_top(L); api_incr_top(L);
} }
/* else n == 1; nothing to do */ /* else n == 1; nothing to do */
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
} }
@@ -1183,10 +1183,10 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {
LUA_API void *lua_newuserdata (lua_State *L, size_t size) { LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
Udata *u; Udata *u;
lua_lock(L); lua_lock(L);
luaC_checkGC(L);
u = luaS_newudata(L, size); u = luaS_newudata(L, size);
setuvalue(L, L->top, u); setuvalue(L, L->top, u);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
return getudatamem(u); return getudatamem(u);
} }

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lauxlib.c,v 1.283 2015/10/06 16:10:22 roberto Exp roberto $ ** $Id: lauxlib.c,v 1.288 2016/12/04 20:17:24 roberto Exp roberto $
** Auxiliary functions for building Lua libraries ** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -17,7 +17,8 @@
#include <string.h> #include <string.h>
/* This file uses only the official API of Lua. /*
** This file uses only the official API of Lua.
** Any function declared here could be written as an application function. ** Any function declared here could be written as an application function.
*/ */
@@ -68,12 +69,11 @@ static int findfield (lua_State *L, int objidx, int level) {
/* /*
** Search for a name for a function in all loaded modules ** Search for a name for a function in all loaded modules
** (registry._LOADED).
*/ */
static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
int top = lua_gettop(L); int top = lua_gettop(L);
lua_getinfo(L, "f", ar); /* push function */ lua_getinfo(L, "f", ar); /* push function */
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
if (findfield(L, top + 1, 2)) { if (findfield(L, top + 1, 2)) {
const char *name = lua_tostring(L, -1); const char *name = lua_tostring(L, -1);
if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */ if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */
@@ -198,6 +198,10 @@ static void tag_error (lua_State *L, int arg, int tag) {
} }
/*
** The use of 'lua_pushfstring' ensures this function does not
** need reserved stack space when called.
*/
LUALIB_API void luaL_where (lua_State *L, int level) { LUALIB_API void luaL_where (lua_State *L, int level) {
lua_Debug ar; lua_Debug ar;
if (lua_getstack(L, level, &ar)) { /* check function at level */ if (lua_getstack(L, level, &ar)) { /* check function at level */
@@ -207,10 +211,15 @@ LUALIB_API void luaL_where (lua_State *L, int level) {
return; return;
} }
} }
lua_pushliteral(L, ""); /* else, no information available... */ lua_pushfstring(L, ""); /* else, no information available... */
} }
/*
** Again, the use of 'lua_pushvfstring' ensures this function does
** not need reserved stack space when called. (At worst, it generates
** an error with "stack overflow" instead of the given message.)
*/
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
va_list argp; va_list argp;
va_start(argp, fmt); va_start(argp, fmt);
@@ -349,10 +358,15 @@ LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,
} }
/*
** Ensures the stack has at least 'space' extra slots, raising an error
** if it cannot fulfill the request. (The error handling needs a few
** extra slots to format the error message. In case of an error without
** this extra space, Lua will generate the same 'stack overflow' error,
** but without 'msg'.)
*/
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
/* keep some extra space to run error routines, if needed */ if (!lua_checkstack(L, space)) {
const int extra = LUA_MINSTACK;
if (!lua_checkstack(L, space + extra)) {
if (msg) if (msg)
luaL_error(L, "stack overflow (%s)", msg); luaL_error(L, "stack overflow (%s)", msg);
else else
@@ -678,7 +692,7 @@ static int skipcomment (LoadF *lf, int *cp) {
if (c == '#') { /* first line is a comment (Unix exec. file)? */ if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */ do { /* skip first line */
c = getc(lf->f); c = getc(lf->f);
} while (c != EOF && c != '\n') ; } while (c != EOF && c != '\n');
*cp = getc(lf->f); /* skip end-of-line, if present */ *cp = getc(lf->f); /* skip end-of-line, if present */
return 1; /* there was a comment */ return 1; /* there was a comment */
} }
@@ -794,13 +808,17 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */ if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */
if (!lua_isstring(L, -1))
luaL_error(L, "'__tostring' must return a string");
}
else {
switch (lua_type(L, idx)) { switch (lua_type(L, idx)) {
case LUA_TNUMBER: { case LUA_TNUMBER: {
if (lua_isinteger(L, idx)) if (lua_isinteger(L, idx))
lua_pushfstring(L, "%I", lua_tointeger(L, idx)); lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx));
else else
lua_pushfstring(L, "%f", lua_tonumber(L, idx)); lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx));
break; break;
} }
case LUA_TSTRING: case LUA_TSTRING:
@@ -812,10 +830,15 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
case LUA_TNIL: case LUA_TNIL:
lua_pushliteral(L, "nil"); lua_pushliteral(L, "nil");
break; break;
default: default: {
lua_pushfstring(L, "%s: %p", luaL_typename(L, idx), int tt = luaL_getmetafield(L, idx, "__name"); /* try name */
lua_topointer(L, idx)); const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) :
luaL_typename(L, idx);
lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx));
if (tt != LUA_TNIL)
lua_remove(L, -2); /* remove '__name' */
break; break;
}
} }
} }
return lua_tolstring(L, -1, len); return lua_tolstring(L, -1, len);
@@ -867,23 +890,23 @@ static int libsize (const luaL_Reg *l) {
/* /*
** Find or create a module table with a given name. The function ** Find or create a module table with a given name. The function
** first looks at the _LOADED table and, if that fails, try a ** first looks at the LOADED table and, if that fails, try a
** global variable with that name. In any case, leaves on the stack ** global variable with that name. In any case, leaves on the stack
** the module table. ** the module table.
*/ */
LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname, LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
int sizehint) { int sizehint) {
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */ luaL_findtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE, 1);
if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no _LOADED[modname]? */ if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no LOADED[modname]? */
lua_pop(L, 1); /* remove previous result */ lua_pop(L, 1); /* remove previous result */
/* try global variable (and create one if it does not exist) */ /* try global variable (and create one if it does not exist) */
lua_pushglobaltable(L); lua_pushglobaltable(L);
if (luaL_findtable(L, 0, modname, sizehint) != NULL) if (luaL_findtable(L, 0, modname, sizehint) != NULL)
luaL_error(L, "name conflict for module '%s'", modname); luaL_error(L, "name conflict for module '%s'", modname);
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */ lua_setfield(L, -3, modname); /* LOADED[modname] = new table */
} }
lua_remove(L, -2); /* remove _LOADED table */ lua_remove(L, -2); /* remove LOADED table */
} }
@@ -947,17 +970,17 @@ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
*/ */
LUALIB_API void luaL_requiref (lua_State *L, const char *modname, LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
lua_CFunction openf, int glb) { lua_CFunction openf, int glb) {
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_getfield(L, -1, modname); /* _LOADED[modname] */ lua_getfield(L, -1, modname); /* LOADED[modname] */
if (!lua_toboolean(L, -1)) { /* package not already loaded? */ if (!lua_toboolean(L, -1)) { /* package not already loaded? */
lua_pop(L, 1); /* remove field */ lua_pop(L, 1); /* remove field */
lua_pushcfunction(L, openf); lua_pushcfunction(L, openf);
lua_pushstring(L, modname); /* argument to open function */ lua_pushstring(L, modname); /* argument to open function */
lua_call(L, 1, 1); /* call 'openf' to open module */ lua_call(L, 1, 1); /* call 'openf' to open module */
lua_pushvalue(L, -1); /* make copy of module (call result) */ lua_pushvalue(L, -1); /* make copy of module (call result) */
lua_setfield(L, -3, modname); /* _LOADED[modname] = module */ lua_setfield(L, -3, modname); /* LOADED[modname] = module */
} }
lua_remove(L, -2); /* remove _LOADED table */ lua_remove(L, -2); /* remove LOADED table */
if (glb) { if (glb) {
lua_pushvalue(L, -1); /* copy of module */ lua_pushvalue(L, -1); /* copy of module */
lua_setglobal(L, modname); /* _G[modname] = module */ lua_setglobal(L, modname); /* _G[modname] = module */
@@ -1015,6 +1038,6 @@ LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) {
luaL_error(L, "multiple Lua VMs detected"); luaL_error(L, "multiple Lua VMs detected");
else if (*v != ver) else if (*v != ver)
luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
ver, *v); (LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)*v);
} }

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lauxlib.h,v 1.128 2014/10/29 16:11:17 roberto Exp roberto $ ** $Id: lauxlib.h,v 1.130 2016/12/04 20:17:24 roberto Exp roberto $
** Auxiliary functions for building Lua libraries ** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -16,10 +16,18 @@
/* extra error code for 'luaL_load' */ /* extra error code for 'luaL_loadfilex' */
#define LUA_ERRFILE (LUA_ERRERR+1) #define LUA_ERRFILE (LUA_ERRERR+1)
/* key, in the registry, for table of loaded modules */
#define LUA_LOADED_TABLE "_LOADED"
/* key, in the registry, for table of preloaded loaders */
#define LUA_PRELOAD_TABLE "_PRELOAD"
typedef struct luaL_Reg { typedef struct luaL_Reg {
const char *name; const char *name;
lua_CFunction func; lua_CFunction func;

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lbaselib.c,v 1.311 2015/06/26 19:25:45 roberto Exp roberto $ ** $Id: lbaselib.c,v 1.313 2016/04/11 19:18:40 roberto Exp roberto $
** Basic library ** Basic library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -102,8 +102,8 @@ static int luaB_tonumber (lua_State *L) {
static int luaB_error (lua_State *L) { static int luaB_error (lua_State *L) {
int level = (int)luaL_optinteger(L, 2, 1); int level = (int)luaL_optinteger(L, 2, 1);
lua_settop(L, 1); lua_settop(L, 1);
if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ if (lua_type(L, 1) == LUA_TSTRING && level > 0) {
luaL_where(L, level); luaL_where(L, level); /* add extra information */
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
lua_concat(L, 2); lua_concat(L, 2);
} }
@@ -208,8 +208,8 @@ static int luaB_type (lua_State *L) {
static int pairsmeta (lua_State *L, const char *method, int iszero, static int pairsmeta (lua_State *L, const char *method, int iszero,
lua_CFunction iter) { lua_CFunction iter) {
luaL_checkany(L, 1);
if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */ if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */
luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */
lua_pushcfunction(L, iter); /* will return generator, */ lua_pushcfunction(L, iter); /* will return generator, */
lua_pushvalue(L, 1); /* state, */ lua_pushvalue(L, 1); /* state, */
if (iszero) lua_pushinteger(L, 0); /* and initial value */ if (iszero) lua_pushinteger(L, 0); /* and initial value */
@@ -251,9 +251,8 @@ static int ipairsaux (lua_State *L) {
/* /*
** This function will use either 'ipairsaux' or 'ipairsaux_raw' to ** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
** traverse a table, depending on whether the table has metamethods ** (The given "table" may not be a table.)
** that can affect the traversal.
*/ */
static int luaB_ipairs (lua_State *L) { static int luaB_ipairs (lua_State *L) {
#if defined(LUA_COMPAT_IPAIRS) #if defined(LUA_COMPAT_IPAIRS)

702
lcode.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lcode.h,v 1.62 2013/12/18 14:12:03 roberto Exp roberto $ ** $Id: lcode.h,v 1.63 2013/12/30 20:47:58 roberto Exp roberto $
** Code generator for Lua ** Code generator for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -40,7 +40,8 @@ typedef enum BinOpr {
typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
#define getcode(fs,e) ((fs)->f->code[(e)->u.info]) /* get (pointer to) instruction of given 'expdesc' */
#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info])
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) #define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lcorolib.c,v 1.8 2014/10/25 11:50:46 roberto Exp roberto $ ** $Id: lcorolib.c,v 1.9 2014/11/02 19:19:04 roberto Exp roberto $
** Coroutine Library ** Coroutine Library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -75,7 +75,7 @@ static int luaB_auxwrap (lua_State *L) {
lua_State *co = lua_tothread(L, lua_upvalueindex(1)); lua_State *co = lua_tothread(L, lua_upvalueindex(1));
int r = auxresume(L, co, lua_gettop(L)); int r = auxresume(L, co, lua_gettop(L));
if (r < 0) { if (r < 0) {
if (lua_isstring(L, -1)) { /* error object is a string? */ if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */
luaL_where(L, 1); /* add extra info */ luaL_where(L, 1); /* add extra info */
lua_insert(L, -2); lua_insert(L, -2);
lua_concat(L, 2); lua_concat(L, 2);

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ldebug.c,v 2.116 2015/10/22 14:40:47 roberto Exp roberto $ ** $Id: ldebug.c,v 2.120 2016/03/31 19:01:21 roberto Exp roberto $
** Debug Interface ** Debug Interface
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -38,7 +38,8 @@
#define ci_func(ci) (clLvalue((ci)->func)) #define ci_func(ci) (clLvalue((ci)->func))
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
const char **name);
static int currentpc (CallInfo *ci) { static int currentpc (CallInfo *ci) {
@@ -69,7 +70,13 @@ static void swapextra (lua_State *L) {
/* /*
** this function can be called asynchronous (e.g. during a signal) ** This function can be called asynchronously (e.g. during a signal).
** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by
** 'resethookcount') are for debug only, and it is no problem if they
** get arbitrary values (causes at most one wrong hook call). 'hookmask'
** is an atomic value. We assume that pointers are atomic too (e.g., gcc
** ensures that for all platforms where it runs). Moreover, 'hook' is
** always checked before being called (see 'luaD_hook').
*/ */
LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
if (func == NULL || mask == 0) { /* turn off hooks? */ if (func == NULL || mask == 0) { /* turn off hooks? */
@@ -238,6 +245,20 @@ static void collectvalidlines (lua_State *L, Closure *f) {
} }
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
if (ci == NULL) /* no 'ci'? */
return NULL; /* no info */
else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */
*name = "__gc";
return "metamethod"; /* report it as such */
}
/* calling function is a known Lua function? */
else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
return funcnamefromcode(L, ci->previous, name);
else return NULL; /* no way to find a name */
}
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
Closure *f, CallInfo *ci) { Closure *f, CallInfo *ci) {
int status = 1; int status = 1;
@@ -268,11 +289,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
break; break;
} }
case 'n': { case 'n': {
/* calling function is a known Lua function? */ ar->namewhat = getfuncname(L, ci, &ar->name);
if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
ar->namewhat = getfuncname(L, ci->previous, &ar->name);
else
ar->namewhat = NULL;
if (ar->namewhat == NULL) { if (ar->namewhat == NULL) {
ar->namewhat = ""; /* not found */ ar->namewhat = ""; /* not found */
ar->name = NULL; ar->name = NULL;
@@ -465,8 +482,15 @@ static const char *getobjname (Proto *p, int lastpc, int reg,
} }
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { /*
TMS tm = (TMS)0; /* to avoid warnings */ ** Try to find a name for a function based on the code that called it.
** (Only works when function was called by a Lua function.)
** Returns what the name is (e.g., "for iterator", "method",
** "metamethod") and sets '*name' to point to the name.
*/
static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
const char **name) {
TMS tm = (TMS)0; /* (initial value avoids warnings) */
Proto *p = ci_func(ci)->p; /* calling function */ Proto *p = ci_func(ci)->p; /* calling function */
int pc = currentpc(ci); /* calling instruction index */ int pc = currentpc(ci); /* calling instruction index */
Instruction i = p->code[pc]; /* calling instruction */ Instruction i = p->code[pc]; /* calling instruction */
@@ -476,13 +500,13 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
} }
switch (GET_OPCODE(i)) { switch (GET_OPCODE(i)) {
case OP_CALL: case OP_CALL:
case OP_TAILCALL: /* get function name */ case OP_TAILCALL:
return getobjname(p, pc, GETARG_A(i), name); return getobjname(p, pc, GETARG_A(i), name); /* get function name */
case OP_TFORCALL: { /* for iterator */ case OP_TFORCALL: { /* for iterator */
*name = "for iterator"; *name = "for iterator";
return "for iterator"; return "for iterator";
} }
/* all other instructions can call only through metamethods */ /* other instructions can do calls through metamethods */
case OP_SELF: case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: case OP_GETTABUP: case OP_GETTABLE:
tm = TM_INDEX; tm = TM_INDEX;
break; break;
@@ -503,7 +527,8 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
case OP_EQ: tm = TM_EQ; break; case OP_EQ: tm = TM_EQ; break;
case OP_LT: tm = TM_LT; break; case OP_LT: tm = TM_LT; break;
case OP_LE: tm = TM_LE; break; case OP_LE: tm = TM_LE; break;
default: lua_assert(0); /* other instructions cannot call a function */ default:
return NULL; /* cannot find a reasonable name */
} }
*name = getstr(G(L)->tmname[tm]); *name = getstr(G(L)->tmname[tm]);
return "metamethod"; return "metamethod";
@@ -558,7 +583,7 @@ static const char *varinfo (lua_State *L, const TValue *o) {
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
const char *t = objtypename(o); const char *t = luaT_objtypename(L, o);
luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
} }
@@ -590,9 +615,9 @@ l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
const char *t1 = objtypename(p1); const char *t1 = luaT_objtypename(L, p1);
const char *t2 = objtypename(p2); const char *t2 = luaT_objtypename(L, p2);
if (t1 == t2) if (strcmp(t1, t2) == 0)
luaG_runerror(L, "attempt to compare two %s values", t1); luaG_runerror(L, "attempt to compare two %s values", t1);
else else
luaG_runerror(L, "attempt to compare %s with %s", t1, t2); luaG_runerror(L, "attempt to compare %s with %s", t1, t2);

233
ldo.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ldo.c,v 2.149 2015/11/13 13:24:26 roberto Exp roberto $ ** $Id: ldo.c,v 2.156 2016/09/20 16:37:45 roberto Exp roberto $
** Stack and Call structure of Lua ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -211,9 +211,9 @@ static int stackinuse (lua_State *L) {
CallInfo *ci; CallInfo *ci;
StkId lim = L->top; StkId lim = L->top;
for (ci = L->ci; ci != NULL; ci = ci->previous) { for (ci = L->ci; ci != NULL; ci = ci->previous) {
lua_assert(ci->top <= L->stack_last);
if (lim < ci->top) lim = ci->top; if (lim < ci->top) lim = ci->top;
} }
lua_assert(lim <= L->stack_last);
return cast_int(lim - L->stack) + 1; /* part of stack in use */ return cast_int(lim - L->stack) + 1; /* part of stack in use */
} }
@@ -221,16 +221,19 @@ static int stackinuse (lua_State *L) {
void luaD_shrinkstack (lua_State *L) { void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L); int inuse = stackinuse(L);
int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK; if (goodsize > LUAI_MAXSTACK)
if (L->stacksize > LUAI_MAXSTACK) /* was handling stack overflow? */ goodsize = LUAI_MAXSTACK; /* respect stack limit */
if (L->stacksize > LUAI_MAXSTACK) /* had been handling stack overflow? */
luaE_freeCI(L); /* free all CIs (list grew because of an error) */ luaE_freeCI(L); /* free all CIs (list grew because of an error) */
else else
luaE_shrinkCI(L); /* shrink list */ luaE_shrinkCI(L); /* shrink list */
if (inuse <= LUAI_MAXSTACK && /* not handling stack overflow? */ /* if thread is currently not handling a stack overflow and its
goodsize < L->stacksize) /* trying to shrink? */ good size is smaller than current size, shrink its stack */
luaD_reallocstack(L, goodsize); /* shrink it */ if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) &&
else goodsize < L->stacksize)
condmovestack(L,,); /* don't change stack (change only for debugging) */ luaD_reallocstack(L, goodsize);
else /* don't change stack */
condmovestack(L,{},{}); /* (change only for debugging) */
} }
@@ -242,9 +245,14 @@ void luaD_inctop (lua_State *L) {
/* }================================================================== */ /* }================================================================== */
/*
** Call a hook for the given event. Make sure there is a hook to be
** called. (Both 'L->hook' and 'L->hookmask', which triggers this
** function, can be changed asynchronously by signals.)
*/
void luaD_hook (lua_State *L, int event, int line) { void luaD_hook (lua_State *L, int event, int line) {
lua_Hook hook = L->hook; lua_Hook hook = L->hook;
if (hook && L->allowhook) { if (hook && L->allowhook) { /* make sure there is a hook */
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top); ptrdiff_t top = savestack(L, L->top);
ptrdiff_t ci_top = savestack(L, ci->top); ptrdiff_t ci_top = savestack(L, ci->top);
@@ -317,86 +325,6 @@ static void tryfuncTM (lua_State *L, StkId func) {
} }
#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
/* macro to check stack size, preserving 'p' */
#define checkstackp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
luaC_checkGC(L), /* stack grow uses memory */ \
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
/*
** Prepares a function call: checks the stack, creates a new CallInfo
** entry, fills in the relevant information, calls hook if needed.
** If function is a C function, does the call, too. (Otherwise, leave
** the execution ('luaV_execute') to the caller, to allow stackless
** calls.) Returns true iff function has been executed (C function).
*/
int luaD_precall (lua_State *L, StkId func, int nresults) {
lua_CFunction f;
CallInfo *ci;
switch (ttype(func)) {
case LUA_TCCL: /* C closure */
f = clCvalue(func)->f;
goto Cfunc;
case LUA_TLCF: /* light C function */
f = fvalue(func);
Cfunc: {
int n; /* number of returns */
checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = func;
ci->top = L->top + LUA_MINSTACK;
lua_assert(ci->top <= L->stack_last);
ci->callstatus = 0;
if (L->hookmask & LUA_MASKCALL)
luaD_hook(L, LUA_HOOKCALL, -1);
lua_unlock(L);
n = (*f)(L); /* do the actual call */
lua_lock(L);
api_checknelems(L, n);
luaD_poscall(L, ci, L->top - n, n);
return 1;
}
case LUA_TLCL: { /* Lua function: prepare its call */
StkId base;
Proto *p = clLvalue(func)->p;
int n = cast_int(L->top - func) - 1; /* number of real arguments */
int fsize = p->maxstacksize; /* frame size */
checkstackp(L, fsize, func);
if (p->is_vararg != 1) { /* do not use vararg? */
for (; n < p->numparams; n++)
setnilvalue(L->top++); /* complete missing arguments */
base = func + 1;
}
else
base = adjust_varargs(L, p, n);
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = func;
ci->u.l.base = base;
L->top = ci->top = base + fsize;
lua_assert(ci->top <= L->stack_last);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus = CIST_LUA;
if (L->hookmask & LUA_MASKCALL)
callhook(L, ci);
return 0;
}
default: { /* not a function */
checkstackp(L, 1, func); /* ensure space for metamethod */
tryfuncTM(L, func); /* try to get '__call' metamethod */
return luaD_precall(L, func, nresults); /* now it must be a function */
}
}
}
/* /*
** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'. ** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'.
** Handle most typical cases (zero results for commands, one result for ** Handle most typical cases (zero results for commands, one result for
@@ -463,6 +391,86 @@ int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
} }
#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
/* macro to check stack size, preserving 'p' */
#define checkstackp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
luaC_checkGC(L), /* stack grow uses memory */ \
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
/*
** Prepares a function call: checks the stack, creates a new CallInfo
** entry, fills in the relevant information, calls hook if needed.
** If function is a C function, does the call, too. (Otherwise, leave
** the execution ('luaV_execute') to the caller, to allow stackless
** calls.) Returns true iff function has been executed (C function).
*/
int luaD_precall (lua_State *L, StkId func, int nresults) {
lua_CFunction f;
CallInfo *ci;
switch (ttype(func)) {
case LUA_TCCL: /* C closure */
f = clCvalue(func)->f;
goto Cfunc;
case LUA_TLCF: /* light C function */
f = fvalue(func);
Cfunc: {
int n; /* number of returns */
checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = func;
ci->top = L->top + LUA_MINSTACK;
lua_assert(ci->top <= L->stack_last);
ci->callstatus = 0;
if (L->hookmask & LUA_MASKCALL)
luaD_hook(L, LUA_HOOKCALL, -1);
lua_unlock(L);
n = (*f)(L); /* do the actual call */
lua_lock(L);
api_checknelems(L, n);
luaD_poscall(L, ci, L->top - n, n);
return 1;
}
case LUA_TLCL: { /* Lua function: prepare its call */
StkId base;
Proto *p = clLvalue(func)->p;
int n = cast_int(L->top - func) - 1; /* number of real arguments */
int fsize = p->maxstacksize; /* frame size */
checkstackp(L, fsize, func);
if (p->is_vararg)
base = adjust_varargs(L, p, n);
else { /* non vararg function */
for (; n < p->numparams; n++)
setnilvalue(L->top++); /* complete missing arguments */
base = func + 1;
}
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = func;
ci->u.l.base = base;
L->top = ci->top = base + fsize;
lua_assert(ci->top <= L->stack_last);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus = CIST_LUA;
if (L->hookmask & LUA_MASKCALL)
callhook(L, ci);
return 0;
}
default: { /* not a function */
checkstackp(L, 1, func); /* ensure space for metamethod */
tryfuncTM(L, func); /* try to get '__call' metamethod */
return luaD_precall(L, func, nresults); /* now it must be a function */
}
}
}
/* /*
** Check appropriate error for stack overflow ("regular" overflow or ** Check appropriate error for stack overflow ("regular" overflow or
** overflow while handling stack overflow). If 'nCalls' is larger than ** overflow while handling stack overflow). If 'nCalls' is larger than
@@ -515,19 +523,17 @@ static void finishCcall (lua_State *L, int status) {
/* error status can only happen in a protected call */ /* error status can only happen in a protected call */
lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);
if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */
ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */ ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */
L->errfunc = ci->u.c.old_errfunc; L->errfunc = ci->u.c.old_errfunc; /* with the same error function */
} }
/* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
handled */ handled */
adjustresults(L, ci->nresults); adjustresults(L, ci->nresults);
/* call continuation function */
lua_unlock(L); lua_unlock(L);
n = (*ci->u.c.k)(L, status, ci->u.c.ctx); n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */
lua_lock(L); lua_lock(L);
api_checknelems(L, n); api_checknelems(L, n);
/* finish 'luaD_precall' */ luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_precall' */
luaD_poscall(L, ci, L->top - n, n);
} }
@@ -590,15 +596,16 @@ static int recover (lua_State *L, int status) {
/* /*
** signal an error in the call to 'resume', not in the execution of the ** Signal an error in the call to 'lua_resume', not in the execution
** coroutine itself. (Such errors should not be handled by any coroutine ** of the coroutine itself. (Such errors should not be handled by any
** error handler and should not kill the coroutine.) ** coroutine error handler and should not kill the coroutine.)
*/ */
static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) { static int resume_error (lua_State *L, const char *msg, int narg) {
L->top = firstArg; /* remove args from the stack */ L->top -= narg; /* remove args from the stack */
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
api_incr_top(L); api_incr_top(L);
luaD_throw(L, -1); /* jump back to 'lua_resume' */ lua_unlock(L);
return LUA_ERRRUN;
} }
@@ -610,22 +617,15 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
** coroutine. ** coroutine.
*/ */
static void resume (lua_State *L, void *ud) { static void resume (lua_State *L, void *ud) {
int nCcalls = L->nCcalls;
int n = *(cast(int*, ud)); /* number of arguments */ int n = *(cast(int*, ud)); /* number of arguments */
StkId firstArg = L->top - n; /* first argument */ StkId firstArg = L->top - n; /* first argument */
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (nCcalls >= LUAI_MAXCCALLS) if (L->status == LUA_OK) { /* starting a coroutine? */
resume_error(L, "C stack overflow", firstArg);
if (L->status == LUA_OK) { /* may be starting a coroutine */
if (ci != &L->base_ci) /* not in base level? */
resume_error(L, "cannot resume non-suspended coroutine", firstArg);
/* coroutine is in base level; start running it */
if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */
luaV_execute(L); /* call it */ luaV_execute(L); /* call it */
} }
else if (L->status != LUA_YIELD)
resume_error(L, "cannot resume dead coroutine", firstArg);
else { /* resuming from previous yield */ else { /* resuming from previous yield */
lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */ L->status = LUA_OK; /* mark that it is running (again) */
ci->func = restorestack(L, ci->extra); ci->func = restorestack(L, ci->extra);
if (isLua(ci)) /* yielded inside a hook? */ if (isLua(ci)) /* yielded inside a hook? */
@@ -642,7 +642,6 @@ static void resume (lua_State *L, void *ud) {
} }
unroll(L, NULL); /* run continuation */ unroll(L, NULL); /* run continuation */
} }
lua_assert(nCcalls == L->nCcalls);
} }
@@ -650,8 +649,16 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
int status; int status;
unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */ unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */
lua_lock(L); lua_lock(L);
luai_userstateresume(L, nargs); if (L->status == LUA_OK) { /* may be starting a coroutine */
if (L->ci != &L->base_ci) /* not in base level? */
return resume_error(L, "cannot resume non-suspended coroutine", nargs);
}
else if (L->status != LUA_YIELD)
return resume_error(L, "cannot resume dead coroutine", nargs);
L->nCcalls = (from) ? from->nCcalls + 1 : 1; L->nCcalls = (from) ? from->nCcalls + 1 : 1;
if (L->nCcalls >= LUAI_MAXCCALLS)
return resume_error(L, "C stack overflow", nargs);
luai_userstateresume(L, nargs);
L->nny = 0; /* allow yields */ L->nny = 0; /* allow yields */
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
status = luaD_rawrunprotected(L, resume, &nargs); status = luaD_rawrunprotected(L, resume, &nargs);

4
ldo.h
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ldo.h,v 2.27 2015/11/19 19:16:22 roberto Exp roberto $ ** $Id: ldo.h,v 2.28 2015/11/23 11:29:43 roberto Exp roberto $
** Stack and Call structure of Lua ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -25,7 +25,7 @@
{ pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); } { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); }
/* In general, 'pre'/'pos' are empty (nothing to save) */ /* In general, 'pre'/'pos' are empty (nothing to save) */
#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,,) #define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)

41
lgc.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lgc.c,v 2.209 2015/11/02 18:48:07 roberto Exp roberto $ ** $Id: lgc.c,v 2.214 2016/11/07 12:38:35 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -467,7 +467,7 @@ static lu_mem traversetable (global_State *g, Table *h) {
else /* not weak */ else /* not weak */
traversestrongtable(g, h); traversestrongtable(g, h);
return sizeof(Table) + sizeof(TValue) * h->sizearray + return sizeof(Table) + sizeof(TValue) * h->sizearray +
sizeof(Node) * cast(size_t, sizenode(h)); sizeof(Node) * cast(size_t, allocsizenode(h));
} }
@@ -539,7 +539,7 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
StkId lim = th->stack + th->stacksize; /* real end of stack */ StkId lim = th->stack + th->stacksize; /* real end of stack */
for (; o < lim; o++) /* clear not-marked stack slice */ for (; o < lim; o++) /* clear not-marked stack slice */
setnilvalue(o); setnilvalue(o);
/* 'remarkupvals' may have removed thread from 'twups' list */ /* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) { if (!isintwups(th) && th->openupval != NULL) {
th->twups = g->twups; /* link it back to the list */ th->twups = g->twups; /* link it back to the list */
g->twups = th; g->twups = th;
@@ -754,14 +754,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
/* /*
** sweep a list until a live object (or end of list) ** sweep a list until a live object (or end of list)
*/ */
static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { static GCObject **sweeptolive (lua_State *L, GCObject **p) {
GCObject **old = p; GCObject **old = p;
int i = 0;
do { do {
i++;
p = sweeplist(L, p, 1); p = sweeplist(L, p, 1);
} while (p == old); } while (p == old);
if (n) *n += i;
return p; return p;
} }
@@ -821,7 +818,9 @@ static void GCTM (lua_State *L, int propagateerrors) {
setobj2s(L, L->top, tm); /* push finalizer... */ setobj2s(L, L->top, tm); /* push finalizer... */
setobj2s(L, L->top + 1, &v); /* ... and its argument */ setobj2s(L, L->top + 1, &v); /* ... and its argument */
L->top += 2; /* and (next line) call the finalizer */ L->top += 2; /* and (next line) call the finalizer */
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */ L->allowhook = oldah; /* restore hooks */
g->gcrunning = running; /* restore state */ g->gcrunning = running; /* restore state */
if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ if (status != LUA_OK && propagateerrors) { /* error while running __gc? */
@@ -856,10 +855,10 @@ static int runafewfinalizers (lua_State *L) {
/* /*
** call all pending finalizers ** call all pending finalizers
*/ */
static void callallpendingfinalizers (lua_State *L, int propagateerrors) { static void callallpendingfinalizers (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
while (g->tobefnz) while (g->tobefnz)
GCTM(L, propagateerrors); GCTM(L, 0);
} }
@@ -909,7 +908,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
if (issweepphase(g)) { if (issweepphase(g)) {
makewhite(g, o); /* "sweep" object 'o' */ makewhite(g, o); /* "sweep" object 'o' */
if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */
g->sweepgc = sweeptolive(L, g->sweepgc, NULL); /* change 'sweepgc' */ g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */
} }
/* search for pointer pointing to 'o' */ /* search for pointer pointing to 'o' */
for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }
@@ -951,19 +950,16 @@ static void setpause (global_State *g) {
/* /*
** Enter first sweep phase. ** Enter first sweep phase.
** The call to 'sweeptolive' makes pointer point to an object inside ** The call to 'sweeplist' tries to make pointer point to an object
** the list (instead of to the header), so that the real sweep do not ** inside the list (instead of to the header), so that the real sweep do
** need to skip objects created between "now" and the start of the real ** not need to skip objects created between "now" and the start of the
** sweep. ** real sweep.
** Returns how many objects it swept.
*/ */
static int entersweep (lua_State *L) { static void entersweep (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
int n = 0;
g->gcstate = GCSswpallgc; g->gcstate = GCSswpallgc;
lua_assert(g->sweepgc == NULL); lua_assert(g->sweepgc == NULL);
g->sweepgc = sweeptolive(L, &g->allgc, &n); g->sweepgc = sweeplist(L, &g->allgc, 1);
return n;
} }
@@ -971,7 +967,7 @@ void luaC_freeallobjects (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
separatetobefnz(g, 1); /* separate all objects with finalizers */ separatetobefnz(g, 1); /* separate all objects with finalizers */
lua_assert(g->finobj == NULL); lua_assert(g->finobj == NULL);
callallpendingfinalizers(L, 0); callallpendingfinalizers(L);
lua_assert(g->tobefnz == NULL); lua_assert(g->tobefnz == NULL);
g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
g->gckind = KGC_NORMAL; g->gckind = KGC_NORMAL;
@@ -1064,12 +1060,11 @@ static lu_mem singlestep (lua_State *L) {
} }
case GCSatomic: { case GCSatomic: {
lu_mem work; lu_mem work;
int sw;
propagateall(g); /* make sure gray list is empty */ propagateall(g); /* make sure gray list is empty */
work = atomic(L); /* work is what was traversed by 'atomic' */ work = atomic(L); /* work is what was traversed by 'atomic' */
sw = entersweep(L); entersweep(L);
g->GCestimate = gettotalbytes(g); /* first estimate */; g->GCestimate = gettotalbytes(g); /* first estimate */;
return work + sw * GCSWEEPCOST; return work;
} }
case GCSswpallgc: { /* sweep "regular" objects */ case GCSswpallgc: { /* sweep "regular" objects */
return sweepstep(L, g, GCSswpfinobj, &g->finobj); return sweepstep(L, g, GCSswpfinobj, &g->finobj);

4
lgc.h
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lgc.h,v 2.89 2015/10/20 18:00:19 roberto Exp roberto $ ** $Id: lgc.h,v 2.90 2015/10/21 18:15:15 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -112,7 +112,7 @@
condchangemem(L,pre,pos); } condchangemem(L,pre,pos); }
/* more often than not, 'pre'/'pos' are empty */ /* more often than not, 'pre'/'pos' are empty */
#define luaC_checkGC(L) luaC_condGC(L,,) #define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
#define luaC_barrier(L,p,v) ( \ #define luaC_barrier(L,p,v) ( \

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: linit.c,v 1.37 2014/12/09 15:00:17 roberto Exp roberto $ ** $Id: linit.c,v 1.38 2015/01/05 13:48:33 roberto Exp roberto $
** Initialization of libraries for lua.c and other clients ** Initialization of libraries for lua.c and other clients
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -18,10 +18,10 @@
** open the library, which is already linked to the application. ** open the library, which is already linked to the application.
** For that, do the following code: ** For that, do the following code:
** **
** luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); ** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
** lua_pushcfunction(L, luaopen_modname); ** lua_pushcfunction(L, luaopen_modname);
** lua_setfield(L, -2, modname); ** lua_setfield(L, -2, modname);
** lua_pop(L, 1); // remove _PRELOAD table ** lua_pop(L, 1); // remove PRELOAD table
*/ */
#include "lprefix.h" #include "lprefix.h"

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: liolib.c,v 2.147 2015/07/15 14:40:28 roberto Exp roberto $ ** $Id: liolib.c,v 2.150 2016/09/01 16:14:56 roberto Exp roberto $
** Standard I/O (and system) library ** Standard I/O (and system) library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -37,10 +37,11 @@
#endif #endif
/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */ /* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */
#define l_checkmode(mode) \ static int l_checkmode (const char *mode) {
(*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \ return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL &&
(*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ \ (*mode != '+' || (++mode, 1)) && /* skip if char is '+' */
(strspn(mode, L_MODEEXT) == strlen(mode))) (strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */
}
#endif #endif
@@ -375,14 +376,17 @@ static int io_lines (lua_State *L) {
/* maximum length of a numeral */ /* maximum length of a numeral */
#define MAXRN 200 #if !defined (L_MAXLENNUM)
#define L_MAXLENNUM 200
#endif
/* auxiliary structure used by 'read_number' */ /* auxiliary structure used by 'read_number' */
typedef struct { typedef struct {
FILE *f; /* file being read */ FILE *f; /* file being read */
int c; /* current character (look ahead) */ int c; /* current character (look ahead) */
int n; /* number of elements in buffer 'buff' */ int n; /* number of elements in buffer 'buff' */
char buff[MAXRN + 1]; /* +1 for ending '\0' */ char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */
} RN; } RN;
@@ -390,7 +394,7 @@ typedef struct {
** Add current char to buffer (if not out of space) and read next one ** Add current char to buffer (if not out of space) and read next one
*/ */
static int nextc (RN *rn) { static int nextc (RN *rn) {
if (rn->n >= MAXRN) { /* buffer overflow? */ if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */
rn->buff[0] = '\0'; /* invalidate result */ rn->buff[0] = '\0'; /* invalidate result */
return 0; /* fail */ return 0; /* fail */
} }
@@ -403,10 +407,10 @@ static int nextc (RN *rn) {
/* /*
** Accept current char if it is in 'set' (of size 1 or 2) ** Accept current char if it is in 'set' (of size 2)
*/ */
static int test2 (RN *rn, const char *set) { static int test2 (RN *rn, const char *set) {
if (rn->c == set[0] || (rn->c == set[1] && rn->c != '\0')) if (rn->c == set[0] || rn->c == set[1])
return nextc(rn); return nextc(rn);
else return 0; else return 0;
} }
@@ -435,11 +439,11 @@ static int read_number (lua_State *L, FILE *f) {
char decp[2]; char decp[2];
rn.f = f; rn.n = 0; rn.f = f; rn.n = 0;
decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */
decp[1] = '\0'; decp[1] = '.'; /* always accept a dot */
l_lockfile(rn.f); l_lockfile(rn.f);
do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */
test2(&rn, "-+"); /* optional signal */ test2(&rn, "-+"); /* optional signal */
if (test2(&rn, "0")) { if (test2(&rn, "00")) {
if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */
else count = 1; /* count initial '0' as a valid digit */ else count = 1; /* count initial '0' as a valid digit */
} }
@@ -615,8 +619,10 @@ static int g_write (lua_State *L, FILE *f, int arg) {
if (lua_type(L, arg) == LUA_TNUMBER) { if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */ /* optimization: could be done exactly as for strings */
int len = lua_isinteger(L, arg) int len = lua_isinteger(L, arg)
? fprintf(f, LUA_INTEGER_FMT, lua_tointeger(L, arg)) ? fprintf(f, LUA_INTEGER_FMT,
: fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)); (LUAI_UACINT)lua_tointeger(L, arg))
: fprintf(f, LUA_NUMBER_FMT,
(LUAI_UACNUMBER)lua_tonumber(L, arg));
status = status && (len > 0); status = status && (len > 0);
} }
else { else {

35
llex.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: llex.c,v 2.94 2015/10/28 18:51:47 roberto Exp roberto $ ** $Id: llex.c,v 2.95 2015/11/19 19:16:22 roberto Exp roberto $
** Lexical Analyzer ** Lexical Analyzer
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -162,7 +162,6 @@ static void inclinenumber (LexState *ls) {
void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
int firstchar) { int firstchar) {
ls->t.token = 0; ls->t.token = 0;
ls->decpoint = '.';
ls->L = L; ls->L = L;
ls->current = firstchar; ls->current = firstchar;
ls->lookahead.token = TK_EOS; /* no look-ahead token */ ls->lookahead.token = TK_EOS; /* no look-ahead token */
@@ -207,35 +206,6 @@ static int check_next2 (LexState *ls, const char *set) {
} }
/*
** change all characters 'from' in buffer to 'to'
*/
static void buffreplace (LexState *ls, char from, char to) {
if (from != to) {
size_t n = luaZ_bufflen(ls->buff);
char *p = luaZ_buffer(ls->buff);
while (n--)
if (p[n] == from) p[n] = to;
}
}
/*
** in case of format error, try to change decimal point separator to
** the one defined in the current locale and check again
*/
static void trydecpoint (LexState *ls, TValue *o) {
char old = ls->decpoint;
ls->decpoint = lua_getlocaledecpoint();
buffreplace(ls, old, ls->decpoint); /* try new decimal separator */
if (luaO_str2num(luaZ_buffer(ls->buff), o) == 0) {
/* format error with correct decimal point: no more options */
buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
lexerror(ls, "malformed number", TK_FLT);
}
}
/* LUA_NUMBER */ /* LUA_NUMBER */
/* /*
** this function is quite liberal in what it accepts, as 'luaO_str2num' ** this function is quite liberal in what it accepts, as 'luaO_str2num'
@@ -259,9 +229,8 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) {
else break; else break;
} }
save(ls, '\0'); save(ls, '\0');
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */ if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */
trydecpoint(ls, &obj); /* try to update decimal point separator */ lexerror(ls, "malformed number", TK_FLT);
if (ttisinteger(&obj)) { if (ttisinteger(&obj)) {
seminfo->i = ivalue(&obj); seminfo->i = ivalue(&obj);
return TK_INT; return TK_INT;

3
llex.h
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: llex.h,v 1.77 2014/10/25 11:50:46 roberto Exp roberto $ ** $Id: llex.h,v 1.78 2014/10/29 15:38:24 roberto Exp roberto $
** Lexical Analyzer ** Lexical Analyzer
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -69,7 +69,6 @@ typedef struct LexState {
struct Dyndata *dyd; /* dynamic structures used by the parser */ struct Dyndata *dyd; /* dynamic structures used by the parser */
TString *source; /* current source name */ TString *source; /* current source name */
TString *envn; /* environment variable name */ TString *envn; /* environment variable name */
char decpoint; /* locale decimal point */
} LexState; } LexState;

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lmathlib.c,v 1.116 2015/06/26 19:30:32 roberto Exp $ ** $Id: lmathlib.c,v 1.118 2016/12/20 18:37:00 roberto Exp roberto $
** Standard mathematical library ** Standard mathematical library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -184,10 +184,13 @@ static int math_log (lua_State *L) {
else { else {
lua_Number base = luaL_checknumber(L, 2); lua_Number base = luaL_checknumber(L, 2);
#if !defined(LUA_USE_C89) #if !defined(LUA_USE_C89)
if (base == 2.0) res = l_mathop(log2)(x); else if (base == l_mathop(2.0))
res = l_mathop(log2)(x); else
#endif #endif
if (base == 10.0) res = l_mathop(log10)(x); if (base == l_mathop(10.0))
else res = l_mathop(log)(x)/l_mathop(log)(base); res = l_mathop(log10)(x);
else
res = l_mathop(log)(x)/l_mathop(log)(base);
} }
lua_pushnumber(L, res); lua_pushnumber(L, res);
return 1; return 1;
@@ -262,7 +265,7 @@ static int math_random (lua_State *L) {
default: return luaL_error(L, "wrong number of arguments"); default: return luaL_error(L, "wrong number of arguments");
} }
/* random integer in the interval [low, up] */ /* random integer in the interval [low, up] */
luaL_argcheck(L, low <= up, 1, "interval is empty"); luaL_argcheck(L, low <= up, 1, "interval is empty");
luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1, luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1,
"interval too large"); "interval too large");
r *= (double)(up - low) + 1.0; r *= (double)(up - low) + 1.0;
@@ -281,9 +284,9 @@ static int math_randomseed (lua_State *L) {
static int math_type (lua_State *L) { static int math_type (lua_State *L) {
if (lua_type(L, 1) == LUA_TNUMBER) { if (lua_type(L, 1) == LUA_TNUMBER) {
if (lua_isinteger(L, 1)) if (lua_isinteger(L, 1))
lua_pushliteral(L, "integer"); lua_pushliteral(L, "integer");
else else
lua_pushliteral(L, "float"); lua_pushliteral(L, "float");
} }
else { else {
luaL_checkany(L, 1); luaL_checkany(L, 1);

169
loadlib.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: loadlib.c,v 1.126 2015/02/16 13:14:33 roberto Exp roberto $ ** $Id: loadlib.c,v 1.129 2016/12/04 20:17:24 roberto Exp roberto $
** Dynamic library loader for Lua ** Dynamic library loader for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
** **
@@ -25,40 +25,9 @@
/* /*
** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment
** variables that Lua check to set its paths.
*/
#if !defined(LUA_PATH_VAR)
#define LUA_PATH_VAR "LUA_PATH"
#endif
#if !defined(LUA_CPATH_VAR)
#define LUA_CPATH_VAR "LUA_CPATH"
#endif
#define LUA_PATHSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
#define LUA_PATHVARVERSION LUA_PATH_VAR LUA_PATHSUFFIX
#define LUA_CPATHVARVERSION LUA_CPATH_VAR LUA_PATHSUFFIX
/*
** LUA_PATH_SEP is the character that separates templates in a path.
** LUA_PATH_MARK is the string that marks the substitution points in a
** template.
** LUA_EXEC_DIR in a Windows path is replaced by the executable's
** directory.
** LUA_IGMARK is a mark to ignore all before it when building the ** LUA_IGMARK is a mark to ignore all before it when building the
** luaopen_ function name. ** luaopen_ function name.
*/ */
#if !defined (LUA_PATH_SEP)
#define LUA_PATH_SEP ";"
#endif
#if !defined (LUA_PATH_MARK)
#define LUA_PATH_MARK "?"
#endif
#if !defined (LUA_EXEC_DIR)
#define LUA_EXEC_DIR "!"
#endif
#if !defined (LUA_IGMARK) #if !defined (LUA_IGMARK)
#define LUA_IGMARK "-" #define LUA_IGMARK "-"
#endif #endif
@@ -94,7 +63,8 @@ static const int CLIBS = 0;
#define LIB_FAIL "open" #define LIB_FAIL "open"
#define setprogdir(L) ((void)0)
#define setprogdir(L) ((void)0)
/* /*
@@ -179,7 +149,6 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
#include <windows.h> #include <windows.h>
#undef setprogdir
/* /*
** optional flags for LoadLibraryEx ** optional flags for LoadLibraryEx
@@ -189,21 +158,30 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
#endif #endif
#undef setprogdir
/*
** Replace in the path (on the top of the stack) any occurrence
** of LUA_EXEC_DIR with the executable's path.
*/
static void setprogdir (lua_State *L) { static void setprogdir (lua_State *L) {
char buff[MAX_PATH + 1]; char buff[MAX_PATH + 1];
char *lb; char *lb;
DWORD nsize = sizeof(buff)/sizeof(char); DWORD nsize = sizeof(buff)/sizeof(char);
DWORD n = GetModuleFileNameA(NULL, buff, nsize); DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */
if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL)
luaL_error(L, "unable to get ModuleFileName"); luaL_error(L, "unable to get ModuleFileName");
else { else {
*lb = '\0'; *lb = '\0'; /* cut name on the last '\\' to get the path */
luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff);
lua_remove(L, -2); /* remove original string */ lua_remove(L, -2); /* remove original string */
} }
} }
static void pusherror (lua_State *L) { static void pusherror (lua_State *L) {
int error = GetLastError(); int error = GetLastError();
char buffer[128]; char buffer[128];
@@ -272,6 +250,67 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
#endif /* } */ #endif /* } */
/*
** {==================================================================
** Set Paths
** ===================================================================
*/
/*
** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment
** variables that Lua check to set its paths.
*/
#if !defined(LUA_PATH_VAR)
#define LUA_PATH_VAR "LUA_PATH"
#endif
#if !defined(LUA_CPATH_VAR)
#define LUA_CPATH_VAR "LUA_CPATH"
#endif
#define AUXMARK "\1" /* auxiliary mark */
/*
** return registry.LUA_NOENV as a boolean
*/
static int noenv (lua_State *L) {
int b;
lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
b = lua_toboolean(L, -1);
lua_pop(L, 1); /* remove value */
return b;
}
/*
** Set a path
*/
static void setpath (lua_State *L, const char *fieldname,
const char *envname,
const char *dft) {
const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX);
const char *path = getenv(nver); /* use versioned name */
if (path == NULL) /* no environment variable? */
path = getenv(envname); /* try unversioned name */
if (path == NULL || noenv(L)) /* no environment variable? */
lua_pushstring(L, dft); /* use default */
else {
/* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP,
LUA_PATH_SEP AUXMARK LUA_PATH_SEP);
luaL_gsub(L, path, AUXMARK, dft);
lua_remove(L, -2); /* remove result from 1st 'gsub' */
}
setprogdir(L);
lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */
lua_pop(L, 1); /* pop versioned variable name */
}
/* }================================================================== */
/* /*
** return registry.CLIBS[path] ** return registry.CLIBS[path]
*/ */
@@ -520,7 +559,7 @@ static int searcher_Croot (lua_State *L) {
static int searcher_preload (lua_State *L) { static int searcher_preload (lua_State *L) {
const char *name = luaL_checkstring(L, 1); const char *name = luaL_checkstring(L, 1);
lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */ if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */
lua_pushfstring(L, "\n\tno field package.preload['%s']", name); lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
return 1; return 1;
@@ -557,9 +596,9 @@ static void findloader (lua_State *L, const char *name) {
static int ll_require (lua_State *L) { static int ll_require (lua_State *L) {
const char *name = luaL_checkstring(L, 1); const char *name = luaL_checkstring(L, 1);
lua_settop(L, 1); /* _LOADED table will be at index 2 */ lua_settop(L, 1); /* LOADED table will be at index 2 */
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_getfield(L, 2, name); /* _LOADED[name] */ lua_getfield(L, 2, name); /* LOADED[name] */
if (lua_toboolean(L, -1)) /* is it there? */ if (lua_toboolean(L, -1)) /* is it there? */
return 1; /* package is already loaded */ return 1; /* package is already loaded */
/* else must load package */ /* else must load package */
@@ -569,11 +608,11 @@ static int ll_require (lua_State *L) {
lua_insert(L, -2); /* name is 1st argument (before search data) */ lua_insert(L, -2); /* name is 1st argument (before search data) */
lua_call(L, 2, 1); /* run loader to load module */ lua_call(L, 2, 1); /* run loader to load module */
if (!lua_isnil(L, -1)) /* non-nil return? */ if (!lua_isnil(L, -1)) /* non-nil return? */
lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ lua_setfield(L, 2, name); /* LOADED[name] = returned value */
if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */
lua_pushboolean(L, 1); /* use true as result */ lua_pushboolean(L, 1); /* use true as result */
lua_pushvalue(L, -1); /* extra copy to be returned */ lua_pushvalue(L, -1); /* extra copy to be returned */
lua_setfield(L, 2, name); /* _LOADED[name] = true */ lua_setfield(L, 2, name); /* LOADED[name] = true */
} }
return 1; return 1;
} }
@@ -666,41 +705,6 @@ static int ll_seeall (lua_State *L) {
/* auxiliary mark (for internal use) */
#define AUXMARK "\1"
/*
** return registry.LUA_NOENV as a boolean
*/
static int noenv (lua_State *L) {
int b;
lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
b = lua_toboolean(L, -1);
lua_pop(L, 1); /* remove value */
return b;
}
static void setpath (lua_State *L, const char *fieldname, const char *envname1,
const char *envname2, const char *def) {
const char *path = getenv(envname1);
if (path == NULL) /* no environment variable? */
path = getenv(envname2); /* try alternative name */
if (path == NULL || noenv(L)) /* no environment variable? */
lua_pushstring(L, def); /* use default */
else {
/* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP,
LUA_PATH_SEP AUXMARK LUA_PATH_SEP);
luaL_gsub(L, path, AUXMARK, def);
lua_remove(L, -2);
}
setprogdir(L);
lua_setfield(L, -2, fieldname);
}
static const luaL_Reg pk_funcs[] = { static const luaL_Reg pk_funcs[] = {
{"loadlib", ll_loadlib}, {"loadlib", ll_loadlib},
{"searchpath", ll_searchpath}, {"searchpath", ll_searchpath},
@@ -764,19 +768,18 @@ LUAMOD_API int luaopen_package (lua_State *L) {
createclibstable(L); createclibstable(L);
luaL_newlib(L, pk_funcs); /* create 'package' table */ luaL_newlib(L, pk_funcs); /* create 'package' table */
createsearcherstable(L); createsearcherstable(L);
/* set field 'path' */ /* set paths */
setpath(L, "path", LUA_PATHVARVERSION, LUA_PATH_VAR, LUA_PATH_DEFAULT); setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT);
/* set field 'cpath' */ setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
setpath(L, "cpath", LUA_CPATHVARVERSION, LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
/* store config information */ /* store config information */
lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"
LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
lua_setfield(L, -2, "config"); lua_setfield(L, -2, "config");
/* set field 'loaded' */ /* set field 'loaded' */
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_setfield(L, -2, "loaded"); lua_setfield(L, -2, "loaded");
/* set field 'preload' */ /* set field 'preload' */
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
lua_setfield(L, -2, "preload"); lua_setfield(L, -2, "preload");
lua_pushglobaltable(L); lua_pushglobaltable(L);
lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lobject.c,v 2.107 2015/11/02 14:02:35 roberto Exp roberto $ ** $Id: lobject.c,v 2.112 2016/06/27 13:15:08 roberto Exp roberto $
** Some generic functions over Lua objects ** Some generic functions over Lua objects
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -243,20 +243,59 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
/* }====================================================== */ /* }====================================================== */
static const char *l_str2d (const char *s, lua_Number *result) { /* maximum length of a numeral */
#if !defined (L_MAXLENNUM)
#define L_MAXLENNUM 200
#endif
static const char *l_str2dloc (const char *s, lua_Number *result, int mode) {
char *endptr; char *endptr;
if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */ *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */
return NULL; : lua_str2number(s, &endptr);
else if (strpbrk(s, "xX")) /* hex? */ if (endptr == s) return NULL; /* nothing recognized? */
*result = lua_strx2number(s, &endptr); while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */
else return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */
*result = lua_str2number(s, &endptr);
if (endptr == s) return NULL; /* nothing recognized */
while (lisspace(cast_uchar(*endptr))) endptr++;
return (*endptr == '\0' ? endptr : NULL); /* OK if no trailing characters */
} }
/*
** Convert string 's' to a Lua number (put in 'result'). Return NULL
** on fail or the address of the ending '\0' on success.
** 'pmode' points to (and 'mode' contains) special things in the string:
** - 'x'/'X' means an hexadecimal numeral
** - 'n'/'N' means 'inf' or 'nan' (which should be rejected)
** - '.' just optimizes the search for the common case (nothing special)
** This function accepts both the current locale or a dot as the radix
** mark. If the convertion fails, it may mean number has a dot but
** locale accepts something else. In that case, the code copies 's'
** to a buffer (because 's' is read-only), changes the dot to the
** current locale radix mark, and tries to convert again.
*/
static const char *l_str2d (const char *s, lua_Number *result) {
const char *endptr;
const char *pmode = strpbrk(s, ".xXnN");
int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;
if (mode == 'n') /* reject 'inf' and 'nan' */
return NULL;
endptr = l_str2dloc(s, result, mode); /* try to convert */
if (endptr == NULL) { /* failed? may be a different locale */
char buff[L_MAXLENNUM + 1];
const char *pdot = strchr(s, '.');
if (strlen(s) > L_MAXLENNUM || pdot == NULL)
return NULL; /* string too long or no dot; fail */
strcpy(buff, s); /* copy string to buffer */
buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */
endptr = l_str2dloc(buff, result, mode); /* try again */
if (endptr != NULL)
endptr = s + (endptr - buff); /* make relative to 's' */
}
return endptr;
}
#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10)
#define MAXLASTD cast_int(LUA_MAXINTEGER % 10)
static const char *l_str2int (const char *s, lua_Integer *result) { static const char *l_str2int (const char *s, lua_Integer *result) {
lua_Unsigned a = 0; lua_Unsigned a = 0;
int empty = 1; int empty = 1;
@@ -273,7 +312,10 @@ static const char *l_str2int (const char *s, lua_Integer *result) {
} }
else { /* decimal */ else { /* decimal */
for (; lisdigit(cast_uchar(*s)); s++) { for (; lisdigit(cast_uchar(*s)); s++) {
a = a * 10 + *s - '0'; int d = *s - '0';
if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */
return NULL; /* do not accept it (as integer) */
a = a * 10 + d;
empty = 0; empty = 0;
} }
} }
@@ -351,8 +393,10 @@ static void pushstr (lua_State *L, const char *str, size_t l) {
} }
/* this function handles only '%d', '%c', '%f', '%p', and '%s' /*
conventional formats, plus Lua-specific '%I' and '%U' */ ** this function handles only '%d', '%c', '%f', '%p', and '%s'
conventional formats, plus Lua-specific '%I' and '%U'
*/
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
int n = 0; int n = 0;
for (;;) { for (;;) {
@@ -360,13 +404,13 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
if (e == NULL) break; if (e == NULL) break;
pushstr(L, fmt, e - fmt); pushstr(L, fmt, e - fmt);
switch (*(e+1)) { switch (*(e+1)) {
case 's': { case 's': { /* zero-terminated string */
const char *s = va_arg(argp, char *); const char *s = va_arg(argp, char *);
if (s == NULL) s = "(null)"; if (s == NULL) s = "(null)";
pushstr(L, s, strlen(s)); pushstr(L, s, strlen(s));
break; break;
} }
case 'c': { case 'c': { /* an 'int' as a character */
char buff = cast(char, va_arg(argp, int)); char buff = cast(char, va_arg(argp, int));
if (lisprint(cast_uchar(buff))) if (lisprint(cast_uchar(buff)))
pushstr(L, &buff, 1); pushstr(L, &buff, 1);
@@ -374,28 +418,28 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
luaO_pushfstring(L, "<\\%d>", cast_uchar(buff)); luaO_pushfstring(L, "<\\%d>", cast_uchar(buff));
break; break;
} }
case 'd': { case 'd': { /* an 'int' */
setivalue(L->top, va_arg(argp, int)); setivalue(L->top, va_arg(argp, int));
goto top2str; goto top2str;
} }
case 'I': { case 'I': { /* a 'lua_Integer' */
setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt))); setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt)));
goto top2str; goto top2str;
} }
case 'f': { case 'f': { /* a 'lua_Number' */
setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber)));
top2str: top2str: /* convert the top element to a string */
luaD_inctop(L); luaD_inctop(L);
luaO_tostring(L, L->top - 1); luaO_tostring(L, L->top - 1);
break; break;
} }
case 'p': { case 'p': { /* a pointer */
char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */ char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */
int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *)); int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *));
pushstr(L, buff, l); pushstr(L, buff, l);
break; break;
} }
case 'U': { case 'U': { /* an 'int' as a UTF-8 sequence */
char buff[UTF8BUFFSZ]; char buff[UTF8BUFFSZ];
int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long))); int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long)));
pushstr(L, buff + UTF8BUFFSZ - l, l); pushstr(L, buff + UTF8BUFFSZ - l, l);

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lobject.h,v 2.115 2015/10/28 17:28:40 roberto Exp roberto $ ** $Id: lobject.h,v 2.116 2015/11/03 18:33:10 roberto Exp roberto $
** Type definitions for Lua objects ** Type definitions for Lua objects
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -407,7 +407,7 @@ typedef struct LocVar {
typedef struct Proto { typedef struct Proto {
CommonHeader; CommonHeader;
lu_byte numparams; /* number of fixed parameters */ lu_byte numparams; /* number of fixed parameters */
lu_byte is_vararg; /* 2: declared vararg; 1: uses vararg */ lu_byte is_vararg;
lu_byte maxstacksize; /* number of registers needed by this function */ lu_byte maxstacksize; /* number of registers needed by this function */
int sizeupvalues; /* size of 'upvalues' */ int sizeupvalues; /* size of 'upvalues' */
int sizek; /* size of 'k' */ int sizek; /* size of 'k' */

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lopcodes.h,v 1.147 2014/10/20 18:29:55 roberto Exp roberto $ ** $Id: lopcodes.h,v 1.148 2014/10/25 11:50:46 roberto Exp roberto $
** Opcodes for Lua virtual machine ** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -139,7 +139,9 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
/* gets the index of the constant */ /* gets the index of the constant */
#define INDEXK(r) ((int)(r) & ~BITRK) #define INDEXK(r) ((int)(r) & ~BITRK)
#if !defined(MAXINDEXRK) /* (for debugging only) */
#define MAXINDEXRK (BITRK - 1) #define MAXINDEXRK (BITRK - 1)
#endif
/* code a constant index as a RK value */ /* code a constant index as a RK value */
#define RKASK(x) ((x) | BITRK) #define RKASK(x) ((x) | BITRK)

101
loslib.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: loslib.c,v 1.59 2015/07/06 15:16:51 roberto Exp roberto $ ** $Id: loslib.c,v 1.64 2016/04/18 13:06:55 roberto Exp $
** Standard Operating System library ** Standard Operating System library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -24,18 +24,29 @@
/* /*
** {================================================================== ** {==================================================================
** list of valid conversion specifiers for the 'strftime' function ** List of valid conversion specifiers for the 'strftime' function;
** options are grouped by length; group of length 2 start with '||'.
** =================================================================== ** ===================================================================
*/ */
#if !defined(LUA_STRFTIMEOPTIONS) /* { */ #if !defined(LUA_STRFTIMEOPTIONS) /* { */
#if defined(LUA_USE_C89) /* options for ANSI C 89 (only 1-char options) */
#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } #define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
/* options for ISO C 99 and POSIX */
#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
/* options for Windows */
#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
#if defined(LUA_USE_WINDOWS)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
#elif defined(LUA_USE_C89)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
#else /* C99 specification */ #else /* C99 specification */
#define LUA_STRFTIMEOPTIONS \ #define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
{ "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \
"E", "cCxXyY", \
"O", "deHImMSuUVwWy" }
#endif #endif
#endif /* } */ #endif /* } */
@@ -195,6 +206,23 @@ static void setboolfield (lua_State *L, const char *key, int value) {
lua_setfield(L, -2, key); lua_setfield(L, -2, key);
} }
/*
** Set all fields from structure 'tm' in the table on top of the stack
*/
static void setallfields (lua_State *L, struct tm *stm) {
setfield(L, "sec", stm->tm_sec);
setfield(L, "min", stm->tm_min);
setfield(L, "hour", stm->tm_hour);
setfield(L, "day", stm->tm_mday);
setfield(L, "month", stm->tm_mon + 1);
setfield(L, "year", stm->tm_year + 1900);
setfield(L, "wday", stm->tm_wday + 1);
setfield(L, "yday", stm->tm_yday + 1);
setboolfield(L, "isdst", stm->tm_isdst);
}
static int getboolfield (lua_State *L, const char *key) { static int getboolfield (lua_State *L, const char *key) {
int res; int res;
res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
@@ -210,18 +238,18 @@ static int getboolfield (lua_State *L, const char *key) {
static int getfield (lua_State *L, const char *key, int d, int delta) { static int getfield (lua_State *L, const char *key, int d, int delta) {
int isnum; int isnum;
int t = lua_getfield(L, -1, key); int t = lua_getfield(L, -1, key); /* get field and its type */
lua_Integer res = lua_tointegerx(L, -1, &isnum); lua_Integer res = lua_tointegerx(L, -1, &isnum);
if (!isnum) { /* field is not a number? */ if (!isnum) { /* field is not an integer? */
if (t != LUA_TNIL) /* some other value? */ if (t != LUA_TNIL) /* some other value? */
return luaL_error(L, "field '%s' not an integer", key); return luaL_error(L, "field '%s' is not an integer", key);
else if (d < 0) /* absent field; no default? */ else if (d < 0) /* absent field; no default? */
return luaL_error(L, "field '%s' missing in date table", key); return luaL_error(L, "field '%s' missing in date table", key);
res = d; res = d;
} }
else { else {
if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD)) if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))
return luaL_error(L, "field '%s' out-of-bounds", key); return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta; res -= delta;
} }
lua_pop(L, 1); lua_pop(L, 1);
@@ -229,22 +257,17 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
} }
static const char *checkoption (lua_State *L, const char *conv, char *buff) { static const char *checkoption (lua_State *L, const char *conv,
static const char *const options[] = LUA_STRFTIMEOPTIONS; ptrdiff_t convlen, char *buff) {
unsigned int i; const char *option = LUA_STRFTIMEOPTIONS;
for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) { int oplen = 1; /* length of options being checked */
if (*conv != '\0' && strchr(options[i], *conv) != NULL) { for (; *option != '\0' && oplen <= convlen; option += oplen) {
buff[1] = *conv; if (*option == '|') /* next block? */
if (*options[i + 1] == '\0') { /* one-char conversion specifier? */ oplen++; /* will check options with next length (+1) */
buff[2] = '\0'; /* end buffer */ else if (memcmp(conv, option, oplen) == 0) { /* match? */
return conv + 1; memcpy(buff, conv, oplen); /* copy valid option to buffer */
} buff[oplen] = '\0';
else if (*(conv + 1) != '\0' && return conv + oplen; /* return next item */
strchr(options[i + 1], *(conv + 1)) != NULL) {
buff[2] = *(conv + 1); /* valid two-char conversion specifier */
buff[3] = '\0'; /* end buffer */
return conv + 2;
}
} }
} }
luaL_argerror(L, 1, luaL_argerror(L, 1,
@@ -258,8 +281,10 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) {
static int os_date (lua_State *L) { static int os_date (lua_State *L) {
const char *s = luaL_optstring(L, 1, "%c"); size_t slen;
const char *s = luaL_optlstring(L, 1, "%c", &slen);
time_t t = luaL_opt(L, l_checktime, 2, time(NULL)); time_t t = luaL_opt(L, l_checktime, 2, time(NULL));
const char *se = s + slen; /* 's' end */
struct tm tmr, *stm; struct tm tmr, *stm;
if (*s == '!') { /* UTC? */ if (*s == '!') { /* UTC? */
stm = l_gmtime(&t, &tmr); stm = l_gmtime(&t, &tmr);
@@ -271,28 +296,21 @@ static int os_date (lua_State *L) {
luaL_error(L, "time result cannot be represented in this installation"); luaL_error(L, "time result cannot be represented in this installation");
if (strcmp(s, "*t") == 0) { if (strcmp(s, "*t") == 0) {
lua_createtable(L, 0, 9); /* 9 = number of fields */ lua_createtable(L, 0, 9); /* 9 = number of fields */
setfield(L, "sec", stm->tm_sec); setallfields(L, stm);
setfield(L, "min", stm->tm_min);
setfield(L, "hour", stm->tm_hour);
setfield(L, "day", stm->tm_mday);
setfield(L, "month", stm->tm_mon+1);
setfield(L, "year", stm->tm_year+1900);
setfield(L, "wday", stm->tm_wday+1);
setfield(L, "yday", stm->tm_yday+1);
setboolfield(L, "isdst", stm->tm_isdst);
} }
else { else {
char cc[4]; char cc[4]; /* buffer for individual conversion specifiers */
luaL_Buffer b; luaL_Buffer b;
cc[0] = '%'; cc[0] = '%';
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
while (*s) { while (s < se) {
if (*s != '%') /* not a conversion specifier? */ if (*s != '%') /* not a conversion specifier? */
luaL_addchar(&b, *s++); luaL_addchar(&b, *s++);
else { else {
size_t reslen; size_t reslen;
char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
s = checkoption(L, s + 1, cc); s++; /* skip '%' */
s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */
reslen = strftime(buff, SIZETIMEFMT, cc, stm); reslen = strftime(buff, SIZETIMEFMT, cc, stm);
luaL_addsize(&b, reslen); luaL_addsize(&b, reslen);
} }
@@ -319,6 +337,7 @@ static int os_time (lua_State *L) {
ts.tm_year = getfield(L, "year", -1, 1900); ts.tm_year = getfield(L, "year", -1, 1900);
ts.tm_isdst = getboolfield(L, "isdst"); ts.tm_isdst = getboolfield(L, "isdst");
t = mktime(&ts); t = mktime(&ts);
setallfields(L, &ts); /* update fields with normalized values */
} }
if (t != (time_t)(l_timet)t || t == (time_t)(-1)) if (t != (time_t)(l_timet)t || t == (time_t)(-1))
luaL_error(L, "time result cannot be represented in this installation"); luaL_error(L, "time result cannot be represented in this installation");

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lparser.c,v 2.148 2015/10/28 17:28:40 roberto Exp roberto $ ** $Id: lparser.c,v 2.154 2016/06/22 15:48:25 roberto Exp roberto $
** Lua Parser ** Lua Parser
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -164,7 +164,8 @@ static int registerlocalvar (LexState *ls, TString *varname) {
int oldsize = f->sizelocvars; int oldsize = f->sizelocvars;
luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
LocVar, SHRT_MAX, "local variables"); LocVar, SHRT_MAX, "local variables");
while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; while (oldsize < f->sizelocvars)
f->locvars[oldsize++].varname = NULL;
f->locvars[fs->nlocvars].varname = varname; f->locvars[fs->nlocvars].varname = varname;
luaC_objbarrier(ls->L, f, varname); luaC_objbarrier(ls->L, f, varname);
return fs->nlocvars++; return fs->nlocvars++;
@@ -230,7 +231,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues, luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
Upvaldesc, MAXUPVAL, "upvalues"); Upvaldesc, MAXUPVAL, "upvalues");
while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL; while (oldsize < f->sizeupvalues)
f->upvalues[oldsize++].name = NULL;
f->upvalues[fs->nups].instack = (v->k == VLOCAL); f->upvalues[fs->nups].instack = (v->k == VLOCAL);
f->upvalues[fs->nups].idx = cast_byte(v->u.info); f->upvalues[fs->nups].idx = cast_byte(v->u.info);
f->upvalues[fs->nups].name = name; f->upvalues[fs->nups].name = name;
@@ -255,7 +257,8 @@ static int searchvar (FuncState *fs, TString *n) {
*/ */
static void markupval (FuncState *fs, int level) { static void markupval (FuncState *fs, int level) {
BlockCnt *bl = fs->bl; BlockCnt *bl = fs->bl;
while (bl->nactvar > level) bl = bl->previous; while (bl->nactvar > level)
bl = bl->previous;
bl->upval = 1; bl->upval = 1;
} }
@@ -264,27 +267,26 @@ static void markupval (FuncState *fs, int level) {
Find variable with given name 'n'. If it is an upvalue, add this Find variable with given name 'n'. If it is an upvalue, add this
upvalue into all intermediate functions. upvalue into all intermediate functions.
*/ */
static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
if (fs == NULL) /* no more levels? */ if (fs == NULL) /* no more levels? */
return VVOID; /* default is global */ init_exp(var, VVOID, 0); /* default is global */
else { else {
int v = searchvar(fs, n); /* look up locals at current level */ int v = searchvar(fs, n); /* look up locals at current level */
if (v >= 0) { /* found? */ if (v >= 0) { /* found? */
init_exp(var, VLOCAL, v); /* variable is local */ init_exp(var, VLOCAL, v); /* variable is local */
if (!base) if (!base)
markupval(fs, v); /* local will be used as an upval */ markupval(fs, v); /* local will be used as an upval */
return VLOCAL;
} }
else { /* not found as local at current level; try upvalues */ else { /* not found as local at current level; try upvalues */
int idx = searchupvalue(fs, n); /* try existing upvalues */ int idx = searchupvalue(fs, n); /* try existing upvalues */
if (idx < 0) { /* not found? */ if (idx < 0) { /* not found? */
if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */ singlevaraux(fs->prev, n, var, 0); /* try upper levels */
return VVOID; /* not found; is a global */ if (var->k == VVOID) /* not found? */
return; /* it is a global */
/* else was LOCAL or UPVAL */ /* else was LOCAL or UPVAL */
idx = newupvalue(fs, n, var); /* will be a new upvalue */ idx = newupvalue(fs, n, var); /* will be a new upvalue */
} }
init_exp(var, VUPVAL, idx); init_exp(var, VUPVAL, idx); /* new or old upvalue */
return VUPVAL;
} }
} }
} }
@@ -293,10 +295,11 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
static void singlevar (LexState *ls, expdesc *var) { static void singlevar (LexState *ls, expdesc *var) {
TString *varname = str_checkname(ls); TString *varname = str_checkname(ls);
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */ singlevaraux(fs, varname, var, 1);
if (var->k == VVOID) { /* global name? */
expdesc key; expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k == VLOCAL || var->k == VUPVAL); lua_assert(var->k != VVOID); /* this one must exist */
codestring(ls, &key, varname); /* key is variable name */ codestring(ls, &key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */ luaK_indexed(fs, var, &key); /* env[varname] */
} }
@@ -320,6 +323,8 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
luaK_nil(fs, reg, extra); luaK_nil(fs, reg, extra);
} }
} }
if (nexps > nvars)
ls->fs->freereg -= nexps - nvars; /* remove extra values */
} }
@@ -499,7 +504,8 @@ static Proto *addprototype (LexState *ls) {
if (fs->np >= f->sizep) { if (fs->np >= f->sizep) {
int oldsize = f->sizep; int oldsize = f->sizep;
luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");
while (oldsize < f->sizep) f->p[oldsize++] = NULL; while (oldsize < f->sizep)
f->p[oldsize++] = NULL;
} }
f->p[fs->np++] = clp = luaF_newproto(L); f->p[fs->np++] = clp = luaF_newproto(L);
luaC_objbarrier(L, f, clp); luaC_objbarrier(L, f, clp);
@@ -760,7 +766,7 @@ static void parlist (LexState *ls) {
} }
case TK_DOTS: { /* param -> '...' */ case TK_DOTS: { /* param -> '...' */
luaX_next(ls); luaX_next(ls);
f->is_vararg = 2; /* declared vararg */ f->is_vararg = 1; /* declared vararg */
break; break;
} }
default: luaX_syntaxerror(ls, "<name> or '...' expected"); default: luaX_syntaxerror(ls, "<name> or '...' expected");
@@ -956,7 +962,6 @@ static void simpleexp (LexState *ls, expdesc *v) {
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
check_condition(ls, fs->f->is_vararg, check_condition(ls, fs->f->is_vararg,
"cannot use '...' outside a vararg function"); "cannot use '...' outside a vararg function");
fs->f->is_vararg = 1; /* function actually uses vararg */
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
break; break;
} }
@@ -1156,11 +1161,8 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
int nexps; int nexps;
checknext(ls, '='); checknext(ls, '=');
nexps = explist(ls, &e); nexps = explist(ls, &e);
if (nexps != nvars) { if (nexps != nvars)
adjust_assign(ls, nvars, nexps, &e); adjust_assign(ls, nvars, nexps, &e);
if (nexps > nvars)
ls->fs->freereg -= nexps - nvars; /* remove extra values */
}
else { else {
luaK_setoneret(ls->fs, &e); /* close last expression */ luaK_setoneret(ls->fs, &e); /* close last expression */
luaK_storevar(ls->fs, &lh->v, &e); luaK_storevar(ls->fs, &lh->v, &e);
@@ -1226,7 +1228,7 @@ static void labelstat (LexState *ls, TString *label, int line) {
checkrepeated(fs, ll, label); /* check for repeated labels */ checkrepeated(fs, ll, label); /* check for repeated labels */
checknext(ls, TK_DBCOLON); /* skip double colon */ checknext(ls, TK_DBCOLON); /* skip double colon */
/* create new entry for this label */ /* create new entry for this label */
l = newlabelentry(ls, ll, label, line, fs->pc); l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));
skipnoopstat(ls); /* skip other no-op statements */ skipnoopstat(ls); /* skip other no-op statements */
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */ /* assume that locals are already out of scope */
@@ -1494,7 +1496,7 @@ static void exprstat (LexState *ls) {
} }
else { /* stat -> func */ else { /* stat -> func */
check_condition(ls, v.v.k == VCALL, "syntax error"); check_condition(ls, v.v.k == VCALL, "syntax error");
SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */
} }
} }
@@ -1511,8 +1513,8 @@ static void retstat (LexState *ls) {
if (hasmultret(e.k)) { if (hasmultret(e.k)) {
luaK_setmultret(fs, &e); luaK_setmultret(fs, &e);
if (e.k == VCALL && nret == 1) { /* tail call? */ if (e.k == VCALL && nret == 1) { /* tail call? */
SET_OPCODE(getcode(fs,&e), OP_TAILCALL); SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);
lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);
} }
first = fs->nactvar; first = fs->nactvar;
nret = LUA_MULTRET; /* return all values */ nret = LUA_MULTRET; /* return all values */
@@ -1611,7 +1613,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
BlockCnt bl; BlockCnt bl;
expdesc v; expdesc v;
open_func(ls, fs, &bl); open_func(ls, fs, &bl);
fs->f->is_vararg = 2; /* main function is always declared vararg */ fs->f->is_vararg = 1; /* main function is always declared vararg */
init_exp(&v, VLOCAL, 0); /* create and... */ init_exp(&v, VLOCAL, 0); /* create and... */
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
luaX_next(ls); /* read first token */ luaX_next(ls); /* read first token */

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lparser.h,v 1.73 2014/06/19 18:27:20 roberto Exp roberto $ ** $Id: lparser.h,v 1.75 2015/12/17 15:44:50 roberto Exp roberto $
** Lua Parser ** Lua Parser
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -13,25 +13,38 @@
/* /*
** Expression descriptor ** Expression and variable descriptor.
** Code generation for variables and expressions can be delayed to allow
** optimizations; An 'expdesc' structure describes a potentially-delayed
** variable/expression. It has a description of its "main" value plus a
** list of conditional jumps that can also produce its value (generated
** by short-circuit operators 'and'/'or').
*/ */
/* kinds of variables/expressions */
typedef enum { typedef enum {
VVOID, /* no value */ VVOID, /* when 'expdesc' describes the last expression a list,
VNIL, this kind means an empty list (so, no expression) */
VTRUE, VNIL, /* constant nil */
VFALSE, VTRUE, /* constant true */
VK, /* info = index of constant in 'k' */ VFALSE, /* constant false */
VKFLT, /* nval = numerical float value */ VK, /* constant in 'k'; info = index of constant in 'k' */
VKINT, /* nval = numerical integer value */ VKFLT, /* floating constant; nval = numerical float value */
VNONRELOC, /* info = result register */ VKINT, /* integer constant; nval = numerical integer value */
VLOCAL, /* info = local register */ VNONRELOC, /* expression has its value in a fixed register;
VUPVAL, /* info = index of upvalue in 'upvalues' */ info = result register */
VINDEXED, /* t = table register/upvalue; idx = index R/K */ VLOCAL, /* local variable; info = local register */
VJMP, /* info = instruction pc */ VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
VRELOCABLE, /* info = instruction pc */ VINDEXED, /* indexed variable;
VCALL, /* info = instruction pc */ ind.vt = whether 't' is register or upvalue;
VVARARG /* info = instruction pc */ ind.t = table register or upvalue;
ind.idx = key's R/K index */
VJMP, /* expression is a test/comparison;
info = pc of corresponding jump instruction */
VRELOCABLE, /* expression can put result in any register;
info = instruction pc */
VCALL, /* expression is a function call; info = instruction pc */
VVARARG /* vararg expression; info = instruction pc */
} expkind; } expkind;
@@ -41,14 +54,14 @@ typedef enum {
typedef struct expdesc { typedef struct expdesc {
expkind k; expkind k;
union { union {
lua_Integer ival; /* for VKINT */
lua_Number nval; /* for VKFLT */
int info; /* for generic use */
struct { /* for indexed variables (VINDEXED) */ struct { /* for indexed variables (VINDEXED) */
short idx; /* index (R/K) */ short idx; /* index (R/K) */
lu_byte t; /* table (register or upvalue) */ lu_byte t; /* table (register or upvalue) */
lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
} ind; } ind;
int info; /* for generic use */
lua_Number nval; /* for VKFLT */
lua_Integer ival; /* for VKINT */
} u; } u;
int t; /* patch list of 'exit when true' */ int t; /* patch list of 'exit when true' */
int f; /* patch list of 'exit when false' */ int f; /* patch list of 'exit when false' */

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lstate.h,v 2.127 2015/11/02 16:01:41 roberto Exp roberto $ ** $Id: lstate.h,v 2.132 2016/10/19 12:31:42 roberto Exp roberto $
** Global State ** Global State
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -23,7 +23,7 @@
** **
** 'allgc': all objects not marked for finalization; ** 'allgc': all objects not marked for finalization;
** 'finobj': all objects marked for finalization; ** 'finobj': all objects marked for finalization;
** 'tobefnz': all objects ready to be finalized; ** 'tobefnz': all objects ready to be finalized;
** 'fixedgc': all objects that are not to be collected (currently ** 'fixedgc': all objects that are not to be collected (currently
** only small strings, such as reserved words). ** only small strings, such as reserved words).
@@ -33,6 +33,15 @@
struct lua_longjmp; /* defined in ldo.c */ struct lua_longjmp; /* defined in ldo.c */
/*
** Atomic type (relative to signals) to better ensure that 'lua_sethook'
** is thread safe
*/
#if !defined(l_signalT)
#include <signal.h>
#define l_signalT sig_atomic_t
#endif
/* extra stack space to handle TM calls and some other extras */ /* extra stack space to handle TM calls and some other extras */
#define EXTRA_STACK 5 #define EXTRA_STACK 5
@@ -57,7 +66,7 @@ typedef struct stringtable {
** Information about a call. ** Information about a call.
** When a thread yields, 'func' is adjusted to pretend that the ** When a thread yields, 'func' is adjusted to pretend that the
** top function has only the yielded values in its stack; in that ** top function has only the yielded values in its stack; in that
** case, the actual 'func' value is saved in field 'extra'. ** case, the actual 'func' value is saved in field 'extra'.
** When a function calls another with a continuation, 'extra' keeps ** When a function calls another with a continuation, 'extra' keeps
** the function index so that, in case of errors, the continuation ** the function index so that, in case of errors, the continuation
** function can be called with the correct top. ** function can be called with the correct top.
@@ -79,7 +88,7 @@ typedef struct CallInfo {
} u; } u;
ptrdiff_t extra; ptrdiff_t extra;
short nresults; /* expected number of results from this function */ short nresults; /* expected number of results from this function */
lu_byte callstatus; unsigned short callstatus;
} CallInfo; } CallInfo;
@@ -95,6 +104,7 @@ typedef struct CallInfo {
#define CIST_TAIL (1<<5) /* call was tail called */ #define CIST_TAIL (1<<5) /* call was tail called */
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
#define CIST_LEQ (1<<7) /* using __lt for __le */ #define CIST_LEQ (1<<7) /* using __lt for __le */
#define CIST_FIN (1<<8) /* call is running a finalizer */
#define isLua(ci) ((ci)->callstatus & CIST_LUA) #define isLua(ci) ((ci)->callstatus & CIST_LUA)
@@ -162,14 +172,14 @@ struct lua_State {
struct lua_State *twups; /* list of threads with open upvalues */ struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */ struct lua_longjmp *errorJmp; /* current error recover point */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
lua_Hook hook; volatile lua_Hook hook;
ptrdiff_t errfunc; /* current error handling function (stack index) */ ptrdiff_t errfunc; /* current error handling function (stack index) */
int stacksize; int stacksize;
int basehookcount; int basehookcount;
int hookcount; int hookcount;
unsigned short nny; /* number of non-yieldable calls in stack */ unsigned short nny; /* number of non-yieldable calls in stack */
unsigned short nCcalls; /* number of nested C calls */ unsigned short nCcalls; /* number of nested C calls */
lu_byte hookmask; l_signalT hookmask;
lu_byte allowhook; lu_byte allowhook;
}; };

157
lstrlib.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lstrlib.c,v 1.238 2015/11/23 11:31:21 roberto Exp roberto $ ** $Id: lstrlib.c,v 1.253 2016/12/20 18:37:00 roberto Exp roberto $
** Standard library for string operations and pattern-matching ** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -13,6 +13,7 @@
#include <ctype.h> #include <ctype.h>
#include <float.h> #include <float.h>
#include <limits.h> #include <limits.h>
#include <locale.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -26,7 +27,8 @@
/* /*
** maximum number of captures that a pattern can do during ** maximum number of captures that a pattern can do during
** pattern-matching. This limit is arbitrary. ** pattern-matching. This limit is arbitrary, but must fit in
** an unsigned char.
*/ */
#if !defined(LUA_MAXCAPTURES) #if !defined(LUA_MAXCAPTURES)
#define LUA_MAXCAPTURES 32 #define LUA_MAXCAPTURES 32
@@ -214,9 +216,8 @@ typedef struct MatchState {
const char *src_end; /* end ('\0') of source string */ const char *src_end; /* end ('\0') of source string */
const char *p_end; /* end ('\0') of pattern */ const char *p_end; /* end ('\0') of pattern */
lua_State *L; lua_State *L;
size_t nrep; /* limit to avoid non-linear complexity */
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */ int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
int level; /* total number of captures (finished or unfinished) */ unsigned char level; /* total number of captures (finished or unfinished) */
struct { struct {
const char *init; const char *init;
ptrdiff_t len; ptrdiff_t len;
@@ -234,17 +235,6 @@ static const char *match (MatchState *ms, const char *s, const char *p);
#endif #endif
/*
** parameters to control the maximum number of operators handled in
** a match (to avoid non-linear complexity). The maximum will be:
** (subject length) * A_REPS + B_REPS
*/
#if !defined(A_REPS)
#define A_REPS 4
#define B_REPS 100000
#endif
#define L_ESC '%' #define L_ESC '%'
#define SPECIALS "^$*+?.([%-" #define SPECIALS "^$*+?.([%-"
@@ -502,8 +492,6 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
s = NULL; /* fail */ s = NULL; /* fail */
} }
else { /* matched once */ else { /* matched once */
if (ms->nrep-- == 0)
luaL_error(ms->L, "pattern too complex");
switch (*ep) { /* handle optional suffix */ switch (*ep) { /* handle optional suffix */
case '?': { /* optional */ case '?': { /* optional */
const char *res; const char *res;
@@ -607,10 +595,6 @@ static void prepstate (MatchState *ms, lua_State *L,
ms->src_init = s; ms->src_init = s;
ms->src_end = s + ls; ms->src_end = s + ls;
ms->p_end = p + lp; ms->p_end = p + lp;
if (ls < (MAX_SIZET - B_REPS) / A_REPS)
ms->nrep = A_REPS * ls + B_REPS;
else /* overflow (very long subject) */
ms->nrep = MAX_SIZET; /* no limit */
} }
@@ -681,6 +665,7 @@ static int str_match (lua_State *L) {
typedef struct GMatchState { typedef struct GMatchState {
const char *src; /* current position */ const char *src; /* current position */
const char *p; /* pattern */ const char *p; /* pattern */
const char *lastmatch; /* end of last match */
MatchState ms; /* match state */ MatchState ms; /* match state */
} GMatchState; } GMatchState;
@@ -688,14 +673,12 @@ typedef struct GMatchState {
static int gmatch_aux (lua_State *L) { static int gmatch_aux (lua_State *L) {
GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3));
const char *src; const char *src;
gm->ms.L = L;
for (src = gm->src; src <= gm->ms.src_end; src++) { for (src = gm->src; src <= gm->ms.src_end; src++) {
const char *e; const char *e;
reprepstate(&gm->ms); reprepstate(&gm->ms);
if ((e = match(&gm->ms, src, gm->p)) != NULL) { if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) {
if (e == src) /* empty match? */ gm->src = gm->lastmatch = e;
gm->src =src + 1; /* go at least one position */
else
gm->src = e;
return push_captures(&gm->ms, src, e); return push_captures(&gm->ms, src, e);
} }
} }
@@ -711,7 +694,7 @@ static int gmatch (lua_State *L) {
lua_settop(L, 2); /* keep them on closure to avoid being collected */ lua_settop(L, 2); /* keep them on closure to avoid being collected */
gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState));
prepstate(&gm->ms, L, s, ls, p, lp); prepstate(&gm->ms, L, s, ls, p, lp);
gm->src = s; gm->p = p; gm->src = s; gm->p = p; gm->lastmatch = NULL;
lua_pushcclosure(L, gmatch_aux, 3); lua_pushcclosure(L, gmatch_aux, 3);
return 1; return 1;
} }
@@ -778,12 +761,13 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
static int str_gsub (lua_State *L) { static int str_gsub (lua_State *L) {
size_t srcl, lp; size_t srcl, lp;
const char *src = luaL_checklstring(L, 1, &srcl); const char *src = luaL_checklstring(L, 1, &srcl); /* subject */
const char *p = luaL_checklstring(L, 2, &lp); const char *p = luaL_checklstring(L, 2, &lp); /* pattern */
int tr = lua_type(L, 3); const char *lastmatch = NULL; /* end of last match */
lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); int tr = lua_type(L, 3); /* replacement type */
lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */
int anchor = (*p == '^'); int anchor = (*p == '^');
lua_Integer n = 0; lua_Integer n = 0; /* replacement count */
MatchState ms; MatchState ms;
luaL_Buffer b; luaL_Buffer b;
luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
@@ -796,16 +780,15 @@ static int str_gsub (lua_State *L) {
prepstate(&ms, L, src, srcl, p, lp); prepstate(&ms, L, src, srcl, p, lp);
while (n < max_s) { while (n < max_s) {
const char *e; const char *e;
reprepstate(&ms); reprepstate(&ms); /* (re)prepare state for new match */
if ((e = match(&ms, src, p)) != NULL) { if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
n++; n++;
add_value(&ms, &b, src, e, tr); add_value(&ms, &b, src, e, tr); /* add replacement to buffer */
src = lastmatch = e;
} }
if (e && e>src) /* non empty match? */ else if (src < ms.src_end) /* otherwise, skip one character */
src = e; /* skip it */
else if (src < ms.src_end)
luaL_addchar(&b, *src++); luaL_addchar(&b, *src++);
else break; else break; /* end of subject */
if (anchor) break; if (anchor) break;
} }
luaL_addlstring(&b, src, ms.src_end-src); luaL_addlstring(&b, src, ms.src_end-src);
@@ -830,7 +813,6 @@ static int str_gsub (lua_State *L) {
** Hexadecimal floating-point formatter ** Hexadecimal floating-point formatter
*/ */
#include <locale.h>
#include <math.h> #include <math.h>
#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) #define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char))
@@ -857,11 +839,12 @@ static lua_Number adddigit (char *buff, int n, lua_Number x) {
static int num2straux (char *buff, int sz, lua_Number x) { static int num2straux (char *buff, int sz, lua_Number x) {
if (x != x || x == HUGE_VAL || x == -HUGE_VAL) /* inf or NaN? */ /* if 'inf' or 'NaN', format it like '%g' */
return l_sprintf(buff, sz, LUA_NUMBER_FMT, x); /* equal to '%g' */ if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL)
return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x);
else if (x == 0) { /* can be -0... */ else if (x == 0) { /* can be -0... */
/* create "0" or "-0" followed by exponent */ /* create "0" or "-0" followed by exponent */
return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", x); return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x);
} }
else { else {
int e; int e;
@@ -922,16 +905,14 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
#define MAX_FORMAT 32 #define MAX_FORMAT 32
static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
size_t l;
const char *s = luaL_checklstring(L, arg, &l);
luaL_addchar(b, '"'); luaL_addchar(b, '"');
while (l--) { while (len--) {
if (*s == '"' || *s == '\\' || *s == '\n') { if (*s == '"' || *s == '\\' || *s == '\n') {
luaL_addchar(b, '\\'); luaL_addchar(b, '\\');
luaL_addchar(b, *s); luaL_addchar(b, *s);
} }
else if (*s == '\0' || iscntrl(uchar(*s))) { else if (iscntrl(uchar(*s))) {
char buff[10]; char buff[10];
if (!isdigit(uchar(*(s+1)))) if (!isdigit(uchar(*(s+1))))
l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s));
@@ -946,6 +927,57 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
luaL_addchar(b, '"'); luaL_addchar(b, '"');
} }
/*
** Ensures the 'buff' string uses a dot as the radix character.
*/
static void checkdp (char *buff, int nb) {
if (memchr(buff, '.', nb) == NULL) { /* no dot? */
char point = lua_getlocaledecpoint(); /* try locale point */
char *ppoint = (char *)memchr(buff, point, nb);
if (ppoint) *ppoint = '.'; /* change it to a dot */
}
}
static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
switch (lua_type(L, arg)) {
case LUA_TSTRING: {
size_t len;
const char *s = lua_tolstring(L, arg, &len);
addquoted(b, s, len);
break;
}
case LUA_TNUMBER: {
char *buff = luaL_prepbuffsize(b, MAX_ITEM);
int nb;
if (!lua_isinteger(L, arg)) { /* float? */
lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */
nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n);
checkdp(buff, nb); /* ensure it uses a dot */
}
else { /* integers */
lua_Integer n = lua_tointeger(L, arg);
const char *format = (n == LUA_MININTEGER) /* corner case? */
? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */
: LUA_INTEGER_FMT; /* else use default format */
nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n);
}
luaL_addsize(b, nb);
break;
}
case LUA_TNIL: case LUA_TBOOLEAN: {
luaL_tolstring(L, arg, NULL);
luaL_addvalue(b);
break;
}
default: {
luaL_argerror(L, arg, "value has no literal form");
}
}
}
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
const char *p = strfrmt; const char *p = strfrmt;
while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
@@ -1010,7 +1042,7 @@ static int str_format (lua_State *L) {
case 'o': case 'u': case 'x': case 'X': { case 'o': case 'u': case 'x': case 'X': {
lua_Integer n = luaL_checkinteger(L, arg); lua_Integer n = luaL_checkinteger(L, arg);
addlenmod(form, LUA_INTEGER_FRMLEN); addlenmod(form, LUA_INTEGER_FRMLEN);
nb = l_sprintf(buff, MAX_ITEM, form, n); nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n);
break; break;
} }
case 'a': case 'A': case 'a': case 'A':
@@ -1020,12 +1052,13 @@ static int str_format (lua_State *L) {
break; break;
case 'e': case 'E': case 'f': case 'e': case 'E': case 'f':
case 'g': case 'G': { case 'g': case 'G': {
lua_Number n = luaL_checknumber(L, arg);
addlenmod(form, LUA_NUMBER_FRMLEN); addlenmod(form, LUA_NUMBER_FRMLEN);
nb = l_sprintf(buff, MAX_ITEM, form, luaL_checknumber(L, arg)); nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n);
break; break;
} }
case 'q': { case 'q': {
addquoted(L, &b, arg); addliteral(L, &b, arg);
break; break;
} }
case 's': { case 's': {
@@ -1070,8 +1103,8 @@ static int str_format (lua_State *L) {
/* value used for padding */ /* value used for padding */
#if !defined(LUA_PACKPADBYTE) #if !defined(LUAL_PACKPADBYTE)
#define LUA_PACKPADBYTE 0x00 #define LUAL_PACKPADBYTE 0x00
#endif #endif
/* maximum size for the binary representation of an integer */ /* maximum size for the binary representation of an integer */
@@ -1228,7 +1261,7 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
** 'psize' is filled with option's size, 'notoalign' with its ** 'psize' is filled with option's size, 'notoalign' with its
** alignment requirements. ** alignment requirements.
** Local variable 'size' gets the size to be aligned. (Kpadal option ** Local variable 'size' gets the size to be aligned. (Kpadal option
** always gets its full alignment, other options are limited by ** always gets its full alignment, other options are limited by
** the maximum alignment ('maxalign'). Kchar option needs no alignment ** the maximum alignment ('maxalign'). Kchar option needs no alignment
** despite its size. ** despite its size.
*/ */
@@ -1308,7 +1341,7 @@ static int str_pack (lua_State *L) {
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
totalsize += ntoalign + size; totalsize += ntoalign + size;
while (ntoalign-- > 0) while (ntoalign-- > 0)
luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */ luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
arg++; arg++;
switch (opt) { switch (opt) {
case Kint: { /* signed integers */ case Kint: { /* signed integers */
@@ -1343,13 +1376,11 @@ static int str_pack (lua_State *L) {
case Kchar: { /* fixed-size string */ case Kchar: { /* fixed-size string */
size_t len; size_t len;
const char *s = luaL_checklstring(L, arg, &len); const char *s = luaL_checklstring(L, arg, &len);
if ((size_t)size <= len) /* string larger than (or equal to) needed? */ luaL_argcheck(L, len <= (size_t)size, arg,
luaL_addlstring(&b, s, size); /* truncate string to asked size */ "string longer than given size");
else { /* string smaller than needed */ luaL_addlstring(&b, s, len); /* add string */
luaL_addlstring(&b, s, len); /* add it all */ while (len++ < (size_t)size) /* pad extra space */
while (len++ < (size_t)size) /* pad extra space */ luaL_addchar(&b, LUAL_PACKPADBYTE);
luaL_addchar(&b, LUA_PACKPADBYTE);
}
break; break;
} }
case Kstring: { /* strings with length count */ case Kstring: { /* strings with length count */
@@ -1372,7 +1403,7 @@ static int str_pack (lua_State *L) {
totalsize += len + 1; totalsize += len + 1;
break; break;
} }
case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* FALLTHROUGH */ case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */
case Kpaddalign: case Knop: case Kpaddalign: case Knop:
arg--; /* undo increment */ arg--; /* undo increment */
break; break;

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ltable.c,v 2.116 2015/11/03 18:35:21 roberto Exp roberto $ ** $Id: ltable.c,v 2.117 2015/11/19 19:16:22 roberto Exp roberto $
** Lua tables (hash) ** Lua tables (hash)
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -74,8 +74,6 @@
#define dummynode (&dummynode_) #define dummynode (&dummynode_)
#define isdummy(n) ((n) == dummynode)
static const Node dummynode_ = { static const Node dummynode_ = {
{NILCONSTANT}, /* value */ {NILCONSTANT}, /* value */
{{NILCONSTANT, 0}} /* key */ {{NILCONSTANT, 0}} /* key */
@@ -308,14 +306,14 @@ static void setarrayvector (lua_State *L, Table *t, unsigned int size) {
static void setnodevector (lua_State *L, Table *t, unsigned int size) { static void setnodevector (lua_State *L, Table *t, unsigned int size) {
int lsize;
if (size == 0) { /* no elements to hash part? */ if (size == 0) { /* no elements to hash part? */
t->node = cast(Node *, dummynode); /* use common 'dummynode' */ t->node = cast(Node *, dummynode); /* use common 'dummynode' */
lsize = 0; t->lsizenode = 0;
t->lastfree = NULL; /* signal that it is using dummy node */
} }
else { else {
int i; int i;
lsize = luaO_ceillog2(size); int lsize = luaO_ceillog2(size);
if (lsize > MAXHBITS) if (lsize > MAXHBITS)
luaG_runerror(L, "table overflow"); luaG_runerror(L, "table overflow");
size = twoto(lsize); size = twoto(lsize);
@@ -326,9 +324,9 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
setnilvalue(wgkey(n)); setnilvalue(wgkey(n));
setnilvalue(gval(n)); setnilvalue(gval(n));
} }
t->lsizenode = cast_byte(lsize);
t->lastfree = gnode(t, size); /* all positions are free */
} }
t->lsizenode = cast_byte(lsize);
t->lastfree = gnode(t, size); /* all positions are free */
} }
@@ -337,7 +335,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
unsigned int i; unsigned int i;
int j; int j;
unsigned int oldasize = t->sizearray; unsigned int oldasize = t->sizearray;
int oldhsize = t->lsizenode; int oldhsize = allocsizenode(t);
Node *nold = t->node; /* save old hash ... */ Node *nold = t->node; /* save old hash ... */
if (nasize > oldasize) /* array part must grow? */ if (nasize > oldasize) /* array part must grow? */
setarrayvector(L, t, nasize); setarrayvector(L, t, nasize);
@@ -354,7 +352,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
luaM_reallocvector(L, t->array, oldasize, nasize, TValue); luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
} }
/* re-insert elements from hash part */ /* re-insert elements from hash part */
for (j = twoto(oldhsize) - 1; j >= 0; j--) { for (j = oldhsize - 1; j >= 0; j--) {
Node *old = nold + j; Node *old = nold + j;
if (!ttisnil(gval(old))) { if (!ttisnil(gval(old))) {
/* doesn't need barrier/invalidate cache, as entry was /* doesn't need barrier/invalidate cache, as entry was
@@ -362,13 +360,13 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old)); setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old));
} }
} }
if (!isdummy(nold)) if (oldhsize > 0) /* not the dummy node? */
luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old hash */ luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */
} }
void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) { void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) {
int nsize = isdummy(t->node) ? 0 : sizenode(t); int nsize = allocsizenode(t);
luaH_resize(L, t, nasize, nsize); luaH_resize(L, t, nasize, nsize);
} }
@@ -414,7 +412,7 @@ Table *luaH_new (lua_State *L) {
void luaH_free (lua_State *L, Table *t) { void luaH_free (lua_State *L, Table *t) {
if (!isdummy(t->node)) if (!isdummy(t))
luaM_freearray(L, t->node, cast(size_t, sizenode(t))); luaM_freearray(L, t->node, cast(size_t, sizenode(t)));
luaM_freearray(L, t->array, t->sizearray); luaM_freearray(L, t->array, t->sizearray);
luaM_free(L, t); luaM_free(L, t);
@@ -422,10 +420,12 @@ void luaH_free (lua_State *L, Table *t) {
static Node *getfreepos (Table *t) { static Node *getfreepos (Table *t) {
while (t->lastfree > t->node) { if (!isdummy(t)) {
t->lastfree--; while (t->lastfree > t->node) {
if (ttisnil(gkey(t->lastfree))) t->lastfree--;
return t->lastfree; if (ttisnil(gkey(t->lastfree)))
return t->lastfree;
}
} }
return NULL; /* could not find a free place */ return NULL; /* could not find a free place */
} }
@@ -445,7 +445,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
if (ttisnil(key)) luaG_runerror(L, "table index is nil"); if (ttisnil(key)) luaG_runerror(L, "table index is nil");
else if (ttisfloat(key)) { else if (ttisfloat(key)) {
lua_Integer k; lua_Integer k;
if (luaV_tointeger(key, &k, 0)) { /* index is int? */ if (luaV_tointeger(key, &k, 0)) { /* does index fit in an integer? */
setivalue(&aux, k); setivalue(&aux, k);
key = &aux; /* insert it as an integer */ key = &aux; /* insert it as an integer */
} }
@@ -453,7 +453,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
luaG_runerror(L, "table index is NaN"); luaG_runerror(L, "table index is NaN");
} }
mp = mainposition(t, key); mp = mainposition(t, key);
if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */ if (!ttisnil(gval(mp)) || isdummy(t)) { /* main position is taken? */
Node *othern; Node *othern;
Node *f = getfreepos(t); /* get a free place */ Node *f = getfreepos(t); /* get a free place */
if (f == NULL) { /* cannot find a free place? */ if (f == NULL) { /* cannot find a free place? */
@@ -461,7 +461,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
/* whatever called 'newkey' takes care of TM cache */ /* whatever called 'newkey' takes care of TM cache */
return luaH_set(L, t, key); /* insert key into grown table */ return luaH_set(L, t, key); /* insert key into grown table */
} }
lua_assert(!isdummy(f)); lua_assert(!isdummy(t));
othern = mainposition(t, gkey(mp)); othern = mainposition(t, gkey(mp));
if (othern != mp) { /* is colliding node out of its main position? */ if (othern != mp) { /* is colliding node out of its main position? */
/* yes; move colliding node into free position */ /* yes; move colliding node into free position */
@@ -651,7 +651,7 @@ int luaH_getn (Table *t) {
return i; return i;
} }
/* else must find a boundary in hash part */ /* else must find a boundary in hash part */
else if (isdummy(t->node)) /* hash part is empty? */ else if (isdummy(t)) /* hash part is empty? */
return j; /* that is easy... */ return j; /* that is easy... */
else return unbound_search(t, j); else return unbound_search(t, j);
} }
@@ -664,6 +664,6 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainposition(t, key); return mainposition(t, key);
} }
int luaH_isdummy (Node *n) { return isdummy(n); } int luaH_isdummy (const Table *t) { return isdummy(t); }
#endif #endif

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ltable.h,v 2.20 2014/09/04 18:15:29 roberto Exp roberto $ ** $Id: ltable.h,v 2.22 2016/11/07 12:38:35 roberto Exp roberto $
** Lua tables (hash) ** Lua tables (hash)
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -15,7 +15,7 @@
#define gnext(n) ((n)->i_key.nk.next) #define gnext(n) ((n)->i_key.nk.next)
/* 'const' to avoid wrong writings that can mess up field 'next' */ /* 'const' to avoid wrong writings that can mess up field 'next' */
#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk)) #define gkey(n) cast(const TValue*, (&(n)->i_key.tvk))
/* /*
@@ -27,6 +27,14 @@
#define invalidateTMcache(t) ((t)->flags = 0) #define invalidateTMcache(t) ((t)->flags = 0)
/* true when 't' is using 'dummynode' as its hash part */
#define isdummy(t) ((t)->lastfree == NULL)
/* allocated size for hash nodes */
#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t))
/* returns the key, given the value of a table entry */ /* returns the key, given the value of a table entry */
#define keyfromval(v) \ #define keyfromval(v) \
(gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
@@ -51,7 +59,7 @@ LUAI_FUNC int luaH_getn (Table *t);
#if defined(LUA_DEBUG) #if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
LUAI_FUNC int luaH_isdummy (Node *n); LUAI_FUNC int luaH_isdummy (const Table *t);
#endif #endif

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ltablib.c,v 1.89 2015/11/24 16:54:32 roberto Exp roberto $ ** $Id: ltablib.c,v 1.92 2016/02/08 12:55:19 roberto Exp roberto $
** Library for Table Manipulation ** Library for Table Manipulation
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -53,7 +53,7 @@ static void checktab (lua_State *L, int arg, int what) {
lua_pop(L, n); /* pop metatable and tested metamethods */ lua_pop(L, n); /* pop metatable and tested metamethods */
} }
else else
luaL_argerror(L, arg, "table expected"); /* force an error */ luaL_checktype(L, arg, LUA_TTABLE); /* force an error */
} }
} }
@@ -139,7 +139,7 @@ static int tmove (lua_State *L) {
n = e - f + 1; /* number of elements to move */ n = e - f + 1; /* number of elements to move */
luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4,
"destination wrap around"); "destination wrap around");
if (t > e || t <= f || tt != 1) { if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) {
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
lua_geti(L, 1, f + i); lua_geti(L, 1, f + i);
lua_seti(L, tt, t + i); lua_seti(L, tt, t + i);
@@ -152,7 +152,7 @@ static int tmove (lua_State *L) {
} }
} }
} }
lua_pushvalue(L, tt); /* return "to table" */ lua_pushvalue(L, tt); /* return destination table */
return 1; return 1;
} }
@@ -172,7 +172,7 @@ static int tconcat (lua_State *L) {
size_t lsep; size_t lsep;
const char *sep = luaL_optlstring(L, 2, "", &lsep); const char *sep = luaL_optlstring(L, 2, "", &lsep);
lua_Integer i = luaL_optinteger(L, 3, 1); lua_Integer i = luaL_optinteger(L, 3, 1);
last = luaL_opt(L, luaL_checkinteger, 4, last); last = luaL_optinteger(L, 4, last);
luaL_buffinit(L, &b); luaL_buffinit(L, &b);
for (; i < last; i++) { for (; i < last; i++) {
addfield(L, &b, i); addfield(L, &b, i);
@@ -232,6 +232,10 @@ static int unpack (lua_State *L) {
*/ */
/* type for array indices */
typedef unsigned int IdxT;
/* /*
** Produce a "random" 'unsigned int' to randomize pivot choice. This ** Produce a "random" 'unsigned int' to randomize pivot choice. This
** macro is used only when 'sort' detects a big imbalance in the result ** macro is used only when 'sort' detects a big imbalance in the result
@@ -270,7 +274,7 @@ static unsigned int l_randomizePivot (void) {
#define RANLIMIT 100u #define RANLIMIT 100u
static void set2 (lua_State *L, unsigned int i, unsigned int j) { static void set2 (lua_State *L, IdxT i, IdxT j) {
lua_seti(L, 1, i); lua_seti(L, 1, i);
lua_seti(L, 1, j); lua_seti(L, 1, j);
} }
@@ -303,10 +307,9 @@ static int sort_comp (lua_State *L, int a, int b) {
** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] ** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up]
** returns 'i'. ** returns 'i'.
*/ */
static unsigned int partition (lua_State *L, unsigned int lo, static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
unsigned int up) { IdxT i = lo; /* will be incremented before first use */
unsigned int i = lo; /* will be incremented before first use */ IdxT j = up - 1; /* will be decremented before first use */
unsigned int j = up - 1; /* will be decremented before first use */
/* loop invariant: a[lo .. i] <= P <= a[j .. up] */ /* loop invariant: a[lo .. i] <= P <= a[j .. up] */
for (;;) { for (;;) {
/* next loop: repeat ++i while a[i] < P */ /* next loop: repeat ++i while a[i] < P */
@@ -340,10 +343,9 @@ static unsigned int partition (lua_State *L, unsigned int lo,
** Choose an element in the middle (2nd-3th quarters) of [lo,up] ** Choose an element in the middle (2nd-3th quarters) of [lo,up]
** "randomized" by 'rnd' ** "randomized" by 'rnd'
*/ */
static unsigned int choosePivot (unsigned int lo, unsigned int up, static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
unsigned int rnd) { IdxT r4 = (up - lo) / 4; /* range/4 */
unsigned int r4 = (unsigned int)(up - lo) / 4u; /* range/4 */ IdxT p = rnd % (r4 * 2) + (lo + r4);
unsigned int p = rnd % (r4 * 2) + (lo + r4);
lua_assert(lo + r4 <= p && p <= up - r4); lua_assert(lo + r4 <= p && p <= up - r4);
return p; return p;
} }
@@ -352,11 +354,11 @@ static unsigned int choosePivot (unsigned int lo, unsigned int up,
/* /*
** QuickSort algorithm (recursive function) ** QuickSort algorithm (recursive function)
*/ */
static void auxsort (lua_State *L, unsigned int lo, unsigned int up, static void auxsort (lua_State *L, IdxT lo, IdxT up,
unsigned int rnd) { unsigned int rnd) {
while (lo < up) { /* loop for tail recursion */ while (lo < up) { /* loop for tail recursion */
unsigned int p; /* Pivot index */ IdxT p; /* Pivot index */
unsigned int n; /* to be used later */ IdxT n; /* to be used later */
/* sort elements 'lo', 'p', and 'up' */ /* sort elements 'lo', 'p', and 'up' */
lua_geti(L, 1, lo); lua_geti(L, 1, lo);
lua_geti(L, 1, up); lua_geti(L, 1, up);
@@ -400,7 +402,7 @@ static void auxsort (lua_State *L, unsigned int lo, unsigned int up,
n = up - p; /* size of smaller interval */ n = up - p; /* size of smaller interval */
up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */
} }
if ((up - lo) / 128u > n) /* partition too imbalanced? */ if ((up - lo) / 128 > n) /* partition too imbalanced? */
rnd = l_randomizePivot(); /* try a new randomization */ rnd = l_randomizePivot(); /* try a new randomization */
} /* tail call auxsort(L, lo, up, rnd) */ } /* tail call auxsort(L, lo, up, rnd) */
} }
@@ -410,11 +412,10 @@ static int sort (lua_State *L) {
lua_Integer n = aux_getn(L, 1, TAB_RW); lua_Integer n = aux_getn(L, 1, TAB_RW);
if (n > 1) { /* non-trivial interval? */ if (n > 1) { /* non-trivial interval? */
luaL_argcheck(L, n < INT_MAX, 1, "array too big"); luaL_argcheck(L, n < INT_MAX, 1, "array too big");
luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */
if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */
lua_settop(L, 2); /* make sure there are two arguments */ lua_settop(L, 2); /* make sure there are two arguments */
auxsort(L, 1, (unsigned int)n, 0u); auxsort(L, 1, (IdxT)n, 0);
} }
return 0; return 0;
} }

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ltests.c,v 2.208 2015/09/08 16:55:43 roberto Exp roberto $ ** $Id: ltests.c,v 2.210 2016/11/07 12:38:35 roberto Exp roberto $
** Internal Module for Debugging of the Lua Implementation ** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -687,8 +687,8 @@ static int table_query (lua_State *L) {
t = hvalue(obj_at(L, 1)); t = hvalue(obj_at(L, 1));
if (i == -1) { if (i == -1) {
lua_pushinteger(L, t->sizearray); lua_pushinteger(L, t->sizearray);
lua_pushinteger(L, luaH_isdummy(t->node) ? 0 : sizenode(t)); lua_pushinteger(L, allocsizenode(t));
lua_pushinteger(L, t->lastfree - t->node); lua_pushinteger(L, isdummy(t) ? 0 : t->lastfree - t->node);
} }
else if ((unsigned int)i < t->sizearray) { else if ((unsigned int)i < t->sizearray) {
lua_pushinteger(L, i); lua_pushinteger(L, i);
@@ -869,7 +869,7 @@ static int loadlib (lua_State *L) {
luaL_requiref(L1, "package", NULL, 1); /* seg. fault if it reloads */ luaL_requiref(L1, "package", NULL, 1); /* seg. fault if it reloads */
/* ...but should return the same module */ /* ...but should return the same module */
lua_assert(lua_compare(L1, -1, -2, LUA_OPEQ)); lua_assert(lua_compare(L1, -1, -2, LUA_OPEQ));
luaL_getsubtable(L1, LUA_REGISTRYINDEX, "_PRELOAD"); luaL_getsubtable(L1, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
for (i = 0; libs[i].name; i++) { for (i = 0; libs[i].name; i++) {
lua_pushcfunction(L1, libs[i].func); lua_pushcfunction(L1, libs[i].func);
lua_setfield(L1, -2, libs[i].name); lua_setfield(L1, -2, libs[i].name);

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ltests.h,v 2.48 2015/06/18 14:27:44 roberto Exp roberto $ ** $Id: ltests.h,v 2.49 2015/09/22 14:18:24 roberto Exp roberto $
** Internal Header for Debugging of the Lua Implementation ** Internal Header for Debugging of the Lua Implementation
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -98,7 +98,9 @@ LUA_API void *debug_realloc (void *ud, void *block,
#if defined(lua_c) #if defined(lua_c)
#define luaL_newstate() lua_newstate(debug_realloc, &l_memcontrol) #define luaL_newstate() lua_newstate(debug_realloc, &l_memcontrol)
#define luaL_openlibs(L) \ #define luaL_openlibs(L) \
{ (luaL_openlibs)(L); luaL_requiref(L, "T", luaB_opentests, 1); } { (luaL_openlibs)(L); \
luaL_requiref(L, "T", luaB_opentests, 1); \
lua_pop(L, 1); }
#endif #endif
@@ -108,6 +110,7 @@ LUA_API void *debug_realloc (void *ud, void *block,
#undef LUAL_BUFFERSIZE #undef LUAL_BUFFERSIZE
#define LUAL_BUFFERSIZE 23 #define LUAL_BUFFERSIZE 23
#define MINSTRTABSIZE 2 #define MINSTRTABSIZE 2
#define MAXINDEXRK 1
/* make stack-overflow tests run faster */ /* make stack-overflow tests run faster */

20
ltm.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ltm.c,v 2.35 2015/11/02 18:48:07 roberto Exp roberto $ ** $Id: ltm.c,v 2.37 2016/02/26 19:20:15 roberto Exp roberto $
** Tag methods ** Tag methods
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -15,7 +15,7 @@
#include "lua.h" #include "lua.h"
#include "ldebug.h" #include "ldebug.h"
#include "ldo.h" #include "ldo.h"
#include "lobject.h" #include "lobject.h"
#include "lstate.h" #include "lstate.h"
#include "lstring.h" #include "lstring.h"
@@ -83,6 +83,22 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
} }
/*
** Return the name of the type of an object. For tables and userdata
** with metatable, use their '__name' metafield, if present.
*/
const char *luaT_objtypename (lua_State *L, const TValue *o) {
Table *mt;
if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) ||
(ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) {
const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name"));
if (ttisstring(name)) /* is '__name' a string? */
return getstr(tsvalue(name)); /* use it as type name */
}
return ttypename(ttnov(o)); /* else use standard type name */
}
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, TValue *p3, int hasres) { const TValue *p2, TValue *p3, int hasres) {
ptrdiff_t result = savestack(L, p3); ptrdiff_t result = savestack(L, p3);

5
ltm.h
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ltm.h,v 2.20 2014/06/10 18:53:18 roberto Exp roberto $ ** $Id: ltm.h,v 2.21 2014/10/25 11:50:46 roberto Exp roberto $
** Tag methods ** Tag methods
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -51,11 +51,12 @@ typedef enum {
#define fasttm(l,et,e) gfasttm(G(l), et, e) #define fasttm(l,et,e) gfasttm(G(l), et, e)
#define ttypename(x) luaT_typenames_[(x) + 1] #define ttypename(x) luaT_typenames_[(x) + 1]
#define objtypename(x) ttypename(ttnov(x))
LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS];
LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);
LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);
LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
TMS event); TMS event);

13
lua.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lua.c,v 1.225 2015/03/30 15:42:59 roberto Exp roberto $ ** $Id: lua.c,v 1.229 2016/12/22 13:08:50 roberto Exp roberto $
** Lua stand-alone interpreter ** Lua stand-alone interpreter
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -20,6 +20,7 @@
#include "lualib.h" #include "lualib.h"
#if !defined(LUA_PROMPT) #if !defined(LUA_PROMPT)
#define LUA_PROMPT "> " #define LUA_PROMPT "> "
#define LUA_PROMPT2 ">> " #define LUA_PROMPT2 ">> "
@@ -37,8 +38,7 @@
#define LUA_INIT_VAR "LUA_INIT" #define LUA_INIT_VAR "LUA_INIT"
#endif #endif
#define LUA_INITVARVERSION \ #define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX
LUA_INIT_VAR "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
/* /*
@@ -55,6 +55,8 @@
#elif defined(LUA_USE_WINDOWS) /* }{ */ #elif defined(LUA_USE_WINDOWS) /* }{ */
#include <io.h> #include <io.h>
#include <windows.h>
#define lua_stdin_is_tty() _isatty(_fileno(stdin)) #define lua_stdin_is_tty() _isatty(_fileno(stdin))
#else /* }{ */ #else /* }{ */
@@ -457,7 +459,7 @@ static int handle_script (lua_State *L, char **argv) {
/* /*
** Traverses all arguments from 'argv', returning a mask with those ** Traverses all arguments from 'argv', returning a mask with those
** needed before running any Lua code (or an error code if it finds ** needed before running any Lua code (or an error code if it finds
** any invalid argument). 'first' returns the first not-handled argument ** any invalid argument). 'first' returns the first not-handled argument
** (either the script name or a bad argument in case of error). ** (either the script name or a bad argument in case of error).
*/ */
static int collectargs (char **argv, int *first) { static int collectargs (char **argv, int *first) {
@@ -481,7 +483,7 @@ static int collectargs (char **argv, int *first) {
args |= has_E; args |= has_E;
break; break;
case 'i': case 'i':
args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */ args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */
case 'v': case 'v':
if (argv[i][2] != '\0') /* extra characters after 1st? */ if (argv[i][2] != '\0') /* extra characters after 1st? */
return has_error; /* invalid option */ return has_error; /* invalid option */
@@ -529,6 +531,7 @@ static int runargs (lua_State *L, char **argv, int n) {
} }
static int handle_luainit (lua_State *L) { static int handle_luainit (lua_State *L) {
const char *name = "=" LUA_INITVARVERSION; const char *name = "=" LUA_INITVARVERSION;
const char *init = getenv(name + 1); const char *init = getenv(name + 1);

10
lua.h
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lua.h,v 1.328 2015/06/03 13:03:38 roberto Exp roberto $ ** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp roberto $
** Lua - A Scripting Language ** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file ** See Copyright Notice at the end of this file
@@ -19,11 +19,11 @@
#define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "3" #define LUA_VERSION_MINOR "3"
#define LUA_VERSION_NUM 503 #define LUA_VERSION_NUM 503
#define LUA_VERSION_RELEASE "2" #define LUA_VERSION_RELEASE "4"
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2015 Lua.org, PUC-Rio" #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2017 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -361,7 +361,7 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
#define lua_pushliteral(L, s) lua_pushstring(L, "" s) #define lua_pushliteral(L, s) lua_pushstring(L, "" s)
#define lua_pushglobaltable(L) \ #define lua_pushglobaltable(L) \
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS) ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) #define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
@@ -460,7 +460,7 @@ struct lua_Debug {
/****************************************************************************** /******************************************************************************
* Copyright (C) 1994-2015 Lua.org, PUC-Rio. * Copyright (C) 1994-2017 Lua.org, PUC-Rio.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: luaconf.h,v 1.253 2015/06/24 18:23:57 roberto Exp roberto $ ** $Id: luaconf.h,v 1.258 2016/12/20 18:37:00 roberto Exp roberto $
** Configuration file for Lua ** Configuration file for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -158,6 +158,18 @@
** =================================================================== ** ===================================================================
*/ */
/*
** LUA_PATH_SEP is the character that separates templates in a path.
** LUA_PATH_MARK is the string that marks the substitution points in a
** template.
** LUA_EXEC_DIR in a Windows path is replaced by the executable's
** directory.
*/
#define LUA_PATH_SEP ";"
#define LUA_PATH_MARK "?"
#define LUA_EXEC_DIR "!"
/* /*
@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
** Lua libraries. ** Lua libraries.
@@ -404,7 +416,7 @@
/* /*
@@ LUA_NUMBER is the floating-point type used by Lua. @@ LUA_NUMBER is the floating-point type used by Lua.
@@ LUAI_UACNUMBER is the result of an 'usual argument conversion' @@ LUAI_UACNUMBER is the result of a 'default argument promotion'
@@ over a floating number. @@ over a floating number.
@@ l_mathlim(x) corrects limit name 'x' to the proper float type @@ l_mathlim(x) corrects limit name 'x' to the proper float type
** by prefixing it with one of FLT/DBL/LDBL. ** by prefixing it with one of FLT/DBL/LDBL.
@@ -421,7 +433,8 @@
#define l_floor(x) (l_mathop(floor)(x)) #define l_floor(x) (l_mathop(floor)(x))
#define lua_number2str(s,sz,n) l_sprintf((s), sz, LUA_NUMBER_FMT, (n)) #define lua_number2str(s,sz,n) \
l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n))
/* /*
@@ lua_numbertointeger converts a float number to an integer, or @@ lua_numbertointeger converts a float number to an integer, or
@@ -498,7 +511,7 @@
** **
@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. @@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
** **
@@ LUAI_UACINT is the result of an 'usual argument conversion' @@ LUAI_UACINT is the result of a 'default argument promotion'
@@ over a lUA_INTEGER. @@ over a lUA_INTEGER.
@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. @@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
@@ LUA_INTEGER_FMT is the format for writing integers. @@ LUA_INTEGER_FMT is the format for writing integers.
@@ -511,10 +524,12 @@
/* The following definitions are good for most cases here */ /* The following definitions are good for most cases here */
#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" #define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
#define lua_integer2str(s,sz,n) l_sprintf((s), sz, LUA_INTEGER_FMT, (n))
#define LUAI_UACINT LUA_INTEGER #define LUAI_UACINT LUA_INTEGER
#define lua_integer2str(s,sz,n) \
l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n))
/* /*
** use LUAI_UACINT here to avoid problems with promotions (which ** use LUAI_UACINT here to avoid problems with promotions (which
** can turn a comparison between unsigneds into a signed comparison) ** can turn a comparison between unsigneds into a signed comparison)
@@ -606,13 +621,14 @@
/* /*
@@ lua_number2strx converts a float to an hexadecimal numeric string. @@ lua_number2strx converts a float to an hexadecimal numeric string.
** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. ** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
** Otherwise, you can leave 'lua_number2strx' undefined and Lua will ** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
** provide its own implementation. ** provide its own implementation.
*/ */
#if !defined(LUA_USE_C89) #if !defined(LUA_USE_C89)
#define lua_number2strx(L,b,sz,f,n) l_sprintf(b,sz,f,n) #define lua_number2strx(L,b,sz,f,n) \
((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n)))
#endif #endif
@@ -728,11 +744,11 @@
/* /*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. @@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
** CHANGE it if it uses too much C-stack space. (For long double, ** CHANGE it if it uses too much C-stack space. (For long double,
** 'string.format("%.99f", 1e4932)' needs ~5030 bytes, so a ** 'string.format("%.99f", -1e4932)' needs 5034 bytes, so a
** smaller buffer would force a memory allocation for each call to ** smaller buffer would force a memory allocation for each call to
** 'string.format'.) ** 'string.format'.)
*/ */
#if defined(LUA_FLOAT_LONGDOUBLE) #if LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE
#define LUAL_BUFFERSIZE 8192 #define LUAL_BUFFERSIZE 8192
#else #else
#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer))) #define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lualib.h,v 1.43 2011/12/08 12:11:37 roberto Exp roberto $ ** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp roberto $
** Lua standard libraries ** Lua standard libraries
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -11,6 +11,9 @@
#include "lua.h" #include "lua.h"
/* version suffix for environment variable names */
#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
LUAMOD_API int (luaopen_base) (lua_State *L); LUAMOD_API int (luaopen_base) (lua_State *L);

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lutf8lib.c,v 1.14 2015/03/05 16:07:46 roberto Exp roberto $ ** $Id: lutf8lib.c,v 1.15 2015/03/28 19:16:55 roberto Exp roberto $
** Standard library for UTF-8 manipulation ** Standard library for UTF-8 manipulation
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -194,7 +194,7 @@ static int byteoffset (lua_State *L) {
lua_pushinteger(L, posi + 1); lua_pushinteger(L, posi + 1);
else /* no such character */ else /* no such character */
lua_pushnil(L); lua_pushnil(L);
return 1; return 1;
} }

105
lvm.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lvm.c,v 2.264 2015/11/19 19:16:22 roberto Exp roberto $ ** $Id: lvm.c,v 2.267 2016/01/05 16:07:21 roberto Exp roberto $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -153,55 +153,69 @@ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
/* /*
** Complete a table access: if 't' is a table, 'tm' has its metamethod; ** Finish the table access 'val = t[key]'.
** otherwise, 'tm' is NULL. ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to
** t[k] entry (which must be nil).
*/ */
void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
const TValue *tm) { const TValue *slot) {
int loop; /* counter to avoid infinite loops */ int loop; /* counter to avoid infinite loops */
lua_assert(tm != NULL || !ttistable(t)); const TValue *tm; /* metamethod */
for (loop = 0; loop < MAXTAGLOOP; loop++) { for (loop = 0; loop < MAXTAGLOOP; loop++) {
if (tm == NULL) { /* no metamethod (from a table)? */ if (slot == NULL) { /* 't' is not a table? */
if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) lua_assert(!ttistable(t));
tm = luaT_gettmbyobj(L, t, TM_INDEX);
if (ttisnil(tm))
luaG_typeerror(L, t, "index"); /* no metamethod */ luaG_typeerror(L, t, "index"); /* no metamethod */
/* else will try the metamethod */
} }
if (ttisfunction(tm)) { /* metamethod is a function */ else { /* 't' is a table */
lua_assert(ttisnil(slot));
tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */
if (tm == NULL) { /* no metamethod? */
setnilvalue(val); /* result is nil */
return;
}
/* else will try the metamethod */
}
if (ttisfunction(tm)) { /* is metamethod a function? */
luaT_callTM(L, tm, t, key, val, 1); /* call it */ luaT_callTM(L, tm, t, key, val, 1); /* call it */
return; return;
} }
t = tm; /* else repeat access over 'tm' */ t = tm; /* else try to access 'tm[key]' */
if (luaV_fastget(L,t,key,tm,luaH_get)) { /* try fast track */ if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */
setobj2s(L, val, tm); /* done */ setobj2s(L, val, slot); /* done */
return; return;
} }
/* else repeat */ /* else repeat (tail call 'luaV_finishget') */
} }
luaG_runerror(L, "gettable chain too long; possible loop"); luaG_runerror(L, "'__index' chain too long; possible loop");
} }
/* /*
** Main function for table assignment (invoking metamethods if needed). ** Finish a table assignment 't[key] = val'.
** Compute 't[key] = val' ** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points
** to the entry 't[key]', or to 'luaO_nilobject' if there is no such
** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset'
** would have done the job.)
*/ */
void luaV_finishset (lua_State *L, const TValue *t, TValue *key, void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *oldval) { StkId val, const TValue *slot) {
int loop; /* counter to avoid infinite loops */ int loop; /* counter to avoid infinite loops */
for (loop = 0; loop < MAXTAGLOOP; loop++) { for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm; const TValue *tm; /* '__newindex' metamethod */
if (oldval != NULL) { if (slot != NULL) { /* is 't' a table? */
lua_assert(ttistable(t) && ttisnil(oldval)); Table *h = hvalue(t); /* save 't' table */
/* must check the metamethod */ lua_assert(ttisnil(slot)); /* old value must be nil */
if ((tm = fasttm(L, hvalue(t)->metatable, TM_NEWINDEX)) == NULL && tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
/* no metamethod; is there a previous entry in the table? */ if (tm == NULL) { /* no metamethod? */
(oldval != luaO_nilobject || if (slot == luaO_nilobject) /* no previous entry? */
/* no previous entry; must create one. (The next test is slot = luaH_newkey(L, h, key); /* create one */
always true; we only need the assignment.) */
(oldval = luaH_newkey(L, hvalue(t), key), 1))) {
/* no metamethod and (now) there is an entry with given key */ /* no metamethod and (now) there is an entry with given key */
setobj2t(L, cast(TValue *, oldval), val); setobj2t(L, cast(TValue *, slot), val); /* set its new value */
invalidateTMcache(hvalue(t)); invalidateTMcache(h);
luaC_barrierback(L, hvalue(t), val); luaC_barrierback(L, h, val);
return; return;
} }
/* else will try the metamethod */ /* else will try the metamethod */
@@ -216,11 +230,11 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
return; return;
} }
t = tm; /* else repeat assignment over 'tm' */ t = tm; /* else repeat assignment over 'tm' */
if (luaV_fastset(L, t, key, oldval, luaH_get, val)) if (luaV_fastset(L, t, key, slot, luaH_get, val))
return; /* done */ return; /* done */
/* else loop */ /* else loop */
} }
luaG_runerror(L, "settable chain too long; possible loop"); luaG_runerror(L, "'__newindex' chain too long; possible loop");
} }
@@ -738,18 +752,28 @@ void luaV_finishOp (lua_State *L) {
luai_threadyield(L); } luai_threadyield(L); }
/* fetch an instruction and prepare its execution */
#define vmfetch() { \
i = *(ci->u.l.savedpc++); \
if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \
Protect(luaG_traceexec(L)); \
ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
lua_assert(base == ci->u.l.base); \
lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \
}
#define vmdispatch(o) switch(o) #define vmdispatch(o) switch(o)
#define vmcase(l) case l: #define vmcase(l) case l:
#define vmbreak break #define vmbreak break
/* /*
** copy of 'luaV_gettable', but protecting call to potential metamethod ** copy of 'luaV_gettable', but protecting the call to potential
** (which can reallocate the stack) ** metamethod (which can reallocate the stack)
*/ */
#define gettableProtected(L,t,k,v) { const TValue *aux; \ #define gettableProtected(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else Protect(luaV_finishget(L,t,k,v,aux)); } else Protect(luaV_finishget(L,t,k,v,slot)); }
/* same for 'luaV_settable' */ /* same for 'luaV_settable' */
@@ -772,14 +796,9 @@ void luaV_execute (lua_State *L) {
base = ci->u.l.base; /* local copy of function's base */ base = ci->u.l.base; /* local copy of function's base */
/* main loop of interpreter */ /* main loop of interpreter */
for (;;) { for (;;) {
Instruction i = *(ci->u.l.savedpc++); Instruction i;
StkId ra; StkId ra;
if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) vmfetch();
Protect(luaG_traceexec(L));
/* WARNING: several calls may realloc the stack and invalidate 'ra' */
ra = RA(i);
lua_assert(base == ci->u.l.base);
lua_assert(base <= L->top && L->top < L->stack + L->stacksize);
vmdispatch (GET_OPCODE(i)) { vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) { vmcase(OP_MOVE) {
setobjs2s(L, ra, RB(i)); setobjs2s(L, ra, RB(i));

33
lvm.h
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lvm.h,v 2.38 2015/08/03 20:40:26 roberto Exp roberto $ ** $Id: lvm.h,v 2.40 2016/01/05 16:07:21 roberto Exp roberto $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -49,25 +49,24 @@
/* /*
** fast track for 'gettable': 1 means 'aux' points to resulted value; ** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
** 0 means 'aux' is metamethod (if 't' is a table) or NULL. 'f' is ** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise,
** the raw get function to use. ** return 0 (meaning it will have to check metamethod) with 'slot'
** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).
** 'f' is the raw get function to use.
*/ */
#define luaV_fastget(L,t,k,aux,f) \ #define luaV_fastget(L,t,k,slot,f) \
(!ttistable(t) \ (!ttistable(t) \
? (aux = NULL, 0) /* not a table; 'aux' is NULL and result is 0 */ \ ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
: (aux = f(hvalue(t), k), /* else, do raw access */ \ : (slot = f(hvalue(t), k), /* else, do raw access */ \
!ttisnil(aux) ? 1 /* result not nil? 'aux' has it */ \ !ttisnil(slot))) /* result not nil? */
: (aux = fasttm(L, hvalue(t)->metatable, TM_INDEX), /* get metamethod */\
aux != NULL ? 0 /* has metamethod? must call it */ \
: (aux = luaO_nilobject, 1)))) /* else, final result is nil */
/* /*
** standard implementation for 'gettable' ** standard implementation for 'gettable'
*/ */
#define luaV_gettable(L,t,k,v) { const TValue *aux; \ #define luaV_gettable(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else luaV_finishget(L,t,k,v,aux); } else luaV_finishget(L,t,k,v,slot); }
/* /*
@@ -91,7 +90,7 @@
#define luaV_settable(L,t,k,v) { const TValue *slot; \ #define luaV_settable(L,t,k,v) { const TValue *slot; \
if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
luaV_finishset(L,t,k,v,slot); } luaV_finishset(L,t,k,v,slot); }
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
@@ -100,9 +99,9 @@ LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);
LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *tm); StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *oldval); StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishOp (lua_State *L); LUAI_FUNC void luaV_finishOp (lua_State *L);
LUAI_FUNC void luaV_execute (lua_State *L); LUAI_FUNC void luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total); LUAI_FUNC void luaV_concat (lua_State *L, int total);

View File

@@ -14,12 +14,14 @@ CWARNSCPP= \
-Wwrite-strings \ -Wwrite-strings \
-Wredundant-decls \ -Wredundant-decls \
-Wdisabled-optimization \ -Wdisabled-optimization \
# the next warnings generate to much noise, so they are disabled -Waggregate-return \
# -Wdouble-promotion \ -Wdouble-promotion \
#-Wno-aggressive-loop-optimizations # not accepted by clang \
#-Wlogical-op # not accepted by clang \
# the next warnings generate too much noise, so they are disabled
# -Wconversion -Wno-sign-conversion \ # -Wconversion -Wno-sign-conversion \
# -Wsign-conversion \ # -Wsign-conversion \
# -Wconversion \ # -Wconversion \
# -Wlogical-op \
# -Wstrict-overflow=2 \ # -Wstrict-overflow=2 \
# -Wformat=2 \ # -Wformat=2 \
# -Wcast-qual \ # -Wcast-qual \
@@ -33,7 +35,7 @@ CWARNSC= -Wdeclaration-after-statement \
-Wold-style-definition \ -Wold-style-definition \
CWARNS= $(CWARNSCPP) $(CWARNSC) CWARNS= $(CWARNSCPP) $(CWARNSC)
# -DEXTERNMEMCHECK -DHARDSTACKTESTS -DHARDMEMTESTS -DTRACEMEM='"tempmem"' # -DEXTERNMEMCHECK -DHARDSTACKTESTS -DHARDMEMTESTS -DTRACEMEM='"tempmem"'
@@ -42,9 +44,10 @@ CWARNS= $(CWARNSCPP) $(CWARNSC)
# -DLUA_USE_CTYPE -DLUA_USE_APICHECK # -DLUA_USE_CTYPE -DLUA_USE_APICHECK
# (in clang, '-ftrapv' for runtime checks of integer overflows) # (in clang, '-ftrapv' for runtime checks of integer overflows)
# -fsanitize=undefined -ftrapv # -fsanitize=undefined -ftrapv
# TESTS= -DLUA_USER_H='"ltests.h"' TESTS= -DLUA_USER_H='"ltests.h"'
# -mtune=native -fomit-frame-pointer # -mtune=native -fomit-frame-pointer
# -fno-stack-protector
LOCAL = $(TESTS) $(CWARNS) -g LOCAL = $(TESTS) $(CWARNS) -g
@@ -52,10 +55,10 @@ LOCAL = $(TESTS) $(CWARNS) -g
# enable Linux goodies # enable Linux goodies
MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX -DLUA_COMPAT_5_2 MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX -DLUA_COMPAT_5_2
MYLDFLAGS= $(LOCAL) -Wl,-E MYLDFLAGS= $(LOCAL) -Wl,-E
MYLIBS= -ldl -lreadline -lhistory -lncurses MYLIBS= -ldl -lreadline
CC= clang-3.6 CC= clang-3.8
CFLAGS= -Wall -O2 $(MYCFLAGS) CFLAGS= -Wall -O2 $(MYCFLAGS)
AR= ar rcu AR= ar rcu
RANLIB= ranlib RANLIB= ranlib