Analyze the lua source code
Use the command git grep -n "error info"
, we can find the relational function source code:
pi@rpi /opt/software/lua-5.3.2 $ git grep -n "position out of bounds"
src/ltablib.c:90: luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
src/ltablib.c:110: luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds");
pi@rpi /opt/software/lua-5.3.2 $
The result is clear, we know that the code is in file src/ltablib.c
, line 90
and 110
, the code is below:
79 static int tinsert (lua_State *L) {
80 lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */
81 lua_Integer pos; /* where to insert new element */
82 switch (lua_gettop(L)) {
83 case 2: { /* called with only 2 arguments */
84 pos = e; /* insert new element at the end */
85 break;
86 }
87 case 3: {
88 lua_Integer i;
89 pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */
90 luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
91 for (i = e; i > pos; i--) { /* move up elements */
92 lua_geti(L, 1, i - 1);
93 lua_seti(L, 1, i); /* t[i] = t[i - 1] */
94 }
95 break;
96 }
97 default: {
98 return luaL_error(L, "wrong number of arguments to 'insert'");
99 }
100 }
101 lua_seti(L, 1, pos); /* t[pos] = v */
102 return 0;
103 }
104
105
106 static int tremove (lua_State *L) {
107 lua_Integer size = aux_getn(L, 1, TAB_RW);
108 lua_Integer pos = luaL_optinteger(L, 2, size);
109 if (pos != size) /* validate 'pos' if given */
110 luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds");
111 lua_geti(L, 1, pos); /* result = t[pos] */
112 for ( ; pos < size; pos++) {
113 lua_geti(L, 1, pos + 1);
114 lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */
115 }
116 lua_pushnil(L);
117 lua_seti(L, 1, pos); /* t[pos] = nil */
118 return 1;
119 }
We can see the check 1 <= pos && pos <= e
in function tinsert
and the check 1 <= pos && pos <= size + 1
in function tremove
. And we can find the define of e
and size
:
lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */
The relational code:
27 #define TAB_R 1 /* read */
28 #define TAB_W 2 /* write */
29 #define TAB_L 4 /* length */
30 #define TAB_RW (TAB_R | TAB_W) /* read/write */
31
32
33 #define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n))
34
35
36 static int checkfield (lua_State *L, const char *key, int n) {
37 lua_pushstring(L, key);
38 return (lua_rawget(L, -n) != LUA_TNIL);
39 }
40
41
42 /*
43 ** Check that 'arg' either is a table or can behave like one (that is,
44 ** has a metatable with the required metamethods)
45 */
46 static void checktab (lua_State *L, int arg, int what) {
47 if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */
48 int n = 1; /* number of elements to pop */
49 if (lua_getmetatable(L, arg) && /* must have metatable */
50 (!(what & TAB_R) || checkfield(L, "__index", ++n)) &&
51 (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) &&
52 (!(what & TAB_L) || checkfield(L, "__len", ++n))) {
53 lua_pop(L, n); /* pop metatable and tested metamethods */
54 }
55 else
56 luaL_argerror(L, arg, "table expected"); /* force an error */
57 }
58 }
Now we know the meaning: check the insert position, if it is bigger than the current size of the table, then return error with info “position out of bounds”.
In version 5.1
, we can insert in any position:
pi@rpi /opt/software $ lua5.1
Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio
> touches = {}
> touch={id=100}
> table.insert(touches, 1000000, touch)
>
Let us see the source code in version 5.1
:
90 static int tinsert (lua_State *L) {
91 int e = aux_getn(L, 1) + 1; /* first empty element */
92 int pos; /* where to insert new element */
93 switch (lua_gettop(L)) {
94 case 2: { /* called with only 2 arguments */
95 pos = e; /* insert new element at the end */
96 break;
97 }
98 case 3: {
99 int i;
100 pos = luaL_checkint(L, 2); /* 2nd argument is the position */
101 if (pos > e) e = pos; /* `grow' array if necessary */
102 for (i = e; i > pos; i--) { /* move up elements */
103 lua_rawgeti(L, 1, i-1);
104 lua_rawseti(L, 1, i); /* t[i] = t[i-1] */
105 }
106 break;
107 }
108 default: {
109 return luaL_error(L, "wrong number of arguments to " LUA_QL("insert"));
110 }
111 }
112 luaL_setn(L, 1, e); /* new size */
113 lua_rawseti(L, 1, pos); /* t[pos] = v */
114 return 0;
115 }
116
117
118 static int tremove (lua_State *L) {
119 int e = aux_getn(L, 1);
120 int pos = luaL_optint(L, 2, e);
121 if (!(1 <= pos && pos <= e)) /* position is outside bounds? */
122 return 0; /* nothing to remove */
123 luaL_setn(L, 1, e - 1); /* t.n = n-1 */
124 lua_rawgeti(L, 1, pos); /* result = t[pos] */
125 for ( ;pos<e; pos++) {
126 lua_rawgeti(L, 1, pos+1);
127 lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */
128 }
129 lua_pushnil(L);
130 lua_rawseti(L, 1, e); /* t[e] = nil */
131 return 1;
132 }
We can see that, it is a different dealing with the insert position argument.
if (pos > e) e = pos; /* `grow' array if necessary */
If the pos is bigger than the current max position(the e
), then expand the table with the pos, It is a “grow” array, but it need alloc more memery. Maybe for the optimizing reason, in 5.3
this is not allowed, then the old code get error.
More details of source code
If you want get more details about the source code, you can search luaL_argcheck
:
pi@rpi /opt/software/lua-5.3.2 $ git grep -n "luaL_argcheck"
...
src/lauxlib.h:114:#define luaL_argcheck(L, cond,arg,extramsg) \\
...
Open src/lauxlib.h
with vi
:
114 #define luaL_argcheck(L, cond,arg,extramsg) \\
115 ((void)((cond) || luaL_argerror(L, (arg), (extramsg))))
Search luaL_argerror
:
38 LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);
Use git grep -n
:
pi@rpi /opt/software/lua-5.3.2 $ git grep -n "luaL_argerror"
...
src/lauxlib.c:164:LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {
...
Ok, see the code:
164 LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {
165 lua_Debug ar;
166 if (!lua_getstack(L, 0, &ar)) /* no stack frame? */
167 return luaL_error(L, "bad argument #%d (%s)", arg, extramsg);
168 lua_getinfo(L, "n", &ar);
169 if (strcmp(ar.namewhat, "method") == 0) {
170 arg--; /* do not count 'self' */
171 if (arg == 0) /* error is in the self argument itself? */
172 return luaL_error(L, "calling '%s' on bad self (%s)",
173 ar.name, extramsg);
174 }
175 if (ar.name == NULL)
176 ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
177 return luaL_error(L, "bad argument #%d to '%s' (%s)",
178 arg, ar.name, extramsg);
179 }
It seemed that our test code trigger the last statement:
...
175 if (ar.name == NULL)
176 ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
177 return luaL_error(L, "bad argument #%d to '%s' (%s)",
178 arg, ar.name, extramsg);
...
–The End