diff -u -r lua-5.3.2/Makefile lua-5.3.3/Makefile --- lua-5.3.2/Makefile 2015-11-18 17:00:04.000000000 -0200 +++ lua-5.3.3/Makefile 2016-01-13 23:13:47.000000000 -0200 @@ -46,7 +46,7 @@ # Lua version and release. V= 5.3 -R= $V.2 +R= $V.3 # Targets start here. all: $(PLAT) diff -u -r lua-5.3.2/README lua-5.3.3/README --- lua-5.3.2/README 2015-11-25 15:23:08.000000000 -0200 +++ lua-5.3.3/README 2016-05-30 13:12:16.000000000 -0300 @@ -1,5 +1,5 @@ -This is Lua 5.3.2, released on 25 Nov 2015. +This is Lua 5.3.3, released on 30 May 2016. For installation instructions, license details, and further information about Lua, see doc/readme.html. diff -u -r lua-5.3.2/doc/contents.html lua-5.3.3/doc/contents.html --- lua-5.3.2/doc/contents.html 2015-06-03 08:27:31.000000000 -0300 +++ lua-5.3.3/doc/contents.html 2016-01-14 10:14:29.000000000 -0200 @@ -32,7 +32,7 @@

-Copyright © 2015 Lua.org, PUC-Rio. +Copyright © 2015–2016 Lua.org, PUC-Rio. Freely available under the terms of the Lua license. @@ -608,10 +608,10 @@

diff -u -r lua-5.3.2/doc/lua.css lua-5.3.3/doc/lua.css --- lua-5.3.2/doc/lua.css 2015-06-27 09:56:17.000000000 -0300 +++ lua-5.3.3/doc/lua.css 2016-02-28 08:34:42.000000000 -0300 @@ -92,6 +92,7 @@ .footer { color: gray ; font-size: x-small ; + text-transform: lowercase ; } input[type=text] { @@ -157,3 +158,7 @@ display: block ; margin-top: 0.25em ; } + +img { + background-color: white ; +} diff -u -r lua-5.3.2/doc/manual.html lua-5.3.3/doc/manual.html --- lua-5.3.2/doc/manual.html 2015-11-25 15:19:11.000000000 -0200 +++ lua-5.3.3/doc/manual.html 2016-05-30 13:11:09.000000000 -0300 @@ -19,7 +19,7 @@

-Copyright © 2015 Lua.org, PUC-Rio. +Copyright © 2015–2016 Lua.org, PUC-Rio. Freely available under the terms of the Lua license. @@ -35,7 +35,7 @@

- + @@ -43,30 +43,47 @@

1 – Introduction

-Lua is an extension programming language designed to support -general procedural programming with data description -facilities. -Lua also offers good support for object-oriented programming, -functional programming, and data-driven programming. -Lua is intended to be used as a powerful, lightweight, -embeddable scripting language for any program that needs one. +Lua is a powerful, efficient, lightweight, embeddable scripting language. +It supports procedural programming, +object-oriented programming, functional programming, +data-driven programming, and data description. + + +

+Lua combines simple procedural syntax with powerful data description +constructs based on associative arrays and extensible semantics. +Lua is dynamically typed, +runs by interpreting bytecode with a register-based +virtual machine, +and has automatic memory management with +incremental garbage collection, +making it ideal for configuration, scripting, +and rapid prototyping. + + +

Lua is implemented as a library, written in clean C, the common subset of Standard C and C++. +The Lua distribution includes a host program called lua, +which uses the Lua library to offer a complete, +standalone Lua interpreter, +for interactive or batch use. +Lua is intended to be used both as a powerful, lightweight, +embeddable scripting language for any program that needs one, +and as a powerful but lightweight and efficient stand-alone language.

As an extension language, Lua has no notion of a "main" program: -it only works embedded in a host client, +it works embedded in a host client, called the embedding program or simply the host. +(Frequently, this host is the stand-alone lua program.) The host program can invoke functions to execute a piece of Lua code, can write and read Lua variables, and can register C functions to be called by Lua code. Through the use of C functions, Lua can be augmented to cope with a wide range of different domains, thus creating customized programming languages sharing a syntactical framework. -The Lua distribution includes a sample host program called lua, -which uses the Lua library to offer a complete, standalone Lua interpreter, -for interactive or batch use.

@@ -351,8 +368,8 @@ When you use xpcall or lua_pcall, you may give a message handler to be called in case of errors. -This function is called with the original error message -and returns a new error message. +This function is called with the original error object +and returns a new error object. It is called before the error unwinds the stack, so that it can gather more information about the error, for instance by inspecting the stack and creating a stack traceback. @@ -382,16 +399,23 @@

-The keys in a metatable are derived from the event names; +The key for each event in a metatable is a string +with the event name prefixed by two underscores; the corresponding values are called metamethods. -In the previous example, the event is "add" +In the previous example, the key is "__add" and the metamethod is the function that performs the addition.

You can query the metatable of any value using the getmetatable function. +Lua queries metamethods in metatables using a raw access (see rawget). +So, to retrieve the metamethod for event ev in object o, +Lua does the equivalent to the following code: +

+     rawget(getmetatable(o) or {}, "__ev")
+

You can replace the metatable of tables @@ -420,18 +444,7 @@

-A detailed list of events controlled by metatables is given next. -Each operation is identified by its corresponding event name. -The key for each event is a string with its name prefixed by -two underscores, '__'; -for instance, the key for operation "add" is the -string "__add". -Note that queries for metamethods are always raw; -the access to a metamethod does not invoke other metamethods. - - -

-For the unary operators (negation, length, and bitwise not), +For the unary operators (negation, length, and bitwise NOT), the metamethod is computed and called with a dummy second operand, equal to the first one. This extra operand is only to simplify Lua's internals @@ -440,17 +453,21 @@ (For most uses this extra operand is irrelevant.) +

+A detailed list of events controlled by metatables is given next. +Each operation is identified by its corresponding key. + +

@@ -664,10 +666,19 @@

It is a good practice to add all needed metamethods to a table before setting it as a metatable of some object. -In particular, the "__gc" metamethod works only when this order +In particular, the __gc metamethod works only when this order is followed (see §2.5.1). +

+Because metatables are regular tables, +they can contain arbitrary fields, +not only the event names defined above. +Some functions in the standard library +(e.g., tostring) +use other fields in metatables for their own purposes. + + @@ -935,7 +946,7 @@ coroutine.resume returns true, plus any values returned by the coroutine main function. In case of errors, coroutine.resume returns false -plus an error message. +plus an error object.

@@ -1168,7 +1179,7 @@ some control characters. So, it is safer to represent non-text data as a quoted literal with -explicit escape sequences for non-text characters. +explicit escape sequences for the non-text characters.

@@ -1201,9 +1212,11 @@ Hexadecimal constants also accept an optional fractional part plus an optional binary exponent, marked by a letter 'p' or 'P'. -A numeric constant with a fractional dot or an exponent +A numeric constant with a radix point or an exponent denotes a float; -otherwise it denotes an integer. +otherwise, +if its value fits in an integer, +it denotes an integer. Examples of valid integer constants are

@@ -1794,7 +1807,7 @@
 relational operators (see §3.4.4), logical operators (see §3.4.5),
 and the concatenation operator (see §3.4.6).
 Unary operators comprise the unary minus (see §3.4.1),
-the unary bitwise not (see §3.4.2),
+the unary bitwise NOT (see §3.4.2),
 the unary logical not (see §3.4.5),
 and the unary length operator (see §3.4.7).
 
@@ -1908,12 +1921,12 @@
 Lua supports the following bitwise operators:
 
 
 
 

@@ -1984,6 +1997,13 @@

+All conversions from strings to numbers +accept both a dot and the current locale mark +as the radix character. +(The Lua lexer, however, accepts only a dot.) + + +

The conversion from numbers to strings uses a non-specified human-readable format. For complete control over how numbers are converted to strings, @@ -2792,7 +2812,7 @@

