summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-03-13 13:16:53 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-03-13 13:16:53 -0300
commitcf71a5ddc742692fad813f89f1c9ef53e1ffde0f (patch)
treedf02305ff3cf05908f21829384e3a7f8699d2331
parent2c32bff60987d38a60a58d4f0123f3783da60a63 (diff)
downloadlua-github-cf71a5ddc742692fad813f89f1c9ef53e1ffde0f.tar.gz
Details
Several small improvements (code style, warnings, comments, more tests), in particular: - 'lua_topointer' extended to handle strings - raises an error in 'string.format("%10q")' ('%q' with modifiers) - in the manual for 'string.format', the term "option" replaced by "conversion specifier" (the term used by the C standard)
-rw-r--r--lapi.c31
-rw-r--r--lfunc.c3
-rw-r--r--lopcodes.h15
-rw-r--r--lstrlib.c6
-rw-r--r--ltests.c7
-rw-r--r--manual/manual.of54
-rw-r--r--testes/api.lua21
-rw-r--r--testes/strings.lua1
8 files changed, 87 insertions, 51 deletions
diff --git a/lapi.c b/lapi.c
index 4026497e..66d75649 100644
--- a/lapi.c
+++ b/lapi.c
@@ -414,8 +414,7 @@ LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) {
}
-LUA_API void *lua_touserdata (lua_State *L, int idx) {
- const TValue *o = index2value(L, idx);
+static void *touserdata (const TValue *o) {
switch (ttype(o)) {
case LUA_TUSERDATA: return getudatamem(uvalue(o));
case LUA_TLIGHTUSERDATA: return pvalue(o);
@@ -424,23 +423,37 @@ LUA_API void *lua_touserdata (lua_State *L, int idx) {
}
+LUA_API void *lua_touserdata (lua_State *L, int idx) {
+ const TValue *o = index2value(L, idx);
+ return touserdata(o);
+}
+
+
LUA_API lua_State *lua_tothread (lua_State *L, int idx) {
const TValue *o = index2value(L, idx);
return (!ttisthread(o)) ? NULL : thvalue(o);
}
+/*
+** Returns a pointer to the internal representation of an object.
+** Note that ANSI C does not allow the conversion of a pointer to
+** function to a 'void*', so the conversion here goes through
+** a 'size_t'. (As the returned pointer is only informative, this
+** conversion should not be a problem.)
+*/
LUA_API const void *lua_topointer (lua_State *L, int idx) {
const TValue *o = index2value(L, idx);
switch (ttypetag(o)) {
- case LUA_TTABLE: return hvalue(o);
- case LUA_TLCL: return clLvalue(o);
- case LUA_TCCL: return clCvalue(o);
case LUA_TLCF: return cast_voidp(cast_sizet(fvalue(o)));
- case LUA_TTHREAD: return thvalue(o);
- case LUA_TUSERDATA: return getudatamem(uvalue(o));
- case LUA_TLIGHTUSERDATA: return pvalue(o);
- default: return NULL;
+ case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA:
+ return touserdata(o);
+ default: {
+ if (iscollectable(o))
+ return gcvalue(o);
+ else
+ return NULL;
+ }
}
}
diff --git a/lfunc.c b/lfunc.c
index 362b798c..3e044b65 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -138,7 +138,8 @@ static int callclosemth (lua_State *L, TValue *uv, StkId level, int status) {
if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */
callclose(L, NULL); /* call closing method */
else if (!ttisnil(uv)) { /* non-closable non-nil value? */
- const char *vname = luaG_findlocal(L, L->ci, level - L->ci->func, NULL);
+ int idx = cast_int(level - L->ci->func);
+ const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
if (vname == NULL) vname = "?";
luaG_runerror(L, "attempt to close non-closable variable '%s'", vname);
}
diff --git a/lopcodes.h b/lopcodes.h
index d7403caf..3e100259 100644
--- a/lopcodes.h
+++ b/lopcodes.h
@@ -90,7 +90,6 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
#define MAXARG_B ((1<<SIZE_B)-1)
#define MAXARG_C ((1<<SIZE_C)-1)
#define OFFSET_sC (MAXARG_C >> 1)
-#define MAXARG_Cx ((1<<(SIZE_C + 1))-1)
/* creates a mask with 'n' 1 bits at position 'p' */
@@ -233,8 +232,8 @@ OP_BANDK,/* A B C R(A) := R(B) & K(C):integer */
OP_BORK,/* A B C R(A) := R(B) | K(C):integer */
OP_BXORK,/* A B C R(A) := R(B) ~ K(C):integer */
-OP_SHRI,/* A B C R(A) := R(B) >> C */
-OP_SHLI,/* A B C R(A) := C << R(B) */
+OP_SHRI,/* A B sC R(A) := R(B) >> C */
+OP_SHLI,/* A B sC R(A) := C << R(B) */
OP_ADD,/* A B C R(A) := R(B) + R(C) */
OP_SUB,/* A B C R(A) := R(B) - R(C) */
@@ -272,7 +271,7 @@ OP_GTI,/* A sB if ((R(A) > sB) ~= k) then pc++ */
OP_GEI,/* A sB if ((R(A) >= sB) ~= k) then pc++ */
OP_TEST,/* A if (not R(A) == k) then pc++ */
-OP_TESTSET,/* A B if (not R(B) == k) then R(A) := R(B) else pc++ */
+OP_TESTSET,/* A B if (not R(B) == k) then pc++ else R(A) := R(B) */
OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
@@ -305,15 +304,15 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
} OpCode;
-#define NUM_OPCODES (cast_int(OP_EXTRAARG) + 1)
+#define NUM_OPCODES ((int)(OP_EXTRAARG) + 1)
/*===========================================================================
Notes:
- (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then 'top' is
- set to last_result+1, so next open instruction (OP_CALL, OP_RETURN*,
- OP_SETLIST) may use 'top'.
+ (*) In OP_CALL, if (B == 0) then B = top - A. If (C == 0), then
+ 'top' is set to last_result+1, so next open instruction (OP_CALL,
+ OP_RETURN*, OP_SETLIST) may use 'top'.
(*) In OP_VARARG, if (C == 0) then use actual number of varargs and
set top (like in OP_CALL with C == 0).
diff --git a/lstrlib.c b/lstrlib.c
index 41ebc523..ab4258e5 100644
--- a/lstrlib.c
+++ b/lstrlib.c
@@ -181,7 +181,7 @@ static int str_byte (lua_State *L) {
size_t pose = getendpos(L, 3, pi, l);
int n, i;
if (posi > pose) return 0; /* empty interval; return no values */
- if (pose - posi >= INT_MAX) /* arithmetic overflow? */
+ if (pose - posi >= (size_t)INT_MAX) /* arithmetic overflow? */
return luaL_error(L, "string slice too long");
n = (int)(pose - posi) + 1;
luaL_checkstack(L, n, "string slice too long");
@@ -1159,7 +1159,7 @@ static int str_format (lua_State *L) {
char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */
int nb = 0; /* number of bytes in added item */
if (++arg > top)
- luaL_argerror(L, arg, "no value");
+ return luaL_argerror(L, arg, "no value");
strfrmt = scanformat(L, strfrmt, form);
switch (*strfrmt++) {
case 'c': {
@@ -1186,6 +1186,8 @@ static int str_format (lua_State *L) {
break;
}
case 'q': {
+ if (form[2] != '\0') /* modifiers? */
+ return luaL_error(L, "specifier '%%q' cannot have modifiers");
addliteral(L, &b, arg);
break;
}
diff --git a/ltests.c b/ltests.c
index 36a974ae..23375382 100644
--- a/ltests.c
+++ b/ltests.c
@@ -164,7 +164,7 @@ typedef union Header {
Memcontrol l_memcontrol =
- {0L, 0L, 0L, 0L, (~0L), {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}};
+ {0UL, 0UL, 0UL, 0UL, (~0UL), {0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL}};
static void freeblock (Memcontrol *mc, Header *block) {
@@ -1596,7 +1596,10 @@ static struct X { int x; } x;
lua_pushnumber(L1, lua_tonumber(L1, getindex));
}
else if EQ("topointer") {
- lua_pushnumber(L1, cast_sizet(lua_topointer(L1, getindex)));
+ lua_pushlightuserdata(L1, cast_voidp(lua_topointer(L1, getindex)));
+ }
+ else if EQ("touserdata") {
+ lua_pushlightuserdata(L1, lua_touserdata(L1, getindex));
}
else if EQ("tostring") {
const char *s = lua_tostring(L1, getindex);
diff --git a/manual/manual.of b/manual/manual.of
index 421d04de..9c8ab033 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -143,7 +143,7 @@ that is, @x{arrays} that can have as indices not only numbers,
but any Lua value except @nil and @x{NaN}.
(@emphx{Not a Number} is a special floating-point value
used by the @x{IEEE 754} standard to represent
-undefined or unrepresentable numerical results, such as @T{0/0}.)
+undefined numerical results, such as @T{0/0}.)
Tables can be @emph{heterogeneous};
that is, they can contain values of all types (except @nil).
Any key with value @nil is not considered part of the table.
@@ -670,8 +670,8 @@ are called when the garbage collector detects that the
corresponding table or userdata is unreachable.
Finalizers allow you to coordinate Lua's garbage collection
with external resource management
-(such as closing files, network or database connections,
-or freeing your own memory).
+such as closing files, network or database connections,
+or freeing your own memory.
For an object (table or userdata) to be finalized when collected,
you must @emph{mark} it for finalization.
@@ -1323,11 +1323,12 @@ labels in Lua are considered statements too:
}
A label is visible in the entire block where it is defined,
-except
-inside nested blocks where a label with the same name is defined and
-inside nested functions.
+except inside nested functions.
A goto may jump to any visible label as long as it does not
enter into the scope of a local variable.
+A label should not be declared
+where a label with the same name is visible,
+even if this other label has been declared in an enclosing block.
Labels and empty statements are called @def{void statements},
as they perform no actions.
@@ -1537,7 +1538,7 @@ goes out of scope, including normal block termination,
exiting its block by @Rw{break}/@Rw{goto}/@Rw{return},
or exiting by an error.
-Here, to \emph{close} a value means
+Here, to @emph{close} a value means
to call its @idx{__close} metamethod.
If the value is @nil, it is ignored;
otherwise,
@@ -4236,7 +4237,7 @@ indicates whether the operation succeeded.
Converts the value at the given index to a generic
@N{C pointer} (@T{void*}).
-The value can be a userdata, a table, a thread, or a function;
+The value can be a userdata, a table, a thread, a string, or a function;
otherwise, @id{lua_topointer} returns @id{NULL}.
Different objects will give different pointers.
There is no way to convert the pointer back to its original value.
@@ -6712,8 +6713,10 @@ to save space.
Functions with upvalues have only their number of upvalues saved.
When (re)loaded,
-those upvalues receive fresh instances containing @nil.
-(You can use the debug library to serialize
+those upvalues receive fresh instances.
+(See the @Lid{load} function for details about
+how these upvalues are initialized.
+You can use the debug library to serialize
and reload the upvalues of a function
in a way adequate to your needs.)
@@ -6747,12 +6750,12 @@ after the two indices.
Returns a formatted version of its variable number of arguments
following the description given in its first argument (which must be a string).
The format string follows the same rules as the @ANSI{sprintf}.
-The only differences are that the options/modifiers
+The only differences are that the conversion specifiers and modifiers
@T{*}, @id{h}, @id{L}, @id{l}, @id{n},
and @id{p} are not supported
-and that there is an extra option, @id{q}.
+and that there is an extra specifier, @id{q}.
-The @id{q} option formats booleans, nil, numbers, and strings
+The specifier @id{q} formats booleans, nil, numbers, and strings
in a way that the result is a valid constant in Lua source code.
Booleans and nil are written in the obvious way
(@id{true}, @id{false}, @id{nil}).
@@ -6770,22 +6773,23 @@ may produce the string:
"a string with \"quotes\" and \
new line"
}
+This specifier does not support modifiers (flags, width, length).
-Options
+The conversion specifiers
@id{A}, @id{a}, @id{E}, @id{e}, @id{f},
@id{G}, and @id{g} all expect a number as argument.
-Options @id{c}, @id{d},
+The specifiers @id{c}, @id{d},
@id{i}, @id{o}, @id{u}, @id{X}, and @id{x}
expect an integer.
When Lua is compiled with a C89 compiler,
-options @id{A} and @id{a} (hexadecimal floats)
-do not support any modifier (flags, width, length).
+the specifiers @id{A} and @id{a} (hexadecimal floats)
+do not support modifiers.
-Option @id{s} expects a string;
+The specifier @id{s} expects a string;
if its argument is not a string,
it is converted to one following the same rules of @Lid{tostring}.
-If the option has any modifier (flags, width, length),
-the string argument should not contain @x{embedded zeros}.
+If the specifier has any modifier,
+the corresponding string argument should not contain @x{embedded zeros}.
}
@@ -8009,8 +8013,8 @@ or there is any input from some special files
}
}
-For the last two cases, @id{size}
-specifies the size of the buffer, in bytes.
+For the last two cases,
+@id{size} is a hint for the size of the buffer, in bytes.
The default is an appropriate size.
}
@@ -8698,6 +8702,12 @@ When a coroutine finishes with an error,
its stack is unwound (to run any pending closing methods).
}
+@item{
+A label for a @Rw{goto} cannot be declared where a label with the same
+name is visible, even if this other label is declared in an enclosing
+block.
+}
+
}
}
diff --git a/testes/api.lua b/testes/api.lua
index 9904dadf..d034ea80 100644
--- a/testes/api.lua
+++ b/testes/api.lua
@@ -332,6 +332,7 @@ function to (s, x, n)
return T.testC(string.format("%s %d; return 1", s, n), x)
end
+local null = T.pushuserdata(0)
local hfunc = string.gmatch("", "") -- a "heavy C function" (with upvalues)
assert(debug.getupvalue(hfunc, 1))
assert(to("tostring", {}) == nil)
@@ -349,13 +350,19 @@ assert(to("tonumber", {}) == 0)
assert(to("tonumber", "12") == 12)
assert(to("tonumber", "s2") == 0)
assert(to("tonumber", 1, 20) == 0)
-assert(to("topointer", 10) == 0)
-assert(to("topointer", true) == 0)
-assert(to("topointer", T.pushuserdata(20)) == 20)
-assert(to("topointer", io.read) ~= 0) -- light C function
-assert(to("topointer", hfunc) ~= 0) -- "heavy" C function
-assert(to("topointer", function () end) ~= 0) -- Lua function
-assert(to("topointer", io.stdin) ~= 0) -- full userdata
+assert(to("topointer", 10) == null)
+assert(to("topointer", true) == null)
+assert(to("topointer", nil) == null)
+assert(to("topointer", "abc") ~= null)
+assert(to("topointer", string.rep("x", 10)) ==
+ to("topointer", string.rep("x", 10))) -- short strings
+assert(to("topointer", string.rep("x", 300)) ~=
+ to("topointer", string.rep("x", 300))) -- long strings
+assert(to("topointer", T.pushuserdata(20)) ~= null)
+assert(to("topointer", io.read) ~= null) -- light C function
+assert(to("topointer", hfunc) ~= null) -- "heavy" C function
+assert(to("topointer", function () end) ~= null) -- Lua function
+assert(to("topointer", io.stdin) ~= null) -- full userdata
assert(to("func2num", 20) == 0)
assert(to("func2num", T.pushuserdata(10)) == 0)
assert(to("func2num", io.read) ~= 0) -- light C function
diff --git a/testes/strings.lua b/testes/strings.lua
index 88480924..da53a87e 100644
--- a/testes/strings.lua
+++ b/testes/strings.lua
@@ -199,6 +199,7 @@ end
assert(string.format("\0%s\0", "\0\0\1") == "\0\0\0\1\0")
checkerror("contains zeros", string.format, "%10s", "\0")
+checkerror("cannot have modifiers", string.format, "%10q", "1")
-- format x tostring
assert(string.format("%s %s", nil, true) == "nil true")