80 Commits

Author SHA1 Message Date
Koushik Dutta
42364df8be Fix bug with JavaMember Varargs invocation. Coerce the element type, not Array. 2021-11-12 01:49:20 -05:00
yut23
8a05f69f50 Fix JavaMember varargs argument construction 2021-11-12 01:48:07 -05:00
Enyby
daf3da94e3 Fix #66: Broken license link. 2020-04-01 19:36:00 +03:00
Enyby
30e60a883e Create LICENSE
Source: https://web.archive.org/web/20140514153921/http://sourceforge.net/dbimage.php?id=196142
2020-04-01 19:31:39 +03:00
Enyby
27edcc9a92 Fix possible error in rare cases in LuaTable:
java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
2019-12-29 16:46:58 +02:00
Enyby
d6737c0bb3 Improve work with weak keys.
```
for _, m in ipairs({'', 'k', 'kv', 'v'}) do
	print('test', m)
	a = {}; setmetatable(a, {__mode = m});
	a[1], a[2], a[3] = {}, {}, {};
	for k, v in pairs(a) do
		print(k, v)
	end
end
print('ok')
```
2019-12-16 15:31:13 +02:00
Enyby
d201bc3012 Fix work with weak tables.
```
a = {}; setmetatable(a, {__mode = 'vk'});
a[1], a[2], a[3] = {}, {}, {};
for k, v in pairs(a) do
	print(k, v)
end
print('ok')
```
2019-12-15 20:39:26 +02:00
Enyby
ca64666242 Fix metamethods for compare with numbers.
```
t = {}
t.__lt = function (a,b,c)
  collectgarbage()
  assert(c == nil)
  if type(a) == 'table' then a = a.x end
  if type(b) == 'table' then b = b.x end
 return a<b, "dummy"
end

function Op(x) return setmetatable({x=x}, t) end

local function test ()
  assert(not(Op(1)<Op(1)) and (Op(1)<Op(2)) and not(Op(2)<Op(1)))
  assert(not(1 < Op(1)) and (Op(1) < 2) and not(2 < Op(1)))
  assert(not(Op('a')<Op('a')) and (Op('a')<Op('b')) and not(Op('b')<Op('a')))
  assert(not('a' < Op('a')) and (Op('a') < 'b') and not(Op('b') < Op('a')))
  assert((Op(1)<=Op(1)) and (Op(1)<=Op(2)) and not(Op(2)<=Op(1)))
  assert((Op('a')<=Op('a')) and (Op('a')<=Op('b')) and not(Op('b')<=Op('a')))
  assert(not(Op(1)>Op(1)) and not(Op(1)>Op(2)) and (Op(2)>Op(1)))
  assert(not(Op('a')>Op('a')) and not(Op('a')>Op('b')) and (Op('b')>Op('a')))
  assert((Op(1)>=Op(1)) and not(Op(1)>=Op(2)) and (Op(2)>=Op(1)))
  assert((1 >= Op(1)) and not(1 >= Op(2)) and (Op(2) >= 1))
  assert((Op('a')>=Op('a')) and not(Op('a')>=Op('b')) and (Op('b')>=Op('a')))
  assert(('a' >= Op('a')) and not(Op('a') >= 'b') and (Op('b') >= Op('a')))
end

test()
```
2019-11-11 02:47:19 +02:00
Enyby
725cf89b6f Fix metamethods for compare with string. 2019-11-11 02:29:20 +02:00
Enyby
da0b06555a Fix pattern error message. 2019-11-09 23:26:48 +02:00
Enyby
ee2d5284e7 Fix '%b' pattern error message. 2019-11-09 23:25:58 +02:00
Enyby
0f0ec4bf7b Add check for too complex patterns.
```
-- bug since 2.5 (C-stack overflow)
do
  local function f (size)
    local s = string.rep("a", size)
    local p = string.rep(".?", size)
    return pcall(string.match, s, p)
  end
  local r, m = f(80)
  assert(r and #m == 80)
  r, m = f(200000)
  assert(not r and string.find(m, "too complex"), tostring(r)..", "..tostring(m))
end
```
2019-11-09 23:25:07 +02:00
Enyby
5813d56f89 Improve error messages for invalid capture index. 2019-11-09 23:21:39 +02:00
Enyby
8c42c4712b Fix empty matches in patterns.
```
do   -- new (5.3.3) semantics for empty matches
  assert(string.gsub("a b cd", " *", "-") == "-a-b-c-d-")

  local res = ""
  local sub = "a  \nbc\t\td"
  local i = 1
  for p, e in string.gmatch(sub, "()%s*()") do
    res = res .. string.sub(sub, i, p - 1) .. "-"
    i = e
  end
  assert(res == "-a-b-c-d-")
end
```
2019-11-09 23:20:06 +02:00
Enyby
6bc8fd6b1b Fix numeric for add order. 2019-11-09 23:12:31 +02:00
Enyby
bf663878cb Add support for metatags to table lib methods: sort, insert, remove, unpack.
```
do   -- testing table library with metamethods
  local function test (proxy, t)
    for i = 1, 10 do
      table.insert(proxy, 1, i)
    end
    assert(#proxy == 10 and #t == 10, tostring(#proxy)..'; '..tostring(#t))
    for i = 1, 10 do
      assert(t[i] == 11 - i)
    end
    table.sort(proxy)
    for i = 1, 10 do
      assert(t[i] == i and proxy[i] == i, i..': '..tostring(proxy[i])..'; '..tostring(t[i]))
    end
    assert(table.concat(proxy, ",") == "1,2,3,4,5,6,7,8,9,10")
    for i = 1, 8 do
      assert(table.remove(proxy, 1) == i)
    end
    assert(#proxy == 2 and #t == 2)
    local a, b, c = table.unpack(proxy)
    assert(a == 9 and b == 10 and c == nil)
  end

  -- all virtual
  local t = {}
  local proxy = setmetatable({}, {
    __len = function () return #t end,
    __index = t,
    __newindex = t,
  })
  test(proxy, t)

  -- only __newindex
  local count = 0
  t = setmetatable({}, {
    __newindex = function (t,k,v) count = count + 1; rawset(t,k,v) end})
  test(t, t)
  assert(count == 10)   -- after first 10, all other sets are not new

  -- no __newindex
  t = setmetatable({}, {
    __index = function (_,k) return k + 1 end,
    __len = function (_) return 5 end})
  assert(table.concat(t, ";") == "2;3;4;5;6")

end

function check (a, f)
  f = f or function (x,y) return x<y end;
  for n = #a, 2, -1 do
    local cmp = f(a[n], a[n-1])
    if cmp then print(tostring(a)..'\n'..n..': "'..tostring(a[n])..'" < "'..tostring(a[n-1])..'"') end
    assert(not cmp)
  end
end

for b = 1, 2 do
	a = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
	     "Oct", "Nov", "Dec"}
	if b == 2 then a[15] = 'Aaa' a[14] = 'Iii' a[13] = 'Mmm' end
	print(#a)
	table.sort(a)
	check(a)
end
```
2019-11-04 07:57:49 +02:00
Enyby
e120008f9b Validate table.remove pos. 2019-11-03 16:08:01 +02:00
Enyby
9a20aa8077 Check pos bounds for table.insert. 2019-11-03 15:55:32 +02:00
Enyby
99f21b6277 Speed up table.sort. 2019-11-03 14:03:53 +02:00
Enyby
53bd4bf71f Fix compiler Bug{
what = [[label between local definitions can mix-up their initializations]],
report = [[Karel Tuma, 2016/03/01]],
since = [[5.2]],
fix = nil,
example = [[
do
  local k = 0
  local x
  ::foo::
  local y       -- should be reset to nil after goto, but it is not
  assert(not y)
  y = true
  k = k + 1
  if k < 2 then goto foo end
end
]],
patch = [[
--- lparser.c	2015/11/02 16:09:30	2.149
+++ lparser.c	2016/03/03 12:03:37
@@ -1226,7 +1226,7 @@
   checkrepeated(fs, ll, label);  /* check for repeated labels */
   checknext(ls, TK_DBCOLON);  /* skip double colon */
   /* create new entry for this label */
-  l = newlabelentry(ls, ll, label, line, fs->pc);
+  l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));
   skipnoopstat(ls);  /* skip other no-op statements */
   if (block_follow(ls, 0)) {  /* label is last no-op statement in the block? */
     /* assume that locals are already out of scope */
]]
}
2019-11-02 17:02:21 +02:00
Enyby
b57eb247ba Fix table.unpack. 2019-11-02 15:18:48 +02:00
Enyby
05e82f1c3f Add package.config. #49 2019-10-27 23:08:44 +02:00
Enyby
9b2f0a2805 Fix os.tmpname. 2019-10-22 07:00:21 +03:00
Enyby
ef8175050b Remove unused field. 2019-10-21 23:26:10 +03:00
Enyby
0d2aa6cc54 Switch little-endian by default as original Lua does. 2019-10-21 23:25:30 +03:00
Enyby
fe7bd07450 Fix lexer bugs.
Wrong work with spaces.
2019-10-21 10:20:06 +03:00
Enyby
f0e9348ae2 Fix lexer bugs.
Already handled by inside isalnum.
2019-10-21 10:17:26 +03:00
Enyby
22e7a8c620 Fix lexer bugs.
Already handled by case above.
2019-10-21 10:16:43 +03:00
Enyby
c8461b8128 Fix pattern classes in string lib.
```
local ref = {
}
for cl in string.gmatch('acdglpsuwxACDGLPSUWX', '.') do
	local list = ''
	for i = 0, 255 do
		if string.match(string.char(i), '%'..cl) then
			list = list..i..','
		end
	end
	if ref[cl] then
		assert(ref[cl] == list, cl..':\n'..list..'\n'..ref[cl])
	else
		print(cl..' = "'..list..'",')
	end
end

print('+')
```
2019-10-21 08:43:53 +03:00
Enyby
3a6c382570 Fix 'error' call. #60 2019-10-20 19:19:14 +03:00
Enyby
4db34780b7 Fix build error. 2019-10-20 18:43:10 +03:00
Enyby
ac3475deee Improved error messages for lib functions. 2019-10-20 07:19:34 +03:00
Enyby
af35c4d89e Improve error messages for base lib. 2019-10-20 07:17:46 +03:00
Enyby
c71f277697 Improve error messages for lib table. 2019-10-20 07:07:17 +03:00
Enyby
5fe0a3950d Improve get name for func. 2019-10-20 06:45:53 +03:00
Enyby
169202362e Fix error message for collectgarbage invalid option. 2019-10-20 00:34:54 +03:00
Enyby
5609d8c92b Add check mode for io.open. #57 2019-10-19 20:53:56 +03:00
Enyby
dbab0aed01 Fix odd varargs methods. 2019-10-14 18:33:25 +03:00
Enyby
f8d7731b56 Fix NPE on getobjname in some cases. 2019-10-14 14:12:08 +03:00
Enyby
2f5aa594bd Fix getobjname for get constant name if it stored on register. 2019-10-14 14:11:38 +03:00
Enyby
edfe1a5fde Add check for io.popen modes. 2019-10-13 06:16:21 +03:00
Enyby
6efb6f000e Improve error message for file:seek and file:setvbuf. 2019-10-13 05:58:32 +03:00
Enyby
f3b8a1eddc Fix default setvbuf size. 2019-10-12 19:12:44 +03:00
Enyby
20eca5760d Fix detect io lib read modes like file:read('*all'). 2019-10-12 17:57:37 +03:00
Enyby
3613bc0862 Add check for values passed to file:vsetbuf and file:seek. 2019-10-12 17:51:04 +03:00
Enyby
6985980572 Merge branch 'master' of https://github.com/luaj/luaj 2019-10-12 16:09:03 +03:00
Enyby
60d130cecc Fix corrupted args for io.lines and file:lines on reuse stack elements. 2019-10-12 16:08:36 +03:00
Enyby
b705eb05f4 Merge pull request #59 from Mikhael-Danilov/patch-1
Fix link
2019-10-07 21:53:17 +03:00
Mikhael-Danilov
d0bb0409a3 Fix link
Fix link to examples/android/src/android/LuajViewLuajView.java
2019-10-07 20:23:45 +03:00
Enyby
db58e1808b Fix load script from func. 2019-10-07 18:08:47 +03:00
Enyby
e2ede7f91c Fix call io.lines(nil, ...). 2019-10-07 17:11:13 +03:00
Enyby
a50deaa75c Fix raise error from io.lines and file:lines. 2019-10-07 14:52:12 +03:00
Enyby
f9f78b81da Allow read zero bytes in io lib methods. 2019-10-07 14:26:21 +03:00
Enyby
984fa30bf6 Fix read all stdin in JSE. 2019-10-07 00:25:07 +03:00
Enyby
65beda4c2b Fix read all at EOF. 2019-10-07 00:23:34 +03:00
Enyby
934a8fc57b Fix io.read(0) on EOF. 2019-10-06 23:49:04 +03:00
Enyby
832ec739ea Close not closed file on GC. #55
Relevant only for J2SE, not for J2ME.
2019-10-06 23:35:45 +03:00
Enyby
8345bee6b4 Fix io.lines and file:lines do not honor additional params. #52
Fix io.lines do not close file on EOF. #53
Improve error message for io.lines and file:lines on closed file.
2019-10-06 19:09:01 +03:00
Enyby
83f2e1d96a Fix io.read and file:read do not support '*L' format. #54 2019-10-06 18:53:15 +03:00
Enyby
14745ba76a Fix call io.read, file:read without params. 2019-10-06 18:40:31 +03:00
Enyby
c62ba1f22e File tostring respect closed. 2019-10-06 16:54:44 +03:00
Enyby
868928779f Fix rewrite io.input inside io.lines.
```
do
	local t = os.tmpname()
	local f = io.open(t, 'w')
	f:write('test')
	f:close()

	local i = io.input()
	for l in io.lines(t) do end
	local n = io.input()
	assert(n == i, tostring(n).." ~= "..tostring(i))
	os.remove(t)
	print('+')
end
```
2019-10-06 16:43:11 +03:00
Enyby
f383c27728 We not in C anymore. 2019-09-23 01:54:27 +03:00
Enyby
e7b11110a3 Raise lexerror if failed parse number as double. 2019-09-23 01:53:01 +03:00
Enyby
0fa27c3783 EOZ (-1) not a space char.
Fix bug with endless loop at not ended \z sequence.