The panic function runs as if it were a message handler (see §2.3); -in particular, the error message is at the top of the stack. +in particular, the error object is at the top of the stack. However, there is no guarantee about stack space. To push anything on the stack, the panic function must first check the available space (see §4.2). @@ -2974,8 +2994,11 @@ The third field, x, tells whether the function may raise errors: '-' means the function never raises any error; -'m' means the function may raise memory errors; -'e' means the function may raise errors; +'m' means the function may raise out-of-memory errors +and errors running a __gc metamethod; +'e' means the function may raise any errors +(it can run arbitrary Lua code, +either directly or through metamethods); 'v' means the function may raise an error on purpose. @@ -3102,10 +3125,10 @@

  • LUA_OPMOD: performs modulo (%)
  • LUA_OPPOW: performs exponentiation (^)
  • LUA_OPUNM: performs mathematical negation (unary -)
  • -
  • LUA_OPBNOT: performs bitwise negation (~)
  • -
  • LUA_OPBAND: performs bitwise and (&)
  • -
  • LUA_OPBOR: performs bitwise or (|)
  • -
  • LUA_OPBXOR: performs bitwise exclusive or (~)
  • +
  • LUA_OPBNOT: performs bitwise NOT (~)
  • +
  • LUA_OPBAND: performs bitwise AND (&)
  • +
  • LUA_OPBOR: performs bitwise OR (|)
  • +
  • LUA_OPBXOR: performs bitwise exclusive OR (~)
  • LUA_OPSHL: performs left shift (<<)
  • LUA_OPSHR: performs right shift (>>)
  • @@ -3424,7 +3447,7 @@

    lua_gc

    -[-0, +0, e] +[-0, +0, m]

    int lua_gc (lua_State *L, int what, int data);

    @@ -3919,7 +3942,7 @@ syntax error during precompilation;

  • LUA_ERRMEM: -memory allocation error;
  • +memory allocation (out-of-memory) error;
  • LUA_ERRGCMM: error while running a __gc metamethod. @@ -4128,7 +4151,7 @@ lua_pcall behaves exactly like lua_call. However, if there is any error, lua_pcall catches it, -pushes a single value on the stack (the error message), +pushes a single value on the stack (the error object), and returns an error code. Like lua_call, lua_pcall always removes the function @@ -4137,20 +4160,20 @@

    If msgh is 0, -then the error message returned on the stack -is exactly the original error message. +then the error object returned on the stack +is exactly the original error object. Otherwise, msgh is the stack index of a message handler. (This index cannot be a pseudo-index.) In case of runtime errors, -this function will be called with the error message -and its return value will be the message +this function will be called with the error object +and its return value will be the object returned on the stack by lua_pcall.

    Typically, the message handler is used to add more debug -information to the error message, such as a stack traceback. +information to the error object, such as a stack traceback. Such information cannot be gathered after the return of lua_pcall, since by then the stack has unwound. @@ -4284,7 +4307,7 @@


    lua_pushfstring

    -[-0, +1, m] +[-0, +1, e]

    const char *lua_pushfstring (lua_State *L, const char *fmt, ...);

    @@ -4317,6 +4340,12 @@ +

    +Unlike other push functions, +this function checks for the stack space it needs, +including the slot for its result. + + @@ -4486,7 +4515,7 @@

    Returns 1 if the two values in indices index1 and index2 are primitively equal -(that is, without calling metamethods). +(that is, without calling the __eq metamethod). Otherwise returns 0. Also returns 0 if any of the indices are not valid. @@ -4513,8 +4542,8 @@

    Pushes onto the stack the value t[n], where t is the table at the given index. -The access is raw; -that is, it does not invoke metamethods. +The access is raw, +that is, it does not invoke the __index metamethod.

    @@ -4533,7 +4562,7 @@ where t is the table at the given index and k is the pointer p represented as a light userdata. The access is raw; -that is, it does not invoke metamethods. +that is, it does not invoke the __index metamethod.

    @@ -4584,8 +4613,8 @@

    This function pops the value from the stack. -The assignment is raw; -that is, it does not invoke metamethods. +The assignment is raw, +that is, it does not invoke the __newindex metamethod. @@ -4604,8 +4633,8 @@

    This function pops the value from the stack. -The assignment is raw; -that is, it does not invoke metamethods. +The assignment is raw, +that is, it does not invoke __newindex metamethod. @@ -4704,7 +4733,7 @@ In case of errors, the stack is not unwound, so you can use the debug API over it. -The error message is on the top of the stack. +The error object is on the top of the stack.

    @@ -5179,11 +5208,13 @@


    lua_version

    -[-0, +0, v] +[-0, +0, –]

    const lua_Number *lua_version (lua_State *L);

    -Returns the address of the version number stored in the Lua core. +Returns the address of the version number +(a C static variable) +stored in the Lua core. When called with a valid lua_State, returns the address of the version used to create that state. When called with NULL, @@ -5287,9 +5318,9 @@ it continues executing the continuation function. However, there is one special case, which is when this function is called -from inside a line hook (see §4.9). +from inside a line or a count hook (see §4.9). In that case, lua_yieldk should be called with no continuation -(probably in the form of lua_yield), +(probably in the form of lua_yield) and no results, and the hook should return immediately after the call. Lua will yield and, when the coroutine resumes again, @@ -5704,7 +5735,7 @@

    Argument f is the hook function. mask specifies on which events the hook will be called: -it is formed by a bitwise or of the constants +it is formed by a bitwise OR of the constants LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE, @@ -6256,7 +6287,7 @@


    luaL_checkversion

    -[-0, +0, –] +[-0, +0, v]

    void luaL_checkversion (lua_State *L);

    @@ -6472,7 +6503,7 @@


    luaL_loadfile

    -[-0, +1, e] +[-0, +1, m]

    int luaL_loadfile (lua_State *L, const char *filename);

    @@ -6483,7 +6514,7 @@


    luaL_loadfilex

    -[-0, +1, e] +[-0, +1, m]

    int luaL_loadfilex (lua_State *L, const char *filename,
                                                 const char *mode);
    @@ -6634,6 +6665,27 @@ +

    luaL_opt

    +[-0, +0, e] +

    T luaL_opt (L, func, arg, dflt);
    + +

    +This macro is defined as follows: + +

    +     (lua_isnoneornil(L,(arg)) ? (dflt) : func(L,(arg)))
    +

    +In words, if the argument arg is nil or absent, +the macro results in the default dflt. +Otherwise, it results in the result of calling func +with the state L and the argument index arg as +parameters. +Note that it evaluates the expression dflt only if needed. + + + + +


    luaL_optinteger

    [-0, +0, v]

    lua_Integer luaL_optinteger (lua_State *L,
    @@ -6931,7 +6983,7 @@
     
     
     

    -If the value has a metatable with a "__tostring" field, +If the value has a metatable with a __tostring field, then luaL_tolstring calls the corresponding metamethod with the value as argument, and uses the result of the call as its result. @@ -7220,7 +7272,7 @@

    If object does not have a metatable, returns nil. Otherwise, -if the object's metatable has a "__metatable" field, +if the object's metatable has a __metatable field, returns the associated value. Otherwise, returns the metatable of the given object. @@ -7424,7 +7476,7 @@


    rawequal (v1, v2)

    Checks whether v1 is equal to v2, -without invoking any metamethod. +without invoking the __eq metamethod. Returns a boolean. @@ -7433,7 +7485,7 @@


    rawget (table, index)

    Gets the real value of table[index], -without invoking any metamethod. +without invoking the __index metamethod. table must be a table; index may be any value. @@ -7444,7 +7496,7 @@

    rawlen (v)

    Returns the length of the object v, which must be a table or a string, -without invoking any metamethod. +without invoking the __len metamethod. Returns an integer. @@ -7453,7 +7505,7 @@


    rawset (table, index, value)

    Sets the real value of table[index] to value, -without invoking any metamethod. +without invoking the __newindex metamethod. table must be a table, index any value different from nil and NaN, and value any Lua value. @@ -7489,7 +7541,7 @@ you must use the debug library (§6.10).) If metatable is nil, removes the metatable of the given table. -If the original metatable has a "__metatable" field, +If the original metatable has a __metatable field, raises an error. @@ -7541,7 +7593,7 @@

    -If the metatable of v has a "__tostring" field, +If the metatable of v has a __tostring field, then tostring calls the corresponding value with v as argument, and uses the result of the call as its result. @@ -8184,6 +8236,9 @@ *, h, L, l, n, and p are not supported and that there is an extra option, q. + + +

    The q option formats a string between double quotes, using escape sequences when necessary to ensure that it can safely be read back by the Lua interpreter. @@ -8206,7 +8261,12 @@ Options c, d, i, o, u, X, and x expect an integer. -Option q expects a string. +When Lua is compiled with a C89 compiler, +options A and a (hexadecimal floats) +do not support any modifier (flags, width, length). + + +

    Option s expects a string; if its argument is not a string, it is converted to one following the same rules of tostring. @@ -8214,12 +8274,6 @@ the string argument should not contain embedded zeros. -

    -When Lua is compiled with a non-C99 compiler, -options A and a (hexadecimal floats) -do not support any modifier (flags, width, length). - -

    @@ -8548,6 +8602,14 @@

    +You can put a closing square bracket in a set +by positioning it as the first character in the set. +You can put an hyphen in a set +by positioning it as the first or the last character in the set. +(You can also use an escape for both cases.) + + +

    The interaction between ranges and classes is not defined. Therefore, patterns like [%a-z] or [a-%%] have no meaning. @@ -8925,8 +8987,8 @@

    -Moves elements from table a1 to table a2. -This function performs the equivalent to the following +Moves elements from table a1 to table a2, +performing the equivalent to the following multiple assignment: a2[t],··· = a1[f],···,a1[e]. The default for a2 is a1. @@ -8934,6 +8996,10 @@ The number of elements to be moved must fit in a Lua integer. +

    +Returns the destination table a2. + +

    @@ -9457,8 +9523,8 @@

    This function opens a file, in the mode specified in the string mode. -It returns a new file handle, -or, in case of errors, nil plus an error message. +In case of success, +it returns a new file handle.

    @@ -9523,7 +9589,8 @@

    -Returns a handle for a temporary file. +In case of success, +returns a handle for a temporary file. This file is opened in update mode and it is automatically removed when the program ends. @@ -9801,8 +9868,8 @@ then date returns a table with the following fields: year, month (1–12), day (1–31), hour (0–23), min (0–59), sec (0–61), -wday (weekday, Sunday is 1), -yday (day of the year), +wday (weekday, 1–7, Sunday is 1), +yday (day of the year, 1–366), and isdst (daylight saving flag, a boolean). This last field may be absent if the information is not available. @@ -10505,6 +10572,14 @@

    +If the global variable _PROMPT contains a string, +then its value is used as the prompt. +Similarly, if the global variable _PROMPT2 contains a string, +its value is used as the secondary prompt +(issued during incomplete statements). + + +

    In case of unprotected errors in the script, the interpreter reports the error to the standard error stream. If the error object is not a string but @@ -10825,10 +10900,10 @@

    diff -u -r lua-5.3.2/doc/readme.html lua-5.3.3/doc/readme.html --- lua-5.3.2/doc/readme.html 2015-06-01 21:48:24.000000000 -0300 +++ lua-5.3.3/doc/readme.html 2016-02-02 22:25:28.000000000 -0200 @@ -276,7 +276,7 @@

    Language

    • userdata can have any Lua value as uservalue -
    • integer division +
    • floor division
    • more flexible rules for some metamethods
    @@ -328,7 +328,7 @@ this.
    -Copyright © 1994–2015 Lua.org, PUC-Rio. +Copyright © 1994–2016 Lua.org, PUC-Rio.

    Permission is hereby granted, free of charge, to any person obtaining a copy @@ -355,10 +355,10 @@

    diff -u -r lua-5.3.2/src/lapi.c lua-5.3.3/src/lapi.c --- lua-5.3.2/src/lapi.c 2015-11-02 16:48:07.000000000 -0200 +++ lua-5.3.3/src/lapi.c 2016-02-29 11:27:14.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.257 2015/11/02 18:48:07 roberto Exp $ +** $Id: lapi.c,v 2.259 2016/02/29 14:27:14 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -378,9 +378,9 @@ return NULL; } lua_lock(L); /* 'luaO_tostring' may create a new string */ + luaO_tostring(L, o); luaC_checkGC(L); o = index2addr(L, idx); /* previous call may reallocate the stack */ - luaO_tostring(L, o); lua_unlock(L); } if (len != NULL) @@ -479,10 +479,10 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { TString *ts; lua_lock(L); - luaC_checkGC(L); ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); setsvalue2s(L, L->top, ts); api_incr_top(L); + luaC_checkGC(L); lua_unlock(L); return getstr(ts); } @@ -494,12 +494,12 @@ setnilvalue(L->top); else { TString *ts; - luaC_checkGC(L); ts = luaS_new(L, s); setsvalue2s(L, L->top, ts); s = getstr(ts); /* internal copy's address */ } api_incr_top(L); + luaC_checkGC(L); lua_unlock(L); return s; } @@ -509,8 +509,8 @@ va_list argp) { const char *ret; lua_lock(L); - luaC_checkGC(L); ret = luaO_pushvfstring(L, fmt, argp); + luaC_checkGC(L); lua_unlock(L); return ret; } @@ -520,10 +520,10 @@ const char *ret; va_list argp; lua_lock(L); - luaC_checkGC(L); va_start(argp, fmt); ret = luaO_pushvfstring(L, fmt, argp); va_end(argp); + luaC_checkGC(L); lua_unlock(L); return ret; } @@ -538,7 +538,6 @@ CClosure *cl; api_checknelems(L, n); api_check(L, n <= MAXUPVAL, "upvalue index too large"); - luaC_checkGC(L); cl = luaF_newCclosure(L, n); cl->f = fn; L->top -= n; @@ -549,6 +548,7 @@ setclCvalue(L, L->top, cl); } api_incr_top(L); + luaC_checkGC(L); lua_unlock(L); } @@ -585,16 +585,16 @@ static int auxgetstr (lua_State *L, const TValue *t, const char *k) { - const TValue *aux; + const TValue *slot; TString *str = luaS_new(L, k); - if (luaV_fastget(L, t, str, aux, luaH_getstr)) { - setobj2s(L, L->top, aux); + if (luaV_fastget(L, t, str, slot, luaH_getstr)) { + setobj2s(L, L->top, slot); api_incr_top(L); } else { setsvalue2s(L, L->top, str); 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); return ttnov(L->top - 1); @@ -626,17 +626,17 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { StkId t; - const TValue *aux; + const TValue *slot; lua_lock(L); t = index2addr(L, idx); - if (luaV_fastget(L, t, n, aux, luaH_getint)) { - setobj2s(L, L->top, aux); + if (luaV_fastget(L, t, n, slot, luaH_getint)) { + setobj2s(L, L->top, slot); api_incr_top(L); } else { setivalue(L->top, n); 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); return ttnov(L->top - 1); @@ -683,12 +683,12 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { Table *t; lua_lock(L); - luaC_checkGC(L); t = luaH_new(L); sethvalue(L, L->top, t); api_incr_top(L); if (narray > 0 || nrec > 0) luaH_resize(L, t, narray, nrec); + luaC_checkGC(L); lua_unlock(L); } @@ -740,15 +740,15 @@ ** 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) { - const TValue *aux; + const TValue *slot; TString *str = luaS_new(L, k); 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 */ else { setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ 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 */ } lua_unlock(L); /* lock done by caller */ @@ -781,16 +781,16 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { StkId t; - const TValue *aux; + const TValue *slot; lua_lock(L); api_checknelems(L, 1); 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 */ else { setivalue(L->top, n); 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 */ } lua_unlock(L); @@ -1140,7 +1140,6 @@ lua_lock(L); api_checknelems(L, n); if (n >= 2) { - luaC_checkGC(L); luaV_concat(L, n); } else if (n == 0) { /* push empty string */ @@ -1148,6 +1147,7 @@ api_incr_top(L); } /* else n == 1; nothing to do */ + luaC_checkGC(L); lua_unlock(L); } @@ -1183,10 +1183,10 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) { Udata *u; lua_lock(L); - luaC_checkGC(L); u = luaS_newudata(L, size); setuvalue(L, L->top, u); api_incr_top(L); + luaC_checkGC(L); lua_unlock(L); return getudatamem(u); } diff -u -r lua-5.3.2/src/lauxlib.c lua-5.3.3/src/lauxlib.c --- lua-5.3.2/src/lauxlib.c 2015-11-19 17:16:22.000000000 -0200 +++ lua-5.3.3/src/lauxlib.c 2016-01-08 13:33:09.000000000 -0200 @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.284 2015/11/19 19:16:22 roberto Exp $ +** $Id: lauxlib.c,v 1.286 2016/01/08 15:33:09 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -17,7 +17,8 @@ #include -/* 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. */ @@ -198,6 +199,10 @@ } +/* +** 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) { lua_Debug ar; if (lua_getstack(L, level, &ar)) { /* check function at level */ @@ -207,10 +212,15 @@ 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, ...) { va_list argp; va_start(argp, fmt); @@ -349,10 +359,15 @@ } +/* +** 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) { - /* keep some extra space to run error routines, if needed */ - const int extra = LUA_MINSTACK; - if (!lua_checkstack(L, space + extra)) { + if (!lua_checkstack(L, space)) { if (msg) luaL_error(L, "stack overflow (%s)", msg); else @@ -678,7 +693,7 @@ if (c == '#') { /* first line is a comment (Unix exec. file)? */ do { /* skip first line */ c = getc(lf->f); - } while (c != EOF && c != '\n') ; + } while (c != EOF && c != '\n'); *cp = getc(lf->f); /* skip end-of-line, if present */ return 1; /* there was a comment */ } diff -u -r lua-5.3.2/src/lbaselib.c lua-5.3.3/src/lbaselib.c --- lua-5.3.2/src/lbaselib.c 2015-10-29 13:21:04.000000000 -0200 +++ lua-5.3.3/src/lbaselib.c 2016-04-11 16:18:40.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.312 2015/10/29 15:21:04 roberto Exp $ +** $Id: lbaselib.c,v 1.313 2016/04/11 19:18:40 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ @@ -102,8 +102,8 @@ static int luaB_error (lua_State *L) { int level = (int)luaL_optinteger(L, 2, 1); lua_settop(L, 1); - if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ - luaL_where(L, level); + if (lua_type(L, 1) == LUA_TSTRING && level > 0) { + luaL_where(L, level); /* add extra information */ lua_pushvalue(L, 1); lua_concat(L, 2); } @@ -251,9 +251,8 @@ /* -** This function will use either 'ipairsaux' or 'ipairsaux_raw' to -** traverse a table, depending on whether the table has metamethods -** that can affect the traversal. +** 'ipairs' function. Returns 'ipairsaux', given "table", 0. +** (The given "table" may not be a table.) */ static int luaB_ipairs (lua_State *L) { #if defined(LUA_COMPAT_IPAIRS) diff -u -r lua-5.3.2/src/lcode.c lua-5.3.3/src/lcode.c --- lua-5.3.2/src/lcode.c 2015-11-19 17:16:22.000000000 -0200 +++ lua-5.3.3/src/lcode.c 2016-05-13 16:09:21.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.103 2015/11/19 19:16:22 roberto Exp $ +** $Id: lcode.c,v 2.109 2016/05/13 19:09:21 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -36,6 +36,10 @@ #define hasjumps(e) ((e)->t != (e)->f) +/* +** If expression is a numeric constant, fills 'v' with its value +** and returns 1. Otherwise, returns 0. +*/ static int tonumeral(expdesc *e, TValue *v) { if (hasjumps(e)) return 0; /* not a numeral */ @@ -51,13 +55,19 @@ } +/* +** Create a OP_LOADNIL instruction, but try to optimize: if the previous +** instruction is also OP_LOADNIL and ranges are compatible, adjust +** range of previous instruction instead of emitting a new one. (For +** instance, 'local a; local b' will generate a single opcode.) +*/ void luaK_nil (FuncState *fs, int from, int n) { Instruction *previous; int l = from + n - 1; /* last register to set nil */ if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ previous = &fs->f->code[fs->pc-1]; - if (GET_OPCODE(*previous) == OP_LOADNIL) { - int pfrom = GETARG_A(*previous); + if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */ + int pfrom = GETARG_A(*previous); /* get previous range */ int pl = pfrom + GETARG_B(*previous); if ((pfrom <= from && from <= pl + 1) || (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ @@ -73,37 +83,84 @@ } +/* +** Gets the destination address of a jump instruction. Used to traverse +** a list of jumps. +*/ +static int getjump (FuncState *fs, int pc) { + int offset = GETARG_sBx(fs->f->code[pc]); + if (offset == NO_JUMP) /* point to itself represents end of list */ + return NO_JUMP; /* end of list */ + else + return (pc+1)+offset; /* turn offset into absolute position */ +} + + +/* +** Fix jump instruction at position 'pc' to jump to 'dest'. +** (Jump addresses are relative in Lua) +*/ +static void fixjump (FuncState *fs, int pc, int dest) { + Instruction *jmp = &fs->f->code[pc]; + int offset = dest - (pc + 1); + lua_assert(dest != NO_JUMP); + if (abs(offset) > MAXARG_sBx) + luaX_syntaxerror(fs->ls, "control structure too long"); + SETARG_sBx(*jmp, offset); +} + + +/* +** Concatenate jump-list 'l2' into jump-list 'l1' +*/ +void luaK_concat (FuncState *fs, int *l1, int l2) { + if (l2 == NO_JUMP) return; /* nothing to concatenate? */ + else if (*l1 == NO_JUMP) /* no original list? */ + *l1 = l2; /* 'l1' points to 'l2' */ + else { + int list = *l1; + int next; + while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ + list = next; + fixjump(fs, list, l2); /* last element links to 'l2' */ + } +} + + +/* +** Create a jump instruction and return its position, so its destination +** can be fixed later (with 'fixjump'). If there are jumps to +** this position (kept in 'jpc'), link them all together so that +** 'patchlistaux' will fix all them directly to the final destination. +*/ int luaK_jump (FuncState *fs) { int jpc = fs->jpc; /* save list of jumps to here */ int j; - fs->jpc = NO_JUMP; + fs->jpc = NO_JUMP; /* no more jumps to here */ j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); luaK_concat(fs, &j, jpc); /* keep them on hold */ return j; } +/* +** Code a 'return' instruction +*/ void luaK_ret (FuncState *fs, int first, int nret) { luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); } +/* +** Code a "conditional jump", that is, a test or comparison opcode +** followed by a jump. Return jump position. +*/ static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { luaK_codeABC(fs, op, A, B, C); return luaK_jump(fs); } -static void fixjump (FuncState *fs, int pc, int dest) { - Instruction *jmp = &fs->f->code[pc]; - int offset = dest-(pc+1); - lua_assert(dest != NO_JUMP); - if (abs(offset) > MAXARG_sBx) - luaX_syntaxerror(fs->ls, "control structure too long"); - SETARG_sBx(*jmp, offset); -} - - /* ** returns current 'pc' and marks it as a jump target (to avoid wrong ** optimizations with consecutive instructions not in the same basic block). @@ -114,15 +171,11 @@ } -static int getjump (FuncState *fs, int pc) { - int offset = GETARG_sBx(fs->f->code[pc]); - if (offset == NO_JUMP) /* point to itself represents end of list */ - return NO_JUMP; /* end of list */ - else - return (pc+1)+offset; /* turn offset into absolute position */ -} - - +/* +** Returns the position of the instruction "controlling" a given +** jump (that is, its condition), or the jump itself if it is +** unconditional. +*/ static Instruction *getjumpcontrol (FuncState *fs, int pc) { Instruction *pi = &fs->f->code[pc]; if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) @@ -133,37 +186,41 @@ /* -** check whether list has any jump that do not produce a value -** (or produce an inverted value) +** Patch destination register for a TESTSET instruction. +** If instruction in position 'node' is not a TESTSET, return 0 ("fails"). +** Otherwise, if 'reg' is not 'NO_REG', set it as the destination +** register. Otherwise, change instruction to a simple 'TEST' (produces +** no register value) */ -static int need_value (FuncState *fs, int list) { - for (; list != NO_JUMP; list = getjump(fs, list)) { - Instruction i = *getjumpcontrol(fs, list); - if (GET_OPCODE(i) != OP_TESTSET) return 1; - } - return 0; /* not found */ -} - - static int patchtestreg (FuncState *fs, int node, int reg) { Instruction *i = getjumpcontrol(fs, node); if (GET_OPCODE(*i) != OP_TESTSET) return 0; /* cannot patch other instructions */ if (reg != NO_REG && reg != GETARG_B(*i)) SETARG_A(*i, reg); - else /* no register to put value or register already has the value */ + else { + /* no register to put value or register already has the value; + change instruction to simple test */ *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); - + } return 1; } +/* +** Traverse a list of tests ensuring no one produces a value +*/ static void removevalues (FuncState *fs, int list) { for (; list != NO_JUMP; list = getjump(fs, list)) patchtestreg(fs, list, NO_REG); } +/* +** Traverse a list of tests, patching their destination address and +** registers: tests producing values jump to 'vtarget' (and put their +** values in 'reg'), other tests jump to 'dtarget'. +*/ static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, int dtarget) { while (list != NO_JUMP) { @@ -177,15 +234,35 @@ } +/* +** Ensure all pending jumps to current position are fixed (jumping +** to current position with no values) and reset list of pending +** jumps +*/ static void dischargejpc (FuncState *fs) { patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); fs->jpc = NO_JUMP; } +/* +** Add elements in 'list' to list of pending jumps to "here" +** (current position) +*/ +void luaK_patchtohere (FuncState *fs, int list) { + luaK_getlabel(fs); /* mark "here" as a jump target */ + luaK_concat(fs, &fs->jpc, list); +} + + +/* +** Path all jumps in 'list' to jump to 'target'. +** (The assert means that we cannot fix a jump to a forward address +** because we only know addresses once code is generated.) +*/ void luaK_patchlist (FuncState *fs, int list, int target) { - if (target == fs->pc) - luaK_patchtohere(fs, list); + if (target == fs->pc) /* 'target' is current position? */ + luaK_patchtohere(fs, list); /* add list to pending jumps */ else { lua_assert(target < fs->pc); patchlistaux(fs, list, target, NO_REG, target); @@ -193,39 +270,26 @@ } +/* +** Path all jumps in 'list' to close upvalues up to given 'level' +** (The assertion checks that jumps either were closing nothing +** or were closing higher levels, from inner blocks.) +*/ void luaK_patchclose (FuncState *fs, int list, int level) { level++; /* argument is +1 to reserve 0 as non-op */ - while (list != NO_JUMP) { - int next = getjump(fs, list); + for (; list != NO_JUMP; list = getjump(fs, list)) { lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && (GETARG_A(fs->f->code[list]) == 0 || GETARG_A(fs->f->code[list]) >= level)); SETARG_A(fs->f->code[list], level); - list = next; - } -} - - -void luaK_patchtohere (FuncState *fs, int list) { - luaK_getlabel(fs); - luaK_concat(fs, &fs->jpc, list); -} - - -void luaK_concat (FuncState *fs, int *l1, int l2) { - if (l2 == NO_JUMP) return; - else if (*l1 == NO_JUMP) - *l1 = l2; - else { - int list = *l1; - int next; - while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ - list = next; - fixjump(fs, list, l2); } } +/* +** Emit instruction 'i', checking for array sizes and saving also its +** line information. Return 'i' position. +*/ static int luaK_code (FuncState *fs, Instruction i) { Proto *f = fs->f; dischargejpc(fs); /* 'pc' will change */ @@ -241,6 +305,10 @@ } +/* +** Format and emit an 'iABC' instruction. (Assertions check consistency +** of parameters versus opcode.) +*/ int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { lua_assert(getOpMode(o) == iABC); lua_assert(getBMode(o) != OpArgN || b == 0); @@ -250,6 +318,9 @@ } +/* +** Format and emit an 'iABx' instruction. +*/ int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); lua_assert(getCMode(o) == OpArgN); @@ -258,12 +329,20 @@ } +/* +** Emit an "extra argument" instruction (format 'iAx') +*/ static int codeextraarg (FuncState *fs, int a) { lua_assert(a <= MAXARG_Ax); return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); } +/* +** Emit a "load constant" instruction, using either 'OP_LOADK' +** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX' +** instruction with "extra argument". +*/ int luaK_codek (FuncState *fs, int reg, int k) { if (k <= MAXARG_Bx) return luaK_codeABx(fs, OP_LOADK, reg, k); @@ -275,6 +354,10 @@ } +/* +** Check register-stack level, keeping track of its maximum size +** in field 'maxstacksize' +*/ void luaK_checkstack (FuncState *fs, int n) { int newstack = fs->freereg + n; if (newstack > fs->f->maxstacksize) { @@ -286,12 +369,20 @@ } +/* +** Reserve 'n' registers in register stack +*/ void luaK_reserveregs (FuncState *fs, int n) { luaK_checkstack(fs, n); fs->freereg += n; } +/* +** Free register 'reg', if it is neither a constant index nor +** a local variable. +) +*/ static void freereg (FuncState *fs, int reg) { if (!ISK(reg) && reg >= fs->nactvar) { fs->freereg--; @@ -300,6 +391,9 @@ } +/* +** Free register used by expression 'e' (if any) +*/ static void freeexp (FuncState *fs, expdesc *e) { if (e->k == VNONRELOC) freereg(fs, e->u.info); @@ -307,8 +401,29 @@ /* +** Free registers used by expressions 'e1' and 'e2' (if any) in proper +** order. +*/ +static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) { + int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1; + int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1; + if (r1 > r2) { + freereg(fs, r1); + freereg(fs, r2); + } + else { + freereg(fs, r2); + freereg(fs, r1); + } +} + + +/* +** Add constant 'v' to prototype's list of constants (field 'k'). ** Use scanner's table to cache position of constants in constant list -** and try to reuse constants +** and try to reuse constants. Because some values should not be used +** as keys (nil cannot be a key, integer keys can collapse with float +** keys), the caller must provide a useful 'key' for indexing the cache. */ static int addk (FuncState *fs, TValue *key, TValue *v) { lua_State *L = fs->ls->L; @@ -337,17 +452,21 @@ } +/* +** Add a string to list of constants and return its index. +*/ int luaK_stringK (FuncState *fs, TString *s) { TValue o; setsvalue(fs->ls->L, &o, s); - return addk(fs, &o, &o); + return addk(fs, &o, &o); /* use string itself as key */ } /* -** Integers use userdata as keys to avoid collision with floats with same -** value; conversion to 'void*' used only for hashing, no "precision" -** problems +** Add an integer to list of constants and return its index. +** Integers use userdata as keys to avoid collision with floats with +** same value; conversion to 'void*' is used only for hashing, so there +** are no "precision" problems. */ int luaK_intK (FuncState *fs, lua_Integer n) { TValue k, o; @@ -356,21 +475,29 @@ return addk(fs, &k, &o); } - +/* +** Add a float to list of constants and return its index. +*/ static int luaK_numberK (FuncState *fs, lua_Number r) { TValue o; setfltvalue(&o, r); - return addk(fs, &o, &o); + return addk(fs, &o, &o); /* use number itself as key */ } +/* +** Add a boolean to list of constants and return its index. +*/ static int boolK (FuncState *fs, int b) { TValue o; setbvalue(&o, b); - return addk(fs, &o, &o); + return addk(fs, &o, &o); /* use boolean itself as key */ } +/* +** Add nil to list of constants and return its index. +*/ static int nilK (FuncState *fs) { TValue k, v; setnilvalue(&v); @@ -380,54 +507,79 @@ } +/* +** Fix an expression to return the number of results 'nresults'. +** Either 'e' is a multi-ret expression (function call or vararg) +** or 'nresults' is LUA_MULTRET (as any expression can satisfy that). +*/ void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { if (e->k == VCALL) { /* expression is an open function call? */ - SETARG_C(getcode(fs, e), nresults+1); + SETARG_C(getinstruction(fs, e), nresults + 1); } else if (e->k == VVARARG) { - SETARG_B(getcode(fs, e), nresults+1); - SETARG_A(getcode(fs, e), fs->freereg); + Instruction *pc = &getinstruction(fs, e); + SETARG_B(*pc, nresults + 1); + SETARG_A(*pc, fs->freereg); luaK_reserveregs(fs, 1); } + else lua_assert(nresults == LUA_MULTRET); } +/* +** Fix an expression to return one result. +** If expression is not a multi-ret expression (function call or +** vararg), it already returns one result, so nothing needs to be done. +** Function calls become VNONRELOC expressions (as its result comes +** fixed in the base register of the call), while vararg expressions +** become VRELOCABLE (as OP_VARARG puts its results where it wants). +** (Calls are created returning one result, so that does not need +** to be fixed.) +*/ void luaK_setoneret (FuncState *fs, expdesc *e) { if (e->k == VCALL) { /* expression is an open function call? */ - e->k = VNONRELOC; - e->u.info = GETARG_A(getcode(fs, e)); + /* already returns 1 value */ + lua_assert(GETARG_C(getinstruction(fs, e)) == 2); + e->k = VNONRELOC; /* result has fixed position */ + e->u.info = GETARG_A(getinstruction(fs, e)); } else if (e->k == VVARARG) { - SETARG_B(getcode(fs, e), 2); + SETARG_B(getinstruction(fs, e), 2); e->k = VRELOCABLE; /* can relocate its simple result */ } } +/* +** Ensure that expression 'e' is not a variable. +*/ void luaK_dischargevars (FuncState *fs, expdesc *e) { switch (e->k) { - case VLOCAL: { - e->k = VNONRELOC; + case VLOCAL: { /* already in a register */ + e->k = VNONRELOC; /* becomes a non-relocatable value */ break; } - case VUPVAL: { + case VUPVAL: { /* move value to some (pending) register */ e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); e->k = VRELOCABLE; break; } case VINDEXED: { - OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */ + OpCode op; freereg(fs, e->u.ind.idx); - if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */ + if (e->u.ind.vt == VLOCAL) { /* is 't' in a register? */ freereg(fs, e->u.ind.t); op = OP_GETTABLE; } + else { + lua_assert(e->u.ind.vt == VUPVAL); + op = OP_GETTABUP; /* 't' is in an upvalue */ + } e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); e->k = VRELOCABLE; break; } - case VVARARG: - case VCALL: { + case VVARARG: case VCALL: { luaK_setoneret(fs, e); break; } @@ -436,12 +588,10 @@ } -static int code_label (FuncState *fs, int A, int b, int jump) { - luaK_getlabel(fs); /* those instructions may be jump targets */ - return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); -} - - +/* +** Ensures expression value is in register 'reg' (and therefore +** 'e' will become a non-relocatable expression). +*/ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { luaK_dischargevars(fs, e); switch (e->k) { @@ -466,8 +616,8 @@ break; } case VRELOCABLE: { - Instruction *pc = &getcode(fs, e); - SETARG_A(*pc, reg); + Instruction *pc = &getinstruction(fs, e); + SETARG_A(*pc, reg); /* instruction will put result in 'reg' */ break; } case VNONRELOC: { @@ -476,7 +626,7 @@ break; } default: { - lua_assert(e->k == VVOID || e->k == VJMP); + lua_assert(e->k == VJMP); return; /* nothing to do... */ } } @@ -485,17 +635,46 @@ } +/* +** Ensures expression value is in any register. +*/ static void discharge2anyreg (FuncState *fs, expdesc *e) { - if (e->k != VNONRELOC) { - luaK_reserveregs(fs, 1); - discharge2reg(fs, e, fs->freereg-1); + if (e->k != VNONRELOC) { /* no fixed register yet? */ + luaK_reserveregs(fs, 1); /* get a register */ + discharge2reg(fs, e, fs->freereg-1); /* put value there */ + } +} + + +static int code_loadbool (FuncState *fs, int A, int b, int jump) { + luaK_getlabel(fs); /* those instructions may be jump targets */ + return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); +} + + +/* +** check whether list has any jump that do not produce a value +** or produce an inverted value +*/ +static int need_value (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) { + Instruction i = *getjumpcontrol(fs, list); + if (GET_OPCODE(i) != OP_TESTSET) return 1; } + return 0; /* not found */ } +/* +** Ensures final expression result (including results from its jump +** lists) is in register 'reg'. +** If expression has jumps, need to patch these jumps either to +** its final position or to "load" instructions (for those tests +** that do not produce values). +*/ static void exp2reg (FuncState *fs, expdesc *e, int reg) { discharge2reg(fs, e, reg); - if (e->k == VJMP) + if (e->k == VJMP) /* expression itself is a test? */ luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */ if (hasjumps(e)) { int final; /* position after whole expression */ @@ -503,8 +682,8 @@ int p_t = NO_JUMP; /* position of an eventual LOAD true */ if (need_value(fs, e->t) || need_value(fs, e->f)) { int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); - p_f = code_label(fs, reg, 0, 1); - p_t = code_label(fs, reg, 1, 0); + p_f = code_loadbool(fs, reg, 0, 1); + p_t = code_loadbool(fs, reg, 1, 0); luaK_patchtohere(fs, fj); } final = luaK_getlabel(fs); @@ -517,6 +696,10 @@ } +/* +** Ensures final expression result (including results from its jump +** lists) is in next available register. +*/ void luaK_exp2nextreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); freeexp(fs, e); @@ -525,26 +708,39 @@ } +/* +** Ensures final expression result (including results from its jump +** lists) is in some (any) register and return that register. +*/ int luaK_exp2anyreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); - if (e->k == VNONRELOC) { - if (!hasjumps(e)) return e->u.info; /* exp is already in a register */ + if (e->k == VNONRELOC) { /* expression already has a register? */ + if (!hasjumps(e)) /* no jumps? */ + return e->u.info; /* result is already in a register */ if (e->u.info >= fs->nactvar) { /* reg. is not a local? */ - exp2reg(fs, e, e->u.info); /* put value on it */ + exp2reg(fs, e, e->u.info); /* put final result in it */ return e->u.info; } } - luaK_exp2nextreg(fs, e); /* default */ + luaK_exp2nextreg(fs, e); /* otherwise, use next available register */ return e->u.info; } +/* +** Ensures final expression result is either in a register or in an +** upvalue. +*/ void luaK_exp2anyregup (FuncState *fs, expdesc *e) { if (e->k != VUPVAL || hasjumps(e)) luaK_exp2anyreg(fs, e); } +/* +** Ensures final expression result is either in a register or it is +** a constant. +*/ void luaK_exp2val (FuncState *fs, expdesc *e) { if (hasjumps(e)) luaK_exp2anyreg(fs, e); @@ -553,35 +749,26 @@ } +/* +** Ensures final expression result is in a valid R/K index +** (that is, it is either in a register or in 'k' with an index +** in the range of R/K indices). +** Returns R/K index. +*/ int luaK_exp2RK (FuncState *fs, expdesc *e) { luaK_exp2val(fs, e); - switch (e->k) { - case VTRUE: - case VFALSE: - case VNIL: { - if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */ - e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE)); - e->k = VK; - return RKASK(e->u.info); - } - else break; - } - case VKINT: { - e->u.info = luaK_intK(fs, e->u.ival); - e->k = VK; - goto vk; - } - case VKFLT: { - e->u.info = luaK_numberK(fs, e->u.nval); - e->k = VK; - } - /* FALLTHROUGH */ - case VK: { + switch (e->k) { /* move constants to 'k' */ + case VTRUE: e->u.info = boolK(fs, 1); goto vk; + case VFALSE: e->u.info = boolK(fs, 0); goto vk; + case VNIL: e->u.info = nilK(fs); goto vk; + case VKINT: e->u.info = luaK_intK(fs, e->u.ival); goto vk; + case VKFLT: e->u.info = luaK_numberK(fs, e->u.nval); goto vk; + case VK: vk: + e->k = VK; if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */ return RKASK(e->u.info); else break; - } default: break; } /* not a constant in the right range: put it in a register */ @@ -589,11 +776,14 @@ } +/* +** Generate code to store result of expression 'ex' into variable 'var'. +*/ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { switch (var->k) { case VLOCAL: { freeexp(fs, ex); - exp2reg(fs, ex, var->u.info); + exp2reg(fs, ex, var->u.info); /* compute 'ex' into proper place */ return; } case VUPVAL: { @@ -607,29 +797,32 @@ luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); break; } - default: { - lua_assert(0); /* invalid var kind to store */ - break; - } + default: lua_assert(0); /* invalid var kind to store */ } freeexp(fs, ex); } +/* +** Emit SELF instruction (convert expression 'e' into 'e:key(e,'). +*/ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { int ereg; luaK_exp2anyreg(fs, e); ereg = e->u.info; /* register where 'e' was placed */ freeexp(fs, e); e->u.info = fs->freereg; /* base register for op_self */ - e->k = VNONRELOC; + e->k = VNONRELOC; /* self expression has a fixed register */ luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key)); freeexp(fs, key); } -static void invertjump (FuncState *fs, expdesc *e) { +/* +** Negate condition 'e' (where 'e' is a comparison). +*/ +static void negatecondition (FuncState *fs, expdesc *e) { Instruction *pc = getjumpcontrol(fs, e->u.info); lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && GET_OPCODE(*pc) != OP_TEST); @@ -637,9 +830,15 @@ } +/* +** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond' +** is true, code will jump if 'e' is true.) Return jump position. +** Optimize when 'e' is 'not' something, inverting the condition +** and removing the 'not'. +*/ static int jumponcond (FuncState *fs, expdesc *e, int cond) { if (e->k == VRELOCABLE) { - Instruction ie = getcode(fs, e); + Instruction ie = getinstruction(fs, e); if (GET_OPCODE(ie) == OP_NOT) { fs->pc--; /* remove previous OP_NOT */ return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); @@ -652,13 +851,16 @@ } +/* +** Emit code to go through if 'e' is true, jump otherwise. +*/ void luaK_goiftrue (FuncState *fs, expdesc *e) { - int pc; /* pc of last jump */ + int pc; /* pc of new jump */ luaK_dischargevars(fs, e); switch (e->k) { - case VJMP: { - invertjump(fs, e); - pc = e->u.info; + case VJMP: { /* condition? */ + negatecondition(fs, e); /* jump when it is false */ + pc = e->u.info; /* save jump position */ break; } case VK: case VKFLT: case VKINT: case VTRUE: { @@ -666,22 +868,25 @@ break; } default: { - pc = jumponcond(fs, e, 0); + pc = jumponcond(fs, e, 0); /* jump when false */ break; } } - luaK_concat(fs, &e->f, pc); /* insert last jump in 'f' list */ - luaK_patchtohere(fs, e->t); + luaK_concat(fs, &e->f, pc); /* insert new jump in false list */ + luaK_patchtohere(fs, e->t); /* true list jumps to here (to go through) */ e->t = NO_JUMP; } +/* +** Emit code to go through if 'e' is false, jump otherwise. +*/ void luaK_goiffalse (FuncState *fs, expdesc *e) { - int pc; /* pc of last jump */ + int pc; /* pc of new jump */ luaK_dischargevars(fs, e); switch (e->k) { case VJMP: { - pc = e->u.info; + pc = e->u.info; /* already jump if true */ break; } case VNIL: case VFALSE: { @@ -689,29 +894,32 @@ break; } default: { - pc = jumponcond(fs, e, 1); + pc = jumponcond(fs, e, 1); /* jump if true */ break; } } - luaK_concat(fs, &e->t, pc); /* insert last jump in 't' list */ - luaK_patchtohere(fs, e->f); + luaK_concat(fs, &e->t, pc); /* insert new jump in 't' list */ + luaK_patchtohere(fs, e->f); /* false list jumps to here (to go through) */ e->f = NO_JUMP; } +/* +** Code 'not e', doing constant folding. +*/ static void codenot (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); switch (e->k) { case VNIL: case VFALSE: { - e->k = VTRUE; + e->k = VTRUE; /* true == not nil == not false */ break; } case VK: case VKFLT: case VKINT: case VTRUE: { - e->k = VFALSE; + e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */ break; } case VJMP: { - invertjump(fs, e); + negatecondition(fs, e); break; } case VRELOCABLE: @@ -722,30 +930,32 @@ e->k = VRELOCABLE; break; } - default: { - lua_assert(0); /* cannot happen */ - break; - } + default: lua_assert(0); /* cannot happen */ } /* interchange true and false lists */ { int temp = e->f; e->f = e->t; e->t = temp; } - removevalues(fs, e->f); + removevalues(fs, e->f); /* values are useless when negated */ removevalues(fs, e->t); } +/* +** Create expression 't[k]'. 't' must have its final result already in a +** register or upvalue. +*/ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { - lua_assert(!hasjumps(t)); - t->u.ind.t = t->u.info; - t->u.ind.idx = luaK_exp2RK(fs, k); - t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL - : check_exp(vkisinreg(t->k), VLOCAL); + lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL)); + t->u.ind.t = t->u.info; /* register or upvalue index */ + t->u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */ + t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL; t->k = VINDEXED; } /* -** return false if folding can raise an error +** Return false if folding can raise an error. +** Bitwise operations need operands convertible to integers; division +** operations cannot have 0 as divisor. */ static int validop (int op, TValue *v1, TValue *v2) { switch (op) { @@ -762,7 +972,8 @@ /* -** Try to "constant-fold" an operation; return 1 iff successful +** Try to "constant-fold" an operation; return 1 iff successful. +** (In this case, 'e1' has the final result.) */ static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) { TValue v1, v2, res; @@ -773,7 +984,7 @@ e1->k = VKINT; e1->u.ival = ivalue(&res); } - else { /* folds neither NaN nor 0.0 (to avoid collapsing with -0.0) */ + else { /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */ lua_Number n = fltvalue(&res); if (luai_numisnan(n) || n == 0) return 0; @@ -785,81 +996,97 @@ /* -** Code for binary and unary expressions that "produce values" -** (arithmetic operations, bitwise operations, concat, length). First -** try to do constant folding (only for numeric [arithmetic and -** bitwise] operations, which is what 'lua_arith' accepts). +** Emit code for unary expressions that "produce values" +** (everything but 'not'). +** Expression to produce final result will be encoded in 'e'. +*/ +static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) { + int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */ + freeexp(fs, e); + e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */ + e->k = VRELOCABLE; /* all those operations are relocatable */ + luaK_fixline(fs, line); +} + + +/* +** Emit code for binary expressions that "produce values" +** (everything but logical operators 'and'/'or' and comparison +** operators). ** Expression to produce final result will be encoded in 'e1'. */ -static void codeexpval (FuncState *fs, OpCode op, - expdesc *e1, expdesc *e2, int line) { - lua_assert(op >= OP_ADD); - if (op <= OP_BNOT && constfolding(fs, (op - OP_ADD) + LUA_OPADD, e1, e2)) - return; /* result has been folded */ - else { - int o1, o2; - /* move operands to registers (if needed) */ - if (op == OP_UNM || op == OP_BNOT || op == OP_LEN) { /* unary op? */ - o2 = 0; /* no second expression */ - o1 = luaK_exp2anyreg(fs, e1); /* cannot operate on constants */ - } - else { /* regular case (binary operators) */ - o2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */ - o1 = luaK_exp2RK(fs, e1); - } - if (o1 > o2) { /* free registers in proper order */ - freeexp(fs, e1); - freeexp(fs, e2); - } - else { - freeexp(fs, e2); - freeexp(fs, e1); - } - e1->u.info = luaK_codeABC(fs, op, 0, o1, o2); /* generate opcode */ - e1->k = VRELOCABLE; /* all those operations are relocatable */ - luaK_fixline(fs, line); - } +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); + freeexps(fs, e1, e2); + e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */ + e1->k = VRELOCABLE; /* all those operations are relocatable */ + luaK_fixline(fs, line); } -static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, - expdesc *e2) { - int o1 = luaK_exp2RK(fs, e1); - int o2 = luaK_exp2RK(fs, e2); - freeexp(fs, e2); - freeexp(fs, e1); - if (cond == 0 && op != OP_EQ) { - int temp; /* exchange args to replace by '<' or '<=' */ - temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ - cond = 1; +/* +** Emit code for comparisons. +** 'e1' was already put in R/K form by 'luaK_infix'. +*/ +static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { + int rk1 = (e1->k == VK) ? RKASK(e1->u.info) + : check_exp(e1->k == VNONRELOC, e1->u.info); + int rk2 = luaK_exp2RK(fs, e2); + freeexps(fs, e1, e2); + switch (opr) { + case OPR_NE: { /* '(a ~= b)' ==> 'not (a == b)' */ + e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2); + break; + } + case OPR_GT: case OPR_GE: { + /* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */ + OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ); + e1->u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */ + break; + } + default: { /* '==', '<', '<=' use their own opcodes */ + OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ); + e1->u.info = condjump(fs, op, 1, rk1, rk2); + break; + } } - e1->u.info = condjump(fs, op, cond, o1, o2); e1->k = VJMP; } +/* +** Aplly prefix operation 'op' to expression 'e'. +*/ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { - expdesc e2; - e2.t = e2.f = NO_JUMP; e2.k = VKINT; e2.u.ival = 0; + static expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; /* fake 2nd operand */ switch (op) { - case OPR_MINUS: case OPR_BNOT: case OPR_LEN: { - codeexpval(fs, cast(OpCode, (op - OPR_MINUS) + OP_UNM), e, &e2, line); + case OPR_MINUS: case OPR_BNOT: + if (constfolding(fs, op + LUA_OPUNM, e, &ef)) + break; + /* FALLTHROUGH */ + case OPR_LEN: + codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); break; - } case OPR_NOT: codenot(fs, e); break; default: lua_assert(0); } } +/* +** Process 1st operand 'v' of binary operation 'op' before reading +** 2nd operand. +*/ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { switch (op) { case OPR_AND: { - luaK_goiftrue(fs, v); + luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */ break; } case OPR_OR: { - luaK_goiffalse(fs, v); + luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */ break; } case OPR_CONCAT: { @@ -871,7 +1098,9 @@ case OPR_MOD: case OPR_POW: case OPR_BAND: case OPR_BOR: case OPR_BXOR: case OPR_SHL: case OPR_SHR: { - if (!tonumeral(v, NULL)) luaK_exp2RK(fs, v); + if (!tonumeral(v, NULL)) + luaK_exp2RK(fs, v); + /* else keep numeral, which may be folded with 2nd operand */ break; } default: { @@ -882,18 +1111,24 @@ } +/* +** Finalize code for binary operation, after reading 2nd operand. +** For '(a .. b .. c)' (which is '(a .. (b .. c))', because +** concatenation is right associative), merge second CONCAT into first +** one. +*/ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2, int line) { switch (op) { case OPR_AND: { - lua_assert(e1->t == NO_JUMP); /* list must be closed */ + lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */ luaK_dischargevars(fs, e2); luaK_concat(fs, &e2->f, e1->f); *e1 = *e2; break; } case OPR_OR: { - lua_assert(e1->f == NO_JUMP); /* list must be closed */ + lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */ luaK_dischargevars(fs, e2); luaK_concat(fs, &e2->t, e1->t); *e1 = *e2; @@ -901,15 +1136,16 @@ } case OPR_CONCAT: { luaK_exp2val(fs, e2); - if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { - lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1); + if (e2->k == VRELOCABLE && + GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) { + lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1); freeexp(fs, e1); - SETARG_B(getcode(fs, e2), e1->u.info); + SETARG_B(getinstruction(fs, e2), e1->u.info); e1->k = VRELOCABLE; e1->u.info = e2->u.info; } else { luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ - codeexpval(fs, OP_CONCAT, e1, e2, line); + codebinexpval(fs, OP_CONCAT, e1, e2, line); } break; } @@ -917,15 +1153,13 @@ case OPR_IDIV: case OPR_MOD: case OPR_POW: case OPR_BAND: case OPR_BOR: case OPR_BXOR: case OPR_SHL: case OPR_SHR: { - codeexpval(fs, cast(OpCode, (op - OPR_ADD) + OP_ADD), e1, e2, line); - break; - } - case OPR_EQ: case OPR_LT: case OPR_LE: { - codecomp(fs, cast(OpCode, (op - OPR_EQ) + OP_EQ), 1, e1, e2); + if (!constfolding(fs, op + LUA_OPADD, e1, e2)) + codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line); break; } + case OPR_EQ: case OPR_LT: case OPR_LE: case OPR_NE: case OPR_GT: case OPR_GE: { - codecomp(fs, cast(OpCode, (op - OPR_NE) + OP_EQ), 0, e1, e2); + codecomp(fs, op, e1, e2); break; } default: lua_assert(0); @@ -933,15 +1167,25 @@ } +/* +** Change line information associated with current position. +*/ void luaK_fixline (FuncState *fs, int line) { fs->f->lineinfo[fs->pc - 1] = line; } +/* +** Emit a SETLIST instruction. +** 'base' is register that keeps table; +** 'nelems' is #table plus those to be stored now; +** 'tostore' is number of values (in registers 'base + 1',...) to add to +** table (or LUA_MULTRET to add up to stack top). +*/ void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; int b = (tostore == LUA_MULTRET) ? 0 : tostore; - lua_assert(tostore != 0); + lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH); if (c <= MAXARG_C) luaK_codeABC(fs, OP_SETLIST, base, b, c); else if (c <= MAXARG_Ax) { diff -u -r lua-5.3.2/src/lcode.h lua-5.3.3/src/lcode.h --- lua-5.3.2/src/lcode.h 2013-12-30 18:47:58.000000000 -0200 +++ lua-5.3.3/src/lcode.h 2016-01-05 14:22:37.000000000 -0200 @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.63 2013/12/30 20:47:58 roberto Exp $ +** $Id: lcode.h,v 1.64 2016/01/05 16:22:37 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -40,7 +40,8 @@ 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) diff -u -r lua-5.3.2/src/lcorolib.c lua-5.3.3/src/lcorolib.c --- lua-5.3.2/src/lcorolib.c 2014-11-02 17:19:04.000000000 -0200 +++ lua-5.3.3/src/lcorolib.c 2016-04-11 16:19:55.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: lcorolib.c,v 1.9 2014/11/02 19:19:04 roberto Exp $ +** $Id: lcorolib.c,v 1.10 2016/04/11 19:19:55 roberto Exp $ ** Coroutine Library ** See Copyright Notice in lua.h */ @@ -75,7 +75,7 @@ lua_State *co = lua_tothread(L, lua_upvalueindex(1)); int r = auxresume(L, co, lua_gettop(L)); 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 */ lua_insert(L, -2); lua_concat(L, 2); diff -u -r lua-5.3.2/src/ldebug.c lua-5.3.3/src/ldebug.c --- lua-5.3.2/src/ldebug.c 2015-11-02 16:48:07.000000000 -0200 +++ lua-5.3.3/src/ldebug.c 2016-03-31 16:01:21.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.117 2015/11/02 18:48:07 roberto Exp $ +** $Id: ldebug.c,v 2.120 2016/03/31 19:01:21 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -69,7 +69,13 @@ /* -** 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) { if (func == NULL || mask == 0) { /* turn off hooks? */ @@ -558,7 +564,7 @@ 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)); } @@ -590,9 +596,9 @@ l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { - const char *t1 = objtypename(p1); - const char *t2 = objtypename(p2); - if (t1 == t2) + const char *t1 = luaT_objtypename(L, p1); + const char *t2 = luaT_objtypename(L, p2); + if (strcmp(t1, t2) == 0) luaG_runerror(L, "attempt to compare two %s values", t1); else luaG_runerror(L, "attempt to compare %s with %s", t1, t2); diff -u -r lua-5.3.2/src/ldo.c lua-5.3.3/src/ldo.c --- lua-5.3.2/src/ldo.c 2015-11-19 17:16:22.000000000 -0200 +++ lua-5.3.3/src/ldo.c 2015-12-16 14:40:07.000000000 -0200 @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.150 2015/11/19 19:16:22 roberto Exp $ +** $Id: ldo.c,v 2.151 2015/12/16 16:40:07 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -242,9 +242,14 @@ /* }================================================================== */ +/* +** 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) { lua_Hook hook = L->hook; - if (hook && L->allowhook) { + if (hook && L->allowhook) { /* make sure there is a hook */ CallInfo *ci = L->ci; ptrdiff_t top = savestack(L, L->top); ptrdiff_t ci_top = savestack(L, ci->top); diff -u -r lua-5.3.2/src/ldo.h lua-5.3.3/src/ldo.h --- lua-5.3.2/src/ldo.h 2015-11-23 09:29:43.000000000 -0200 +++ lua-5.3.3/src/ldo.h 2015-12-21 11:02:14.000000000 -0200 @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.28 2015/11/23 11:29:43 roberto Exp $ +** $Id: ldo.h,v 2.29 2015/12/21 13:02:14 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -25,7 +25,7 @@ { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); } /* 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) diff -u -r lua-5.3.2/src/lgc.c lua-5.3.3/src/lgc.c --- lua-5.3.2/src/lgc.c 2015-11-03 16:10:44.000000000 -0200 +++ lua-5.3.3/src/lgc.c 2016-03-31 16:02:03.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.210 2015/11/03 18:10:44 roberto Exp $ +** $Id: lgc.c,v 2.212 2016/03/31 19:02:03 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -754,14 +754,11 @@ /* ** 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; - int i = 0; do { - i++; p = sweeplist(L, p, 1); } while (p == old); - if (n) *n += i; return p; } @@ -856,10 +853,10 @@ /* ** call all pending finalizers */ -static void callallpendingfinalizers (lua_State *L, int propagateerrors) { +static void callallpendingfinalizers (lua_State *L) { global_State *g = G(L); while (g->tobefnz) - GCTM(L, propagateerrors); + GCTM(L, 0); } @@ -909,7 +906,7 @@ if (issweepphase(g)) { makewhite(g, o); /* "sweep" object 'o' */ 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' */ for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } @@ -951,19 +948,16 @@ /* ** Enter first sweep phase. -** The call to 'sweeptolive' makes pointer point to an object inside -** the list (instead of to the header), so that the real sweep do not -** need to skip objects created between "now" and the start of the real -** sweep. -** Returns how many objects it swept. +** The call to 'sweeplist' tries to make pointer point to an object +** inside the list (instead of to the header), so that the real sweep do +** not need to skip objects created between "now" and the start of the +** real sweep. */ -static int entersweep (lua_State *L) { +static void entersweep (lua_State *L) { global_State *g = G(L); - int n = 0; g->gcstate = GCSswpallgc; lua_assert(g->sweepgc == NULL); - g->sweepgc = sweeptolive(L, &g->allgc, &n); - return n; + g->sweepgc = sweeplist(L, &g->allgc, 1); } @@ -971,7 +965,7 @@ global_State *g = G(L); separatetobefnz(g, 1); /* separate all objects with finalizers */ lua_assert(g->finobj == NULL); - callallpendingfinalizers(L, 0); + callallpendingfinalizers(L); lua_assert(g->tobefnz == NULL); g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ g->gckind = KGC_NORMAL; @@ -1064,12 +1058,11 @@ } case GCSatomic: { lu_mem work; - int sw; propagateall(g); /* make sure gray list is empty */ work = atomic(L); /* work is what was traversed by 'atomic' */ - sw = entersweep(L); + entersweep(L); g->GCestimate = gettotalbytes(g); /* first estimate */; - return work + sw * GCSWEEPCOST; + return work; } case GCSswpallgc: { /* sweep "regular" objects */ return sweepstep(L, g, GCSswpfinobj, &g->finobj); diff -u -r lua-5.3.2/src/lgc.h lua-5.3.3/src/lgc.h --- lua-5.3.2/src/lgc.h 2015-10-21 16:15:15.000000000 -0200 +++ lua-5.3.3/src/lgc.h 2015-12-21 11:02:14.000000000 -0200 @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.90 2015/10/21 18:15:15 roberto Exp $ +** $Id: lgc.h,v 2.91 2015/12/21 13:02:14 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -112,7 +112,7 @@ condchangemem(L,pre,pos); } /* 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) ( \ diff -u -r lua-5.3.2/src/liolib.c lua-5.3.3/src/liolib.c --- lua-5.3.2/src/liolib.c 2015-11-23 09:36:11.000000000 -0200 +++ lua-5.3.3/src/liolib.c 2016-05-02 11:03:19.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: liolib.c,v 2.148 2015/11/23 11:36:11 roberto Exp $ +** $Id: liolib.c,v 2.149 2016/05/02 14:03:19 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ @@ -375,14 +375,17 @@ /* maximum length of a numeral */ -#define MAXRN 200 +#if !defined (L_MAXLENNUM) +#define L_MAXLENNUM 200 +#endif + /* auxiliary structure used by 'read_number' */ typedef struct { FILE *f; /* file being read */ int c; /* current character (look ahead) */ 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; @@ -390,7 +393,7 @@ ** Add current char to buffer (if not out of space) and read next one */ static int nextc (RN *rn) { - if (rn->n >= MAXRN) { /* buffer overflow? */ + if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */ rn->buff[0] = '\0'; /* invalidate result */ return 0; /* fail */ } @@ -403,10 +406,10 @@ /* -** 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) { - if (rn->c == set[0] || (rn->c == set[1] && rn->c != '\0')) + if (rn->c == set[0] || rn->c == set[1]) return nextc(rn); else return 0; } @@ -435,11 +438,11 @@ char decp[2]; rn.f = f; rn.n = 0; decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ - decp[1] = '\0'; + decp[1] = '.'; /* always accept a dot */ l_lockfile(rn.f); do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ test2(&rn, "-+"); /* optional signal */ - if (test2(&rn, "0")) { + if (test2(&rn, "00")) { if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ else count = 1; /* count initial '0' as a valid digit */ } diff -u -r lua-5.3.2/src/llex.c lua-5.3.3/src/llex.c --- lua-5.3.2/src/llex.c 2015-11-19 17:16:22.000000000 -0200 +++ lua-5.3.3/src/llex.c 2016-05-02 11:02:12.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: llex.c,v 2.95 2015/11/19 19:16:22 roberto Exp $ +** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -162,7 +162,6 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, int firstchar) { ls->t.token = 0; - ls->decpoint = '.'; ls->L = L; ls->current = firstchar; ls->lookahead.token = TK_EOS; /* no look-ahead token */ @@ -207,35 +206,6 @@ } -/* -** 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 */ /* ** this function is quite liberal in what it accepts, as 'luaO_str2num' @@ -259,9 +229,8 @@ else break; } save(ls, '\0'); - buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ 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)) { seminfo->i = ivalue(&obj); return TK_INT; diff -u -r lua-5.3.2/src/llex.h lua-5.3.3/src/llex.h --- lua-5.3.2/src/llex.h 2014-10-29 13:38:24.000000000 -0200 +++ lua-5.3.3/src/llex.h 2016-05-02 11:02:12.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.78 2014/10/29 15:38:24 roberto Exp $ +** $Id: llex.h,v 1.79 2016/05/02 14:02:12 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -69,7 +69,6 @@ struct Dyndata *dyd; /* dynamic structures used by the parser */ TString *source; /* current source name */ TString *envn; /* environment variable name */ - char decpoint; /* locale decimal point */ } LexState; diff -u -r lua-5.3.2/src/lobject.c lua-5.3.3/src/lobject.c --- lua-5.3.2/src/lobject.c 2015-11-02 14:09:30.000000000 -0200 +++ lua-5.3.3/src/lobject.c 2016-05-20 11:07:48.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.108 2015/11/02 16:09:30 roberto Exp $ +** $Id: lobject.c,v 2.111 2016/05/20 14:07:48 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -243,20 +243,59 @@ /* }====================================================== */ -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; - if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */ + *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */ + : lua_str2number(s, &endptr); + if (endptr == s) return NULL; /* nothing recognized? */ + while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */ + 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; - else if (strpbrk(s, "xX")) /* hex? */ - *result = lua_strx2number(s, &endptr); - else - *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 */ + endptr = l_str2dloc(s, result, mode); /* try to convert */ + if (endptr == NULL) { /* failed? may be a different locale */ + char buff[L_MAXLENNUM + 1]; + 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) { lua_Unsigned a = 0; int empty = 1; @@ -273,7 +312,10 @@ } else { /* decimal */ 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; } } @@ -351,8 +393,10 @@ } -/* 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) { int n = 0; for (;;) { @@ -360,13 +404,13 @@ if (e == NULL) break; pushstr(L, fmt, e - fmt); switch (*(e+1)) { - case 's': { + case 's': { /* zero-terminated string */ const char *s = va_arg(argp, char *); if (s == NULL) s = "(null)"; pushstr(L, s, strlen(s)); break; } - case 'c': { + case 'c': { /* an 'int' as a character */ char buff = cast(char, va_arg(argp, int)); if (lisprint(cast_uchar(buff))) pushstr(L, &buff, 1); @@ -374,28 +418,28 @@ luaO_pushfstring(L, "<\\%d>", cast_uchar(buff)); break; } - case 'd': { + case 'd': { /* an 'int' */ setivalue(L->top, va_arg(argp, int)); goto top2str; } - case 'I': { + case 'I': { /* a 'lua_Integer' */ setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt))); goto top2str; } - case 'f': { + case 'f': { /* a 'lua_Number' */ setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); - top2str: + top2str: /* convert the top element to a string */ luaD_inctop(L); luaO_tostring(L, L->top - 1); break; } - case 'p': { + case 'p': { /* a pointer */ 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 *)); pushstr(L, buff, l); break; } - case 'U': { + case 'U': { /* an 'int' as a UTF-8 sequence */ char buff[UTF8BUFFSZ]; int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long))); pushstr(L, buff + UTF8BUFFSZ - l, l); diff -u -r lua-5.3.2/src/loslib.c lua-5.3.3/src/loslib.c --- lua-5.3.2/src/loslib.c 2015-11-19 17:16:22.000000000 -0200 +++ lua-5.3.3/src/loslib.c 2016-04-18 10:06:55.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.60 2015/11/19 19:16:22 roberto Exp $ +** $Id: loslib.c,v 1.64 2016/04/18 13:06:55 roberto Exp $ ** Standard Operating System library ** 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_USE_C89) -#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } +/* options for ANSI C 89 */ +#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%" + +/* options for ISO C 99 and POSIX */ +#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \ + "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" + +/* options for Windows */ +#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \ + "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" + +#if defined(LUA_USE_WINDOWS) +#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN +#elif defined(LUA_USE_C89) +#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89 #else /* C99 specification */ -#define LUA_STRFTIMEOPTIONS \ - { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \ - "E", "cCxXyY", \ - "O", "deHImMSuUVwWy" } +#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99 #endif #endif /* } */ @@ -195,6 +206,23 @@ 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) { int res; res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); @@ -210,18 +238,18 @@ static int getfield (lua_State *L, const char *key, int d, int delta) { 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); - if (!isnum) { /* field is not a number? */ + if (!isnum) { /* field is not an integer? */ 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? */ return luaL_error(L, "field '%s' missing in date table", key); res = d; } else { 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; } lua_pop(L, 1); @@ -230,21 +258,15 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) { - static const char *const options[] = LUA_STRFTIMEOPTIONS; - unsigned int i; - for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) { - if (*conv != '\0' && strchr(options[i], *conv) != NULL) { - buff[1] = *conv; - if (*options[i + 1] == '\0') { /* one-char conversion specifier? */ - buff[2] = '\0'; /* end buffer */ - return conv + 1; - } - else if (*(conv + 1) != '\0' && - strchr(options[i + 1], *(conv + 1)) != NULL) { - buff[2] = *(conv + 1); /* valid two-char conversion specifier */ - buff[3] = '\0'; /* end buffer */ - return conv + 2; - } + const char *option; + int oplen = 1; + for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) { + if (*option == '|') /* next block? */ + oplen++; /* next length */ + else if (memcmp(conv, option, oplen) == 0) { /* match? */ + memcpy(buff, conv, oplen); /* copy valid option to buffer */ + buff[oplen] = '\0'; + return conv + oplen; /* return next item */ } } luaL_argerror(L, 1, @@ -271,18 +293,10 @@ luaL_error(L, "time result cannot be represented in this installation"); if (strcmp(s, "*t") == 0) { lua_createtable(L, 0, 9); /* 9 = number of fields */ - 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); + setallfields(L, stm); } else { - char cc[4]; + char cc[4]; /* buffer for individual conversion specifiers */ luaL_Buffer b; cc[0] = '%'; luaL_buffinit(L, &b); @@ -292,7 +306,7 @@ else { size_t reslen; char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); - s = checkoption(L, s + 1, cc); + s = checkoption(L, s + 1, cc + 1); /* copy specifier to 'cc' */ reslen = strftime(buff, SIZETIMEFMT, cc, stm); luaL_addsize(&b, reslen); } @@ -319,6 +333,7 @@ ts.tm_year = getfield(L, "year", -1, 1900); ts.tm_isdst = getboolfield(L, "isdst"); t = mktime(&ts); + setallfields(L, &ts); /* update fields with normalized values */ } if (t != (time_t)(l_timet)t || t == (time_t)(-1)) luaL_error(L, "time result cannot be represented in this installation"); diff -u -r lua-5.3.2/src/lparser.c lua-5.3.3/src/lparser.c --- lua-5.3.2/src/lparser.c 2015-11-02 14:09:30.000000000 -0200 +++ lua-5.3.3/src/lparser.c 2016-05-13 16:10:16.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.149 2015/11/02 16:09:30 roberto Exp $ +** $Id: lparser.c,v 2.153 2016/05/13 19:10:16 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -164,7 +164,8 @@ int oldsize = f->sizelocvars; luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, 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; luaC_objbarrier(ls->L, f, varname); return fs->nlocvars++; @@ -230,7 +231,8 @@ checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues, 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].idx = cast_byte(v->u.info); f->upvalues[fs->nups].name = name; @@ -255,7 +257,8 @@ */ static void markupval (FuncState *fs, int level) { BlockCnt *bl = fs->bl; - while (bl->nactvar > level) bl = bl->previous; + while (bl->nactvar > level) + bl = bl->previous; bl->upval = 1; } @@ -264,27 +267,26 @@ Find variable with given name 'n'. If it is an upvalue, add this 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? */ - return VVOID; /* default is global */ + init_exp(var, VVOID, 0); /* default is global */ else { int v = searchvar(fs, n); /* look up locals at current level */ if (v >= 0) { /* found? */ init_exp(var, VLOCAL, v); /* variable is local */ if (!base) markupval(fs, v); /* local will be used as an upval */ - return VLOCAL; } else { /* not found as local at current level; try upvalues */ int idx = searchupvalue(fs, n); /* try existing upvalues */ if (idx < 0) { /* not found? */ - if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */ - return VVOID; /* not found; is a global */ + singlevaraux(fs->prev, n, var, 0); /* try upper levels */ + if (var->k == VVOID) /* not found? */ + return; /* it is a global */ /* else was LOCAL or UPVAL */ idx = newupvalue(fs, n, var); /* will be a new upvalue */ } - init_exp(var, VUPVAL, idx); - return VUPVAL; + init_exp(var, VUPVAL, idx); /* new or old upvalue */ } } } @@ -293,10 +295,11 @@ static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); 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; 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 */ luaK_indexed(fs, var, &key); /* env[varname] */ } @@ -499,7 +502,8 @@ if (fs->np >= f->sizep) { int oldsize = f->sizep; 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); luaC_objbarrier(L, f, clp); @@ -1226,7 +1230,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 */ @@ -1494,7 +1498,7 @@ } else { /* stat -> func */ 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 +1515,8 @@ if (hasmultret(e.k)) { luaK_setmultret(fs, &e); if (e.k == VCALL && nret == 1) { /* tail call? */ - SET_OPCODE(getcode(fs,&e), OP_TAILCALL); - lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); + SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL); + lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar); } first = fs->nactvar; nret = LUA_MULTRET; /* return all values */ diff -u -r lua-5.3.2/src/lparser.h lua-5.3.3/src/lparser.h --- lua-5.3.2/src/lparser.h 2014-10-25 09:50:46.000000000 -0200 +++ lua-5.3.3/src/lparser.h 2015-12-30 16:16:13.000000000 -0200 @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.74 2014/10/25 11:50:46 roberto Exp $ +** $Id: lparser.h,v 1.76 2015/12/30 18:16:13 roberto Exp $ ** Lua Parser ** 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 { - VVOID, /* no value */ - VNIL, - VTRUE, - VFALSE, - VK, /* info = index of constant in 'k' */ - VKFLT, /* nval = numerical float value */ - VKINT, /* nval = numerical integer value */ - VNONRELOC, /* info = result register */ - VLOCAL, /* info = local register */ - VUPVAL, /* info = index of upvalue in 'upvalues' */ - VINDEXED, /* t = table register/upvalue; idx = index R/K */ - VJMP, /* info = instruction pc */ - VRELOCABLE, /* info = instruction pc */ - VCALL, /* info = instruction pc */ - VVARARG /* info = instruction pc */ + VVOID, /* when 'expdesc' describes the last expression a list, + this kind means an empty list (so, no expression) */ + VNIL, /* constant nil */ + VTRUE, /* constant true */ + VFALSE, /* constant false */ + VK, /* constant in 'k'; info = index of constant in 'k' */ + VKFLT, /* floating constant; nval = numerical float value */ + VKINT, /* integer constant; nval = numerical integer value */ + VNONRELOC, /* expression has its value in a fixed register; + info = result register */ + VLOCAL, /* local variable; info = local register */ + VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ + VINDEXED, /* indexed variable; + ind.vt = whether 't' is register or upvalue; + 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; @@ -41,14 +54,14 @@ typedef struct expdesc { expkind k; union { + lua_Integer ival; /* for VKINT */ + lua_Number nval; /* for VKFLT */ + int info; /* for generic use */ struct { /* for indexed variables (VINDEXED) */ short idx; /* index (R/K) */ lu_byte t; /* table (register or upvalue) */ lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ } ind; - int info; /* for generic use */ - lua_Number nval; /* for VKFLT */ - lua_Integer ival; /* for VKINT */ } u; int t; /* patch list of 'exit when true' */ int f; /* patch list of 'exit when false' */ diff -u -r lua-5.3.2/src/lstate.h lua-5.3.3/src/lstate.h --- lua-5.3.2/src/lstate.h 2015-11-13 10:16:51.000000000 -0200 +++ lua-5.3.3/src/lstate.h 2015-12-16 14:39:38.000000000 -0200 @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.128 2015/11/13 12:16:51 roberto Exp $ +** $Id: lstate.h,v 2.130 2015/12/16 16:39:38 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -33,6 +33,15 @@ 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 +#define l_signalT sig_atomic_t +#endif + /* extra stack space to handle TM calls and some other extras */ #define EXTRA_STACK 5 @@ -162,14 +171,14 @@ struct lua_State *twups; /* list of threads with open upvalues */ struct lua_longjmp *errorJmp; /* current error recover point */ 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) */ int stacksize; int basehookcount; int hookcount; unsigned short nny; /* number of non-yieldable calls in stack */ unsigned short nCcalls; /* number of nested C calls */ - lu_byte hookmask; + l_signalT hookmask; lu_byte allowhook; }; diff -u -r lua-5.3.2/src/lstrlib.c lua-5.3.3/src/lstrlib.c --- lua-5.3.2/src/lstrlib.c 2015-11-25 14:28:17.000000000 -0200 +++ lua-5.3.3/src/lstrlib.c 2016-05-20 11:13:21.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.239 2015/11/25 16:28:17 roberto Exp $ +** $Id: lstrlib.c,v 1.251 2016/05/20 14:13:21 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -26,7 +27,8 @@ /* ** 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) #define LUA_MAXCAPTURES 32 @@ -214,9 +216,8 @@ const char *src_end; /* end ('\0') of source string */ const char *p_end; /* end ('\0') of pattern */ lua_State *L; - size_t nrep; /* limit to avoid non-linear complexity */ 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 { const char *init; ptrdiff_t len; @@ -234,17 +235,6 @@ #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 SPECIALS "^$*+?.([%-" @@ -502,8 +492,6 @@ s = NULL; /* fail */ } else { /* matched once */ - if (ms->nrep-- == 0) - luaL_error(ms->L, "pattern too complex"); switch (*ep) { /* handle optional suffix */ case '?': { /* optional */ const char *res; @@ -607,10 +595,6 @@ ms->src_init = s; ms->src_end = s + ls; 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 @@ typedef struct GMatchState { const char *src; /* current position */ const char *p; /* pattern */ + const char *lastmatch; /* end of last match */ MatchState ms; /* match state */ } GMatchState; @@ -688,14 +673,12 @@ 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); - if ((e = match(&gm->ms, src, gm->p)) != NULL) { - if (e == src) /* empty match? */ - gm->src =src + 1; /* go at least one position */ - else - gm->src = e; + if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) { + gm->src = gm->lastmatch = e; return push_captures(&gm->ms, src, e); } } @@ -711,7 +694,7 @@ lua_settop(L, 2); /* keep them on closure to avoid being collected */ gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); 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); return 1; } @@ -778,12 +761,13 @@ static int str_gsub (lua_State *L) { size_t srcl, lp; - const char *src = luaL_checklstring(L, 1, &srcl); - const char *p = luaL_checklstring(L, 2, &lp); - int tr = lua_type(L, 3); - lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); + const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ + const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ + const char *lastmatch = NULL; /* end of last match */ + int tr = lua_type(L, 3); /* replacement type */ + lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ int anchor = (*p == '^'); - lua_Integer n = 0; + lua_Integer n = 0; /* replacement count */ MatchState ms; luaL_Buffer b; luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || @@ -796,16 +780,15 @@ prepstate(&ms, L, src, srcl, p, lp); while (n < max_s) { const char *e; - reprepstate(&ms); - if ((e = match(&ms, src, p)) != NULL) { + reprepstate(&ms); /* (re)prepare state for new match */ + if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ 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? */ - src = e; /* skip it */ - else if (src < ms.src_end) + else if (src < ms.src_end) /* otherwise, skip one character */ luaL_addchar(&b, *src++); - else break; + else break; /* end of subject */ if (anchor) break; } luaL_addlstring(&b, src, ms.src_end-src); @@ -830,7 +813,6 @@ ** Hexadecimal floating-point formatter */ -#include #include #define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) @@ -922,16 +904,14 @@ #define MAX_FORMAT 32 -static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { - size_t l; - const char *s = luaL_checklstring(L, arg, &l); +static void addquoted (luaL_Buffer *b, const char *s, size_t len) { luaL_addchar(b, '"'); - while (l--) { + while (len--) { if (*s == '"' || *s == '\\' || *s == '\n') { luaL_addchar(b, '\\'); luaL_addchar(b, *s); } - else if (*s == '\0' || iscntrl(uchar(*s))) { + else if (iscntrl(uchar(*s))) { char buff[10]; if (!isdigit(uchar(*(s+1)))) l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); @@ -946,6 +926,57 @@ 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 = 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, 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) { const char *p = strfrmt; while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ @@ -1025,7 +1056,7 @@ break; } case 'q': { - addquoted(L, &b, arg); + addliteral(L, &b, arg); break; } case 's': { @@ -1070,8 +1101,8 @@ /* value used for padding */ -#if !defined(LUA_PACKPADBYTE) -#define LUA_PACKPADBYTE 0x00 +#if !defined(LUAL_PACKPADBYTE) +#define LUAL_PACKPADBYTE 0x00 #endif /* maximum size for the binary representation of an integer */ @@ -1308,7 +1339,7 @@ KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); totalsize += ntoalign + size; while (ntoalign-- > 0) - luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */ + luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */ arg++; switch (opt) { case Kint: { /* signed integers */ @@ -1343,13 +1374,11 @@ case Kchar: { /* fixed-size string */ size_t len; const char *s = luaL_checklstring(L, arg, &len); - if ((size_t)size <= len) /* string larger than (or equal to) needed? */ - luaL_addlstring(&b, s, size); /* truncate string to asked size */ - else { /* string smaller than needed */ - luaL_addlstring(&b, s, len); /* add it all */ - while (len++ < (size_t)size) /* pad extra space */ - luaL_addchar(&b, LUA_PACKPADBYTE); - } + luaL_argcheck(L, len <= (size_t)size, arg, + "string longer than given size"); + luaL_addlstring(&b, s, len); /* add string */ + while (len++ < (size_t)size) /* pad extra space */ + luaL_addchar(&b, LUAL_PACKPADBYTE); break; } case Kstring: { /* strings with length count */ @@ -1372,7 +1401,7 @@ totalsize += len + 1; break; } - case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* FALLTHROUGH */ + case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */ case Kpaddalign: case Knop: arg--; /* undo increment */ break; diff -u -r lua-5.3.2/src/ltablib.c lua-5.3.3/src/ltablib.c --- lua-5.3.2/src/ltablib.c 2015-11-25 10:48:57.000000000 -0200 +++ lua-5.3.3/src/ltablib.c 2016-02-25 16:41:54.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: ltablib.c,v 1.90 2015/11/25 12:48:57 roberto Exp $ +** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ @@ -53,7 +53,7 @@ lua_pop(L, n); /* pop metatable and tested metamethods */ } else - luaL_argerror(L, arg, "table expected"); /* force an error */ + luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ } } @@ -139,7 +139,7 @@ n = e - f + 1; /* number of elements to move */ luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, "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++) { lua_geti(L, 1, f + i); lua_seti(L, tt, t + i); @@ -152,7 +152,7 @@ } } } - lua_pushvalue(L, tt); /* return "to table" */ + lua_pushvalue(L, tt); /* return destination table */ return 1; } @@ -172,7 +172,7 @@ size_t lsep; const char *sep = luaL_optlstring(L, 2, "", &lsep); 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); for (; i < last; i++) { addfield(L, &b, i); @@ -232,6 +232,10 @@ */ +/* type for array indices */ +typedef unsigned int IdxT; + + /* ** Produce a "random" 'unsigned int' to randomize pivot choice. This ** macro is used only when 'sort' detects a big imbalance in the result @@ -270,7 +274,7 @@ #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, j); } @@ -303,10 +307,9 @@ ** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] ** returns 'i'. */ -static unsigned int partition (lua_State *L, unsigned int lo, - unsigned int up) { - unsigned int i = lo; /* will be incremented before first use */ - unsigned int j = up - 1; /* will be decremented before first use */ +static IdxT partition (lua_State *L, IdxT lo, IdxT up) { + IdxT i = lo; /* will be incremented before first use */ + IdxT j = up - 1; /* will be decremented before first use */ /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ for (;;) { /* next loop: repeat ++i while a[i] < P */ @@ -340,10 +343,9 @@ ** Choose an element in the middle (2nd-3th quarters) of [lo,up] ** "randomized" by 'rnd' */ -static unsigned int choosePivot (unsigned int lo, unsigned int up, - unsigned int rnd) { - unsigned int r4 = (unsigned int)(up - lo) / 4u; /* range/4 */ - unsigned int p = rnd % (r4 * 2) + (lo + r4); +static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { + IdxT r4 = (up - lo) / 4; /* range/4 */ + IdxT p = rnd % (r4 * 2) + (lo + r4); lua_assert(lo + r4 <= p && p <= up - r4); return p; } @@ -352,11 +354,11 @@ /* ** 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) { while (lo < up) { /* loop for tail recursion */ - unsigned int p; /* Pivot index */ - unsigned int n; /* to be used later */ + IdxT p; /* Pivot index */ + IdxT n; /* to be used later */ /* sort elements 'lo', 'p', and 'up' */ lua_geti(L, 1, lo); lua_geti(L, 1, up); @@ -400,7 +402,7 @@ n = up - p; /* size of smaller 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 */ } /* tail call auxsort(L, lo, up, rnd) */ } @@ -410,11 +412,10 @@ lua_Integer n = aux_getn(L, 1, TAB_RW); if (n > 1) { /* non-trivial interval? */ 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? */ luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ 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; } diff -u -r lua-5.3.2/src/ltm.c lua-5.3.3/src/ltm.c --- lua-5.3.2/src/ltm.c 2015-11-03 13:47:30.000000000 -0200 +++ lua-5.3.3/src/ltm.c 2016-02-26 16:20:15.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 2.36 2015/11/03 15:47:30 roberto Exp $ +** $Id: ltm.c,v 2.37 2016/02/26 19:20:15 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -83,6 +83,22 @@ } +/* +** 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, const TValue *p2, TValue *p3, int hasres) { ptrdiff_t result = savestack(L, p3); diff -u -r lua-5.3.2/src/ltm.h lua-5.3.3/src/ltm.h --- lua-5.3.2/src/ltm.h 2014-10-25 09:50:46.000000000 -0200 +++ lua-5.3.3/src/ltm.h 2016-02-26 16:20:15.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 2.21 2014/10/25 11:50:46 roberto Exp $ +** $Id: ltm.h,v 2.22 2016/02/26 19:20:15 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -51,11 +51,12 @@ #define fasttm(l,et,e) gfasttm(G(l), et, e) #define ttypename(x) luaT_typenames_[(x) + 1] -#define objtypename(x) ttypename(ttnov(x)) 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_gettmbyobj (lua_State *L, const TValue *o, TMS event); diff -u -r lua-5.3.2/src/lua.h lua-5.3.3/src/lua.h --- lua-5.3.2/src/lua.h 2015-11-13 15:18:42.000000000 -0200 +++ lua-5.3.3/src/lua.h 2016-05-30 12:53:28.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.329 2015/11/13 17:18:42 roberto Exp $ +** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -19,11 +19,11 @@ #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "3" #define LUA_VERSION_NUM 503 -#define LUA_VERSION_RELEASE "2" +#define LUA_VERSION_RELEASE "3" #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #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-2016 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" @@ -361,7 +361,7 @@ #define lua_pushliteral(L, s) lua_pushstring(L, "" s) #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) @@ -460,7 +460,7 @@ /****************************************************************************** -* Copyright (C) 1994-2015 Lua.org, PUC-Rio. +* Copyright (C) 1994-2016 Lua.org, PUC-Rio. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff -u -r lua-5.3.2/src/luaconf.h lua-5.3.3/src/luaconf.h --- lua-5.3.2/src/luaconf.h 2015-10-21 16:17:40.000000000 -0200 +++ lua-5.3.3/src/luaconf.h 2016-05-01 17:06:09.000000000 -0300 @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.254 2015/10/21 18:17:40 roberto Exp $ +** $Id: luaconf.h,v 1.255 2016/05/01 20:06:09 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -612,7 +612,7 @@ ** provide its own implementation. */ #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,n)) #endif diff -u -r lua-5.3.2/src/lvm.c lua-5.3.3/src/lvm.c --- lua-5.3.2/src/lvm.c 2015-11-23 09:30:45.000000000 -0200 +++ lua-5.3.3/src/lvm.c 2016-02-05 17:59:14.000000000 -0200 @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.265 2015/11/23 11:30:45 roberto Exp $ +** $Id: lvm.c,v 2.268 2016/02/05 19:59:14 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -153,55 +153,69 @@ /* -** Complete a table access: if 't' is a table, 'tm' has its metamethod; -** otherwise, 'tm' is NULL. +** Finish the table access 'val = t[key]'. +** 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, - const TValue *tm) { + const TValue *slot) { int loop; /* counter to avoid infinite loops */ - lua_assert(tm != NULL || !ttistable(t)); + const TValue *tm; /* metamethod */ for (loop = 0; loop < MAXTAGLOOP; loop++) { - if (tm == NULL) { /* no metamethod (from a table)? */ - if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) + if (slot == NULL) { /* 't' is not a table? */ + lua_assert(!ttistable(t)); + tm = luaT_gettmbyobj(L, t, TM_INDEX); + if (ttisnil(tm)) 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 */ return; } - t = tm; /* else repeat access over 'tm' */ - if (luaV_fastget(L,t,key,tm,luaH_get)) { /* try fast track */ - setobj2s(L, val, tm); /* done */ + t = tm; /* else try to access 'tm[key]' */ + if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */ + setobj2s(L, val, slot); /* done */ 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). -** Compute 't[key] = val' +** Finish a table assignment '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, - StkId val, const TValue *oldval) { + StkId val, const TValue *slot) { int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { - const TValue *tm; - if (oldval != NULL) { - lua_assert(ttistable(t) && ttisnil(oldval)); - /* must check the metamethod */ - if ((tm = fasttm(L, hvalue(t)->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))) { + const TValue *tm; /* '__newindex' metamethod */ + if (slot != NULL) { /* is 't' a table? */ + Table *h = hvalue(t); /* save 't' table */ + lua_assert(ttisnil(slot)); /* old value must be nil */ + tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ + if (tm == NULL) { /* no metamethod? */ + if (slot == luaO_nilobject) /* no previous entry? */ + slot = luaH_newkey(L, h, key); /* create one */ /* 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); + setobj2t(L, cast(TValue *, slot), val); /* set its new value */ + invalidateTMcache(h); + luaC_barrierback(L, h, val); return; } /* else will try the metamethod */ @@ -216,11 +230,11 @@ return; } 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 */ /* else loop */ } - luaG_runerror(L, "settable chain too long; possible loop"); + luaG_runerror(L, "'__newindex' chain too long; possible loop"); } @@ -738,18 +752,28 @@ 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 vmcase(l) case l: #define vmbreak break /* -** copy of 'luaV_gettable', but protecting call to potential metamethod -** (which can reallocate the stack) +** copy of 'luaV_gettable', but protecting the call to potential +** metamethod (which can reallocate the stack) */ -#define gettableProtected(L,t,k,v) { const TValue *aux; \ - if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ - else Protect(luaV_finishget(L,t,k,v,aux)); } +#define gettableProtected(L,t,k,v) { const TValue *slot; \ + if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ + else Protect(luaV_finishget(L,t,k,v,slot)); } /* same for 'luaV_settable' */ @@ -772,14 +796,9 @@ base = ci->u.l.base; /* local copy of function's base */ /* main loop of interpreter */ for (;;) { - Instruction i = *(ci->u.l.savedpc++); + Instruction i; StkId ra; - if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) - 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); + vmfetch(); vmdispatch (GET_OPCODE(i)) { vmcase(OP_MOVE) { setobjs2s(L, ra, RB(i)); diff -u -r lua-5.3.2/src/lvm.h lua-5.3.3/src/lvm.h --- lua-5.3.2/src/lvm.h 2015-09-09 10:44:07.000000000 -0300 +++ lua-5.3.3/src/lvm.h 2016-01-05 14:07:21.000000000 -0200 @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 2.39 2015/09/09 13:44:07 roberto Exp $ +** $Id: lvm.h,v 2.40 2016/01/05 16:07:21 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -49,25 +49,24 @@ /* -** fast track for 'gettable': 1 means 'aux' points to resulted value; -** 0 means 'aux' is metamethod (if 't' is a table) or NULL. 'f' is -** the raw get function to use. +** fast track for 'gettable': if 't' is a table and 't[k]' is not nil, +** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise, +** 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) \ - ? (aux = NULL, 0) /* not a table; 'aux' is NULL and result is 0 */ \ - : (aux = f(hvalue(t), k), /* else, do raw access */ \ - !ttisnil(aux) ? 1 /* result not nil? 'aux' has it */ \ - : (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 */ + ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ + : (slot = f(hvalue(t), k), /* else, do raw access */ \ + !ttisnil(slot))) /* result not nil? */ /* ** standard implementation for 'gettable' */ -#define luaV_gettable(L,t,k,v) { const TValue *aux; \ - if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ - else luaV_finishget(L,t,k,v,aux); } +#define luaV_gettable(L,t,k,v) { const TValue *slot; \ + if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ + else luaV_finishget(L,t,k,v,slot); } /* @@ -100,9 +99,9 @@ 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 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, - StkId val, const TValue *oldval); + StkId val, const TValue *slot); LUAI_FUNC void luaV_finishOp (lua_State *L); LUAI_FUNC void luaV_execute (lua_State *L); LUAI_FUNC void luaV_concat (lua_State *L, int total);