```
local function lexerror (s, err)
  local st, msg = load('return ' .. s, '')
  if err ~= '<eof>' then err = err .. "'" end
  assert(not st and string.find(msg, "near .-" .. err))
end

lexerror("'alo \\z  \n\n", "<eof>")
```
2019-09-23 00:39:42 +03:00
Enyby
72a71e5a65 Merge branch 'master' of https://github.com/luaj/luaj 2019-09-21 07:18:37 +03:00
Enyby
6031d6b479 Fix lua error message on bad arg for 'load'. 2019-09-21 07:18:08 +03:00
Enyby
c1834733c1 Merge pull request #45 from zaoqi/patch-1
readme: fix typo
2019-08-10 02:18:32 +03:00
Zaoqi
10f88d2c31 readme: fix typo 2019-08-09 21:44:25 +08:00
Enyby
6d2deb4cb6 Fix use function as source for load call. 2019-08-05 04:07:09 +03:00
Enyby
5f52729fc9 Fix OP_JMP description. 2019-07-15 05:29:37 +03:00
Enyby
e6736857b6 Add support for OP_LOADKX. #43 2019-06-30 22:18:19 +03:00
Enyby
5c5176727a Merge branch 'master' of https://github.com/luaj/luaj 2019-05-05 17:23:27 +03:00
Enyby
7721380e20 Fix NPE on error. #40 2019-05-05 17:22:24 +03:00
Enyby
16aa199d40 Add debug info to build. 2019-05-05 17:21:25 +03:00
Enyby
177fe4e09f Fix path to build files in Readme.md 2019-03-17 03:12:52 +02:00
Enyby
a7c8a408ce Fix build bug. #33 2019-03-17 03:06:05 +02:00
Enyby
84b0dd171e Fix error messages for pass tests. 2019-03-09 23:35:22 +02:00
Enyby
898208365d Fix print for pass tests. 2019-03-09 23:18:47 +02:00
Enyby
ffb686556f Fix loadlib. 2019-03-09 23:00:28 +02:00
29 changed files with 2195 additions and 1994 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2007 LuaJ. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -12,16 +12,13 @@ on.<br>
-- Benjamin P. Jung, Jan. 26th 2018 -- Benjamin P. Jung, Jan. 26th 2018
</div> </div>
<h1>Getting Started with LuaJ</h1>
<h1>Getting Started with LuaJ</h1> <h1>Getting Started with LuaJ</h1>
James Roseborough, Ian Farmer, Version 3.0.2 James Roseborough, Ian Farmer, Version 3.0.2
<p> <p>
<small> <small>
Copyright &copy; 2009-2014 Luaj.org. Copyright &copy; 2009-2014 Luaj.org.
Freely available under the terms of the Freely available under the terms of the
<a href="http://sourceforge.net/dbimage.php?id=196142">Luaj license</a>. <a href="LICENSE">Luaj license</a>.
</small> </small>
<hr> <hr>
<p> <p>
@@ -186,7 +183,7 @@ It is also faster than Java-lua implementations Jill, Kahlua, and Mochalua for a
From the main distribution directory line type: From the main distribution directory line type:
<pre> <pre>
java -cp lib/luaj-jse-3.0.2.jar lua examples/lua/hello.lua java -cp luaj-jse-3.0.2.jar lua examples/lua/hello.lua
</pre> </pre>
<p> <p>
@@ -198,7 +195,7 @@ You should see the following output:
To see how luaj can be used to acccess most Java API's including swing, try: To see how luaj can be used to acccess most Java API's including swing, try:
<pre> <pre>
java -cp lib/luaj-jse-3.0.2.jar lua examples/lua/swingapp.lua java -cp luaj-jse-3.0.2.jar lua examples/lua/swingapp.lua
</pre> </pre>
<p> <p>
@@ -213,8 +210,8 @@ Links to sources:<pre>
From the main distribution directory line type: From the main distribution directory line type:
<pre> <pre>
java -cp lib/luaj-jse-3.0.2.jar luac examples/lua/hello.lua java -cp luaj-jse-3.0.2.jar luac examples/lua/hello.lua
java -cp lib/luaj-jse-3.0.2.jar lua luac.out java -cp luaj-jse-3.0.2.jar lua luac.out
</pre> </pre>
<p> <p>
@@ -228,8 +225,8 @@ Luaj can compile lua sources or binaries directly to java bytecode if the bcel l
<pre> <pre>
ant bcel-lib ant bcel-lib
java -cp &quot;lib/luaj-jse-3.0.2.jar;lib/bcel-5.2.jar&quot; luajc -s examples/lua -d . hello.lua java -cp &quot;luaj-jse-3.0.2.jar;lib/bcel-5.2.jar&quot; luajc -s examples/lua -d . hello.lua
java -cp &quot;lib/luaj-jse-3.0.2.jar;.&quot; lua -l hello java -cp &quot;luaj-jse-3.0.2.jar;.&quot; lua -l hello
</pre> </pre>
<p> <p>
@@ -240,7 +237,7 @@ but the compiled classes must be in the class path at runtime, unless runtime ji
<p> <p>
Lua scripts can also be run directly in this mode without precompiling using the <em>lua</em> command with the <b><em>-b</em></b> option and providing the <em>bcel</em> library in the class path: Lua scripts can also be run directly in this mode without precompiling using the <em>lua</em> command with the <b><em>-b</em></b> option and providing the <em>bcel</em> library in the class path:
<pre> <pre>
java -cp &quot;lib/luaj-jse-3.0.2.jar;lib/bcel-5.2.jar&quot; lua -b examples/lua/hello.lua java -cp &quot;luaj-jse-3.0.2.jar;lib/bcel-5.2.jar&quot; lua -b examples/lua/hello.lua
</pre> </pre>
@@ -284,7 +281,7 @@ A simple example may be found in
</pre> </pre>
<p> <p>
You must include the library <b>lib/luaj-jse-3.0.2.jar</b> in your class path. You must include the library <b>luaj-jse-3.0.2.jar</b> in your class path.
<h2>Run a script in a MIDlet</h2> <h2>Run a script in a MIDlet</h2>
@@ -311,7 +308,7 @@ A simple example may be found in
</pre> </pre>
<p> <p>
You must include the library <b>lib/luaj-jme-3.0.2.jar</b> in your midlet jar. You must include the library <b>luaj-jme-3.0.2.jar</b> in your midlet jar.
<p> <p>
An ant script to build and run the midlet is in An ant script to build and run the midlet is in
@@ -341,7 +338,7 @@ You can also look up the engine by language "lua" or mimetypes "text/lua" or "ap
All standard aspects of script engines including compiled statements are supported. All standard aspects of script engines including compiled statements are supported.
<p> <p>
You must include the library <b>lib/luaj-jse-3.0.2.jar</b> in your class path. You must include the library <b>luaj-jse-3.0.2.jar</b> in your class path.
<p> <p>
A working example may be found in A working example may be found in
@@ -352,8 +349,8 @@ A working example may be found in
To compile and run it using Java 1.6 or higher: To compile and run it using Java 1.6 or higher:
<pre> <pre>
javac -cp lib/luaj-jse-3.0.2.jar examples/jse/ScriptEngineSample.java javac -cp luaj-jse-3.0.2.jar examples/jse/ScriptEngineSample.java
java -cp &quot;lib/luaj-jse-3.0.2.jar;examples/jse&quot; ScriptEngineSample java -cp &quot;luaj-jse-3.0.2.jar;examples/jse&quot; ScriptEngineSample
</pre> </pre>
<h2>Excluding the lua bytecode compiler</h2> <h2>Excluding the lua bytecode compiler</h2>
@@ -415,7 +412,7 @@ and the math operations include all those supported by Java SE.
Android applications should use the JsePlatform, and can include the <a href="#luajava">Luajava</a> library Android applications should use the JsePlatform, and can include the <a href="#luajava">Luajava</a> library
to simplify access to underlying Android APIs. to simplify access to underlying Android APIs.
A specialized Globals.finder should be provided to find scripts and data for loading. A specialized Globals.finder should be provided to find scripts and data for loading.
See <a href="examples/android/src/android/LuajView">examples/android/src/android/LuajView</a> See <a href="examples/android/src/android/LuajView.java">examples/android/src/android/LuajView.java</a>
for an example that loads from the "res" Android project directory. for an example that loads from the "res" Android project directory.
The ant build script is <a href="examples/android/build.xml">examples/android/build.xml</a>. The ant build script is <a href="examples/android/build.xml">examples/android/build.xml</a>.
@@ -593,7 +590,7 @@ The following lua script will open a swing frame on Java SE:
See a longer sample in <em>examples/lua/swingapp.lua</em> for details, including a simple animation loop, rendering graphics, mouse and key handling, and image loading. See a longer sample in <em>examples/lua/swingapp.lua</em> for details, including a simple animation loop, rendering graphics, mouse and key handling, and image loading.
Or try running it using: Or try running it using:
<pre> <pre>
java -cp lib/luaj-jse-3.0.2.jar lua examples/lua/swingapp.lua java -cp luaj-jse-3.0.2.jar lua examples/lua/swingapp.lua
</pre> </pre>
<p> <p>
@@ -930,7 +927,7 @@ Files are no longer hosted at LuaForge.
<li>Enhance javadoc, put it <a href="docs/api/index.html">in distribution</a> <li>Enhance javadoc, put it <a href="docs/api/index.html">in distribution</a>
and at <a href="http://luaj.sourceforge.net/api/2.0/index.html">http://luaj.sourceforge.net/api/2.0/</a></li> and at <a href="http://luaj.sourceforge.net/api/2.0/index.html">http://luaj.sourceforge.net/api/2.0/</a></li>
<li>Major refactor of luajava type coercion logic, improve method selection.</li> <li>Major refactor of luajava type coercion logic, improve method selection.</li>
<li>Add lib/luaj-sources-2.0.2.jar for easier integration into an IDE such as Netbeans </li> <li>Add luaj-sources-2.0.2.jar for easier integration into an IDE such as Netbeans </li>
<tr valign="top"><td>&nbsp;&nbsp;<b>2.0.3</b></td><td><ul> <tr valign="top"><td>&nbsp;&nbsp;<b>2.0.3</b></td><td><ul>
<li>Improve coroutine state logic including let unreferenced coroutines be garbage collected </li> <li>Improve coroutine state logic including let unreferenced coroutines be garbage collected </li>

View File

@@ -82,17 +82,21 @@
<pathelement path="lib/mmapi.jar"/> <pathelement path="lib/mmapi.jar"/>
</path> </path>
<javac destdir="build/jme/classes" encoding="utf-8" source="1.3" target="1.2" bootclasspathref="wtk-libs" <javac destdir="build/jme/classes" encoding="utf-8" source="1.3" target="1.2" bootclasspathref="wtk-libs"
debug="on"
srcdir="build/jme/src"/> srcdir="build/jme/src"/>
<javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3" <javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3"
classpath="lib/bcel-5.2.jar" classpath="lib/bcel-5.2.jar"
debug="on"
srcdir="build/jse/src" srcdir="build/jse/src"
excludes="**/script/*,**/Lua2Java*,**/server/*,lua*"/> excludes="**/script/*,**/Lua2Java*,**/server/*,lua*"/>
<javac destdir="build/jse/classes" encoding="utf-8" source="1.5" target="1.5" <javac destdir="build/jse/classes" encoding="utf-8" source="1.5" target="1.5"
classpath="build/jse/classes" classpath="build/jse/classes"
debug="on"
srcdir="build/jse/src" srcdir="build/jse/src"
includes="**/script/*,**/Lua2Java*,**/server/*"/> includes="**/script/*,**/Lua2Java*,**/server/*"/>
<javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3" <javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3"
classpath="build/jse/classes" classpath="build/jse/classes"
debug="on"
srcdir="build/jse/src" srcdir="build/jse/src"
includes="lua*"/> includes="lua*"/>
</target> </target>

View File

@@ -155,7 +155,6 @@ public class LoadState {
private static final LuaValue[] NOVALUES = {}; private static final LuaValue[] NOVALUES = {};
private static final Prototype[] NOPROTOS = {}; private static final Prototype[] NOPROTOS = {};
private static final LocVars[] NOLOCVARS = {}; private static final LocVars[] NOLOCVARS = {};
private static final LuaString[] NOSTRVALUES = {};
private static final Upvaldesc[] NOUPVALDESCS = {}; private static final Upvaldesc[] NOUPVALDESCS = {};
private static final int[] NOINTS = {}; private static final int[] NOINTS = {};

View File

@@ -80,7 +80,6 @@ public class Lua {
public static final int POS_Bx = POS_C; public static final int POS_Bx = POS_C;
public static final int POS_Ax = POS_A; public static final int POS_Ax = POS_A;
public static final int MAX_OP = ((1<<SIZE_OP)-1); public static final int MAX_OP = ((1<<SIZE_OP)-1);
public static final int MAXARG_A = ((1<<SIZE_A)-1); public static final int MAXARG_A = ((1<<SIZE_A)-1);
public static final int MAXARG_B = ((1<<SIZE_B)-1); public static final int MAXARG_B = ((1<<SIZE_B)-1);
@@ -94,6 +93,7 @@ public class Lua {
public static final int MASK_B = ((1<<SIZE_B)-1)<<POS_B; public static final int MASK_B = ((1<<SIZE_B)-1)<<POS_B;
public static final int MASK_C = ((1<<SIZE_C)-1)<<POS_C; public static final int MASK_C = ((1<<SIZE_C)-1)<<POS_C;
public static final int MASK_Bx = ((1<<SIZE_Bx)-1)<<POS_Bx; public static final int MASK_Bx = ((1<<SIZE_Bx)-1)<<POS_Bx;
public static final int MASK_Ax = ((1<<SIZE_Ax)-1)<<POS_Ax;
public static final int MASK_NOT_OP = ~MASK_OP; public static final int MASK_NOT_OP = ~MASK_OP;
public static final int MASK_NOT_A = ~MASK_A; public static final int MASK_NOT_A = ~MASK_A;
@@ -208,7 +208,7 @@ public class Lua {
public static final int OP_CONCAT = 22; /* A B C R(A) := R(B).. ... ..R(C) */ public static final int OP_CONCAT = 22; /* A B C R(A) := R(B).. ... ..R(C) */
public static final int OP_JMP = 23; /* sBx pc+=sBx */ public static final int OP_JMP = 23; /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
public static final int OP_EQ = 24; /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ public static final int OP_EQ = 24; /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
public static final int OP_LT = 25; /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ public static final int OP_LT = 25; /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
public static final int OP_LE = 26; /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ public static final int OP_LE = 26; /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */

View File

@@ -21,6 +21,8 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
import org.luaj.vm2.lib.DebugLib.CallFrame;
/** /**
* Extension of {@link LuaFunction} which executes lua bytecode. * Extension of {@link LuaFunction} which executes lua bytecode.
* <p> * <p>
@@ -214,6 +216,17 @@ public class LuaClosure extends LuaFunction {
stack[a] = k[i>>>14]; stack[a] = k[i>>>14];
continue; continue;
case Lua.OP_LOADKX:/* A R(A) := Kst(extra arg) */
++pc;
i = code[pc];
if ((i & 0x3f) != Lua.OP_EXTRAARG) {
int op = i & 0x3f;
throw new LuaError("OP_EXTRAARG expected after OP_LOADKX, got " +
(op < Print.OPNAMES.length - 1 ? Print.OPNAMES[op] : "UNKNOWN_OP_" + op));
}
stack[a] = k[i>>>6];
continue;
case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */ case Lua.OP_LOADBOOL:/* A B C R(A):= (Bool)B: if (C) pc++ */
stack[a] = (i>>>23!=0)? LuaValue.TRUE: LuaValue.FALSE; stack[a] = (i>>>23!=0)? LuaValue.TRUE: LuaValue.FALSE;
if ((i&(0x1ff<<14)) != 0) if ((i&(0x1ff<<14)) != 0)
@@ -309,7 +322,7 @@ public class LuaClosure extends LuaFunction {
} }
continue; continue;
case Lua.OP_JMP: /* sBx pc+=sBx */ case Lua.OP_JMP: /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
pc += (i>>>14)-0x1ffff; pc += (i>>>14)-0x1ffff;
if (a > 0) { if (a > 0) {
for (--a, b = openups.length; --b>=0; ) for (--a, b = openups.length; --b>=0; )
@@ -404,7 +417,7 @@ public class LuaClosure extends LuaFunction {
{ {
LuaValue limit = stack[a + 1]; LuaValue limit = stack[a + 1];
LuaValue step = stack[a + 2]; LuaValue step = stack[a + 2];
LuaValue idx = step.add(stack[a]); LuaValue idx = stack[a].add(step);
if (step.gt_b(0)? idx.lteq_b(limit): idx.gteq_b(limit)) { if (step.gt_b(0)? idx.lteq_b(limit): idx.gteq_b(limit)) {
stack[a] = idx; stack[a] = idx;
stack[a + 3] = idx; stack[a + 3] = idx;
@@ -536,8 +549,24 @@ public class LuaClosure extends LuaFunction {
} }
private void processErrorHooks(LuaError le, Prototype p, int pc) { private void processErrorHooks(LuaError le, Prototype p, int pc) {
le.fileline = (p.source != null? p.source.tojstring(): "?") + ":" String file = "?";
+ (p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length? String.valueOf(p.lineinfo[pc]): "?"); int line = -1;
{
CallFrame frame = null;
if (globals != null && globals.debuglib != null) {
frame = globals.debuglib.getCallFrame(le.level);
if (frame != null) {
String src = frame.shortsource();
file = src != null ? src : "?";
line = frame.currentline();
}
}
if (frame == null) {
file = p.source != null? p.source.tojstring(): "?";
line = p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length ? p.lineinfo[pc] : -1;
}
}
le.fileline = file + ":" + line;
le.traceback = errorHook(le.getMessage(), le.level); le.traceback = errorHook(le.getMessage(), le.level);
} }

View File

@@ -206,28 +206,28 @@ public class LuaDouble extends LuaNumber {
} }
// relational operators // relational operators
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? LuaValue.TRUE: FALSE; } public LuaValue lt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gt_b(v)? TRUE: FALSE) : super.lt(rhs); }
public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; }
public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; }
public boolean lt_b( LuaValue rhs ) { return rhs.gt_b(v); } public boolean lt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gt_b(v) : super.lt_b(rhs); }
public boolean lt_b( int rhs ) { return v < rhs; } public boolean lt_b( int rhs ) { return v < rhs; }
public boolean lt_b( double rhs ) { return v < rhs; } public boolean lt_b( double rhs ) { return v < rhs; }
public LuaValue lteq( LuaValue rhs ) { return rhs.gteq_b(v)? LuaValue.TRUE: FALSE; } public LuaValue lteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gteq_b(v)? TRUE: FALSE) : super.lteq(rhs); }
public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; }
public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; }
public boolean lteq_b( LuaValue rhs ) { return rhs.gteq_b(v); } public boolean lteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gteq_b(v) : super.lteq_b(rhs); }
public boolean lteq_b( int rhs ) { return v <= rhs; } public boolean lteq_b( int rhs ) { return v <= rhs; }
public boolean lteq_b( double rhs ) { return v <= rhs; } public boolean lteq_b( double rhs ) { return v <= rhs; }
public LuaValue gt( LuaValue rhs ) { return rhs.lt_b(v)? LuaValue.TRUE: FALSE; } public LuaValue gt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lt_b(v)? TRUE: FALSE) : super.gt(rhs); }
public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; }
public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; }
public boolean gt_b( LuaValue rhs ) { return rhs.lt_b(v); } public boolean gt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lt_b(v) : super.gt_b(rhs); }
public boolean gt_b( int rhs ) { return v > rhs; } public boolean gt_b( int rhs ) { return v > rhs; }
public boolean gt_b( double rhs ) { return v > rhs; } public boolean gt_b( double rhs ) { return v > rhs; }
public LuaValue gteq( LuaValue rhs ) { return rhs.lteq_b(v)? LuaValue.TRUE: FALSE; } public LuaValue gteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lteq_b(v)? TRUE: FALSE) : super.gteq(rhs); }
public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; }
public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; }
public boolean gteq_b( LuaValue rhs ) { return rhs.lteq_b(v); } public boolean gteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lteq_b(v) : super.gteq_b(rhs); }
public boolean gteq_b( int rhs ) { return v >= rhs; } public boolean gteq_b( int rhs ) { return v >= rhs; }
public boolean gteq_b( double rhs ) { return v >= rhs; } public boolean gteq_b( double rhs ) { return v >= rhs; }

View File

@@ -74,10 +74,13 @@ public class LuaFunction extends LuaValue {
/** Return the last part of the class name, to be used as a function name in tojstring and elsewhere. /** Return the last part of the class name, to be used as a function name in tojstring and elsewhere.
* @return String naming the last part of the class name after the last dot (.) or dollar sign ($). * @return String naming the last part of the class name after the last dot (.) or dollar sign ($).
* If the first character is '_', it is skipped.
*/ */
public String classnamestub() { public String classnamestub() {
String s = getClass().getName(); String s = getClass().getName();
return s.substring(Math.max(s.lastIndexOf('.'),s.lastIndexOf('$'))+1); int offset = Math.max(s.lastIndexOf('.'), s.lastIndexOf('$')) + 1;
if (s.charAt(offset) == '_') offset++;
return s.substring(offset);
} }
/** Return a human-readable name for this function. Returns the last part of the class name by default. /** Return a human-readable name for this function. Returns the last part of the class name by default.

View File

@@ -172,28 +172,28 @@ public class LuaInteger extends LuaNumber {
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); } public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
// relational operators // relational operators
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? TRUE: FALSE; } public LuaValue lt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gt_b(v)? TRUE: FALSE) : super.lt(rhs); }
public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; }
public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; }
public boolean lt_b( LuaValue rhs ) { return rhs.gt_b(v); } public boolean lt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gt_b(v) : super.lt_b(rhs); }
public boolean lt_b( int rhs ) { return v < rhs; } public boolean lt_b( int rhs ) { return v < rhs; }
public boolean lt_b( double rhs ) { return v < rhs; } public boolean lt_b( double rhs ) { return v < rhs; }
public LuaValue lteq( LuaValue rhs ) { return rhs.gteq_b(v)? TRUE: FALSE; } public LuaValue lteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gteq_b(v)? TRUE: FALSE) : super.lteq(rhs); }
public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; }
public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; }
public boolean lteq_b( LuaValue rhs ) { return rhs.gteq_b(v); } public boolean lteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gteq_b(v) : super.lteq_b(rhs); }
public boolean lteq_b( int rhs ) { return v <= rhs; } public boolean lteq_b( int rhs ) { return v <= rhs; }
public boolean lteq_b( double rhs ) { return v <= rhs; } public boolean lteq_b( double rhs ) { return v <= rhs; }
public LuaValue gt( LuaValue rhs ) { return rhs.lt_b(v)? TRUE: FALSE; } public LuaValue gt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lt_b(v)? TRUE: FALSE) : super.gt(rhs); }
public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; }
public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; }
public boolean gt_b( LuaValue rhs ) { return rhs.lt_b(v); } public boolean gt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lt_b(v) : super.gt_b(rhs); }
public boolean gt_b( int rhs ) { return v > rhs; } public boolean gt_b( int rhs ) { return v > rhs; }
public boolean gt_b( double rhs ) { return v > rhs; } public boolean gt_b( double rhs ) { return v > rhs; }
public LuaValue gteq( LuaValue rhs ) { return rhs.lteq_b(v)? TRUE: FALSE; } public LuaValue gteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lteq_b(v)? TRUE: FALSE) : super.gteq(rhs); }
public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; }
public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; }
public boolean gteq_b( LuaValue rhs ) { return rhs.lteq_b(v); } public boolean gteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lteq_b(v) : super.gteq_b(rhs); }
public boolean gteq_b( int rhs ) { return v >= rhs; } public boolean gteq_b( int rhs ) { return v >= rhs; }
public boolean gteq_b( double rhs ) { return v >= rhs; } public boolean gteq_b( double rhs ) { return v >= rhs; }

View File

@@ -289,20 +289,20 @@ public class LuaString extends LuaValue {
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs, checkarith()); } public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs, checkarith()); }
// relational operators, these only work with other strings // relational operators, these only work with other strings
public LuaValue lt( LuaValue rhs ) { return rhs.strcmp(this)>0? LuaValue.TRUE: FALSE; } public LuaValue lt( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)>0? LuaValue.TRUE: FALSE) : super.lt(rhs); }
public boolean lt_b( LuaValue rhs ) { return rhs.strcmp(this)>0; } public boolean lt_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)>0 : super.lt_b(rhs); }
public boolean lt_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean lt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean lt_b( double rhs ) { typerror("attempt to compare string with number"); return false; } public boolean lt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
public LuaValue lteq( LuaValue rhs ) { return rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE; } public LuaValue lteq( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE) : super.lteq(rhs); }
public boolean lteq_b( LuaValue rhs ) { return rhs.strcmp(this)>=0; } public boolean lteq_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)>=0 : super.lteq_b(rhs); }
public boolean lteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean lteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean lteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; } public boolean lteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
public LuaValue gt( LuaValue rhs ) { return rhs.strcmp(this)<0? LuaValue.TRUE: FALSE; } public LuaValue gt( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)<0? LuaValue.TRUE: FALSE) : super.gt(rhs); }
public boolean gt_b( LuaValue rhs ) { return rhs.strcmp(this)<0; } public boolean gt_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)<0 : super.gt_b(rhs); }
public boolean gt_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean gt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean gt_b( double rhs ) { typerror("attempt to compare string with number"); return false; } public boolean gt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
public LuaValue gteq( LuaValue rhs ) { return rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE; } public LuaValue gteq( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE) : super.gteq(rhs); }
public boolean gteq_b( LuaValue rhs ) { return rhs.strcmp(this)<=0; } public boolean gteq_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)<=0 : super.gteq_b(rhs); }
public boolean gteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean gteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean gteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; } public boolean gteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }

View File

@@ -299,15 +299,15 @@ public class LuaTable extends LuaValue implements Metatable {
* @return The removed item, or {@link #NONE} if not removed * @return The removed item, or {@link #NONE} if not removed
*/ */
public LuaValue remove(int pos) { public LuaValue remove(int pos) {
int n = rawlen(); int n = length();
if ( pos == 0 ) if ( pos == 0 )
pos = n; pos = n;
else if (pos > n) else if (pos > n)
return NONE; return NONE;
LuaValue v = rawget(pos); LuaValue v = get(pos);
for ( LuaValue r=v; !r.isnil(); ) { for ( LuaValue r=v; !r.isnil(); ) {
r = rawget(pos+1); r = get(pos+1);
rawset(pos++, r); set(pos++, r);
} }
return v.isnil()? NONE: v; return v.isnil()? NONE: v;
} }
@@ -319,10 +319,10 @@ public class LuaTable extends LuaValue implements Metatable {
*/ */
public void insert(int pos, LuaValue value) { public void insert(int pos, LuaValue value) {
if ( pos == 0 ) if ( pos == 0 )
pos = rawlen()+1; pos = length()+1;
while ( ! value.isnil() ) { while ( ! value.isnil() ) {
LuaValue v = rawget( pos ); LuaValue v = get( pos );
rawset(pos++, value); set(pos++, value);
value = v; value = v;
} }
} }
@@ -472,7 +472,8 @@ public class LuaTable extends LuaValue implements Metatable {
} }
} }
if ( checkLoadFactor() ) { if ( checkLoadFactor() ) {
if ( key.isinttype() && key.toint() > 0 ) { if ( (m_metatable == null || !m_metatable.useWeakValues())
&& key.isinttype() && key.toint() > 0 ) {
// a rehash might make room in the array portion for this key. // a rehash might make room in the array portion for this key.
rehash( key.toint() ); rehash( key.toint() );
if ( arrayset(key.toint(), value) ) if ( arrayset(key.toint(), value) )
@@ -719,7 +720,7 @@ public class LuaTable extends LuaValue implements Metatable {
StrongSlot entry = slot.first(); StrongSlot entry = slot.first();
if (entry != null) if (entry != null)
newArray[ k - 1 ] = entry.value(); newArray[ k - 1 ] = entry.value();
} else { } else if ( !(slot instanceof DeadSlot) ) {
int j = slot.keyindex( newHashMask ); int j = slot.keyindex( newHashMask );
newHash[j] = slot.relink( newHash[j] ); newHash[j] = slot.relink( newHash[j] );
} }
@@ -789,33 +790,35 @@ public class LuaTable extends LuaValue implements Metatable {
if (m_metatable != null && m_metatable.useWeakValues()) { if (m_metatable != null && m_metatable.useWeakValues()) {
dropWeakArrayValues(); dropWeakArrayValues();
} }
int n = array.length; int n = length();
while ( n > 0 && array[n-1] == null )
--n;
if ( n > 1 ) if ( n > 1 )
heapSort(n, comparator); heapSort(n, comparator.isnil() ? null : comparator);
} }
private void heapSort(int count, LuaValue cmpfunc) { private void heapSort(int count, LuaValue cmpfunc) {
heapify(count, cmpfunc); heapify(count, cmpfunc);
for ( int end=count-1; end>0; ) { for ( int end=count; end>1; ) {
swap(end, 0); LuaValue a = get(end); // swap(end, 1)
siftDown(0, --end, cmpfunc); set(end, get(1));
set(1, a);
siftDown(1, --end, cmpfunc);
} }
} }
private void heapify(int count, LuaValue cmpfunc) { private void heapify(int count, LuaValue cmpfunc) {
for ( int start=count/2-1; start>=0; --start ) for ( int start=count/2; start>0; --start )
siftDown(start, count - 1, cmpfunc); siftDown(start, count, cmpfunc);
} }
private void siftDown(int start, int end, LuaValue cmpfunc) { private void siftDown(int start, int end, LuaValue cmpfunc) {
for ( int root=start; root*2+1 <= end; ) { for ( int root=start; root*2 <= end; ) {
int child = root*2+1; int child = root*2;
if (child < end && compare(child, child + 1, cmpfunc)) if (child < end && compare(child, child + 1, cmpfunc))
++child; ++child;
if (compare(root, child, cmpfunc)) { if (compare(root, child, cmpfunc)) {
swap(root, child); LuaValue a = get(root); // swap(root, child)
set(root, get(child));
set(child, a);
root = child; root = child;
} else } else
return; return;
@@ -823,29 +826,16 @@ public class LuaTable extends LuaValue implements Metatable {
} }
private boolean compare(int i, int j, LuaValue cmpfunc) { private boolean compare(int i, int j, LuaValue cmpfunc) {
LuaValue a, b; LuaValue a = get(i), b = get(j);
if (m_metatable == null) {
a = array[i];
b = array[j];
} else {
a = m_metatable.arrayget(array, i);
b = m_metatable.arrayget(array, j);
}
if ( a == null || b == null ) if ( a == null || b == null )
return false; return false;
if ( ! cmpfunc.isnil() ) { if ( cmpfunc != null ) {
return cmpfunc.call(a,b).toboolean(); return cmpfunc.call(a,b).toboolean();
} else { } else {
return a.lt_b(b); return a.lt_b(b);
} }
} }
private void swap(int i, int j) {
LuaValue a = array[i];
array[i] = array[j];
array[j] = a;
}
/** This may be deprecated in a future release. /** This may be deprecated in a future release.
* It is recommended to count via iteration over next() instead * It is recommended to count via iteration over next() instead
* @return count of keys in the table * @return count of keys in the table

View File

@@ -21,8 +21,6 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2; package org.luaj.vm2;
import org.luaj.vm2.Varargs;
/** /**
* Base class for all concrete lua type values. * Base class for all concrete lua type values.
* <p> * <p>
@@ -3362,7 +3360,7 @@ public class LuaValue extends Varargs {
protected LuaValue checkmetatag(LuaValue tag, String reason) { protected LuaValue checkmetatag(LuaValue tag, String reason) {
LuaValue h = this.metatag(tag); LuaValue h = this.metatag(tag);
if ( h.isnil() ) if ( h.isnil() )
throw new LuaError(reason+typename()); throw new LuaError(reason + "a " + typename() + " value");
return h; return h;
} }

View File

@@ -291,7 +291,7 @@ public abstract class Varargs {
* @return java double value if argument i is a number or string that converts to a number * @return java double value if argument i is a number or string that converts to a number
* @exception LuaError if the argument is not a number * @exception LuaError if the argument is not a number
* */ * */
public double checkdouble(int i) { return arg(i).checknumber().todouble(); } public double checkdouble(int i) { return arg(i).checkdouble(); }
/** Return argument i as a function, or throw an error if an incompatible type. /** Return argument i as a function, or throw an error if an incompatible type.
* @param i the index of the argument to test, 1 is the first argument * @param i the index of the argument to test, 1 is the first argument
@@ -300,12 +300,12 @@ public abstract class Varargs {
* */ * */
public LuaFunction checkfunction(int i) { return arg(i).checkfunction(); } public LuaFunction checkfunction(int i) { return arg(i).checkfunction(); }
/** Return argument i as a java int value, discarding any fractional part, or throw an error if not a number. /** Return argument i as a java int value, or throw an error if it cannot be converted to one.
* @param i the index of the argument to test, 1 is the first argument * @param i the index of the argument to test, 1 is the first argument
* @return int value with fraction discarded and truncated if necessary if argument i is number * @return int value if argument i is a number or string that converts to a number
* @exception LuaError if the argument is not a number * @exception LuaError if the argument cannot be represented by a java int value
* */ * */
public int checkint(int i) { return arg(i).checknumber().toint(); } public int checkint(int i) { return arg(i).checkint(); }
/** Return argument i as a java int value, or throw an error if not a number or is not representable by a java int. /** Return argument i as a java int value, or throw an error if not a number or is not representable by a java int.
* @param i the index of the argument to test, 1 is the first argument * @param i the index of the argument to test, 1 is the first argument
@@ -314,12 +314,12 @@ public abstract class Varargs {
* */ * */
public LuaInteger checkinteger(int i) { return arg(i).checkinteger(); } public LuaInteger checkinteger(int i) { return arg(i).checkinteger(); }
/** Return argument i as a java long value, discarding any fractional part, or throw an error if not a number. /** Return argument i as a java long value, or throw an error if it cannot be converted to one.
* @param i the index of the argument to test, 1 is the first argument * @param i the index of the argument to test, 1 is the first argument
* @return long value with fraction discarded and truncated if necessary if argument i is number * @return long value if argument i is a number or string that converts to a number
* @exception LuaError if the argument is not a number * @exception LuaError if the argument cannot be represented by a java long value
* */ * */
public long checklong(int i) { return arg(i).checknumber().tolong(); } public long checklong(int i) { return arg(i).checklong(); }
/** Return argument i as a LuaNumber, or throw an error if not a number or string that can be converted to a number. /** Return argument i as a LuaNumber, or throw an error if not a number or string that can be converted to a number.
* @param i the index of the argument to test, 1 is the first argument * @param i the index of the argument to test, 1 is the first argument
@@ -707,8 +707,10 @@ public abstract class Varargs {
/** Return Varargs that cannot be using a shared array for the storage, and is flattened. /** Return Varargs that cannot be using a shared array for the storage, and is flattened.
* Internal utility method not intended to be called directly from user code. * Internal utility method not intended to be called directly from user code.
* @return Varargs containing same values, but flattened and with a new array if needed. * @return Varargs containing same values, but flattened and with a new array if needed.
* @exclude
* @hide
*/ */
Varargs dealias() { public Varargs dealias() {
int n = narg(); int n = narg();
switch (n) { switch (n) {
case 0: return LuaValue.NONE; case 0: return LuaValue.NONE;

View File

@@ -105,6 +105,11 @@ public class Constants extends Lua {
((bc << POS_Bx) & MASK_Bx) ; ((bc << POS_Bx) & MASK_Bx) ;
} }
static int CREATE_Ax(int o, int a) {
return ((o << POS_OP) & MASK_OP) |
((a << POS_Ax) & MASK_Ax) ;
}
// vector reallocation // vector reallocation
static LuaValue[] realloc(LuaValue[] v, int n) { static LuaValue[] realloc(LuaValue[] v, int n) {

View File

@@ -28,9 +28,9 @@ import java.io.OutputStream;
import org.luaj.vm2.Globals; import org.luaj.vm2.Globals;
import org.luaj.vm2.LoadState; import org.luaj.vm2.LoadState;
import org.luaj.vm2.LocVars; import org.luaj.vm2.LocVars;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.LuaString; import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Prototype;
/** Class to dump a {@link Prototype} into an output stream, as part of compiling. /** Class to dump a {@link Prototype} into an output stream, as part of compiling.
@@ -85,7 +85,7 @@ public class DumpState {
public static final int NUMBER_FORMAT_DEFAULT = NUMBER_FORMAT_FLOATS_OR_DOUBLES; public static final int NUMBER_FORMAT_DEFAULT = NUMBER_FORMAT_FLOATS_OR_DOUBLES;
// header fields // header fields
private boolean IS_LITTLE_ENDIAN = false; private boolean IS_LITTLE_ENDIAN = true;
private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT; private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT;
private int SIZEOF_LUA_NUMBER = 8; private int SIZEOF_LUA_NUMBER = 8;
private static final int SIZEOF_INT = 4; private static final int SIZEOF_INT = 4;

View File

@@ -50,7 +50,6 @@ public class FuncState extends Constants {
Hashtable h; /* table to find (and reuse) elements in `k' */ Hashtable h; /* table to find (and reuse) elements in `k' */
FuncState prev; /* enclosing function */ FuncState prev; /* enclosing function */
LexState ls; /* lexical state */ LexState ls; /* lexical state */
LuaC.CompileState L; /* compiler being invoked */
BlockCnt bl; /* chain of current blocks */ BlockCnt bl; /* chain of current blocks */
int pc; /* next position to code (equivalent to `ncode') */ int pc; /* next position to code (equivalent to `ncode') */
int lasttarget; /* `pc' of last `jump target' */ int lasttarget; /* `pc' of last `jump target' */
@@ -113,8 +112,8 @@ public class FuncState extends Constants {
void errorlimit (int limit, String what) { void errorlimit (int limit, String what) {
// TODO: report message logic. // TODO: report message logic.
String msg = (f.linedefined == 0) ? String msg = (f.linedefined == 0) ?
L.pushfstring("main function has more than "+limit+" "+what) : ls.L.pushfstring("main function has more than "+limit+" "+what) :
L.pushfstring("function at line "+f.linedefined+" has more than "+limit+" "+what); ls.L.pushfstring("function at line "+f.linedefined+" has more than "+limit+" "+what);
ls.lexerror(msg, 0); ls.lexerror(msg, 0);
} }
@@ -581,11 +580,11 @@ public class FuncState extends Constants {
break; break;
} }
case LexState.VK: { case LexState.VK: {
this.codeABx(OP_LOADK, reg, e.u.info); this.codeK(reg, e.u.info);
break; break;
} }
case LexState.VKNUM: { case LexState.VKNUM: {
this.codeABx(OP_LOADK, reg, this.numberK(e.u.nval())); this.codeK(reg, this.numberK(e.u.nval()));
break; break;
} }
case LexState.VRELOCABLE: { case LexState.VRELOCABLE: {
@@ -1117,6 +1116,20 @@ public class FuncState extends Constants {
return this.code(CREATE_ABx(o, a, bc), this.ls.lastline); return this.code(CREATE_ABx(o, a, bc), this.ls.lastline);
} }
int codeextraarg(int a) {
_assert(a <= MAXARG_Ax);
return this.code(CREATE_Ax(OP_EXTRAARG, a), this.ls.lastline);
}
int codeK(int reg, int k) {
if (k <= MAXARG_Bx)
return codeABx(OP_LOADK, reg, k);
else {
int p = codeABx(OP_LOADKX, reg, 0);
codeextraarg(k);
return p;
}
}
void setlist(int base, int nelems, int tostore) { void setlist(int base, int nelems, int tostore) {
int c = (nelems - 1) / LFIELDS_PER_FLUSH + 1; int c = (nelems - 1) / LFIELDS_PER_FLUSH + 1;

View File

@@ -198,7 +198,7 @@ public class LexState extends Constants {
} }
private boolean isspace(int c) { private boolean isspace(int c) {
return (c <= ' '); return (c >= 0 && c <= ' ');
} }
@@ -388,8 +388,13 @@ public class LexState extends Constants {
seminfo.r = LuaValue.ZERO; seminfo.r = LuaValue.ZERO;
else if (str.indexOf('x')>=0 || str.indexOf('X')>=0) else if (str.indexOf('x')>=0 || str.indexOf('X')>=0)
seminfo.r = strx2number(str, seminfo); seminfo.r = strx2number(str, seminfo);
else else {
seminfo.r = LuaValue.valueOf(Double.parseDouble(str.trim())); try {
seminfo.r = LuaValue.valueOf(Double.parseDouble(str.trim()));
} catch (NumberFormatException e) {
lexerror("malformed number (" + e.getMessage() + ")", TK_NUMBER);
}
}
return true; return true;
} }
@@ -408,7 +413,6 @@ public class LexState extends Constants {
else else
break; break;
} }
save('\0');
String str = new String(buff, 0, nbuff); String str = new String(buff, 0, nbuff);
str2d(str, seminfo); str2d(str, seminfo);
} }
@@ -585,6 +589,13 @@ public class LexState extends Constants {
inclinenumber(); inclinenumber();
continue; continue;
} }
case ' ':
case '\f':
case '\t':
case 0x0B: /* \v */ {
nextChar();
continue;
}
case '-': { case '-': {
nextChar(); nextChar();
if (current != '-') if (current != '-')
@@ -688,19 +699,12 @@ public class LexState extends Constants {
return TK_EOS; return TK_EOS;
} }
default: { default: {
if (isspace(current)) { if (isalpha(current) || current == '_') {
_assert (!currIsNewline());
nextChar();
continue;
} else if (isdigit(current)) {
read_numeral(seminfo);
return TK_NUMBER;
} else if (isalpha(current) || current == '_') {
/* identifier or reserved word */ /* identifier or reserved word */
LuaString ts; LuaString ts;
do { do {
save_and_next(); save_and_next();
} while (isalnum(current) || current == '_'); } while (isalnum(current));
ts = newstring(buff, 0, nbuff); ts = newstring(buff, 0, nbuff);
if ( RESERVED.containsKey(ts) ) if ( RESERVED.containsKey(ts) )
return ((Integer)RESERVED.get(ts)).intValue(); return ((Integer)RESERVED.get(ts)).intValue();
@@ -1744,7 +1748,7 @@ public class LexState extends Constants {
fs.checkrepeated(dyd.label, dyd.n_label, label); /* check for repeated labels */ fs.checkrepeated(dyd.label, dyd.n_label, label); /* check for repeated labels */
checknext(TK_DBCOLON); /* skip double colon */ checknext(TK_DBCOLON); /* skip double colon */
/* create new entry for this label */ /* create new entry for this label */
l = newlabelentry(dyd.label=grow(dyd.label, dyd.n_label+1), dyd.n_label++, label, line, fs.pc); l = newlabelentry(dyd.label=grow(dyd.label, dyd.n_label+1), dyd.n_label++, label, line, fs.getlabel());
skipnoopstat(); /* skip other no-op statements */ skipnoopstat(); /* skip other no-op statements */
if (block_follow(false)) { /* label is last no-op statement in the block? */ if (block_follow(false)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */ /* assume that locals are already out of scope */
@@ -1845,7 +1849,7 @@ public class LexState extends Constants {
if (this.testnext(',')) if (this.testnext(','))
this.exp1(); /* optional step */ this.exp1(); /* optional step */
else { /* default step = 1 */ else { /* default step = 1 */
fs.codeABx(Lua.OP_LOADK, fs.freereg, fs.numberK(LuaInteger.valueOf(1))); fs.codeK(fs.freereg, fs.numberK(LuaInteger.valueOf(1)));
fs.reserveregs(1); fs.reserveregs(1);
} }
this.forbody(base, line, 1, true); this.forbody(base, line, 1, true);

View File

@@ -152,7 +152,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
System.gc(); System.gc();
return LuaValue.TRUE; return LuaValue.TRUE;
} else { } else {
this.argerror("gc op"); argerror(1, "invalid option '" + s + "'");
} }
return NIL; return NIL;
} }
@@ -173,16 +173,16 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "error", // ( message [,level] ) -> ERR // "error", // ( message [,level] ) -> ERR
static final class error extends TwoArgFunction { static final class error extends TwoArgFunction {
public LuaValue call(LuaValue arg1, LuaValue arg2) { public LuaValue call(LuaValue arg1, LuaValue arg2) {
throw arg1.isnil()? new LuaError(null, arg2.optint(1)): if (arg1.isnil()) throw new LuaError(NIL);
arg1.isstring()? new LuaError(arg1.tojstring(), arg2.optint(1)): if (!arg1.isstring() || arg2.optint(1) == 0) throw new LuaError(arg1);
new LuaError(arg1); throw new LuaError(arg1.tojstring(), arg2.optint(1));
} }
} }
// "getmetatable", // ( object ) -> table // "getmetatable", // ( object ) -> table
static final class getmetatable extends LibFunction { static final class getmetatable extends LibFunction {
public LuaValue call() { public LuaValue call() {
return argerror(1, "value"); return argerror(1, "value expected");
} }
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
LuaValue mt = arg.getmetatable(); LuaValue mt = arg.getmetatable();
@@ -193,7 +193,9 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
final class load extends VarArgFunction { final class load extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaValue ld = args.arg1(); LuaValue ld = args.arg1();
args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function"); if (!ld.isstring() && !ld.isfunction()) {
throw new LuaError("bad argument #1 to 'load' (string or function expected, got " + ld.typename() + ")");
}
String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)"); String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)");
String mode = args.optjstring(3, "bt"); String mode = args.optjstring(3, "bt");
LuaValue env = args.optvalue(4, globals); LuaValue env = args.optvalue(4, globals);
@@ -245,11 +247,11 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaValue tostring = globals.get("tostring"); LuaValue tostring = globals.get("tostring");
for ( int i=1, n=args.narg(); i<=n; i++ ) { for ( int i=1, n=args.narg(); i<=n; i++ ) {
if ( i>1 ) globals.STDOUT.print( " \t" ); if ( i>1 ) globals.STDOUT.print( '\t' );
LuaString s = tostring.call( args.arg(i) ).strvalue(); LuaString s = tostring.call( args.arg(i) ).strvalue();
globals.STDOUT.print(s.tojstring()); globals.STDOUT.print(s.tojstring());
} }
globals.STDOUT.println(); globals.STDOUT.print('\n');
return NONE; return NONE;
} }
} }
@@ -258,10 +260,10 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "rawequal", // (v1, v2) -> boolean // "rawequal", // (v1, v2) -> boolean
static final class rawequal extends LibFunction { static final class rawequal extends LibFunction {
public LuaValue call() { public LuaValue call() {
return argerror(1, "value"); return argerror(1, "value expected");
} }
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
return argerror(2, "value"); return argerror(2, "value expected");
} }
public LuaValue call(LuaValue arg1, LuaValue arg2) { public LuaValue call(LuaValue arg1, LuaValue arg2) {
return valueOf(arg1.raweq(arg2)); return valueOf(arg1.raweq(arg2));
@@ -269,12 +271,9 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
} }
// "rawget", // (table, index) -> value // "rawget", // (table, index) -> value
static final class rawget extends LibFunction { static final class rawget extends TableLibFunction {
public LuaValue call() {
return argerror(1, "value");
}
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue arg) {
return argerror(2, "value"); return argerror(2, "value expected");
} }
public LuaValue call(LuaValue arg1, LuaValue arg2) { public LuaValue call(LuaValue arg1, LuaValue arg2) {
return arg1.checktable().rawget(arg2); return arg1.checktable().rawget(arg2);
@@ -290,16 +289,16 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
} }
// "rawset", // (table, index, value) -> table // "rawset", // (table, index, value) -> table
static final class rawset extends LibFunction { static final class rawset extends TableLibFunction {
public LuaValue call(LuaValue table) { public LuaValue call(LuaValue table) {
return argerror(2,"value"); return argerror(2,"value expected");
} }
public LuaValue call(LuaValue table, LuaValue index) { public LuaValue call(LuaValue table, LuaValue index) {
return argerror(3,"value"); return argerror(3,"value expected");
} }
public LuaValue call(LuaValue table, LuaValue index, LuaValue value) { public LuaValue call(LuaValue table, LuaValue index, LuaValue value) {
LuaTable t = table.checktable(); LuaTable t = table.checktable();
if (!index.isvalidkey()) argerror(2, "value"); if (!index.isvalidkey()) argerror(2, "table index is nil");
t.rawset(index, value); t.rawset(index, value);
return t; return t;
} }
@@ -319,9 +318,9 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
} }
// "setmetatable", // (table, metatable) -> table // "setmetatable", // (table, metatable) -> table
static final class setmetatable extends LibFunction { static final class setmetatable extends TableLibFunction {
public LuaValue call(LuaValue table) { public LuaValue call(LuaValue table) {
return argerror(2,"value"); return argerror(2,"nil or table expected");
} }
public LuaValue call(LuaValue table, LuaValue metatable) { public LuaValue call(LuaValue table, LuaValue metatable) {
final LuaValue mt0 = table.checktable().getmetatable(); final LuaValue mt0 = table.checktable().getmetatable();
@@ -466,10 +465,12 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
this.func = func; this.func = func;
} }
public int read() throws IOException { public int read() throws IOException {
if ( remaining <= 0 ) { if ( remaining < 0 )
return -1;
if ( remaining == 0 ) {
LuaValue s = func.call(); LuaValue s = func.call();
if ( s.isnil() ) if ( s.isnil() )
return -1; return remaining = -1;
LuaString ls = s.strvalue(); LuaString ls = s.strvalue();
bytes = ls.m_bytes; bytes = ls.m_bytes;
offset = ls.m_offset; offset = ls.m_offset;
@@ -478,7 +479,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
return -1; return -1;
} }
--remaining; --remaining;
return bytes[offset++]; return 0xFF&bytes[offset++];
} }
} }
} }

View File

@@ -442,6 +442,10 @@ public class DebugLib extends TwoArgFunction {
return callstack().traceback(level); return callstack().traceback(level);
} }
public CallFrame getCallFrame(int level) {
return callstack().getCallFrame(level);
}
void callHook(LuaThread.State s, LuaValue type, LuaValue arg) { void callHook(LuaThread.State s, LuaValue type, LuaValue arg) {
if (s.inhook || s.hookfunc == null) return; if (s.inhook || s.hookfunc == null) return;
s.inhook = true; s.inhook = true;
@@ -645,7 +649,7 @@ public class DebugLib extends TwoArgFunction {
} }
static class CallFrame { public static class CallFrame {
LuaFunction f; LuaFunction f;
int pc; int pc;
int top; int top;
@@ -691,7 +695,7 @@ public class DebugLib extends TwoArgFunction {
return NIL; return NIL;
} }
} }
int currentline() { public int currentline() {
if ( !f.isclosure() ) return -1; if ( !f.isclosure() ) return -1;
int[] li = f.checkclosure().p.lineinfo; int[] li = f.checkclosure().p.lineinfo;
return li==null || pc<0 || pc>=li.length? -1: li[pc]; return li==null || pc<0 || pc>=li.length? -1: li[pc];
@@ -796,13 +800,13 @@ public class DebugLib extends TwoArgFunction {
LuaString vn = (Lua.GET_OPCODE(i) == Lua.OP_GETTABLE) /* name of indexed variable */ LuaString vn = (Lua.GET_OPCODE(i) == Lua.OP_GETTABLE) /* name of indexed variable */
? p.getlocalname(t + 1, pc) ? p.getlocalname(t + 1, pc)
: (t < p.upvalues.length ? p.upvalues[t].name : QMARK); : (t < p.upvalues.length ? p.upvalues[t].name : QMARK);
name = kname(p, k); String jname = kname(p, pc, k);
return new NameWhat( name.tojstring(), vn != null && vn.eq_b(ENV)? "global": "field" ); return new NameWhat( jname, vn != null && vn.eq_b(ENV)? "global": "field" );
} }
case Lua.OP_GETUPVAL: { case Lua.OP_GETUPVAL: {
int u = Lua.GETARG_B(i); /* upvalue index */ int u = Lua.GETARG_B(i); /* upvalue index */
name = u < p.upvalues.length ? p.upvalues[u].name : QMARK; name = u < p.upvalues.length ? p.upvalues[u].name : QMARK;
return new NameWhat( name.tojstring(), "upvalue" ); return name == null ? null : new NameWhat( name.tojstring(), "upvalue" );
} }
case Lua.OP_LOADK: case Lua.OP_LOADK:
case Lua.OP_LOADKX: { case Lua.OP_LOADKX: {
@@ -816,8 +820,8 @@ public class DebugLib extends TwoArgFunction {
} }
case Lua.OP_SELF: { case Lua.OP_SELF: {
int k = Lua.GETARG_C(i); /* key index */ int k = Lua.GETARG_C(i); /* key index */
name = kname(p, k); String jname = kname(p, pc, k);
return new NameWhat( name.tojstring(), "method" ); return new NameWhat( jname, "method" );
} }
default: default:
break; break;
@@ -826,11 +830,20 @@ public class DebugLib extends TwoArgFunction {
return null; /* no useful name found */ return null; /* no useful name found */
} }
static LuaString kname(Prototype p, int c) { static String kname(Prototype p, int pc, int c) {
if (Lua.ISK(c) && p.k[Lua.INDEXK(c)].isstring()) if (Lua.ISK(c)) { /* is 'c' a constant? */
return p.k[Lua.INDEXK(c)].strvalue(); LuaValue k = p.k[Lua.INDEXK(c)];
else if (k.isstring()) { /* literal constant? */
return QMARK; return k.tojstring(); /* it is its own name */
} /* else no reasonable name found */
} else { /* 'c' is a register */
NameWhat what = getobjname(p, pc, c); /* search for 'c' */
if (what != null && "constant".equals(what.namewhat)) { /* found a constant name? */
return what.name; /* 'name' already filled */
}
/* else no reasonable name found */
}
return "?"; /* no reasonable name found */
} }
/* /*

View File

@@ -95,6 +95,12 @@ public class IoLib extends TwoArgFunction {
// return number of bytes read if positive, false if eof, throw IOException on other exception // return number of bytes read if positive, false if eof, throw IOException on other exception
abstract public int read(byte[] bytes, int offset, int length) throws IOException; abstract public int read(byte[] bytes, int offset, int length) throws IOException;
public boolean eof() throws IOException {
try {
return peek() < 0;
} catch (EOFException e) { return true; }
}
// delegate method access to file methods table // delegate method access to file methods table
public LuaValue get( LuaValue key ) { public LuaValue get( LuaValue key ) {
return filemethods.get(key); return filemethods.get(key);
@@ -112,6 +118,14 @@ public class IoLib extends TwoArgFunction {
public String tojstring() { public String tojstring() {
return "file: " + Integer.toHexString(hashCode()); return "file: " + Integer.toHexString(hashCode());
} }
public void finalize() {
if (!isclosed()) {
try {
close();
} catch (IOException ignore) {}
}
}
} }
/** Enumerated value representing stdin */ /** Enumerated value representing stdin */
@@ -269,8 +283,15 @@ public class IoLib extends TwoArgFunction {
static final class IoLibV extends VarArgFunction { static final class IoLibV extends VarArgFunction {
private File f; private File f;
public IoLib iolib; public IoLib iolib;
private boolean toclose;
private Varargs args;
public IoLibV() { public IoLibV() {
} }
public IoLibV(File f, String name, int opcode, IoLib iolib, boolean toclose, Varargs args) {
this(f, name, opcode, iolib);
this.toclose = toclose;
this.args = args.dealias();
}
public IoLibV(File f, String name, int opcode, IoLib iolib) { public IoLibV(File f, String name, int opcode, IoLib iolib) {
super(); super();
this.f = f; this.f = f;
@@ -290,22 +311,26 @@ public class IoLib extends TwoArgFunction {
case IO_TYPE: return iolib._io_type(args.arg1()); case IO_TYPE: return iolib._io_type(args.arg1());
case IO_POPEN: return iolib._io_popen(args.checkjstring(1),args.optjstring(2,"r")); case IO_POPEN: return iolib._io_popen(args.checkjstring(1),args.optjstring(2,"r"));
case IO_OPEN: return iolib._io_open(args.checkjstring(1), args.optjstring(2,"r")); case IO_OPEN: return iolib._io_open(args.checkjstring(1), args.optjstring(2,"r"));
case IO_LINES: return iolib._io_lines(args.isvalue(1)? args.checkjstring(1): null); case IO_LINES: return iolib._io_lines(args);
case IO_READ: return iolib._io_read(args); case IO_READ: return iolib._io_read(args);
case IO_WRITE: return iolib._io_write(args); case IO_WRITE: return iolib._io_write(args);
case FILE_CLOSE: return iolib._file_close(args.arg1()); case FILE_CLOSE: return iolib._file_close(args.arg1());
case FILE_FLUSH: return iolib._file_flush(args.arg1()); case FILE_FLUSH: return iolib._file_flush(args.arg1());
case FILE_SETVBUF: return iolib._file_setvbuf(args.arg1(),args.checkjstring(2),args.optint(3,1024)); case FILE_SETVBUF: return iolib._file_setvbuf(args.arg1(),args.checkjstring(2),args.optint(3,8192));
case FILE_LINES: return iolib._file_lines(args.arg1()); case FILE_LINES: return iolib._file_lines(args);
case FILE_READ: return iolib._file_read(args.arg1(),args.subargs(2)); case FILE_READ: return iolib._file_read(args.arg1(),args.subargs(2));
case FILE_SEEK: return iolib._file_seek(args.arg1(),args.optjstring(2,"cur"),args.optint(3,0)); case FILE_SEEK: return iolib._file_seek(args.arg1(),args.optjstring(2,"cur"),args.optint(3,0));
case FILE_WRITE: return iolib._file_write(args.arg1(),args.subargs(2)); case FILE_WRITE: return iolib._file_write(args.arg1(),args.subargs(2));
case IO_INDEX: return iolib._io_index(args.arg(2)); case IO_INDEX: return iolib._io_index(args.arg(2));
case LINES_ITER: return iolib._lines_iter(f); case LINES_ITER: return iolib._lines_iter(f, toclose, this.args);
} }
} catch ( IOException ioe ) { } catch ( IOException ioe ) {
if (opcode == LINES_ITER) {
String s = ioe.getMessage();
error(s != null ? s : ioe.toString());
}
return errorresult(ioe); return errorresult(ioe);
} }
return NONE; return NONE;
@@ -361,6 +386,7 @@ public class IoLib extends TwoArgFunction {
// io.popen(prog, [mode]) -> file // io.popen(prog, [mode]) -> file
public Varargs _io_popen(String prog, String mode) throws IOException { public Varargs _io_popen(String prog, String mode) throws IOException {
if (!"r".equals(mode) && !"w".equals(mode)) argerror(2, "invalid value: '" + mode + "'; must be one of 'r' or 'w'");
return openProgram(prog, mode); return openProgram(prog, mode);
} }
@@ -369,11 +395,12 @@ public class IoLib extends TwoArgFunction {
return rawopenfile(FTYPE_NAMED, filename, mode); return rawopenfile(FTYPE_NAMED, filename, mode);
} }
// io.lines(filename) -> iterator // io.lines(filename, ...) -> iterator
public Varargs _io_lines(String filename) { public Varargs _io_lines(Varargs args) {
infile = filename==null? input(): ioopenfile(FTYPE_NAMED, filename,"r"); String filename = args.optjstring(1, null);
File infile = filename==null? input(): ioopenfile(FTYPE_NAMED, filename,"r");
checkopen(infile); checkopen(infile);
return lines(infile); return lines(infile, filename != null, args.subargs(2));
} }
// io.read(...) -> (...) // io.read(...) -> (...)
@@ -401,13 +428,19 @@ public class IoLib extends TwoArgFunction {
// file:setvbuf(mode,[size]) -> void // file:setvbuf(mode,[size]) -> void
public Varargs _file_setvbuf(LuaValue file, String mode, int size) { public Varargs _file_setvbuf(LuaValue file, String mode, int size) {
if ("no".equals(mode)) {
} else if ("full".equals(mode)) {
} else if ("line".equals(mode)) {
} else {
argerror(1, "invalid value: '" + mode + "'; must be one of 'no', 'full' or 'line'");
}
checkfile(file).setvbuf(mode,size); checkfile(file).setvbuf(mode,size);
return LuaValue.TRUE; return LuaValue.TRUE;
} }
// file:lines() -> iterator // file:lines(...) -> iterator
public Varargs _file_lines(LuaValue file) { public Varargs _file_lines(Varargs args) {
return lines(checkfile(file)); return lines(checkfile(args.arg1()), false, args.subargs(2));
} }
// file:read(...) -> (...) // file:read(...) -> (...)
@@ -417,6 +450,12 @@ public class IoLib extends TwoArgFunction {
// file:seek([whence][,offset]) -> pos | nil,error // file:seek([whence][,offset]) -> pos | nil,error
public Varargs _file_seek(LuaValue file, String whence, int offset) throws IOException { public Varargs _file_seek(LuaValue file, String whence, int offset) throws IOException {
if ("set".equals(whence)) {
} else if ("end".equals(whence)) {
} else if ("cur".equals(whence)) {
} else {
argerror(1, "invalid value: '" + whence + "'; must be one of 'set', 'cur' or 'end'");
}
return valueOf( checkfile(file).seek(whence,offset) ); return valueOf( checkfile(file).seek(whence,offset) );
} }
@@ -433,8 +472,13 @@ public class IoLib extends TwoArgFunction {
} }
// lines iterator(s,var) -> var' // lines iterator(s,var) -> var'
public Varargs _lines_iter(LuaValue file) throws IOException { public Varargs _lines_iter(LuaValue file, boolean toclose, Varargs args) throws IOException {
return freadline(checkfile(file)); File f = optfile(file);
if ( f == null ) argerror(1, "not a file: " + file);
if ( f.isclosed() ) error("file is already closed");
Varargs ret = ioread(f, args);
if (toclose && ret.isnil(1) && f.eof()) f.close();
return ret;
} }
private File output() { private File output() {
@@ -476,9 +520,9 @@ public class IoLib extends TwoArgFunction {
return varargsOf(NIL, valueOf(errortext)); return varargsOf(NIL, valueOf(errortext));
} }
private Varargs lines(final File f) { private Varargs lines(final File f, boolean toclose, Varargs args) {
try { try {
return new IoLibV(f,"lnext",LINES_ITER,this); return new IoLibV(f,"lnext",LINES_ITER,this,toclose,args);
} catch ( Exception e ) { } catch ( Exception e ) {
return error("lines: "+e); return error("lines: "+e);
} }
@@ -492,6 +536,7 @@ public class IoLib extends TwoArgFunction {
private Varargs ioread(File f, Varargs args) throws IOException { private Varargs ioread(File f, Varargs args) throws IOException {
int i,n=args.narg(); int i,n=args.narg();
if (n == 0) return freadline(f,false);
LuaValue[] v = new LuaValue[n]; LuaValue[] v = new LuaValue[n];
LuaValue ai,vi; LuaValue ai,vi;
LuaString fmt; LuaString fmt;
@@ -502,10 +547,11 @@ public class IoLib extends TwoArgFunction {
break item; break item;
case LuaValue.TSTRING: case LuaValue.TSTRING:
fmt = ai.checkstring(); fmt = ai.checkstring();
if ( fmt.m_length == 2 && fmt.m_bytes[fmt.m_offset] == '*' ) { if ( fmt.m_length >= 2 && fmt.m_bytes[fmt.m_offset] == '*' ) {
switch ( fmt.m_bytes[fmt.m_offset+1] ) { switch ( fmt.m_bytes[fmt.m_offset+1] ) {
case 'n': vi = freadnumber(f); break item; case 'n': vi = freadnumber(f); break item;
case 'l': vi = freadline(f); break item; case 'l': vi = freadline(f,false); break item;
case 'L': vi = freadline(f,true); break item;
case 'a': vi = freadall(f); break item; case 'a': vi = freadall(f); break item;
} }
} }
@@ -537,6 +583,17 @@ public class IoLib extends TwoArgFunction {
} }
private File rawopenfile(int filetype, String filename, String mode) throws IOException { private File rawopenfile(int filetype, String filename, String mode) throws IOException {
int len = mode.length();
for (int i = 0; i < len; i++) { // [rwa][+]?b*
char ch = mode.charAt(i);
if (i == 0 && "rwa".indexOf(ch) >= 0) continue;
if (i == 1 && ch == '+') continue;
if (i >= 1 && ch == 'b') continue;
len = -1;
break;
}
if (len <= 0) argerror(2, "invalid mode: '" + mode + "'");
switch (filetype) { switch (filetype) {
case FTYPE_STDIN: return wrapStdin(); case FTYPE_STDIN: return wrapStdin();
case FTYPE_STDOUT: return wrapStdout(); case FTYPE_STDOUT: return wrapStdout();
@@ -553,26 +610,27 @@ public class IoLib extends TwoArgFunction {
// ------------- file reading utilitied ------------------ // ------------- file reading utilitied ------------------
public static LuaValue freadbytes(File f, int count) throws IOException { public static LuaValue freadbytes(File f, int count) throws IOException {
if (count == 0) return f.eof() ? NIL : EMPTYSTRING;
byte[] b = new byte[count]; byte[] b = new byte[count];
int r; int r;
if ( ( r = f.read(b,0,b.length) ) < 0 ) if ( ( r = f.read(b,0,b.length) ) < 0 )
return NIL; return NIL;
return LuaString.valueUsing(b, 0, r); return LuaString.valueUsing(b, 0, r);
} }
public static LuaValue freaduntil(File f,boolean lineonly) throws IOException { public static LuaValue freaduntil(File f,boolean lineonly,boolean withend) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c; int c;
try { try {
if ( lineonly ) { if ( lineonly ) {
loop: while ( (c = f.read()) > 0 ) { loop: while ( (c = f.read()) >= 0 ) {
switch ( c ) { switch ( c ) {
case '\r': break; case '\r': if (withend) baos.write(c); break;
case '\n': break loop; case '\n': if (withend) baos.write(c); break loop;
default: baos.write(c); break; default: baos.write(c); break;
} }
} }
} else { } else {
while ( (c = f.read()) > 0 ) while ( (c = f.read()) >= 0 )
baos.write(c); baos.write(c);
} }
} catch ( EOFException e ) { } catch ( EOFException e ) {
@@ -582,15 +640,15 @@ public class IoLib extends TwoArgFunction {
(LuaValue) NIL: (LuaValue) NIL:
(LuaValue) LuaString.valueUsing(baos.toByteArray()); (LuaValue) LuaString.valueUsing(baos.toByteArray());
} }
public static LuaValue freadline(File f) throws IOException { public static LuaValue freadline(File f,boolean withend) throws IOException {
return freaduntil(f,true); return freaduntil(f,true,withend);
} }
public static LuaValue freadall(File f) throws IOException { public static LuaValue freadall(File f) throws IOException {
int n = f.remaining(); int n = f.remaining();
if ( n >= 0 ) { if ( n >= 0 ) {
return freadbytes(f, n); return n == 0 ? EMPTYSTRING : freadbytes(f, n);
} else { } else {
return freaduntil(f,false); return freaduntil(f,false,false);
} }
} }
public static LuaValue freadnumber(File f) throws IOException { public static LuaValue freadnumber(File f) throws IOException {

View File

@@ -196,7 +196,7 @@ abstract public class LibFunction extends LuaFunction {
} }
public LuaValue call() { public LuaValue call() {
return argerror(1,"value"); return argerror(1,"value expected");
} }
public LuaValue call(LuaValue a) { public LuaValue call(LuaValue a) {
return call(); return call();

View File

@@ -144,6 +144,7 @@ public class PackageLib extends TwoArgFunction {
searchers.set(2, lua_searcher = new lua_searcher()); searchers.set(2, lua_searcher = new lua_searcher());
searchers.set(3, java_searcher = new java_searcher()); searchers.set(3, java_searcher = new java_searcher());
package_.set(_SEARCHERS, searchers); package_.set(_SEARCHERS, searchers);
package_.set("config", FILE_SEP + "\n;\n?\n!\n-\n");
package_.get(_LOADED).set("package", package_); package_.get(_LOADED).set("package", package_);
env.set("package", package_); env.set("package", package_);
globals.package_ = this; globals.package_ = this;
@@ -236,7 +237,7 @@ public class PackageLib extends TwoArgFunction {
} }
public static class loadlib extends VarArgFunction { public static class loadlib extends VarArgFunction {
public Varargs loadlib( Varargs args ) { public Varargs invoke( Varargs args ) {
args.checkstring(1); args.checkstring(1);
return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent")); return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent"));
} }

View File

@@ -83,8 +83,8 @@ public class StringLib extends TwoArgFunction {
*/ */
public LuaValue call(LuaValue modname, LuaValue env) { public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable string = new LuaTable(); LuaTable string = new LuaTable();
string.set("byte", new byte_()); string.set("byte", new _byte());
string.set("char", new char_()); string.set("char", new _char());
string.set("dump", new dump()); string.set("dump", new dump());
string.set("find", new find()); string.set("find", new find());
string.set("format", new format()); string.set("format", new format());
@@ -117,7 +117,7 @@ public class StringLib extends TwoArgFunction {
* *
* @param args the calling args * @param args the calling args
*/ */
static final class byte_ extends VarArgFunction { static final class _byte extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaString s = args.checkstring(1); LuaString s = args.checkstring(1);
int l = s.m_length; int l = s.m_length;
@@ -148,7 +148,7 @@ public class StringLib extends TwoArgFunction {
* *
* @param args the calling VM * @param args the calling VM
*/ */
static final class char_ extends VarArgFunction { static final class _char extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
int n = args.narg(); int n = args.narg();
byte[] bytes = new byte[n]; byte[] bytes = new byte[n];
@@ -527,19 +527,20 @@ public class StringLib extends TwoArgFunction {
private final int srclen; private final int srclen;
private final MatchState ms; private final MatchState ms;
private int soffset; private int soffset;
private int lastmatch;
public GMatchAux(Varargs args, LuaString src, LuaString pat) { public GMatchAux(Varargs args, LuaString src, LuaString pat) {
this.srclen = src.length(); this.srclen = src.length();
this.ms = new MatchState(args, src, pat); this.ms = new MatchState(args, src, pat);
this.soffset = 0; this.soffset = 0;
this.lastmatch = -1;
} }
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
for ( ; soffset<=srclen; soffset++ ) { for ( ; soffset<=srclen; soffset++ ) {
ms.reset(); ms.reset();
int res = ms.match(soffset, 0); int res = ms.match(soffset, 0);
if ( res >=0 ) { if ( res >=0 && res != lastmatch ) {
int soff = soffset; int soff = soffset;
soffset = res; lastmatch = soffset = res;
if (soff == res) soffset++; /* empty match? go at least one position */
return ms.push_captures( true, soff, res ); return ms.push_captures( true, soff, res );
} }
} }
@@ -598,6 +599,7 @@ public class StringLib extends TwoArgFunction {
LuaString src = args.checkstring( 1 ); LuaString src = args.checkstring( 1 );
final int srclen = src.length(); final int srclen = src.length();
LuaString p = args.checkstring( 2 ); LuaString p = args.checkstring( 2 );
int lastmatch = -1; /* end of last match */
LuaValue repl = args.arg( 3 ); LuaValue repl = args.arg( 3 );
int max_s = args.optint( 4, srclen + 1 ); int max_s = args.optint( 4, srclen + 1 );
final boolean anchor = p.length() > 0 && p.charAt( 0 ) == '^'; final boolean anchor = p.length() > 0 && p.charAt( 0 ) == '^';
@@ -610,18 +612,15 @@ public class StringLib extends TwoArgFunction {
while ( n < max_s ) { while ( n < max_s ) {
ms.reset(); ms.reset();
int res = ms.match( soffset, anchor ? 1 : 0 ); int res = ms.match( soffset, anchor ? 1 : 0 );
if ( res != -1 ) { if ( res != -1 && res != lastmatch ) { /* match? */
n++; n++;
ms.add_value( lbuf, soffset, res, repl ); ms.add_value( lbuf, soffset, res, repl ); /* add replacement to buffer */
soffset = lastmatch = res;
} }
if ( res != -1 && res > soffset ) else if ( soffset < srclen ) /* otherwise, skip one character */
soffset = res;
else if ( soffset < srclen )
lbuf.append( (byte) src.luaByte( soffset++ ) ); lbuf.append( (byte) src.luaByte( soffset++ ) );
else else break; /* end of subject */
break; if ( anchor ) break;
if ( anchor )
break;
} }
lbuf.append( src.substring( soffset, srclen ) ); lbuf.append( src.substring( soffset, srclen ) );
return varargsOf(lbuf.tostring(), valueOf(n)); return varargsOf(lbuf.tostring(), valueOf(n));
@@ -804,6 +803,8 @@ public class StringLib extends TwoArgFunction {
private static final LuaString SPECIALS = valueOf("^$*+?.([%-"); private static final LuaString SPECIALS = valueOf("^$*+?.([%-");
private static final int MAX_CAPTURES = 32; private static final int MAX_CAPTURES = 32;
private static final int MAXCCALLS = 200;
private static final int CAP_UNFINISHED = -1; private static final int CAP_UNFINISHED = -1;
private static final int CAP_POSITION = -2; private static final int CAP_POSITION = -2;
@@ -821,7 +822,7 @@ public class StringLib extends TwoArgFunction {
static { static {
CHAR_TABLE = new byte[256]; CHAR_TABLE = new byte[256];
for ( int i = 0; i < 256; ++i ) { for ( int i = 0; i < 128; ++i ) {
final char c = (char) i; final char c = (char) i;
CHAR_TABLE[i] = (byte)( ( Character.isDigit( c ) ? MASK_DIGIT : 0 ) | CHAR_TABLE[i] = (byte)( ( Character.isDigit( c ) ? MASK_DIGIT : 0 ) |
( Character.isLowerCase( c ) ? MASK_LOWERCASE : 0 ) | ( Character.isLowerCase( c ) ? MASK_LOWERCASE : 0 ) |
@@ -830,7 +831,7 @@ public class StringLib extends TwoArgFunction {
if ( ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) || ( c >= '0' && c <= '9' ) ) { if ( ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) || ( c >= '0' && c <= '9' ) ) {
CHAR_TABLE[i] |= MASK_HEXDIGIT; CHAR_TABLE[i] |= MASK_HEXDIGIT;
} }
if ( ( c >= '!' && c <= '/' ) || ( c >= ':' && c <= '@' ) ) { if ( ( c >= '!' && c <= '/' ) || ( c >= ':' && c <= '@' ) || ( c >= '[' && c <= '`' ) || ( c >= '{' && c <= '~' ) ) {
CHAR_TABLE[i] |= MASK_PUNCT; CHAR_TABLE[i] |= MASK_PUNCT;
} }
if ( ( CHAR_TABLE[i] & ( MASK_LOWERCASE | MASK_UPPERCASE ) ) != 0 ) { if ( ( CHAR_TABLE[i] & ( MASK_LOWERCASE | MASK_UPPERCASE ) ) != 0 ) {
@@ -842,11 +843,12 @@ public class StringLib extends TwoArgFunction {
CHAR_TABLE['\r'] |= MASK_SPACE; CHAR_TABLE['\r'] |= MASK_SPACE;
CHAR_TABLE['\n'] |= MASK_SPACE; CHAR_TABLE['\n'] |= MASK_SPACE;
CHAR_TABLE['\t'] |= MASK_SPACE; CHAR_TABLE['\t'] |= MASK_SPACE;
CHAR_TABLE[0x0C /* '\v' */ ] |= MASK_SPACE; CHAR_TABLE[0x0B /* '\v' */ ] |= MASK_SPACE;
CHAR_TABLE['\f'] |= MASK_SPACE; CHAR_TABLE['\f'] |= MASK_SPACE;
}; };
static class MatchState { static class MatchState {
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
final LuaString s; final LuaString s;
final LuaString p; final LuaString p;
final Varargs args; final Varargs args;
@@ -861,10 +863,12 @@ public class StringLib extends TwoArgFunction {
this.level = 0; this.level = 0;
this.cinit = new int[ MAX_CAPTURES ]; this.cinit = new int[ MAX_CAPTURES ];
this.clen = new int[ MAX_CAPTURES ]; this.clen = new int[ MAX_CAPTURES ];
this.matchdepth = MAXCCALLS;
} }
void reset() { void reset() {
level = 0; level = 0;
this.matchdepth = MAXCCALLS;
} }
private void add_s( Buffer lbuf, LuaString news, int soff, int e ) { private void add_s( Buffer lbuf, LuaString news, int soff, int e ) {
@@ -939,7 +943,7 @@ public class StringLib extends TwoArgFunction {
if ( i == 0 ) { if ( i == 0 ) {
return s.substring( soff, end ); return s.substring( soff, end );
} else { } else {
return error( "invalid capture index" ); return error( "invalid capture index %" + (i + 1) );
} }
} else { } else {
int l = clen[i]; int l = clen[i];
@@ -958,7 +962,7 @@ public class StringLib extends TwoArgFunction {
private int check_capture( int l ) { private int check_capture( int l ) {
l -= '1'; l -= '1';
if ( l < 0 || l >= level || this.clen[l] == CAP_UNFINISHED ) { if ( l < 0 || l >= level || this.clen[l] == CAP_UNFINISHED ) {
error("invalid capture index"); error("invalid capture index %" + (l + 1));
} }
return l; return l;
} }
@@ -1008,9 +1012,10 @@ public class StringLib extends TwoArgFunction {
case 'c': res = ( cdata & MASK_CONTROL ) != 0; break; case 'c': res = ( cdata & MASK_CONTROL ) != 0; break;
case 'p': res = ( cdata & MASK_PUNCT ) != 0; break; case 'p': res = ( cdata & MASK_PUNCT ) != 0; break;
case 's': res = ( cdata & MASK_SPACE ) != 0; break; case 's': res = ( cdata & MASK_SPACE ) != 0; break;
case 'g': res = ( cdata & ( MASK_ALPHA | MASK_DIGIT | MASK_PUNCT ) ) != 0; break;
case 'w': res = ( cdata & ( MASK_ALPHA | MASK_DIGIT ) ) != 0; break; case 'w': res = ( cdata & ( MASK_ALPHA | MASK_DIGIT ) ) != 0; break;
case 'x': res = ( cdata & MASK_HEXDIGIT ) != 0; break; case 'x': res = ( cdata & MASK_HEXDIGIT ) != 0; break;
case 'z': res = ( c == 0 ); break; case 'z': res = ( c == 0 ); break; /* deprecated option */
default: return cl == c; default: return cl == c;
} }
return ( lcl == cl ) ? res : !res; return ( lcl == cl ) ? res : !res;
@@ -1052,81 +1057,86 @@ public class StringLib extends TwoArgFunction {
* where match ends, otherwise returns -1. * where match ends, otherwise returns -1.
*/ */
int match( int soffset, int poffset ) { int match( int soffset, int poffset ) {
while ( true ) { if (matchdepth-- == 0) error("pattern too complex");
// Check if we are at the end of the pattern - try {
// equivalent to the '\0' case in the C version, but our pattern while ( true ) {
// string is not NUL-terminated. // Check if we are at the end of the pattern -
if ( poffset == p.length() ) // equivalent to the '\0' case in the C version, but our pattern
return soffset; // string is not NUL-terminated.
switch ( p.luaByte( poffset ) ) { if ( poffset == p.length() )
case '(': return soffset;
if ( ++poffset < p.length() && p.luaByte( poffset ) == ')' ) switch ( p.luaByte( poffset ) ) {
return start_capture( soffset, poffset + 1, CAP_POSITION ); case '(':
else if ( ++poffset < p.length() && p.luaByte( poffset ) == ')' )
return start_capture( soffset, poffset, CAP_UNFINISHED ); return start_capture( soffset, poffset + 1, CAP_POSITION );
case ')': else
return end_capture( soffset, poffset + 1 ); return start_capture( soffset, poffset, CAP_UNFINISHED );
case L_ESC: case ')':
if ( poffset + 1 == p.length() ) return end_capture( soffset, poffset + 1 );
error("malformed pattern (ends with '%')"); case L_ESC:
switch ( p.luaByte( poffset + 1 ) ) { if ( poffset + 1 == p.length() )
case 'b': error("malformed pattern (ends with '%')");
soffset = matchbalance( soffset, poffset + 2 ); switch ( p.luaByte( poffset + 1 ) ) {
if ( soffset == -1 ) return -1; case 'b':
poffset += 4; soffset = matchbalance( soffset, poffset + 2 );
continue; if ( soffset == -1 ) return -1;
case 'f': { poffset += 4;
poffset += 2; continue;
if ( poffset == p.length() || p.luaByte( poffset ) != '[' ) { case 'f': {
error("Missing '[' after '%f' in pattern"); poffset += 2;
if ( poffset == p.length() || p.luaByte( poffset ) != '[' ) {
error("missing '[' after '%f' in pattern");
}
int ep = classend( poffset );
int previous = ( soffset == 0 ) ? '\0' : s.luaByte( soffset - 1 );
int next = ( soffset == s.length() ) ? '\0' : s.luaByte( soffset );
if ( matchbracketclass( previous, poffset, ep - 1 ) ||
!matchbracketclass( next, poffset, ep - 1 ) )
return -1;
poffset = ep;
continue;
} }
int ep = classend( poffset ); default: {
int previous = ( soffset == 0 ) ? '\0' : s.luaByte( soffset - 1 ); int c = p.luaByte( poffset + 1 );
int next = ( soffset == s.length() ) ? '\0' : s.luaByte( soffset ); if ( Character.isDigit( (char) c ) ) {
if ( matchbracketclass( previous, poffset, ep - 1 ) || soffset = match_capture( soffset, c );
!matchbracketclass( next, poffset, ep - 1 ) ) if ( soffset == -1 )
return -1;
return match( soffset, poffset + 2 );
}
}
}
case '$':
if ( poffset + 1 == p.length() )
return ( soffset == s.length() ) ? soffset : -1;
}
int ep = classend( poffset );
boolean m = soffset < s.length() && singlematch( s.luaByte( soffset ), poffset, ep );
int pc = ( ep < p.length() ) ? p.luaByte( ep ) : '\0';
switch ( pc ) {
case '?':
int res;
if ( m && ( ( res = match( soffset + 1, ep + 1 ) ) != -1 ) )
return res;
poffset = ep + 1;
continue;
case '*':
return max_expand( soffset, poffset, ep );
case '+':
return ( m ? max_expand( soffset + 1, poffset, ep ) : -1 );
case '-':
return min_expand( soffset, poffset, ep );
default:
if ( !m )
return -1; return -1;
soffset++;
poffset = ep; poffset = ep;
continue; continue;
} }
default: {
int c = p.luaByte( poffset + 1 );
if ( Character.isDigit( (char) c ) ) {
soffset = match_capture( soffset, c );
if ( soffset == -1 )
return -1;
return match( soffset, poffset + 2 );
}
}
}
case '$':
if ( poffset + 1 == p.length() )
return ( soffset == s.length() ) ? soffset : -1;
}
int ep = classend( poffset );
boolean m = soffset < s.length() && singlematch( s.luaByte( soffset ), poffset, ep );
int pc = ( ep < p.length() ) ? p.luaByte( ep ) : '\0';
switch ( pc ) {
case '?':
int res;
if ( m && ( ( res = match( soffset + 1, ep + 1 ) ) != -1 ) )
return res;
poffset = ep + 1;
continue;
case '*':
return max_expand( soffset, poffset, ep );
case '+':
return ( m ? max_expand( soffset + 1, poffset, ep ) : -1 );
case '-':
return min_expand( soffset, poffset, ep );
default:
if ( !m )
return -1;
soffset++;
poffset = ep;
continue;
} }
} finally {
matchdepth++;
} }
} }
@@ -1191,7 +1201,7 @@ public class StringLib extends TwoArgFunction {
int matchbalance( int soff, int poff ) { int matchbalance( int soff, int poff ) {
final int plen = p.length(); final int plen = p.length();
if ( poff == plen || poff + 1 == plen ) { if ( poff == plen || poff + 1 == plen ) {
error( "unbalanced pattern" ); error( "malformed pattern (missing arguments to '%b')" );
} }
final int slen = s.length(); final int slen = s.length();
if ( soff >= slen ) if ( soff >= slen )

View File

@@ -74,12 +74,6 @@ public class TableLib extends TwoArgFunction {
return NIL; return NIL;
} }
static class TableLibFunction extends LibFunction {
public LuaValue call() {
return argerror(1, "table expected, got no value");
}
}
// "concat" (table [, sep [, i [, j]]]) -> string // "concat" (table [, sep [, i [, j]]]) -> string
static class concat extends TableLibFunction { static class concat extends TableLibFunction {
public LuaValue call(LuaValue list) { public LuaValue call(LuaValue list) {
@@ -100,18 +94,22 @@ public class TableLib extends TwoArgFunction {
static class insert extends VarArgFunction { static class insert extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
switch (args.narg()) { switch (args.narg()) {
case 0: case 1: {
return argerror(2, "value expected");
}
case 2: { case 2: {
LuaTable table = args.arg1().checktable(); LuaTable table = args.checktable(1);
table.insert(table.length()+1,args.arg(2)); table.insert(table.length()+1,args.arg(2));
return NONE; return NONE;
} }
default: { case 3: {
args.arg1().checktable().insert(args.checkint(2),args.arg(3)); LuaTable table = args.checktable(1);
int pos = args.checkint(2);
int max = table.length() + 1;
if (pos < 1 || pos > max) argerror(2, "position out of bounds: " + pos + " not between 1 and " + max);
table.insert(pos, args.arg(3));
return NONE; return NONE;
} }
default: {
return error("wrong number of arguments to 'table.insert': " + args.narg() + " (must be 2 or 3)");
}
} }
} }
} }
@@ -128,15 +126,21 @@ public class TableLib extends TwoArgFunction {
// "remove" (table [, pos]) -> removed-ele // "remove" (table [, pos]) -> removed-ele
static class remove extends VarArgFunction { static class remove extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
return args.arg1().checktable().remove(args.optint(2, 0)); LuaTable table = args.checktable(1);
int size = table.length();
int pos = args.optint(2, size);
if (pos != size && (pos < 1 || pos > size + 1)) {
argerror(2, "position out of bounds: " + pos + " not between 1 and " + (size + 1));
}
return table.remove(pos);
} }
} }
// "sort" (table [, comp]) // "sort" (table [, comp])
static class sort extends VarArgFunction { static class sort extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
args.arg1().checktable().sort( args.checktable(1).sort(
args.arg(2).isnil()? NIL: args.arg(2).checkfunction()); args.isnil(2)? NIL: args.checkfunction(2));
return NONE; return NONE;
} }
} }
@@ -146,11 +150,9 @@ public class TableLib extends TwoArgFunction {
static class unpack extends VarArgFunction { static class unpack extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
LuaTable t = args.checktable(1); LuaTable t = args.checktable(1);
switch (args.narg()) { // do not waste resource for calc rawlen if arg3 is not nil
case 1: return t.unpack(); int len = args.arg(3).isnil() ? t.length() : 0;
case 2: return t.unpack(args.checkint(2)); return t.unpack(args.optint(2, 1), args.optint(3, len));
default: return t.unpack(args.checkint(2), args.checkint(3));
}
} }
} }
} }

View File

@@ -0,0 +1,9 @@
package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
class TableLibFunction extends LibFunction {
public LuaValue call() {
return argerror(1, "table expected, got no value");
}
}

View File

@@ -51,7 +51,7 @@ class JavaMember extends VarArgFunction {
fixedargs = new CoerceLuaToJava.Coercion[isvarargs? params.length-1: params.length]; fixedargs = new CoerceLuaToJava.Coercion[isvarargs? params.length-1: params.length];
for ( int i=0; i<fixedargs.length; i++ ) for ( int i=0; i<fixedargs.length; i++ )
fixedargs[i] = CoerceLuaToJava.getCoercion( params[i] ); fixedargs[i] = CoerceLuaToJava.getCoercion( params[i] );
varargs = isvarargs? CoerceLuaToJava.getCoercion( params[params.length-1] ): null; varargs = isvarargs? CoerceLuaToJava.getCoercion( params[params.length-1].getComponentType() ): null;
} }
int score(Varargs args) { int score(Varargs args) {
@@ -72,12 +72,15 @@ class JavaMember extends VarArgFunction {
for ( int i=0; i<a.length; i++ ) for ( int i=0; i<a.length; i++ )
a[i] = fixedargs[i].coerce( args.arg(i+1) ); a[i] = fixedargs[i].coerce( args.arg(i+1) );
} else { } else {
int n = Math.max(fixedargs.length,args.narg()); // should be the fixed arguments, followed by an array with the varargs
a = new Object[n]; a = new Object[fixedargs.length+1];
int nvar = Math.max(0, args.narg()-fixedargs.length);
Object[] vararray = new Object[nvar];
for ( int i=0; i<fixedargs.length; i++ ) for ( int i=0; i<fixedargs.length; i++ )
a[i] = fixedargs[i].coerce( args.arg(i+1) ); a[i] = fixedargs[i].coerce( args.arg(i+1) );
for ( int i=fixedargs.length; i<n; i++ ) a[a.length-1] = vararray;
a[i] = varargs.coerce( args.arg(i+1) ); for ( int i=0; i<nvar; i++ )
vararray[i] = varargs.coerce( args.arg(fixedargs.length+i+1) );
} }
return a; return a;
} }

View File

@@ -133,7 +133,7 @@ public class JseIoLib extends IoLib {
this( null, null, o ); this( null, null, o );
} }
public String tojstring() { public String tojstring() {
return "file ("+this.hashCode()+")"; return "file (" + (this.closed ? "closed" : String.valueOf(this.hashCode())) + ")";
} }
public boolean isstdfile() { public boolean isstdfile() {
return file == null; return file == null;
@@ -321,7 +321,7 @@ public class JseIoLib extends IoLib {
} }
public int remaining() throws IOException { public int remaining() throws IOException {
return 0; return -1;
} }
public int peek() throws IOException, EOFException { public int peek() throws IOException, EOFException {

View File

@@ -126,7 +126,7 @@ public class JseOsLib extends org.luaj.vm2.lib.OsLib {
protected String tmpname() { protected String tmpname() {
try { try {
java.io.File f = java.io.File.createTempFile(TMP_PREFIX ,TMP_SUFFIX); java.io.File f = java.io.File.createTempFile(TMP_PREFIX ,TMP_SUFFIX);
return f.getName(); return f.getAbsolutePath();
} catch ( IOException ioe ) { } catch ( IOException ioe ) {
return super.tmpname(); return super.tmpname();
} }

View File

@@ -0,0 +1,39 @@
/*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2.lib.jse;
public class JseStringLib extends org.luaj.vm2.lib.StringLib {
/** public constructor */
public JseStringLib() {
}
protected String format(String src, double x) {
String out;
try {
out = String.format(src, new Object[] {Double.valueOf(x)});
} catch (Throwable e) {
out = super.format(src, x);
}
return out;
}
}