139 Commits

Author SHA1 Message Date
Adrian Siekierka
ac261965a8 fix compilation, tests 2022-09-04 02:06:08 +02:00
Adrian Siekierka
342d940b5e Merge remote-tracking branch 'farmboy0/master' 2022-09-04 02:01:30 +02:00
Adrian Siekierka
a3507cf771 Merge remote-tracking branch 'src/master' 2022-09-04 01:43:37 +02:00
Enrico Horn
0775cc6c59 Create sources jars during the build 2021-07-23 17:47:14 +02:00
Enrico Horn
f87e3726a4 Update build information in the README 2021-07-22 23:27:14 +02:00
Enrico Horn
a4d95841e4 Create coverage report during the build 2021-07-22 23:23:34 +02:00
Enrico Horn
c8c2c29d62 Remove ant build files 2021-07-22 22:51:02 +02:00
Enrico Horn
67962d4cc3 Deactivate a few more compatibility tests for now 2021-07-22 22:46:58 +02:00
Enrico Horn
9a65948e26 Rework and complete OsLib's date formatting 2021-07-22 22:46:58 +02:00
Enrico Horn
66130964c6 Convert mathlib.modf result to number 2021-07-22 22:29:09 +02:00
Enrico Horn
abe14ca995 Disable debuglib tests for now
Too many failing tests that need to be fixed first
2021-07-22 22:29:09 +02:00
Enrico Horn
30a3a472bc Luajit crashes when closing a closed file 2021-07-22 22:29:08 +02:00
Enrico Horn
e87d9ceee4 Disabled a few more tests for now 2021-07-22 22:29:07 +02:00
Enrico Horn
3e9ae5c524 Luajit doesnt implement table.unpack in the current stable version 2021-07-22 22:29:03 +02:00
Enrico Horn
ddba10c180 Bring debuglib.getlocal Implementation closer to native 2021-07-22 22:29:02 +02:00
Enrico Horn
39e9be0a2d Deactivate a debuglib.getlocal error test for now 2021-07-22 22:29:02 +02:00
Enrico Horn
b1322640ca Always initialize a CallFrame's stack 2021-07-22 22:29:01 +02:00
Enrico Horn
99bd46876e Report errors about closures as function expected 2021-07-22 22:29:01 +02:00
Enrico Horn
23ae7cdc06 Fix order of argument checks in debug.upvaluejoin 2021-07-22 22:29:00 +02:00
Enrico Horn
942dc4afa3 More debug.upvaluejoin error tests 2021-07-22 22:29:00 +02:00
Enrico Horn
11ec746838 Fix order of argument checks in debug.upvalueid 2021-07-22 22:28:59 +02:00
Enrico Horn
b8b951b7c9 Fix order of argument checks in debug.setupvalue 2021-07-22 22:28:59 +02:00
Enrico Horn
1f9a874979 More setupvalue error tests 2021-07-22 22:28:58 +02:00
Enrico Horn
b121b65151 Handle rhs of zero for operation fmod 2021-07-22 00:06:12 +02:00
Enrico Horn
5851e6994a Lua also returns a negative NaN string 2021-07-22 00:06:12 +02:00
Enrico Horn
5984ec6097 Remove test files created during iolib tests 2021-07-22 00:06:12 +02:00
Enrico Horn
4802623aa3 Only check return type in xpcall pass tests
The error message is more specific with luaj
2021-07-22 00:06:11 +02:00
Enrico Horn
2fdcf5e2ac Disable string.dump pass checks for now 2021-07-22 00:06:11 +02:00
Enrico Horn
560a4694e4 Fix string.gsub behaviour with negative n 2021-07-22 00:06:11 +02:00
Enrico Horn
6b9dece367 Fix mathlib min, max and atan2 behaviour 2021-07-22 00:06:11 +02:00
Enrico Horn
179062493d Implement package.seeall 2021-07-22 00:06:11 +02:00
Enrico Horn
f81bc1e174 Make some errors compatible with native lua 2021-07-22 00:06:11 +02:00
Enrico Horn
bf23883492 Define clean up steps and clean up code 2021-07-22 00:06:11 +02:00
Enrico Horn
5465eff841 Update test result files in a platform dependant manner from native lua 2021-07-22 00:06:11 +02:00
Enrico Horn
ddc7531845 Remove invalid lua5.2 OOB calls from tablelib.lua 2021-07-22 00:06:11 +02:00
Enrico Horn
58a4dec882 Update errors tests for lua 5.2 2021-07-22 00:06:11 +02:00
Enrico Horn
f91cc9a509 Scripts to create result files from native lua 2021-07-22 00:06:11 +02:00
Enrico Horn
9792fcb018 Cleanup Tests with JUnit5 and move to different modules 2021-07-11 23:13:57 +02:00
Enrico Horn
1a6de4a227 Remove temprory test files and ignore them 2021-07-11 23:00:02 +02:00
Enrico Horn
1833c57d4d Extract luaj3.0-tests.zip to luaj-test/src/test/resources and delete it 2021-07-11 22:59:08 +02:00
Enrico Horn
e7e6190f9c Add formatter definition and format code 2021-07-03 22:23:49 +02:00
Enrico Horn
3c266bcc98 Move Lua5x.jj to lua-jse and customize package name 2021-07-03 22:19:30 +02:00
Enrico Horn
d2a92c07d3 Convert all line endings to Unix 2021-07-03 22:15:19 +02:00
Enrico Horn
a58147ddfa Move sources into maven modules 2021-03-11 22:07:08 +01:00
Enrico Horn
74e5ef6f36 Ignore eclipse project files 2021-03-07 01:39:37 +01:00
Enrico Horn
a9d475bbbf Remove eclipse project files 2021-03-05 21:26:41 +01: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
asie
a071b04b8f remove undesirable import 2019-09-03 08:33:28 +02:00
asie
11b29f92c1 fix string.format not converting non-strings for %s (requires __tostring fix) 2019-08-11 13:47:25 +02:00
gamax92
c666a507ab Support 4 byte UTF-8 sequences
Fixes lengthAsUtf8, encodeToUtf8, and isValidUtf8 to support UTF-8's
4-byte sequences or UTF-16's surrogate pairs properly.
Invalid surrogate pairs are converted to '?' as Java's converter does
2019-08-11 13:05:54 +02:00
gamax92
5026b5ac1e string.format fixes
Fix string.format's floating point implementation

Disable space if explicitPlus is set
Disable leftAdjust and zeroPad if no width is specified
precision gets set to zero if only a dot is specified

Add support for %a/A, Lua can use these and Java happens to support it
2019-08-11 12:50:29 +02:00
asie
6ba28727d2 move doubleToRawLongBits (not present on JME) to JSE class 2019-08-11 12:49:56 +02:00
gamax92
0707e71c6c Support __pairs and __ipairs
Added PAIRS and IPAIRS constants to LuaValue
Merged pairs and ipairs into one class with a dynamic constructor, this
is similar to Lua's pairsmeta function.
Check for and call it's specific metamethod if it's available.
2019-08-11 12:14:21 +02:00
gamax92
43f937470f Fix classes based on LibFunction giving "value" for their error message. 2019-08-11 12:11:40 +02:00
gamax92
5d3f2eb72c LuaClosure: Add the colon after line numbers to error messages 2019-08-11 12:11:31 +02:00
gamax92
244eb4b1a1 StringLib: Support seperators in string.rep 2019-08-11 12:07:47 +02:00
gamax92
626664a0fe BaseLib: fix handling of __tostring 2019-08-11 12:05:48 +02:00
gamax92
2bccb4670e LuaValue: add 0x to tojstring() to match Lua 2019-08-11 12:01:51 +02:00
gamax92
89acb5bcb5 LuaString: port strx2number for accurate double scanning, handle plus signs when converting strings to numbers 2019-08-11 11:59:49 +02:00
gamax92
c69585332b LexState: rename TK_EOS and <eos> to TK_EOF and <eof> to match Lua 2019-08-11 11:55:42 +02:00
gamax92
c9fa0f27c7 LuaValue, FuncState: correct error messages to match Lua 2019-08-11 11:50:42 +02:00
asie
af4cfe5e00 LuaDouble: handle negative zero, negative NaN 2019-08-11 11:47:51 +02: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
418 changed files with 53439 additions and 24353 deletions

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/core"/>
<classpathentry excluding="org/luaj/vm2/luajc/antlr/|org/luaj/vm2/luajc/lst/|org/luaj/vm2/luajc/JavaCodeGenerator.java" kind="src" path="src/jse"/>
<classpathentry kind="src" path="src/jme"/>
<classpathentry kind="src" path="test/java"/>
<classpathentry kind="src" path="test/junit"/>
<classpathentry kind="src" path="test/lua"/>
<classpathentry kind="src" path="examples/jse"/>
<classpathentry kind="src" path="examples/jme"/>
<classpathentry kind="src" path="examples/lua"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
<classpathentry kind="lib" path="lib/midpapi20.jar"/>
<classpathentry kind="lib" path="lib/cldcapi11.jar"/>
<classpathentry kind="lib" path="lib/bcel-5.2.jar"/>
<classpathentry kind="var" path="JRE_LIB"/>
<classpathentry kind="output" path="bin"/>
</classpath>

17
.gitignore vendored
View File

@@ -1,15 +1,4 @@
bin/
target/
build/
lib/
jit/
*.ser
*.gz
*.jar
*.lua
*.out
*.tar
*.txt
*.zip
docs
*.0
.classpath
.project
.settings/

138
.ide/cleanup.xml Normal file
View File

@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="2">
<profile kind="CleanUpProfile" name="Default" version="2">
<setting id="cleanup.array_with_curly" value="true"/>
<setting id="cleanup.use_autoboxing" value="true"/>
<setting id="cleanup.always_use_this_for_non_static_method_access" value="false"/>
<setting id="cleanup.remove_trailing_whitespaces_ignore_empty" value="false"/>
<setting id="cleanup.primitive_comparison" value="false"/>
<setting id="cleanup.system_property_file_encoding" value="true"/>
<setting id="cleanup.format_source_code_changes_only" value="false"/>
<setting id="cleanup.remove_redundant_semicolons" value="true"/>
<setting id="cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class" value="true"/>
<setting id="cleanup.useless_continue" value="true"/>
<setting id="cleanup.remove_redundant_type_arguments" value="true"/>
<setting id="cleanup.remove_unused_imports" value="true"/>
<setting id="cleanup.break_loop" value="false"/>
<setting id="cleanup.pull_up_assignment" value="false"/>
<setting id="cleanup.stringbuilder" value="false"/>
<setting id="cleanup.no_super" value="true"/>
<setting id="cleanup.arrays_fill" value="false"/>
<setting id="cleanup.use_lambda" value="true"/>
<setting id="cleanup.operand_factorization" value="false"/>
<setting id="cleanup.simplify_lambda_expression_and_method_ref" value="true"/>
<setting id="cleanup.always_use_blocks" value="true"/>
<setting id="cleanup.sort_members_all" value="false"/>
<setting id="cleanup.system_property_path_separator" value="true"/>
<setting id="cleanup.instanceof" value="false"/>
<setting id="cleanup.add_missing_annotations" value="true"/>
<setting id="cleanup.precompile_regex" value="false"/>
<setting id="cleanup.always_use_this_for_non_static_field_access" value="false"/>
<setting id="cleanup.boolean_literal" value="true"/>
<setting id="cleanup.always_use_parentheses_in_expressions" value="false"/>
<setting id="cleanup.sort_members" value="false"/>
<setting id="cleanup.remove_unused_local_variables" value="false"/>
<setting id="cleanup.add_missing_deprecated_annotations" value="true"/>
<setting id="cleanup.no_string_creation" value="true"/>
<setting id="cleanup.use_unboxing" value="false"/>
<setting id="cleanup.use_blocks_only_for_return_and_throw" value="false"/>
<setting id="cleanup.standard_comparison" value="false"/>
<setting id="cleanup.if_condition" value="true"/>
<setting id="cleanup.system_property_line_separator" value="true"/>
<setting id="cleanup.remove_trailing_whitespaces" value="true"/>
<setting id="cleanup.map_cloning" value="true"/>
<setting id="cleanup.add_serial_version_id" value="false"/>
<setting id="cleanup.try_with_resource" value="true"/>
<setting id="cleanup.use_this_for_non_static_method_access" value="false"/>
<setting id="cleanup.use_this_for_non_static_method_access_only_if_necessary" value="true"/>
<setting id="cleanup.single_used_field" value="false"/>
<setting id="cleanup.reduce_indentation" value="false"/>
<setting id="cleanup.primitive_parsing" value="false"/>
<setting id="cleanup.make_local_variable_final" value="false"/>
<setting id="cleanup.add_missing_methods" value="false"/>
<setting id="cleanup.qualify_static_member_accesses_with_declaring_class" value="true"/>
<setting id="cleanup.add_missing_override_annotations" value="true"/>
<setting id="cleanup.use_blocks" value="false"/>
<setting id="cleanup.multi_catch" value="true"/>
<setting id="cleanup.pull_out_if_from_if_else" value="true"/>
<setting id="cleanup.collection_cloning" value="true"/>
<setting id="cleanup.convert_to_enhanced_for_loop_if_loop_var_used" value="true"/>
<setting id="cleanup.make_variable_declarations_final" value="true"/>
<setting id="cleanup.redundant_comparator" value="false"/>
<setting id="cleanup.remove_unused_private_types" value="true"/>
<setting id="cleanup.system_property_boolean" value="true"/>
<setting id="cleanup.qualify_static_method_accesses_with_declaring_class" value="false"/>
<setting id="cleanup.organize_imports" value="true"/>
<setting id="cleanup.lazy_logical_operator" value="true"/>
<setting id="cleanup.bitwise_conditional_expression" value="false"/>
<setting id="cleanup.use_directly_map_method" value="false"/>
<setting id="cleanup.add_all" value="false"/>
<setting id="cleanup.system_property_file_separator" value="true"/>
<setting id="cleanup.qualify_static_field_accesses_with_declaring_class" value="false"/>
<setting id="cleanup.add_generated_serial_version_id" value="false"/>
<setting id="cleanup.controlflow_merge" value="false"/>
<setting id="cleanup.primitive_serialization" value="false"/>
<setting id="cleanup.comparing_on_criteria" value="true"/>
<setting id="cleanup.comparison_statement" value="true"/>
<setting id="cleanup.extract_increment" value="false"/>
<setting id="cleanup.insert_inferred_type_arguments" value="false"/>
<setting id="cleanup.make_private_fields_final" value="true"/>
<setting id="cleanup.useless_return" value="true"/>
<setting id="cleanup.instanceof_keyword" value="true"/>
<setting id="cleanup.use_this_for_non_static_field_access_only_if_necessary" value="true"/>
<setting id="cleanup.remove_trailing_whitespaces_all" value="true"/>
<setting id="cleanup.one_if_rather_than_duplicate_blocks_that_fall_through" value="true"/>
<setting id="cleanup.valueof_rather_than_instantiation" value="true"/>
<setting id="cleanup.plain_replacement" value="false"/>
<setting id="cleanup.remove_unnecessary_array_creation" value="true"/>
<setting id="cleanup.remove_private_constructors" value="true"/>
<setting id="cleanup.make_parameters_final" value="false"/>
<setting id="cleanup.substring" value="false"/>
<setting id="cleanup.ternary_operator" value="false"/>
<setting id="cleanup.merge_conditional_blocks" value="false"/>
<setting id="cleanup.return_expression" value="true"/>
<setting id="cleanup.system_property" value="true"/>
<setting id="cleanup.unlooped_while" value="true"/>
<setting id="cleanup.convert_to_enhanced_for_loop" value="true"/>
<setting id="cleanup.remove_unused_private_fields" value="true"/>
<setting id="cleanup.never_use_blocks" value="false"/>
<setting id="cleanup.remove_redundant_modifiers" value="true"/>
<setting id="cleanup.unreachable_block" value="false"/>
<setting id="cleanup.redundant_falling_through_block_end" value="false"/>
<setting id="cleanup.switch" value="false"/>
<setting id="cleanup.number_suffix" value="true"/>
<setting id="cleanup.remove_unnecessary_nls_tags" value="true"/>
<setting id="cleanup.convert_to_switch_expressions" value="false"/>
<setting id="cleanup.use_this_for_non_static_field_access" value="false"/>
<setting id="cleanup.static_inner_class" value="false"/>
<setting id="cleanup.use_string_is_blank" value="true"/>
<setting id="cleanup.add_missing_nls_tags" value="false"/>
<setting id="cleanup.qualify_static_member_accesses_through_instances_with_declaring_class" value="true"/>
<setting id="cleanup.remove_unnecessary_casts" value="true"/>
<setting id="cleanup.objects_equals" value="false"/>
<setting id="cleanup.convert_functional_interfaces" value="true"/>
<setting id="cleanup.format_source_code" value="true"/>
<setting id="cleanup.else_if" value="false"/>
<setting id="cleanup.boolean_value_rather_than_comparison" value="true"/>
<setting id="cleanup.add_default_serial_version_id" value="true"/>
<setting id="cleanup.remove_unused_private_methods" value="true"/>
<setting id="cleanup.make_type_abstract_if_missing_method" value="false"/>
<setting id="cleanup.join" value="false"/>
<setting id="cleanup.embedded_if" value="false"/>
<setting id="cleanup.use_anonymous_class_creation" value="false"/>
<setting id="cleanup.invert_equals" value="false"/>
<setting id="cleanup.add_missing_override_annotations_interface_methods" value="true"/>
<setting id="cleanup.remove_unused_private_members" value="false"/>
<setting id="cleanup.strictly_equal_or_different" value="true"/>
<setting id="cleanup.never_use_parentheses_in_expressions" value="true"/>
<setting id="cleanup.push_down_negation" value="false"/>
<setting id="cleanup.evaluate_nullable" value="false"/>
<setting id="cleanup.use_parentheses_in_expressions" value="true"/>
<setting id="cleanup.hash" value="false"/>
<setting id="cleanup.double_negation" value="true"/>
<setting id="cleanup.overridden_assignment" value="true"/>
<setting id="cleanup.primitive_rather_than_wrapper" value="true"/>
<setting id="cleanup.correct_indentation" value="false"/>
<setting id="cleanup.use_var" value="false"/>
</profile>
</profiles>

390
.ide/formatter.xml Normal file
View File

@@ -0,0 +1,390 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="21">
<profile kind="CodeFormatterProfile" name="LuaJ" version="21">
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_preserve"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
</profile>
</profiles>

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>luaj-vm</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

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
</div>
<h1>Getting Started with LuaJ</h1>
<h1>Getting Started with LuaJ</h1>
James Roseborough, Ian Farmer, Version 3.0.2
<p>
<small>
Copyright &copy; 2009-2014 Luaj.org.
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>
<hr>
<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:
<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>
<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:
<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>
<p>
@@ -213,8 +210,8 @@ Links to sources:<pre>
From the main distribution directory line type:
<pre>
java -cp lib/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 luac examples/lua/hello.lua
java -cp luaj-jse-3.0.2.jar lua luac.out
</pre>
<p>
@@ -228,8 +225,8 @@ Luaj can compile lua sources or binaries directly to java bytecode if the bcel l
<pre>
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;lib/luaj-jse-3.0.2.jar;.&quot; lua -l hello
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;luaj-jse-3.0.2.jar;.&quot; lua -l hello
</pre>
<p>
@@ -240,7 +237,7 @@ but the compiled classes must be in the class path at runtime, unless runtime ji
<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:
<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>
@@ -284,7 +281,7 @@ A simple example may be found in
</pre>
<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>
@@ -311,7 +308,7 @@ A simple example may be found in
</pre>
<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>
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.
<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>
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:
<pre>
javac -cp lib/luaj-jse-3.0.2.jar examples/jse/ScriptEngineSample.java
java -cp &quot;lib/luaj-jse-3.0.2.jar;examples/jse&quot; ScriptEngineSample
javac -cp luaj-jse-3.0.2.jar examples/jse/ScriptEngineSample.java
java -cp &quot;luaj-jse-3.0.2.jar;examples/jse&quot; ScriptEngineSample
</pre>
<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
to simplify access to underlying Android APIs.
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.
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.
Or try running it using:
<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>
<p>
@@ -861,37 +858,30 @@ An example skelton maven pom file for a skeleton project is in
<h2>Building the jars</h2>
An ant file is included in the root directory which builds the libraries by default.
Build the jars with maven.
<pre>
mvn clean verify
</pre>
<p>
Other targets exist for creating distribution file an measuring code coverage of unit tests.
<h2>Unit tests</h2>
<p>
The main luaj JUnit tests are organized into a JUnit 3 suite:
<pre>
test/junit/org/luaj/vm2/AllTests.lua
</pre>
All unit tests are executed during the build.
<p>
Unit test scripts can be found in these locations
Test scripts can be found in these locations
<pre>
test/lua/*.lua
test/lua/errors/*.lua
test/lua/perf/*.lua
test/lua/luaj3.0.2-tests.zip
luaj-test/src/test/resources
</pre>
Executon is included in the build of luaj-test.
<h2>Code coverage</h2>
<p>
A build script for running unit tests and producing code coverage statistics is in
<pre>
<a href="build-coverage.xml">build-coverage.xml</a>
</pre>
It relies on the cobertura code coverage library.
The maven build creates the coverage report in the luaj-test/target/site folder
during the verify phase.
<h1>8 - <a name="8">Downloads</a></h1>
@@ -930,7 +920,7 @@ Files are no longer hosted at LuaForge.
<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>
<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>
<li>Improve coroutine state logic including let unreferenced coroutines be garbage collected </li>

View File

@@ -1,108 +0,0 @@
<!-- And build script to compile lua scripts into runnable jar files using the "luajc"
lua to java bytecode compiler.
Each source file is converted into a runnable jar file that takes arguments from the command line.
For example, the program test/lua/perf/binarytrees.lua is converted to a jar that can be run with
java -jar binarytrees.jar 15
-->
<project default="all">
<import file="build.xml"/>
<import file="build-libs.xml"/>
<available file="luaj-jse-${version}.jar" property="luaj.lib.exists"/>
<!-- this may need to be changed when building on mac -->
<property name="rt.jar" value="${java.home}/lib/rt.jar"/>
<target name="luaj-lib" unless="luaj.lib.exists">
<antcall target="jar-jse"/>
</target>
<macrodef name="perftest">
<attribute name="cmd"/>
<sequential>
<echo level="info">------ @{cmd}</echo>
<exec executable="bash">
<arg value="-c"/>
<arg value="time @{cmd}"/>
</exec>
</sequential>
</macrodef>
<macrodef name="buildappjar">
<attribute name="luaprog"/>
<attribute name="arg" default=""/>
<attribute name="srcdir" default="test/lua/perf"/>
<sequential>
<echo level="info">=========== @{srcdir}/@{luaprog} =============</echo>
<delete dir="build/@{luaprog}"/>
<mkdir dir="build/@{luaprog}/class"/>
<java classname="luajc">
<classpath>
<pathelement path="luaj-jse-${version}.jar"/>
<pathelement path="lib/bcel-5.2.jar"/>
</classpath>
<arg value="-s"/>
<arg path="@{srcdir}"/>
<arg value="-d"/>
<arg path="build/@{luaprog}/class"/>
<arg value="-m"/>
<arg value="-v"/>
<arg value="@{luaprog}.lua"/>
</java>
<jar destfile="build/@{luaprog}.jar">
<fileset dir="build/@{luaprog}/class"/>
<zipfileset includes="org/luaj/vm2/*.class,org/luaj/vm2/lib/*.class,org/luaj/vm2/lib/jse/*.class,org/luaj/vm2/compiler/*.class" src="luaj-jse-${version}.jar" />
<manifest>
<attribute name="Main-Class" value="@{luaprog}" />
</manifest>
</jar>
<unjar src="build/@{luaprog}.jar" dest="build/@{luaprog}/unjarred"/>
<perftest cmd="java -jar build/@{luaprog}.jar @{arg}"/>
<!-- The following can be adapted to produce an optimized jar.
<taskdef resource="proguard/ant/task.properties" classpath="lib/proguard.jar" />
<proguard>
-injars build/@{luaprog}.jar
-outjars build/@{luaprog}-opt.jar
-libraryjars ${rt.jar}
-overloadaggressively
-repackageclasses ''
-allowaccessmodification
-printmapping build/@{luaprog}.map
-keep public class @{luaprog} {
public static void main(java.lang.String[]);
}
</proguard>
<unjar src="build/@{luaprog}-opt.jar" dest="build/@{luaprog}/unjarred-opt"/>
<perftest cmd="java -jar build/@{luaprog}-opt.jar @{arg}"/>
-->
</sequential>
</macrodef>
<target name="binarytrees" depends="luaj-lib,proguard-lib">
<buildappjar luaprog="binarytrees" arg="15"/>
</target>
<target name="fannkuch" depends="luaj-lib,proguard-lib">
<buildappjar luaprog="fannkuch" arg="10"/>
</target>
<target name="nbody" depends="luaj-lib,proguard-lib">
<buildappjar luaprog="nbody" arg="1000000"/>
</target>
<target name="nsieve" depends="luaj-lib,proguard-lib">
<buildappjar luaprog="nsieve" arg="8"/>
</target>
<target name="swingapp" depends="luaj-lib,proguard-lib">
<buildappjar luaprog="swingapp" srcdir="examples/lua"/>
</target>
<target name="allappjars" depends="binarytrees,fannkuch,nbody,nsieve,swingapp"/>
<target name="all" depends="allappjars"/>
</project>

View File

@@ -1,116 +0,0 @@
<?xml version="1.0"?>
<project name="sample" default="main" basedir=".">
<property file="version.properties"/>
<!-- find libs -->
<import file="build-libs.xml"/>
<!-- main java class -->
<property name="java.dir" value="examples/jse"/>
<property name="java.name" value="SampleApplet"/>
<!-- main script -->
<property name="script.dir" value="examples/lua"/>
<property name="script.name" value="swingapplet"/>
<property name="image.name" value="logo.gif"/>
<!-- location of luaj jar -->
<property name="libs.dir" value="lib"/>
<property name="luaj.jar" value="${libs.dir}/luaj-jse-${version}.jar"/>
<!-- location of build results -->
<property name="build.dir" value="build/applet"/>
<target name="clean">
<delete failonerror="false" dir="${build.dir}"/>
</target>
<target name="dirs">
<mkdir dir="build/applet/classes"/>
</target>
<target name="classes" depends="dirs">
<copy todir="${build.dir}">
<fileset dir="${script.dir}" includes="${script.name}.lua,${image.name}"/>
</copy>
<javac destdir="${build.dir}/classes" source="1.4" target="1.4"
classpath="${luaj.jar}" srcdir="${java.dir}" includes="${java.name}.java"/>
</target>
<target name="manifest" depends="dirs">
<manifest file="${build.dir}/MANIFEST.MF">
<attribute name="Permissions" value="sandbox"/>
<attribute name="Main-class" value="${java.name}"/>
</manifest>
</target>
<target name="jar" depends="classes,manifest">
<jar destfile="${build.dir}/${script.name}.jar"
manifest="${build.dir}/MANIFEST.MF">
<fileset dir="${build.dir}" includes="*.lua"/>
<fileset dir="${build.dir}/classes"/>
<zipfileset
src="${luaj.jar}"
excludes="**/script/*,**/luajc/**,**/parser/**,**/ast/**,lua*"/>
</jar>
</target>
<target name="obf" depends="jar,proguard-lib">
<taskdef resource="proguard/ant/task.properties" classpath="lib/proguard.jar" />
<copy file="${build.dir}/${script.name}.jar"
tofile="${build.dir}/${script.name}-unobfuscated.jar"/>
<proguard>
-injars ${build.dir}/${script.name}-unobfuscated.jar
-outjars ${build.dir}/${script.name}.jar
-libraryjars ${java.home}/lib/rt.jar
-overloadaggressively
-repackageclasses ''
-allowaccessmodification
-printmapping ${build.dir}/mapping.txt
-keep public class * extends java.applet.Applet
-target 1.4
</proguard>
</target>
<target name="sign" depends="obf">
<signjar jar="${build.dir}/${script.name}.jar"
alias="${sign.alias}"
storepass="${sign.storepass}"
keypass="${sign.keypass}"
keystore="${sign.keystore}" />
</target>
<target name="html" depends="dirs">
<echoxml file="build/applet/LuajSampleApplet.html">
<html>
<head><title>Luaj Sample Applet</title></head>
<body>
<h1>Luaj Sample Applet</h1>
Requires browser that supports applets.
${script.name}
<applet archive='${script.name}.jar'
code='${java.name}.class'
width='800'
height='640' >
<param name='luaj.script' value='${script.name}.lua'/>
<param name="java_version" value="1.4+"/>
</applet>
</body>
</html>
</echoxml>
</target>
<target name="run" depends="jar,html">
<exec executable="open" spawn="true">
<arg value="-a Firefox"/>
<arg path="build/applet/LuajSampleApplet.html"/>
</exec>
</target>
<target name="all" depends="clean,sign,html,run"/>
<target name="main" depends="sign,html"/>
</project>

View File

@@ -1,119 +0,0 @@
<project default="all" xmlns:artifact="antlib:org.apache.maven.artifact.ant">
<!--
Run code coverage for unit tests on the luaj vm and libraries.
-->
<property name="classes.dir" value="build/classes-debug" />
<property name="instrumented.dir" value="build/instrumented" />
<property name="reports.xml.dir" value="build/reports-junit-xml" />
<property name="reports.html.dir" value="build/reports-junit-html" />
<property name="coverage.xml.dir" value="build/reports-coverage-xml" />
<property name="coverage.html.dir" value="build/reports-coverage-html" />
<property name="cobertura.serfile" value="cobertura.ser" />
<property name="cobertura.logfile" value="cobertura.log" />
<artifact:dependencies filesetId="cobutura.fileset">
<dependency groupId="net.sourceforge.cobertura" artifactId="cobertura" version="1.9.4.1"/>
<dependency groupId="junit" artifactId="junit" version="3.8.1"/>
</artifact:dependencies>
<path id="cobertura.classpath">
<fileset refid="cobutura.fileset" />
</path>
<taskdef classpathref="cobertura.classpath" resource="tasks.properties" />
<import file="wtk.xml"/>
<property environment="env"/>
<target name="clean" description="Remove all files created by the build/test process.">
<delete dir="${classes.dir}" failonerror="yes"/>
<delete dir="${instrumented.dir}" failonerror="yes"/>
<delete file="${cobertura.logfile}" />
<delete file="${cobertura.serfile}" />
</target>
<target name="init">
<ant antfile="build.xml" target="bcel-lib"/>
<ant antfile="build.xml" target="luaj1-lib"/>
<mkdir dir="${classes.dir}" />
<mkdir dir="${instrumented.dir}" />
<mkdir dir="${reports.xml.dir}" />
<mkdir dir="${reports.html.dir}" />
<mkdir dir="${coverage.xml.dir}" />
<mkdir dir="${coverage.html.dir}" />
</target>
<target name="compile" depends="init,wtk-or-fail">
<javac destdir="${classes.dir}" debug="yes" target="1.5">
<classpath refid="cobertura.classpath" />
<classpath refid="wtk-libs" />
<classpath path="lib/bcel-5.2.jar" />
<src path="src/core"/>
<src path="src/jme"/>
<src path="src/jse"/>
<src path="test/junit"/>
</javac>
</target>
<target name="instrument" depends="compile">
<delete file="${cobertura.serfile}"/>
<delete dir="${instrumented.dir}" failonerror="no"/>
<cobertura-instrument datafile="${cobertura.serfile}" todir="${instrumented.dir}">
<fileset dir="${classes.dir}">
<include name="org/luaj/vm2/*.class" />
<include name="org/luaj/vm2/lib/*.class" />
<include name="org/luaj/vm2/lib/jse/*.class" />
<include name="org/luaj/vm2/lib/jme/*.class" />
<include name="org/luaj/vm2/compiler/*.class" />
<include name="org/luaj/vm2/luajc/*.class" />
<include name="org/luaj/vm2/lua2java/*.class" />
<include name="org/luaj/vm2/parser/*.class" />
<include name="org/luaj/vm2/ast/*.class" />
<exclude name="**/*Test*.class" />
</fileset>
</cobertura-instrument>
</target>
<target name="test">
<junit fork="yes" dir="${basedir}" showoutput="yes">
<sysproperty key="net.sourceforge.cobertura.serfile"
file="${basedir}/${cobertura.serfile}" />
<classpath location="${instrumented.dir}" />
<classpath location="${classes.dir}" />
<classpath refid="cobertura.classpath" />
<classpath location="test/lua" />
<classpath location="test/junit/org/luaj/vm2/compiler" />
<classpath location="test/junit/org/luaj/vm2/vm1" />
<classpath path="lib/bcel-5.2.jar" />
<formatter type="xml" />
<batchtest todir="${reports.xml.dir}">
<fileset dir="test/junit">
<include name="org/luaj/vm2/AllTests.java" />
</fileset>
</batchtest>
</junit>
<junitreport todir="${reports.xml.dir}">
<fileset dir="${reports.xml.dir}">
<include name="TEST-*.xml" />
</fileset>
<report format="frames" todir="${reports.html.dir}" />
</junitreport>
</target>
<target name="report">
<cobertura-report datafile="${cobertura.serfile}" destdir="${coverage.xml.dir}" format="xml" />
<cobertura-report datafile="${cobertura.serfile}" destdir="${coverage.html.dir}">
<fileset dir="src/core"/>
<fileset dir="src/jse"/>
<fileset dir="src/jme"/>
</cobertura-report>
</target>
<target name="coverage" depends="clean,init,compile,instrument,test,report"/>
<target name="all" depends="coverage" />
</project>

View File

@@ -1,56 +0,0 @@
<project default="all-libs">
<available file="lib/midpapi20.jar" property="midpapi.lib.exists"/>
<available file="lib/bcel-5.2.jar" property="bcel.lib.exists"/>
<available file="lib/javacc.jar" property="javacc.lib.exists"/>
<available file="lib/proguard.jar" property="proguard.lib.exists"/>
<available file="lib/antenna-bin-1.2.0-beta.jar" property="antenna.lib.exists"/>
<available file="lib/junit.jar" property="junit.lib.exists"/>
<available file="lib/cobertura.jar" property="cobertura.lib.exists"/>
<available file="lib/microemulator.jar" property="microemulator.lib.exists"/>
<macrodef name="download">
<attribute name="zipname"/>
<attribute name="jars" default="**/*.jar"/>
<sequential>
<mkdir dir="lib"/>
<get src="http://luaj.sourceforge.net/lib/@{zipname}.tar.gz"
dest="lib/@{zipname}.tar.gz"/>
<gunzip src="lib/@{zipname}.tar.gz" dest="lib/@{zipname}.tar"/>
<untar src="lib/@{zipname}.tar" dest="lib" overwrite="true">
<patternset>
<include name="@{jars}"/>
</patternset>
<mapper type="flatten"/>
</untar>
</sequential>
</macrodef>
<target name="wtk-libs" unless="midpapi.lib.exists">
<download zipname="wtk-2.5.2-api"/>
</target>
<target name="bcel-lib" unless="bcel.lib.exists">
<download zipname="/bcel-5.2"/>
</target>
<target name="javacc-lib" unless="javacc.lib.exists">
<download zipname="javacc-5.0"/>
</target>
<target name="proguard-lib" unless="proguard.lib.exists">
<download zipname="proguard4.6"/>
</target>
<target name="antenna-lib" unless="antenna.lib.exists">
<download zipname="antenna-bin-1.2.0-beta"/>
</target>
<target name="junit-lib" unless="junit.lib.exists">
<download zipname="junit-3.8.2"/>
</target>
<target name="cobertura-lib" unless="cobertura.lib.exists">
<download zipname="cobertura-1.9.4.1-bin"/>
</target>
<target name="microemulator-lib" unless="microemulator.lib.exists">
<download zipname="microemulator-2.0.4" jars="**/microemulator.jar"/>
</target>
<target name="all-libs" depends="wtk-libs,bcel-lib,javacc-lib,proguard-lib,antenna-lib,junit-lib,cobertura-lib"/>
</project>

View File

@@ -1,176 +0,0 @@
<project default="usage">
<!-- Ant file to deploy to maven once the distribution is released on sourceforge.
-->
<property file="version.properties"/>
<macrodef name="write_pom">
<attribute name="platform"/>
<attribute name="snapshot" default=""/>
<sequential>
<mkdir dir="build/maven-${version}"/>
<echo file="build/maven-${version}/luaj-@{platform}-${version}@{snapshot}.pom"><![CDATA[<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.luaj</groupId>
<artifactId>luaj-]]>@{platform}<![CDATA[</artifactId>
<version>]]>${version}@{snapshot}<![CDATA[</version>
<packaging>jar</packaging>
<name>luaj-]]>@{platform}<![CDATA[</name>
<description>Luaj ]]>${version}<![CDATA[ for the ]]>@{platform}<![CDATA[ platform</description>
<url>http://sourceforge.net/projects/luaj/</url>
<licenses>
<license>
<name>MIT License</name>
<url>http://luaj.sourceforge.net/license.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>jrosebor</id>
<name>James Roseborough</name>
<email>jim.roseborough@luaj.org</email>
<timezone>-8</timezone>
<roles></roles>
</developer>
<developer>
<id>ifarmer</id>
<name>Ian Farmer</name>
<email>ian.farmer@luaj.org</email>
<timezone>-8</timezone>
<roles></roles>
</developer>
</developers>
<scm>
<url>http://luaj.cvs.sourceforge.net/viewvc/luaj/luaj-vm/</url>
</scm>
</project>
]]></echo>
</sequential>
</macrodef>
<macrodef name="prepare_files">
<attribute name="platform"/>
<attribute name="snapshot" default=""/>
<sequential>
<mkdir dir="build/maven-${version}"/>
<write_pom platform="@{platform}" snapshot="@{snapshot}"/>
<copy file="luaj-${version}.zip" todir="build/maven-${version}"/>
<unzip src="build/maven-${version}/luaj-${version}.zip" dest="build/maven-${version}"/>
<copy file="build/maven-${version}/luaj-${version}/lib/luaj-@{platform}-${version}.jar" todir="build/maven-${version}"/>
<!-- make a -sources file -->
<mkdir dir="build/maven-${version}/sources-@{platform}"/>
<copy todir="build/maven-${version}/sources-@{platform}">
<fileset dir="build/maven-${version}/luaj-${version}/src/core"/>
<fileset dir="build/maven-${version}/luaj-${version}/src/@{platform}"/>
<filterchain>
<tokenfilter><replacestring from='"Luaj 0.0"' to='"Luaj-@{platform} ${version}"'/></tokenfilter>
</filterchain>
</copy>
<zip destfile="build/maven-${version}/luaj-@{platform}-${version}-sources.jar"
basedir="build/maven-${version}/sources-@{platform}"/>
<!-- make a -javadoc file -->
<mkdir dir="build/maven-${version}/javadoc-@{platform}"/>
<javadoc defaultexcludes="yes"
destdir="build/maven-${version}/javadoc-@{platform}"
author="true"
version="true"
use="true"
windowtitle="Luaj API">
<fileset dir="build/maven-${version}/sources-@{platform}">
<include name="org/luaj/vm/*.java"/>
<include name="org/luaj/vm2/*.java"/>
<include name="org/luaj/vm2/server/*.java"/>
<include name="**/LuaC.java"/>
<include name="**/LuaJC.java"/>
<include name="**/lib/*/*.java"/>
</fileset>
<doctitle><![CDATA[<h1>Luaj API</h1>]]></doctitle>
<bottom><![CDATA[<i>Copyright &#169; 2007-2015 Luaj.org. All Rights Reserved.</i>]]></bottom>
<tag name="todo" scope="all" description="To do:"/>
<link offline="true" href="http://sourceforge.net/projects/luaj/" packagelistLoc="C:\tmp"/>
<link href="http://sourceforge.net/projects/luaj/"/>
</javadoc>
<zip destfile="build/maven-${version}/luaj-@{platform}-${version}-javadoc.jar"
basedir="build/maven-${version}/javadoc-@{platform}"/>
</sequential>
</macrodef>
<macrodef name="shapshot_files">
<attribute name="platform"/>
<sequential>
<exec executable="mvn">
<arg value="deploy:deploy-file"/>
<arg value="-Durl=https://oss.sonatype.org/content/repositories/snapshots"/>
<arg value="-DrepositoryId=nexus-releases"/>
<arg value="-DpomFile=build/maven-${version}/luaj-@{platform}-${version}-SNAPSHOT.pom"/>
<arg value="-Dfile=build/maven-${version}/luaj-@{platform}-${version}.jar"/>
<arg value="-Dsources=build/maven-${version}/luaj-@{platform}-${version}-sources.jar"/>
<arg value="-Djavadoc=build/maven-${version}/luaj-@{platform}-${version}-javadoc.jar"/>
</exec>
</sequential>
</macrodef>
<macrodef name="sign_and_deploy">
<attribute name="platform"/>
<sequential>
<exec executable="mvn">
<arg value="gpg:sign-and-deploy-file"/>
<arg value="-Durl=http://oss.sonatype.org/service/local/staging/deploy/maven2"/>
<arg value="-DrepositoryId=nexus-releases"/>
<arg value="-DpomFile=build/maven-${version}/luaj-@{platform}-${version}.pom"/>
<arg value="-Dfile=build/maven-${version}/luaj-@{platform}-${version}.jar"/>
<arg value="-Dsources=build/maven-${version}/luaj-@{platform}-${version}-sources.jar"/>
<arg value="-Djavadoc=build/maven-${version}/luaj-@{platform}-${version}-javadoc.jar"/>
</exec>
</sequential>
</macrodef>
<macrodef name="prepare_and_install">
<attribute name="platform"/>
<sequential>
<prepare_files platform="@{platform}"/>
<exec executable="mvn">
<arg value="install:install-file"/>
<arg value="-Dfile=build/maven-${version}/luaj-@{platform}-${version}.jar"/>
<arg value="-DpomFile=build/maven-${version}/luaj-@{platform}-${version}.pom"/>
</exec>
</sequential>
</macrodef>
<macrodef name="prepare_and_snapshot">
<attribute name="platform"/>
<sequential>
<prepare_files platform="@{platform}" snapshot="-SNAPSHOT"/>
<shapshot_files platform="@{platform}"/>
</sequential>
</macrodef>
<macrodef name="prepare_and_deploy">
<attribute name="platform"/>
<sequential>
<prepare_files platform="@{platform}"/>
<sign_and_deploy platform="@{platform}"/>
</sequential>
</macrodef>
<target name="install">
<prepare_and_install platform="jse"/>
<prepare_and_install platform="jme"/>
</target>
<target name="snapshot">
<prepare_and_snapshot platform="jse"/>
<prepare_and_snapshot platform="jme"/>
</target>
<target name="deploy">
<prepare_and_deploy platform="jse"/>
<prepare_and_deploy platform="jme"/>
</target>
<target name="usage">
<echo level="info">Usage: ant [-Dversion=${version}] -f build-maven.xml [install | shapshot | deploy]</echo>
</target>
</project>

View File

@@ -1,113 +0,0 @@
<?xml version="1.0"?>
<project name="sample" default="all" basedir=".">
<property file="version.properties"/>
<!-- find libs -->
<import file="build-libs.xml"/>
<!-- main script -->
<property name="script.name" value="hello"/>
<property name="script.dir" value="examples/lua"/>
<target name="clean">
<delete failonerror="false" dir="build"/>
</target>
<target name="dirs">
<mkdir dir="build"/>
<mkdir dir="build/tool"/>
<mkdir dir="build/classes"/>
</target>
<target name="tools" depends="dirs,bcel-lib,wtk-libs,microemulator-lib">
<javac destdir="build/tool" classpath="lib/bcel-5.2.jar">
<src path="src/core"/>
<src path="src/jse"/>
</javac>
</target>
<!-- compile script into lua bytecode -->
<target name="luac" depends="tools">
<java classname="luac" classpath="build/tool">
<arg line="-o build/classes/${script.name}.lua"/>
<arg line="${script.dir}/${script.name}.lua"/>
</java>
</target>
<!-- compile script into java bytecode -->
<target name="luajc" depends="tools,wtk-libs">
<java classname="luajc" classpath="build/tool:lib/bcel-5.2.jar">
<arg line="-verbose"/>
<arg line="-srcdir ${script.dir}"/>
<arg line="-destdir build/classes"/>
<arg line="${script.name}.lua"/>
</java>
</target>
<target name="classes" depends="dirs,wtk-libs">
<mkdir dir="build/midlet/src"/>
<copy todir="build/midlet/src">
<fileset dir="src/core"/>
<fileset dir="src/jme"/>
<fileset dir="examples/jme"/>
<filterchain>
<tokenfilter><replacestring from='"Luaj 0.0"' to='"Luaj-jme ${version}"'/></tokenfilter>
</filterchain>
</copy>
<path id="wtk-libs">
<pathelement path="lib/cldcapi11.jar"/>
<pathelement path="lib/midpapi20.jar"/>
<pathelement path="lib/mmapi.jar"/>
</path>
<javac destdir="build/classes" encoding="utf-8" source="1.3" target="1.2" bootclasspathref="wtk-libs"
srcdir="build/midlet/src"/>
</target>
<target name="jar" depends="luajc,classes">
<jar destfile="build/sample-plain.jar"
basedir="build/classes"/>
</target>
<target name="obf" depends="jar,proguard-lib">
<taskdef resource="proguard/ant/task.properties" classpath="lib/proguard.jar" />
<proguard>
-injars build/sample-plain.jar
-outjars build/sample.jar
-libraryjars lib/midpapi20.jar
-libraryjars lib/cldcapi11.jar
-overloadaggressively
-repackageclasses ''
-microedition
-keep public class SampleMIDlet
-keep public class * extends org.luaj.vm2.LuaValue
</proguard>
</target>
<target name="jad" depends="obf">
<length file="build/sample.jar" property="sample.jar.length" />
<echo level="info">Jar file length is ${sample.jar.length}</echo>
<manifest file="build/sample.jad">
<attribute name="Built-By" value="luaj-${version}"/>
<attribute name="MIDlet-Name" value="Luaj ${script.name}"/>
<attribute name="MIDlet-Version" value="${version}"/>
<attribute name="MIDlet-Vendor" value="luaj.org"/>
<attribute name="MIDlet-Description" value="Luaj Sample Midlet"/>
<attribute name="MIDlet-1" value="${script.name}-${version}, , SampleMIDlet"/>
<attribute name="MIDlet-Jar-URL" value="sample.jar"/>
<attribute name="MIDlet-Jar-Size" value="${sample.jar.length}"/>
<attribute name="script" value="${script.name}"/>
</manifest>
</target>
<target name="package" depends="jad,jar,obf"/>
<target name="run" depends="jad,jar,obf,microemulator-lib">
<java jar="lib/microemulator.jar" fork="true">
<arg path="build/sample.jad"/>
</java>
</target>
<target name="all" depends="clean,package,run"/>
</project>

View File

@@ -1,68 +0,0 @@
<project default="all">
<import file="build.xml"/>
<property name="lua.command" value="lua"/>
<available file="luaj-jse-${version}.jar" property="luaj.lib.exists"/>
<available file="lib/jill-1.0.1.jar" property="jill.lib.exists"/>
<available file="lib/kahlua.jar" property="kahlua.lib.exists"/>
<available file="lib/mochalua-1.0.jar" property="mochalua.lib.exists"/>
<target name="luaj-lib" unless="luaj.lib.exists">
<antcall target="jar-jse"/>
</target>
<target name="jill-lib" unless="jill.lib.exists">
<mkdir dir="lib"/>
<get src="http://jillcode.googlecode.com/files/jill-1.0.1.zip"
dest="lib/jill-1.0.1.zip"/>
<unzip src="lib/jill-1.0.1.zip" dest="lib" overwrite="true"/>
<ant dir="lib/jill-1.0.1" target="compile"/>
<jar destfile="lib/jill-1.0.1.jar" basedir="lib/jill-1.0.1/compiled"/>
</target>
<target name="kahlua-lib" unless="kahlua.lib.exists">
<get src="http://kahlua.googlecode.com/files/kahlua.jar"
dest="lib/kahlua.jar"/>
</target>
<target name="mochalua-lib" unless="mochalua.lib.exists">
<get src="http://mochalua.googlecode.com/files/Mochalua%201.0.jar"
dest="lib/mochalua-1.0.jar"/>
</target>
<target name="perf-libs" depends="luaj-lib,bcel-lib,jill-lib,kahlua-lib,mochalua-lib"/>
<macrodef name="perftest">
<attribute name="program" default="lua"/>
<attribute name="luaprog" default="fannkuch.lua 10"/>
<attribute name="basedir" default="test/lua/perf/"/>
<sequential>
<echo level="info">------ @{program} @{luaprog}</echo>
<exec executable="bash">
<arg value="-c"/>
<arg value="time @{program} @{basedir}@{luaprog}"/>
</exec>
</sequential>
</macrodef>
<macrodef name="testcase">
<attribute name="luaprog" default="fannkuch.lua 10"/>
<sequential>
<echo level="info">=========== @{luaprog} =============</echo>
<perftest program="java -version" luaprog="" basedir=""/>
<perftest program="${lua.command}" luaprog="@{luaprog}"/>
<perftest program="java -cp luaj-jse-${version}.jar lua -n" luaprog="@{luaprog}"/>
<perftest program="java -cp luaj-jse-${version}.jar${path.separator}lib/bcel-5.2.jar lua -b" luaprog="@{luaprog}"/>
</sequential>
</macrodef>
<target name="alltests">
<testcase luaprog="binarytrees.lua 15"/>
<testcase luaprog="fannkuch.lua 10"/>
<testcase luaprog="nbody.lua 1000000"/>
<testcase luaprog="nsieve.lua 9"/>
</target>
<target name="all" depends="alltests"/>
</project>

208
build.xml
View File

@@ -1,208 +0,0 @@
<project default="all">
<property file="version.properties"/>
<property name="jar.name.jme" value="luaj-jme-${version}.jar"/>
<property name="jar.name.jse" value="luaj-jse-${version}.jar"/>
<property name="jar.name.sources" value="luaj-sources-${version}.jar"/>
<target name="clean-build">
<delete dir="build"/>
</target>
<target name="clean" depends="clean-build">
<delete>
<fileset dir="." includes="luaj-*.jar"/>
</delete>
<delete dir="examples/android/bin"/>
<delete dir="examples/android/build"/>
<delete dir="examples/android/gen"/>
<delete dir="examples/android/libs"/>
<delete dir="examples/maven/target"/>
</target>
<import file="build-libs.xml"/>
<target name="parser" depends="javacc-lib">
<java classname="javacc" classpath="lib/javacc.jar">
<arg line="grammar/LuaParser.jj"/>
</java>
</target>
<target name="plain-parser" depends="javacc-lib">
<java dir="src/jse" fork="true" classname="javacc" classpath="lib/javacc.jar">
<arg line="../../grammar/Lua52.jj"/>
</java>
</target>
<target name="compile" depends="wtk-libs,bcel-lib">
<delete dir="build/jme/src"/>
<delete dir="build/jse/src"/>
<mkdir dir="build/jme/src"/>
<mkdir dir="build/jse/src"/>
<mkdir dir="build/jme/classes"/>
<mkdir dir="build/jse/classes"/>
<copy todir="build/jme/src">
<fileset dir="src/core"/>
<fileset dir="src/jme"/>
<filterchain>
<tokenfilter><replacestring from='"Luaj 0.0"' to='"Luaj-jme ${version}"'/></tokenfilter>
</filterchain>
</copy>
<copy todir="build/jse/src">
<fileset dir="src/core"/>
<filterchain>
<tokenfilter><replacestring from='"Luaj 0.0"' to='"Luaj-jse ${version}"'/></tokenfilter>
</filterchain>
</copy>
<copy todir="build/jse/src">
<fileset dir="src/jse"/>
<filterchain>
<tokenfilter><replacestring from='&lt;String&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Stat&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Exp&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Name&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Block&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;TableField&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;VarExp&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Exp.VarExp&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Object,String&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Double,String&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Integer,Integer&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Integer,LocalVariableGen&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;Exp,Integer&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;String,byte[]&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;String,Variable&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;LuaValue,String&gt;' to=''/></tokenfilter>
<tokenfilter><replacestring from='&lt;LuaString,String&gt;' to=''/></tokenfilter>
</filterchain>
</copy>
<path id="wtk-libs">
<pathelement path="lib/cldcapi11.jar"/>
<pathelement path="lib/midpapi20.jar"/>
<pathelement path="lib/mmapi.jar"/>
</path>
<javac destdir="build/jme/classes" encoding="utf-8" source="1.3" target="1.2" bootclasspathref="wtk-libs"
srcdir="build/jme/src"/>
<javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3"
classpath="lib/bcel-5.2.jar"
srcdir="build/jse/src"
excludes="**/script/*,**/Lua2Java*,**/server/*,lua*"/>
<javac destdir="build/jse/classes" encoding="utf-8" source="1.5" target="1.5"
classpath="build/jse/classes"
srcdir="build/jse/src"
includes="**/script/*,**/Lua2Java*,**/server/*"/>
<javac destdir="build/jse/classes" encoding="utf-8" source="1.3" target="1.3"
classpath="build/jse/classes"
srcdir="build/jse/src"
includes="lua*"/>
</target>
<target name="jar-jme" depends="compile">
<jar destfile="${jar.name.jme}" basedir="build/jme/classes"/>
</target>
<target name="jar-jse" depends="compile">
<jar destfile="${jar.name.jse}">
<fileset dir="build/jse/classes"/>
<fileset dir="src/jse/">
<include name="META-INF/services/**"/>
</fileset>
</jar>
</target>
<target name="jar-jse-sources" depends="compile">
<jar destfile="${jar.name.sources}">
<fileset dir="build/jme/src"/>
<fileset dir="build/jse/src"/>
</jar>
</target>
<target name="doc">
<delete dir="docs/api"/>
<mkdir dir="docs/api"/>
<javadoc defaultexcludes="yes"
destdir="docs/api"
author="true"
version="true"
use="true"
windowtitle="Luaj API">
<fileset dir="src/core" defaultexcludes="yes" includes="org/luaj/vm2/*.java,org/luaj/vm2/compiler/LuaC.java,org/luaj/vm2/lib/*.java"/>
<fileset dir="src/jse" defaultexcludes="yes" includes="org/luaj/vm2/lib/jse/*.java,org/luaj/vm2/luajc/LuaJC.java,org/luaj/vm2/server/*.java"/>
<fileset dir="src/jme" defaultexcludes="yes" includes="org/luaj/vm2/lib/jme/*.java"/>
<doctitle><![CDATA[<h1>Luaj API</h1>]]></doctitle>
<bottom><![CDATA[<i>Copyright &#169; 2007-2015 Luaj.org. All Rights Reserved.</i>]]></bottom>
<tag name="todo" scope="all" description="To do:"/>
<group title="Core VM" packages="org.luaj.vm.*"/>
<link offline="true" href="http://sourceforge.net/projects/luaj/" packagelistLoc="C:\tmp"/>
<link href="http://sourceforge.net/projects/luaj/"/>
</javadoc>
</target>
<target name="dist" depends="all,doc">
<delete dir="build/luaj-${version}"/>
<mkdir dir="build/luaj-${version}/src"/>
<mkdir dir="build/luaj-${version}/lib"/>
<copy todir="build/luaj-${version}/src">
<fileset dir="src">
<exclude name="src/test/**"/>
<exclude name="**/antlr/**"/>
<exclude name="**/lst/**"/>
<exclude name="**/JavaCodeGenerator.java"/>
<exclude name="**/LuaJCompiler.java"/>
</fileset>
</copy>
<copy todir="build/luaj-${version}/test">
<fileset dir="test"/>
</copy>
<copy todir="build/luaj-${version}/examples">
<fileset dir="examples">
<include name="android/*.*"/>
<include name="android/assets/**"/>
<include name="android/res/**"/>
<include name="android/src/**"/>
<include name="jme/*.java"/>
<include name="jse/*.java"/>
<include name="lua/*.*"/>
<include name="maven/pom.xml"/>
<include name="maven/src/**"/>
</fileset>
</copy>
<copy todir="build/luaj-${version}/lib">
<fileset dir=".">
<include name="*-${version}.jar"/>
</fileset>
</copy>
<copy todir="build/luaj-${version}">
<fileset dir=".">
<include name="build.xml"/>
<include name="build-libs.xml"/>
<include name="build-coverage.xml"/>
<include name="version.properties"/>
<include name="wtk.xml"/>
<include name="README.html"/>
<include name="names.csv"/>
<include name=".classpath"/>
<include name=".project"/>
</fileset>
</copy>
<copy todir="build/luaj-${version}/docs">
<fileset dir="docs"/>
</copy>
<zip destfile="luaj-${version}.zip"
basedir="build" includes="luaj-${version}/**"/>
</target>
<target name="mvn_install" depends="jar-jse">
<exec executable="mvn">
<arg value="install:install-file"/>
<arg value="-Dfile=${jar.name.jse}"/>
<arg value="-DgroupId=org.luaj"/>
<arg value="-DartifactId=luaj-jse"/>
<arg value="-Dversion=${version}"/>
<arg value="-Dpackaging=jar"/>
</exec>
</target>
<target name="all" depends="clean,jar-jme,jar-jse,jar-jse-sources"/>
</project>

25
luaj-core/pom.xml Normal file
View File

@@ -0,0 +1,25 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.luaj</groupId>
<artifactId>luaj-parent</artifactId>
<version>3.0-SNAPSHOT</version>
</parent>
<artifactId>luaj-core</artifactId>
<name>luaj-core</name>
<description>Core code for LuaJ</description>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -21,16 +21,16 @@
******************************************************************************/
package org.luaj.vm2;
/**
* String buffer for use in string library methods, optimized for production
* of StrValue instances.
* String buffer for use in string library methods, optimized for production of
* StrValue instances.
* <p>
* The buffer can begin initially as a wrapped {@link LuaValue}
* and only when concatenation actually occurs are the bytes first copied.
* The buffer can begin initially as a wrapped {@link LuaValue} and only when
* concatenation actually occurs are the bytes first copied.
* <p>
* To convert back to a {@link LuaValue} again,
* the function {@link Buffer#value()} is used.
* To convert back to a {@link LuaValue} again, the function
* {@link Buffer#value()} is used.
*
* @see LuaValue
* @see LuaValue#buffer()
* @see LuaString
@@ -57,6 +57,7 @@ public final class Buffer {
/**
* Create buffer with default capacity
*
* @see #DEFAULT_CAPACITY
*/
public Buffer() {
@@ -65,6 +66,7 @@ public final class Buffer {
/**
* Create buffer with specified initial capacity
*
* @param initialCapacity the initial capacity
*/
public Buffer(int initialCapacity) {
@@ -76,6 +78,7 @@ public final class Buffer {
/**
* Create buffer with specified initial value
*
* @param value the initial value
*/
public Buffer(LuaValue value) {
@@ -86,6 +89,7 @@ public final class Buffer {
/**
* Get buffer contents as a {@link LuaValue}
*
* @return value as a {@link LuaValue}, converting as necessary
*/
public LuaValue value() {
@@ -94,6 +98,7 @@ public final class Buffer {
/**
* Set buffer contents as a {@link LuaValue}
*
* @param value value to set
*/
public Buffer setvalue(LuaValue value) {
@@ -105,15 +110,17 @@ public final class Buffer {
/**
* Convert the buffer to a {@link LuaString}
*
* @return the value as a {@link LuaString}
*/
public final LuaString tostring() {
public LuaString tostring() {
realloc(length, 0);
return LuaString.valueOf(bytes, offset, length);
}
/**
* Convert the buffer to a Java String
*
* @return the value as a Java String
*/
public String tojstring() {
@@ -122,17 +129,20 @@ public final class Buffer {
/**
* Convert the buffer to a Java String
*
* @return the value as a Java String
*/
@Override
public String toString() {
return tojstring();
}
/**
* Append a single byte to the buffer.
*
* @return {@code this} to allow call chaining
*/
public final Buffer append( byte b ) {
public Buffer append(byte b) {
makeroom(0, 1);
bytes[offset+length++] = b;
return this;
@@ -140,18 +150,20 @@ public final class Buffer {
/**
* Append a {@link LuaValue} to the buffer.
*
* @return {@code this} to allow call chaining
*/
public final Buffer append( LuaValue val ) {
public Buffer append(LuaValue val) {
append(val.strvalue());
return this;
}
/**
* Append a {@link LuaString} to the buffer.
*
* @return {@code this} to allow call chaining
*/
public final Buffer append( LuaString str ) {
public Buffer append(LuaString str) {
final int n = str.m_length;
makeroom(0, n);
str.copyInto(0, bytes, offset+length, n);
@@ -160,12 +172,13 @@ public final class Buffer {
}
/**
* Append a Java String to the buffer.
* The Java string will be converted to bytes using the UTF8 encoding.
* Append a Java String to the buffer. The Java string will be converted to
* bytes using the UTF8 encoding.
*
* @return {@code this} to allow call chaining
* @see LuaString#encodeToUtf8(char[], int, byte[], int)
*/
public final Buffer append( String str ) {
public Buffer append(String str) {
char[] c = str.toCharArray();
final int n = LuaString.lengthAsUtf8(c);
makeroom(0, n);
@@ -174,34 +187,46 @@ public final class Buffer {
return this;
}
/** Concatenate this buffer onto a {@link LuaValue}
* @param lhs the left-hand-side value onto which we are concatenating {@code this}
/**
* Concatenate this buffer onto a {@link LuaValue}
*
* @param lhs the left-hand-side value onto which we are concatenating
* {@code this}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer concatTo(LuaValue lhs) {
return setvalue(lhs.concat(value()));
}
/** Concatenate this buffer onto a {@link LuaString}
* @param lhs the left-hand-side value onto which we are concatenating {@code this}
/**
* Concatenate this buffer onto a {@link LuaString}
*
* @param lhs the left-hand-side value onto which we are concatenating
* {@code this}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer concatTo(LuaString lhs) {
return value != null && !value.isstring()? setvalue(lhs.concat(value)): prepend(lhs);
}
/** Concatenate this buffer onto a {@link LuaNumber}
/**
* Concatenate this buffer onto a {@link LuaNumber}
* <p>
* The {@link LuaNumber} will be converted to a string before concatenating.
* @param lhs the left-hand-side value onto which we are concatenating {@code this}
*
* @param lhs the left-hand-side value onto which we are concatenating
* {@code this}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer concatTo(LuaNumber lhs) {
return value != null && !value.isstring()? setvalue(lhs.concat(value)): prepend(lhs.strvalue());
}
/** Concatenate bytes from a {@link LuaString} onto the front of this buffer
* @param s the left-hand-side value which we will concatenate onto the front of {@code this}
/**
* Concatenate bytes from a {@link LuaString} onto the front of this buffer
*
* @param s the left-hand-side value which we will concatenate onto the
* front of {@code this}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer prepend(LuaString s) {
@@ -214,11 +239,15 @@ public final class Buffer {
return this;
}
/** Ensure there is enough room before and after the bytes.
* @param nbefore number of unused bytes which must precede the data after this completes
* @param nafter number of unused bytes which must follow the data after this completes
/**
* Ensure there is enough room before and after the bytes.
*
* @param nbefore number of unused bytes which must precede the data after
* this completes
* @param nafter number of unused bytes which must follow the data after
* this completes
*/
public final void makeroom( int nbefore, int nafter ) {
public void makeroom(int nbefore, int nafter) {
if (value != null) {
LuaString s = value.strvalue();
value = null;
@@ -233,11 +262,13 @@ public final class Buffer {
}
}
/** Reallocate the internal storage for the buffer
/**
* Reallocate the internal storage for the buffer
*
* @param newSize the size of the buffer to use
* @param newOffset the offset to use
*/
private final void realloc( int newSize, int newOffset ) {
private void realloc(int newSize, int newOffset) {
if (newSize != bytes.length) {
byte[] newBytes = new byte[newSize];
System.arraycopy(bytes, offset, newBytes, newOffset, length);

View File

@@ -33,73 +33,94 @@ import org.luaj.vm2.lib.PackageLib;
import org.luaj.vm2.lib.ResourceFinder;
/**
* Global environment used by luaj. Contains global variables referenced by executing lua.
* Global environment used by luaj. Contains global variables referenced by
* executing lua.
* <p>
*
* <h3>Constructing and Initializing Instances</h3>
* Typically, this is constructed indirectly by a call to
* <h3>Constructing and Initializing Instances</h3> Typically, this is
* constructed indirectly by a call to
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()},
* and then used to load lua scripts for execution as in the following example.
* <pre> {@code
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}, and then used to
* load lua scripts for execution as in the following example.
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.load(new StringReader("print 'hello'"), "main.lua").call();
* } </pre>
* }
* </pre>
*
* The creates a complete global environment with the standard libraries loaded.
* <p>
* For specialized circumstances, the Globals may be constructed directly and loaded
* with only those libraries that are needed, for example.
* <pre> {@code
* For specialized circumstances, the Globals may be constructed directly and
* loaded with only those libraries that are needed, for example.
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new BaseLib());
* } </pre>
* }
* </pre>
*
* <h3>Loading and Executing Lua Code</h3>
* Globals contains convenience functions to load and execute lua source code given a Reader.
* A simple example is:
* <pre> {@code
* <h3>Loading and Executing Lua Code</h3> Globals contains convenience
* functions to load and execute lua source code given a Reader. A simple
* example is:
*
* <pre>
* {@code
* globals.load( new StringReader("print 'hello'"), "main.lua" ).call();
* } </pre>
* }
* </pre>
*
* <h3>Fine-Grained Control of Compiling and Loading Lua</h3>
* Executable LuaFunctions are created from lua code in several steps
* <h3>Fine-Grained Control of Compiling and Loading Lua</h3> Executable
* LuaFunctions are created from lua code in several steps
* <ul>
* <li>find the resource using the platform's {@link ResourceFinder}
* <li>compile lua to lua bytecode using {@link Compiler}
* <li>load lua bytecode to a {@link Prototype} using {@link Undumper}
* <li>construct {@link LuaClosure} from {@link Prototype} with {@link Globals} using {@link Loader}
* <li>construct {@link LuaClosure} from {@link Prototype} with {@link Globals}
* using {@link Loader}
* </ul>
* <p>
* There are alternate flows when the direct lua-to-Java bytecode compiling {@link org.luaj.vm2.luajc.LuaJC} is used.
* There are alternate flows when the direct lua-to-Java bytecode compiling
* {@link org.luaj.vm2.luajc.LuaJC} is used.
* <ul>
* <li>compile lua to lua bytecode using {@link Compiler} or load precompiled code using {@link Undumper}
* <li>convert lua bytecode to equivalent Java bytecode using {@link org.luaj.vm2.luajc.LuaJC} that implements {@link Loader} directly
* <li>compile lua to lua bytecode using {@link Compiler} or load precompiled
* code using {@link Undumper}
* <li>convert lua bytecode to equivalent Java bytecode using
* {@link org.luaj.vm2.luajc.LuaJC} that implements {@link Loader} directly
* </ul>
*
* <h3>Java Field</h3>
* Certain public fields are provided that contain the current values of important global state:
* <h3>Java Field</h3> Certain public fields are provided that contain the
* current values of important global state:
* <ul>
* <li>{@link #STDIN} Current value for standard input in the laaded {@link IoLib}, if any.
* <li>{@link #STDOUT} Current value for standard output in the loaded {@link IoLib}, if any.
* <li>{@link #STDERR} Current value for standard error in the loaded {@link IoLib}, if any.
* <li>{@link #STDIN} Current value for standard input in the laaded
* {@link IoLib}, if any.
* <li>{@link #STDOUT} Current value for standard output in the loaded
* {@link IoLib}, if any.
* <li>{@link #STDERR} Current value for standard error in the loaded
* {@link IoLib}, if any.
* <li>{@link #finder} Current loaded {@link ResourceFinder}, if any.
* <li>{@link #compiler} Current loaded {@link Compiler}, if any.
* <li>{@link #undumper} Current loaded {@link Undumper}, if any.
* <li>{@link #loader} Current loaded {@link Loader}, if any.
* </ul>
*
* <h3>Lua Environment Variables</h3>
* When using {@link org.luaj.vm2.lib.jse.JsePlatform} or {@link org.luaj.vm2.lib.jme.JmePlatform},
* these environment variables are created within the Globals.
* <h3>Lua Environment Variables</h3> When using
* {@link org.luaj.vm2.lib.jse.JsePlatform} or
* {@link org.luaj.vm2.lib.jme.JmePlatform}, these environment variables are
* created within the Globals.
* <ul>
* <li>"_G" Pointer to this Globals.
* <li>"_VERSION" String containing the version of luaj.
* </ul>
*
* <h3>Use in Multithreaded Environments</h3>
* In a multi-threaded server environment, each server thread should create one Globals instance,
* which will be logically distinct and not interfere with each other, but share certain
* static immutable resources such as class data and string data.
* <h3>Use in Multithreaded Environments</h3> In a multi-threaded server
* environment, each server thread should create one Globals instance, which
* will be logically distinct and not interfere with each other, but share
* certain static immutable resources such as class data and string data.
* <p>
*
* @see org.luaj.vm2.lib.jse.JsePlatform
@@ -126,7 +147,9 @@ public class Globals extends LuaTable {
/** The installed ResourceFinder for looking files by name. */
public ResourceFinder finder;
/** The currently running thread. Should not be changed by non-library code. */
/**
* The currently running thread. Should not be changed by non-library code.
*/
public LuaThread running = new LuaThread(this);
/** The BaseLib instance loaded into this Globals */
@@ -135,18 +158,30 @@ public class Globals extends LuaTable {
/** The PackageLib instance loaded into this Globals */
public PackageLib package_;
/** The DebugLib instance loaded into this Globals, or null if debugging is not enabled */
/**
* The DebugLib instance loaded into this Globals, or null if debugging is
* not enabled
*/
public DebugLib debuglib;
/** Interface for module that converts a Prototype into a LuaFunction with an environment. */
/**
* Interface for module that converts a Prototype into a LuaFunction with an
* environment.
*/
public interface Loader {
/** Convert the prototype into a LuaFunction with the supplied environment. */
/**
* Convert the prototype into a LuaFunction with the supplied
* environment.
*/
LuaFunction load(Prototype prototype, String chunkname, LuaValue env) throws IOException;
}
/** Interface for module that converts lua source text into a prototype. */
public interface Compiler {
/** Compile lua source into a Prototype. The InputStream is assumed to be in UTF-8. */
/**
* Compile lua source into a Prototype. The InputStream is assumed to be
* in UTF-8.
*/
Prototype compile(InputStream stream, String chunkname) throws IOException;
}
@@ -156,24 +191,40 @@ public class Globals extends LuaTable {
Prototype undump(InputStream stream, String chunkname) throws IOException;
}
/** Check that this object is a Globals object, and return it, otherwise throw an error. */
/**
* Check that this object is a Globals object, and return it, otherwise
* throw an error.
*/
@Override
public Globals checkglobals() {
return this;
}
/** The installed loader.
* @see Loader */
/**
* The installed loader.
*
* @see Loader
*/
public Loader loader;
/** The installed compiler.
* @see Compiler */
/**
* The installed compiler.
*
* @see Compiler
*/
public Compiler compiler;
/** The installed undumper.
* @see Undumper */
/**
* The installed undumper.
*
* @see Undumper
*/
public Undumper undumper;
/** Convenience function for loading a file that is either binary lua or lua source.
/**
* Convenience function for loading a file that is either binary lua or lua
* source.
*
* @param filename Name of the file to load.
* @return LuaValue that can be call()'ed or invoke()'ed.
* @throws LuaError if the file could not be loaded.
@@ -186,69 +237,96 @@ public class Globals extends LuaTable {
}
}
/** Convenience function to load a string value as a script. Must be lua source.
* @param script Contents of a lua script, such as "print 'hello, world.'"
/**
* Convenience function to load a string value as a script. Must be lua
* source.
*
* @param script Contents of a lua script, such as "print 'hello,
* world.'"
* @param chunkname Name that will be used within the chunk as the source.
* @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
* @return LuaValue that may be executed via .call(), .invoke(), or
* .method() calls.
* @throws LuaError if the script could not be compiled.
*/
public LuaValue load(String script, String chunkname) {
return load(new StrReader(script), chunkname);
}
/** Convenience function to load a string value as a script. Must be lua source.
/**
* Convenience function to load a string value as a script. Must be lua
* source.
*
* @param script Contents of a lua script, such as "print 'hello, world.'"
* @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
* @return LuaValue that may be executed via .call(), .invoke(), or
* .method() calls.
* @throws LuaError if the script could not be compiled.
*/
public LuaValue load(String script) {
return load(new StrReader(script), script);
}
/** Convenience function to load a string value as a script with a custom environment.
* Must be lua source.
* @param script Contents of a lua script, such as "print 'hello, world.'"
/**
* Convenience function to load a string value as a script with a custom
* environment. Must be lua source.
*
* @param script Contents of a lua script, such as "print 'hello,
* world.'"
* @param chunkname Name that will be used within the chunk as the source.
* @param environment LuaTable to be used as the environment for the loaded function.
* @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
* @param environment LuaTable to be used as the environment for the loaded
* function.
* @return LuaValue that may be executed via .call(), .invoke(), or
* .method() calls.
* @throws LuaError if the script could not be compiled.
*/
public LuaValue load(String script, String chunkname, LuaTable environment) {
return load(new StrReader(script), chunkname, environment);
}
/** Load the content form a reader as a text file. Must be lua source.
* The source is converted to UTF-8, so any characters appearing in quoted literals
* above the range 128 will be converted into multiple bytes.
* @param reader Reader containing text of a lua script, such as "print 'hello, world.'"
/**
* Load the content form a reader as a text file. Must be lua source. The
* source is converted to UTF-8, so any characters appearing in quoted
* literals above the range 128 will be converted into multiple bytes.
*
* @param reader Reader containing text of a lua script, such as "print
* 'hello, world.'"
* @param chunkname Name that will be used within the chunk as the source.
* @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
* @return LuaValue that may be executed via .call(), .invoke(), or
* .method() calls.
* @throws LuaError if the script could not be compiled.
*/
public LuaValue load(Reader reader, String chunkname) {
return load(new UTF8Stream(reader), chunkname, "t", this);
}
/** Load the content form a reader as a text file, supplying a custom environment.
* Must be lua source. The source is converted to UTF-8, so any characters
* appearing in quoted literals above the range 128 will be converted into
* multiple bytes.
* @param reader Reader containing text of a lua script, such as "print 'hello, world.'"
/**
* Load the content form a reader as a text file, supplying a custom
* environment. Must be lua source. The source is converted to UTF-8, so any
* characters appearing in quoted literals above the range 128 will be
* converted into multiple bytes.
*
* @param reader Reader containing text of a lua script, such as "print
* 'hello, world.'"
* @param chunkname Name that will be used within the chunk as the source.
* @param environment LuaTable to be used as the environment for the loaded function.
* @return LuaValue that may be executed via .call(), .invoke(), or .method() calls.
* @param environment LuaTable to be used as the environment for the loaded
* function.
* @return LuaValue that may be executed via .call(), .invoke(), or
* .method() calls.
* @throws LuaError if the script could not be compiled.
*/
public LuaValue load(Reader reader, String chunkname, LuaTable environment) {
return load(new UTF8Stream(reader), chunkname, "t", environment);
}
/** Load the content form an input stream as a binary chunk or text file.
/**
* Load the content form an input stream as a binary chunk or text file.
*
* @param is InputStream containing a lua script or compiled lua"
* @param chunkname Name that will be used within the chunk as the source.
* @param mode String containing 'b' or 't' or both to control loading as binary or text or either.
* @param environment LuaTable to be used as the environment for the loaded function.
* */
* @param mode String containing 'b' or 't' or both to control
* loading as binary or text or either.
* @param environment LuaTable to be used as the environment for the loaded
* function.
*/
public LuaValue load(InputStream is, String chunkname, String mode, LuaValue environment) {
try {
Prototype p = loadPrototype(is, chunkname, mode);
@@ -260,12 +338,16 @@ public class Globals extends LuaTable {
}
}
/** Load lua source or lua binary from an input stream into a Prototype.
* The InputStream is either a binary lua chunk starting with the lua binary chunk signature,
* or a text input file. If it is a text input file, it is interpreted as a UTF-8 byte sequence.
/**
* Load lua source or lua binary from an input stream into a Prototype. The
* InputStream is either a binary lua chunk starting with the lua binary
* chunk signature, or a text input file. If it is a text input file, it is
* interpreted as a UTF-8 byte sequence.
*
* @param is Input stream containing a lua script or compiled lua"
* @param chunkname Name that will be used within the chunk as the source.
* @param mode String containing 'b' or 't' or both to control loading as binary or text or either.
* @param mode String containing 'b' or 't' or both to control loading
* as binary or text or either.
*/
public Prototype loadPrototype(InputStream is, String chunkname, String mode) throws IOException {
if (mode.indexOf('b') >= 0) {
@@ -286,17 +368,21 @@ public class Globals extends LuaTable {
return null;
}
/** Compile lua source from a Reader into a Prototype. The characters in the reader
* are converted to bytes using the UTF-8 encoding, so a string literal containing
* characters with codepoints 128 or above will be converted into multiple bytes.
/**
* Compile lua source from a Reader into a Prototype. The characters in the
* reader are converted to bytes using the UTF-8 encoding, so a string
* literal containing characters with codepoints 128 or above will be
* converted into multiple bytes.
*/
public Prototype compilePrototype(Reader reader, String chunkname) throws IOException {
return compilePrototype(new UTF8Stream(reader), chunkname);
}
/** Compile lua source from an InputStream into a Prototype.
* The input is assumed to be UTf-8, but since bytes in the range 128-255 are passed along as
* literal bytes, any ASCII-compatible encoding such as ISO 8859-1 may also be used.
/**
* Compile lua source from an InputStream into a Prototype. The input is
* assumed to be UTf-8, but since bytes in the range 128-255 are passed
* along as literal bytes, any ASCII-compatible encoding such as ISO 8859-1
* may also be used.
*/
public Prototype compilePrototype(InputStream stream, String chunkname) throws IOException {
if (compiler == null)
@@ -304,9 +390,13 @@ public class Globals extends LuaTable {
return compiler.compile(stream, chunkname);
}
/** Function which yields the current thread.
* @param args Arguments to supply as return values in the resume function of the resuming thread.
* @return Values supplied as arguments to the resume() call that reactivates this thread.
/**
* Function which yields the current thread.
*
* @param args Arguments to supply as return values in the resume function
* of the resuming thread.
* @return Values supplied as arguments to the resume() call that
* reactivates this thread.
*/
public Varargs yield(Varargs args) {
if (running == null || running.isMainThread())
@@ -320,16 +410,23 @@ public class Globals extends LuaTable {
final String s;
int i = 0;
final int n;
StrReader(String s) {
this.s = s;
n = s.length();
}
@Override
public void close() throws IOException {
i = n;
}
@Override
public int read() throws IOException {
return i < n? s.charAt(i++): -1;
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
int j = 0;
for (; j < len && i < n; ++j, ++i)
@@ -344,48 +441,66 @@ public class Globals extends LuaTable {
abstract static class AbstractBufferedStream extends InputStream {
protected byte[] b;
protected int i = 0, j = 0;
protected AbstractBufferedStream(int buflen) {
this.b = new byte[buflen];
}
abstract protected int avail() throws IOException;
@Override
public int read() throws IOException {
int a = avail();
return (a <= 0 ? -1 : 0xff & b[i++]);
return a <= 0? -1: 0xff & b[i++];
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int i0, int n) throws IOException {
int a = avail();
if (a <= 0) return -1;
if (a <= 0)
return -1;
final int n_read = Math.min(a, n);
System.arraycopy(this.b, i, b, i0, n_read);
i += n_read;
return n_read;
}
@Override
public long skip(long n) throws IOException {
final long k = Math.min(n, j-i);
i += k;
return k;
}
@Override
public int available() throws IOException {
return j-i;
}
}
/** Simple converter from Reader to InputStream using UTF8 encoding that will work
* on both JME and JSE.
* This class may be moved to its own package in the future.
/**
* Simple converter from Reader to InputStream using UTF8 encoding that will
* work on both JME and JSE. This class may be moved to its own package in
* the future.
*/
static class UTF8Stream extends AbstractBufferedStream {
private final char[] c = new char[32];
private final Reader r;
UTF8Stream(Reader r) {
super(96);
this.r = r;
}
@Override
protected int avail() throws IOException {
if (i < j) return j - i;
if (i < j)
return j-i;
int n = r.read(c);
if (n < 0)
return -1;
@@ -399,29 +514,38 @@ public class Globals extends LuaTable {
j = LuaString.encodeToUtf8(c, n, b, i = 0);
return j;
}
@Override
public void close() throws IOException {
r.close();
}
}
/** Simple buffered InputStream that supports mark.
* Used to examine an InputStream for a 4-byte binary lua signature,
* and fall back to text input when the signature is not found,
* as well as speed up normal compilation and reading of lua scripts.
* This class may be moved to its own package in the future.
/**
* Simple buffered InputStream that supports mark. Used to examine an
* InputStream for a 4-byte binary lua signature, and fall back to text
* input when the signature is not found, as well as speed up normal
* compilation and reading of lua scripts. This class may be moved to its
* own package in the future.
*/
static class BufferedStream extends AbstractBufferedStream {
private final InputStream s;
public BufferedStream(InputStream s) {
this(128, s);
}
BufferedStream(int buflen, InputStream s) {
super(buflen);
this.s = s;
}
@Override
protected int avail() throws IOException {
if (i < j) return j - i;
if (j >= b.length) i = j = 0;
if (i < j)
return j-i;
if (j >= b.length)
i = j = 0;
// leave previous bytes in place to implement mark()/reset().
int n = s.read(b, j, b.length-j);
if (n < 0)
@@ -436,9 +560,13 @@ public class Globals extends LuaTable {
j += n;
return n;
}
@Override
public void close() throws IOException {
s.close();
}
@Override
public synchronized void mark(int n) {
if (i > 0 || n > b.length) {
byte[] dest = n > b.length? new byte[n]: b;
@@ -448,9 +576,13 @@ public class Globals extends LuaTable {
b = dest;
}
}
@Override
public boolean markSupported() {
return true;
}
@Override
public synchronized void reset() throws IOException {
i = 0;
}

View File

@@ -0,0 +1,486 @@
/*******************************************************************************
* 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;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Class to undump compiled lua bytecode into a {@link Prototype} instances.
* <p>
* The {@link LoadState} class provides the default {@link Globals.Undumper}
* which is used to undump a string of bytes that represent a lua binary file
* using either the C-based lua compiler, or luaj's
* {@link org.luaj.vm2.compiler.LuaC} compiler.
* <p>
* The canonical method to load and execute code is done indirectly using the
* Globals:
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* LuaValue chunk = globasl.load("print('hello, world')", "main.lua");
* chunk.call();
* }
* </pre>
*
* This should work regardless of which {@link Globals.Compiler} or
* {@link Globals.Undumper} have been installed.
* <p>
* By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or
* {@link org.luaj.vm2.lib.jme.JmePlatform} to construct globals, the
* {@link LoadState} default undumper is installed as the default
* {@link Globals.Undumper}.
* <p>
*
* A lua binary file is created via the {@link org.luaj.vm2.compiler.DumpState}
* class :
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* Prototype p = globals.compilePrototype(new StringReader("print('hello, world')"), "main.lua");
* ByteArrayOutputStream o = new ByteArrayOutputStream();
* org.luaj.vm2.compiler.DumpState.dump(p, o, false);
* byte[] lua_binary_file_bytes = o.toByteArray();
* }
* </pre>
*
* The {@link LoadState}'s default undumper {@link #instance} may be used
* directly to undump these bytes:
*
* <pre>
* {@code
* Prototypep = LoadState.instance.undump(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua");
* LuaClosure c = new LuaClosure(p, globals);
* c.call();
* }
* </pre>
*
*
* More commonly, the {@link Globals.Undumper} may be used to undump them:
*
* <pre>
* {
* &#64;code
* Prototype p = globals.loadPrototype(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua", "b");
* LuaClosure c = new LuaClosure(p, globals);
* c.call();
* }
* </pre>
*
* @see Globals.Compiler
* @see Globals.Undumper
* @see LuaClosure
* @see LuaFunction
* @see org.luaj.vm2.compiler.LuaC
* @see org.luaj.vm2.luajc.LuaJC
* @see Globals#compiler
* @see Globals#load(InputStream, String, LuaValue)
*/
public class LoadState {
/**
* Shared instance of Globals.Undumper to use loading prototypes from binary
* lua files
*/
public static final Globals.Undumper instance = new GlobalsUndumper();
/**
* format corresponding to non-number-patched lua, all numbers are floats or
* doubles
*/
public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
/** format corresponding to non-number-patched lua, all numbers are ints */
public static final int NUMBER_FORMAT_INTS_ONLY = 1;
/**
* format corresponding to number-patched lua, all numbers are 32-bit (4
* byte) ints
*/
public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
// type constants
public static final int LUA_TINT = -2;
public static final int LUA_TNONE = -1;
public static final int LUA_TNIL = 0;
public static final int LUA_TBOOLEAN = 1;
public static final int LUA_TLIGHTUSERDATA = 2;
public static final int LUA_TNUMBER = 3;
public static final int LUA_TSTRING = 4;
public static final int LUA_TTABLE = 5;
public static final int LUA_TFUNCTION = 6;
public static final int LUA_TUSERDATA = 7;
public static final int LUA_TTHREAD = 8;
public static final int LUA_TVALUE = 9;
/**
* The character encoding to use for file encoding. Null means the default
* encoding
*/
public static String encoding = null;
/** Signature byte indicating the file is a compiled binary chunk */
public static final byte[] LUA_SIGNATURE = { '\033', 'L', 'u', 'a' };
/** Data to catch conversion errors */
public static final byte[] LUAC_TAIL = { (byte) 0x19, (byte) 0x93, '\r', '\n', (byte) 0x1a, '\n', };
/** Name for compiled chunks */
public static final String SOURCE_BINARY_STRING = "binary string";
/** for header of binary files -- this is Lua 5.2 */
public static final int LUAC_VERSION = 0x52;
/** for header of binary files -- this is the official format */
public static final int LUAC_FORMAT = 0;
/** size of header of binary files */
public static final int LUAC_HEADERSIZE = 12;
// values read from the header
private int luacVersion;
private int luacFormat;
private boolean luacLittleEndian;
private int luacSizeofInt;
private int luacSizeofSizeT;
private int luacSizeofInstruction;
private int luacSizeofLuaNumber;
private int luacNumberFormat;
/** input stream from which we are loading */
public final DataInputStream is;
/** Name of what is being loaded? */
String name;
private static final LuaValue[] NOVALUES = {};
private static final Prototype[] NOPROTOS = {};
private static final LocVars[] NOLOCVARS = {};
private static final Upvaldesc[] NOUPVALDESCS = {};
private static final int[] NOINTS = {};
/** Read buffer */
private byte[] buf = new byte[512];
/**
* Install this class as the standard Globals.Undumper for the supplied
* Globals
*/
public static void install(Globals globals) {
globals.undumper = instance;
}
/**
* Load a 4-byte int value from the input stream
*
* @return the int value laoded.
**/
int loadInt() throws IOException {
is.readFully(buf, 0, 4);
return luacLittleEndian? buf[3]<<24 | (0xff & buf[2])<<16 | (0xff & buf[1])<<8 | 0xff & buf[0]
: buf[0]<<24 | (0xff & buf[1])<<16 | (0xff & buf[2])<<8 | 0xff & buf[3];
}
/**
* Load an array of int values from the input stream
*
* @return the array of int values laoded.
**/
int[] loadIntArray() throws IOException {
int n = loadInt();
if (n == 0)
return NOINTS;
// read all data at once
int m = n<<2;
if (buf.length < m)
buf = new byte[m];
is.readFully(buf, 0, m);
int[] array = new int[n];
for (int i = 0, j = 0; i < n; ++i, j += 4)
array[i] = luacLittleEndian? buf[j+3]<<24 | (0xff & buf[j+2])<<16 | (0xff & buf[j+1])<<8 | 0xff & buf[j+0]
: buf[j+0]<<24 | (0xff & buf[j+1])<<16 | (0xff & buf[j+2])<<8 | 0xff & buf[j+3];
return array;
}
/**
* Load a long value from the input stream
*
* @return the long value laoded.
**/
long loadInt64() throws IOException {
int a, b;
if (this.luacLittleEndian) {
a = loadInt();
b = loadInt();
} else {
b = loadInt();
a = loadInt();
}
return (long) b<<32 | a & 0xffffffffL;
}
/**
* Load a lua strin gvalue from the input stream
*
* @return the {@link LuaString} value laoded.
**/
LuaString loadString() throws IOException {
int size = this.luacSizeofSizeT == 8? (int) loadInt64(): loadInt();
if (size == 0)
return null;
byte[] bytes = new byte[size];
is.readFully(bytes, 0, size);
return LuaString.valueUsing(bytes, 0, bytes.length-1);
}
/**
* Convert bits in a long value to a {@link LuaValue}.
*
* @param bits long value containing the bits
* @return {@link LuaInteger} or {@link LuaDouble} whose value corresponds
* to the bits provided.
*/
public static LuaValue longBitsToLuaNumber(long bits) {
if ((bits & (1L<<63)-1) == 0L) {
return LuaValue.ZERO;
}
int e = (int) (bits>>52 & 0x7ffL)-1023;
if (e >= 0 && e < 31) {
long f = bits & 0xFFFFFFFFFFFFFL;
int shift = 52-e;
long intPrecMask = (1L<<shift)-1;
if ((f & intPrecMask) == 0) {
int intValue = (int) (f>>shift) | 1<<e;
return LuaInteger.valueOf(bits>>63 != 0? -intValue: intValue);
}
}
return LuaValue.valueOf(Double.longBitsToDouble(bits));
}
/**
* Load a number from a binary chunk
*
* @return the {@link LuaValue} loaded
* @throws IOException if an i/o exception occurs
*/
LuaValue loadNumber() throws IOException {
if (luacNumberFormat == NUMBER_FORMAT_INTS_ONLY) {
return LuaInteger.valueOf(loadInt());
} else {
return longBitsToLuaNumber(loadInt64());
}
}
/**
* Load a list of constants from a binary chunk
*
* @param f the function prototype
* @throws IOException if an i/o exception occurs
*/
void loadConstants(Prototype f) throws IOException {
int n = loadInt();
LuaValue[] values = n > 0? new LuaValue[n]: NOVALUES;
for (int i = 0; i < n; i++) {
switch (is.readByte()) {
case LUA_TNIL:
values[i] = LuaValue.NIL;
break;
case LUA_TBOOLEAN:
values[i] = 0 != is.readUnsignedByte()? LuaValue.TRUE: LuaValue.FALSE;
break;
case LUA_TINT:
values[i] = LuaInteger.valueOf(loadInt());
break;
case LUA_TNUMBER:
values[i] = loadNumber();
break;
case LUA_TSTRING:
values[i] = loadString();
break;
default:
throw new IllegalStateException("bad constant");
}
}
f.k = values;
n = loadInt();
Prototype[] protos = n > 0? new Prototype[n]: NOPROTOS;
for (int i = 0; i < n; i++)
protos[i] = loadFunction(f.source);
f.p = protos;
}
void loadUpvalues(Prototype f) throws IOException {
int n = loadInt();
f.upvalues = n > 0? new Upvaldesc[n]: NOUPVALDESCS;
for (int i = 0; i < n; i++) {
boolean instack = is.readByte() != 0;
int idx = is.readByte() & 0xff;
f.upvalues[i] = new Upvaldesc(null, instack, idx);
}
}
/**
* Load the debug info for a function prototype
*
* @param f the function Prototype
* @throws IOException if there is an i/o exception
*/
void loadDebug(Prototype f) throws IOException {
f.source = loadString();
f.lineinfo = loadIntArray();
int n = loadInt();
f.locvars = n > 0? new LocVars[n]: NOLOCVARS;
for (int i = 0; i < n; i++) {
LuaString varname = loadString();
int startpc = loadInt();
int endpc = loadInt();
f.locvars[i] = new LocVars(varname, startpc, endpc);
}
n = loadInt();
for (int i = 0; i < n; i++)
f.upvalues[i].name = loadString();
}
/**
* Load a function prototype from the input stream
*
* @param p name of the source
* @return {@link Prototype} instance that was loaded
* @throws IOException
*/
public Prototype loadFunction(LuaString p) throws IOException {
Prototype f = new Prototype();
//// this.L.push(f);
// f.source = loadString();
// if ( f.source == null )
// f.source = p;
f.linedefined = loadInt();
f.lastlinedefined = loadInt();
f.numparams = is.readUnsignedByte();
f.is_vararg = is.readUnsignedByte();
f.maxstacksize = is.readUnsignedByte();
f.code = loadIntArray();
loadConstants(f);
loadUpvalues(f);
loadDebug(f);
// TODO: add check here, for debugging purposes, I believe
// see ldebug.c
// IF (!luaG_checkcode(f), "bad code");
// this.L.pop();
return f;
}
/**
* Load the lua chunk header values.
*
* @throws IOException if an i/o exception occurs.
*/
public void loadHeader() throws IOException {
luacVersion = is.readByte();
luacFormat = is.readByte();
luacLittleEndian = 0 != is.readByte();
luacSizeofInt = is.readByte();
luacSizeofSizeT = is.readByte();
luacSizeofInstruction = is.readByte();
luacSizeofLuaNumber = is.readByte();
luacNumberFormat = is.readByte();
for (int i = 0; i < LUAC_TAIL.length; ++i)
if (is.readByte() != LUAC_TAIL[i])
throw new LuaError("Unexpeted byte in luac tail of header, index=" + i);
}
/**
* Load input stream as a lua binary chunk if the first 4 bytes are the lua
* binary signature.
*
* @param stream InputStream to read, after having read the first byte
* already
* @param chunkname Name to apply to the loaded chunk
* @return {@link Prototype} that was loaded, or null if the first 4 bytes
* were not the lua signature.
* @throws IOException if an IOException occurs
*/
public static Prototype undump(InputStream stream, String chunkname) throws IOException {
// check rest of signature
if (stream.read() != LUA_SIGNATURE[0] || stream.read() != LUA_SIGNATURE[1] || stream.read() != LUA_SIGNATURE[2]
|| stream.read() != LUA_SIGNATURE[3])
return null;
// load file as a compiled chunk
String sname = getSourceName(chunkname);
LoadState s = new LoadState(stream, sname);
s.loadHeader();
// check format
switch (s.luacNumberFormat) {
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
case NUMBER_FORMAT_INTS_ONLY:
case NUMBER_FORMAT_NUM_PATCH_INT32:
break;
default:
throw new LuaError("unsupported int size");
}
return s.loadFunction(LuaString.valueOf(sname));
}
/**
* Construct a source name from a supplied chunk name
*
* @param name String name that appears in the chunk
* @return source file name
*/
public static String getSourceName(String name) {
String sname = name;
if (name.startsWith("@") || name.startsWith("="))
sname = name.substring(1);
else if (name.startsWith("\033"))
sname = SOURCE_BINARY_STRING;
return sname;
}
/** Private constructor for create a load state */
private LoadState(InputStream stream, String name) {
this.name = name;
this.is = new DataInputStream(stream);
}
private static final class GlobalsUndumper implements Globals.Undumper {
@Override
public Prototype undump(InputStream stream, String chunkname) throws IOException {
return LoadState.undump(stream, chunkname);
}
}
}

View File

@@ -22,7 +22,8 @@
package org.luaj.vm2;
/**
* Data class to hold debug information relating to local variables for a {@link Prototype}
* Data class to hold debug information relating to local variables for a
* {@link Prototype}
*/
public class LocVars {
/** The local variable name */
@@ -36,6 +37,7 @@ public class LocVars {
/**
* Construct a LocVars instance.
*
* @param varname The local variable name
* @param startpc The instruction offset when the variable comes into scope
* @param endpc The instruction offset when the variable goes out of scope

View File

@@ -0,0 +1,357 @@
/*******************************************************************************
* Copyright (c) 2009-2011 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;
/**
* Constants for lua limits and opcodes.
* <p>
* This is a direct translation of C lua distribution header file constants for
* bytecode creation and processing.
*/
public class Lua {
/** version is supplied by ant build task */
public static final String _VERSION = "Luaj 0.0";
/** use return values from previous op */
public static final int LUA_MULTRET = -1;
// from lopcodes.h
/*===========================================================================
We assume that instructions are unsigned numbers.
All instructions have an opcode in the first 6 bits.
Instructions can have the following fields:
`A' : 8 bits
`B' : 9 bits
`C' : 9 bits
`Bx' : 18 bits (`B' and `C' together)
`sBx' : signed Bx
A signed argument is represented in excess K; that is, the number
value is the unsigned value minus K. K is exactly the maximum value
for that argument (so that -max is represented by 0, and +max is
represented by 2*max), which is half the maximum for the corresponding
unsigned argument.
===========================================================================*/
/* basic instruction format */
public static final int iABC = 0;
public static final int iABx = 1;
public static final int iAsBx = 2;
public static final int iAx = 3;
/*
** size and position of opcode arguments.
*/
public static final int SIZE_C = 9;
public static final int SIZE_B = 9;
public static final int SIZE_Bx = SIZE_C+SIZE_B;
public static final int SIZE_A = 8;
public static final int SIZE_Ax = SIZE_C+SIZE_B+SIZE_A;
public static final int SIZE_OP = 6;
public static final int POS_OP = 0;
public static final int POS_A = POS_OP+SIZE_OP;
public static final int POS_C = POS_A+SIZE_A;
public static final int POS_B = POS_C+SIZE_C;
public static final int POS_Bx = POS_C;
public static final int POS_Ax = POS_A;
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_B = (1<<SIZE_B)-1;
public static final int MAXARG_C = (1<<SIZE_C)-1;
public static final int MAXARG_Bx = (1<<SIZE_Bx)-1;
public static final int MAXARG_sBx = MAXARG_Bx>>1; /* `sBx' is signed */
public static final int MAXARG_Ax = (1<<SIZE_Ax)-1;
public static final int MASK_OP = (1<<SIZE_OP)-1<<POS_OP;
public static final int MASK_A = (1<<SIZE_A)-1<<POS_A;
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_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_A = ~MASK_A;
public static final int MASK_NOT_B = ~MASK_B;
public static final int MASK_NOT_C = ~MASK_C;
public static final int MASK_NOT_Bx = ~MASK_Bx;
/*
** the following macros help to manipulate instructions
*/
public static int GET_OPCODE(int i) {
return i>>POS_OP & MAX_OP;
}
public static int GETARG_A(int i) {
return i>>POS_A & MAXARG_A;
}
public static int GETARG_Ax(int i) {
return i>>POS_Ax & MAXARG_Ax;
}
public static int GETARG_B(int i) {
return i>>POS_B & MAXARG_B;
}
public static int GETARG_C(int i) {
return i>>POS_C & MAXARG_C;
}
public static int GETARG_Bx(int i) {
return i>>POS_Bx & MAXARG_Bx;
}
public static int GETARG_sBx(int i) {
return (i>>POS_Bx & MAXARG_Bx)-MAXARG_sBx;
}
/*
** Macros to operate RK indices
*/
/** this bit 1 means constant (0 means register) */
public static final int BITRK = 1<<SIZE_B-1;
/** test whether value is a constant */
public static boolean ISK(int x) {
return 0 != (x & BITRK);
}
/** gets the index of the constant */
public static int INDEXK(int r) {
return r & ~BITRK;
}
public static final int MAXINDEXRK = BITRK-1;
/** code a constant index as a RK value */
public static int RKASK(int x) {
return x | BITRK;
}
/**
** invalid register that fits in 8 bits
*/
public static final int NO_REG = MAXARG_A;
/*
** R(x) - register
** Kst(x) - constant (in constant table)
** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
*/
/*
** grep "ORDER OP" if you change these enums
*/
/*----------------------------------------------------------------------
name args description
------------------------------------------------------------------------*/
public static final int OP_MOVE = 0; /* A B R(A) := R(B) */
public static final int OP_LOADK = 1; /* A Bx R(A) := Kst(Bx) */
public static final int OP_LOADKX = 2; /* A R(A) := Kst(extra arg) */
public static final int OP_LOADBOOL = 3; /* A B C R(A) := (Bool)B; if (C) pc++ */
public static final int OP_LOADNIL = 4; /* A B R(A) := ... := R(A+B) := nil */
public static final int OP_GETUPVAL = 5; /* A B R(A) := UpValue[B] */
public static final int OP_GETTABUP = 6; /* A B C R(A) := UpValue[B][RK(C)] */
public static final int OP_GETTABLE = 7; /* A B C R(A) := R(B)[RK(C)] */
public static final int OP_SETTABUP = 8; /* A B C UpValue[A][RK(B)] := RK(C) */
public static final int OP_SETUPVAL = 9; /* A B UpValue[B] := R(A) */
public static final int OP_SETTABLE = 10; /* A B C R(A)[RK(B)] := RK(C) */
public static final int OP_NEWTABLE = 11; /* A B C R(A) := {} (size = B,C) */
public static final int OP_SELF = 12; /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
public static final int OP_ADD = 13; /* A B C R(A) := RK(B) + RK(C) */
public static final int OP_SUB = 14; /* A B C R(A) := RK(B) - RK(C) */
public static final int OP_MUL = 15; /* A B C R(A) := RK(B) * RK(C) */
public static final int OP_DIV = 16; /* A B C R(A) := RK(B) / RK(C) */
public static final int OP_MOD = 17; /* A B C R(A) := RK(B) % RK(C) */
public static final int OP_POW = 18; /* A B C R(A) := RK(B) ^ RK(C) */
public static final int OP_UNM = 19; /* A B R(A) := -R(B) */
public static final int OP_NOT = 20; /* A B R(A) := not R(B) */
public static final int OP_LEN = 21; /* A B R(A) := length of R(B) */
public static final int OP_CONCAT = 22; /* A B C R(A) := R(B).. ... ..R(C) */
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_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_TEST = 27; /* A C if not (R(A) <=> C) then pc++ */
public static final int OP_TESTSET = 28; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
public static final int OP_CALL = 29; /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
public static final int OP_TAILCALL = 30; /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
public static final int OP_RETURN = 31; /* A B return R(A), ... ,R(A+B-2) (see note) */
public static final int OP_FORLOOP = 32; /* A sBx R(A)+=R(A+2);
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
public static final int OP_FORPREP = 33; /* A sBx R(A)-=R(A+2); pc+=sBx */
public static final int OP_TFORCALL = 34; /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
public static final int OP_TFORLOOP = 35; /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx } */
public static final int OP_SETLIST = 36; /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
public static final int OP_CLOSURE = 37; /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
public static final int OP_VARARG = 38; /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
public static final int OP_EXTRAARG = 39; /* Ax extra (larger) argument for previous opcode */
public static final int NUM_OPCODES = OP_EXTRAARG+1;
/* pseudo-opcodes used in parsing only. */
public static final int OP_GT = 63; // >
public static final int OP_GE = 62; // >=
public static final int OP_NEQ = 61; // ~=
public static final int OP_AND = 60; // and
public static final int OP_OR = 59; // or
/*===========================================================================
Notes:
(*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
and can be 0: OP_CALL then sets `top' to last_result+1, so
next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
(*) In OP_VARARG, if (B == 0) then use actual number of varargs and
set top (like in OP_CALL with C == 0).
(*) In OP_RETURN, if (B == 0) then return up to `top'
(*) In OP_SETLIST, if (B == 0) then B = `top';
if (C == 0) then next `instruction' is real C
(*) For comparisons, A specifies what condition the test should accept
(true or false).
(*) All `skips' (pc++) assume that next instruction is a jump
===========================================================================*/
/*
** masks for instruction properties. The format is:
** bits 0-1: op mode
** bits 2-3: C arg mode
** bits 4-5: B arg mode
** bit 6: instruction set register A
** bit 7: operator is a test
*/
public static final int OpArgN = 0; /* argument is not used */
public static final int OpArgU = 1; /* argument is used */
public static final int OpArgR = 2; /* argument is a register or a jump offset */
public static final int OpArgK = 3; /* argument is a constant or register/constant */
public static final int[] luaP_opmodes = {
/* T A B C mode opcode */
0<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iABC, /* OP_MOVE */
0<<7 | 1<<6 | OpArgK<<4 | OpArgN<<2 | iABx, /* OP_LOADK */
0<<7 | 1<<6 | OpArgN<<4 | OpArgN<<2 | iABx, /* OP_LOADKX */
0<<7 | 1<<6 | OpArgU<<4 | OpArgU<<2 | iABC, /* OP_LOADBOOL */
0<<7 | 1<<6 | OpArgU<<4 | OpArgN<<2 | iABC, /* OP_LOADNIL */
0<<7 | 1<<6 | OpArgU<<4 | OpArgN<<2 | iABC, /* OP_GETUPVAL */
0<<7 | 1<<6 | OpArgU<<4 | OpArgK<<2 | iABC, /* OP_GETTABUP */
0<<7 | 1<<6 | OpArgR<<4 | OpArgK<<2 | iABC, /* OP_GETTABLE */
0<<7 | 0<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_SETTABUP */
0<<7 | 0<<6 | OpArgU<<4 | OpArgN<<2 | iABC, /* OP_SETUPVAL */
0<<7 | 0<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_SETTABLE */
0<<7 | 1<<6 | OpArgU<<4 | OpArgU<<2 | iABC, /* OP_NEWTABLE */
0<<7 | 1<<6 | OpArgR<<4 | OpArgK<<2 | iABC, /* OP_SELF */
0<<7 | 1<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_ADD */
0<<7 | 1<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_SUB */
0<<7 | 1<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_MUL */
0<<7 | 1<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_DIV */
0<<7 | 1<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_MOD */
0<<7 | 1<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_POW */
0<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iABC, /* OP_UNM */
0<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iABC, /* OP_NOT */
0<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iABC, /* OP_LEN */
0<<7 | 1<<6 | OpArgR<<4 | OpArgR<<2 | iABC, /* OP_CONCAT */
0<<7 | 0<<6 | OpArgR<<4 | OpArgN<<2 | iAsBx, /* OP_JMP */
1<<7 | 0<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_EQ */
1<<7 | 0<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_LT */
1<<7 | 0<<6 | OpArgK<<4 | OpArgK<<2 | iABC, /* OP_LE */
1<<7 | 0<<6 | OpArgN<<4 | OpArgU<<2 | iABC, /* OP_TEST */
1<<7 | 1<<6 | OpArgR<<4 | OpArgU<<2 | iABC, /* OP_TESTSET */
0<<7 | 1<<6 | OpArgU<<4 | OpArgU<<2 | iABC, /* OP_CALL */
0<<7 | 1<<6 | OpArgU<<4 | OpArgU<<2 | iABC, /* OP_TAILCALL */
0<<7 | 0<<6 | OpArgU<<4 | OpArgN<<2 | iABC, /* OP_RETURN */
0<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iAsBx, /* OP_FORLOOP */
0<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iAsBx, /* OP_FORPREP */
0<<7 | 0<<6 | OpArgN<<4 | OpArgU<<2 | iABC, /* OP_TFORCALL */
1<<7 | 1<<6 | OpArgR<<4 | OpArgN<<2 | iAsBx, /* OP_TFORLOOP */
0<<7 | 0<<6 | OpArgU<<4 | OpArgU<<2 | iABC, /* OP_SETLIST */
0<<7 | 1<<6 | OpArgU<<4 | OpArgN<<2 | iABx, /* OP_CLOSURE */
0<<7 | 1<<6 | OpArgU<<4 | OpArgN<<2 | iABC, /* OP_VARARG */
0<<7 | 0<<6 | OpArgU<<4 | OpArgU<<2 | iAx, /* OP_EXTRAARG */
};
public static int getOpMode(int m) {
return luaP_opmodes[m] & 3;
}
public static int getBMode(int m) {
return luaP_opmodes[m]>>4 & 3;
}
public static int getCMode(int m) {
return luaP_opmodes[m]>>2 & 3;
}
public static boolean testAMode(int m) {
return 0 != (luaP_opmodes[m] & 1<<6);
}
public static boolean testTMode(int m) {
return 0 != (luaP_opmodes[m] & 1<<7);
}
/* number of list items to accumulate before a SETLIST instruction */
public static final int LFIELDS_PER_FLUSH = 50;
private static final int MAXSRC = 80;
public static String chunkid(String source) {
if (source.startsWith("="))
return source.substring(1);
String end = "";
if (source.startsWith("@")) {
source = source.substring(1);
} else {
source = "[string \"" + source;
end = "\"]";
}
int n = source.length()+end.length();
if (n > MAXSRC)
source = source.substring(0, MAXSRC-end.length()-3) + "...";
return source+end;
}
}

View File

@@ -24,16 +24,16 @@ package org.luaj.vm2;
/**
* Extension of {@link LuaValue} which can hold a Java boolean as its value.
* <p>
* These instance are not instantiated directly by clients.
* Instead, there are exactly twon instances of this class,
* {@link LuaValue#TRUE} and {@link LuaValue#FALSE}
* representing the lua values {@code true} and {@code false}.
* The function {@link LuaValue#valueOf(boolean)} will always
* These instance are not instantiated directly by clients. Instead, there are
* exactly twon instances of this class, {@link LuaValue#TRUE} and
* {@link LuaValue#FALSE} representing the lua values {@code true} and
* {@code false}. The function {@link LuaValue#valueOf(boolean)} will always
* return one of these two values.
* <p>
* Any {@link LuaValue} can be converted to its equivalent
* boolean representation using {@link LuaValue#toboolean()}
* Any {@link LuaValue} can be converted to its equivalent boolean
* representation using {@link LuaValue#toboolean()}
* <p>
*
* @see LuaValue
* @see LuaValue#valueOf(boolean)
* @see LuaValue#TRUE
@@ -57,46 +57,56 @@ public final class LuaBoolean extends LuaValue {
this.v = b;
}
@Override
public int type() {
return LuaValue.TBOOLEAN;
}
@Override
public String typename() {
return "boolean";
}
@Override
public boolean isboolean() {
return true;
}
@Override
public LuaValue not() {
return v? FALSE: LuaValue.TRUE;
}
/**
* Return the boolean value for this boolean
*
* @return value as a Java boolean
*/
public boolean booleanValue() {
return v;
}
@Override
public boolean toboolean() {
return v;
}
@Override
public String tojstring() {
return v? "true": "false";
}
@Override
public boolean optboolean(boolean defval) {
return this.v;
}
@Override
public boolean checkboolean() {
return v;
}
@Override
public LuaValue getmetatable() {
return s_metatable;
}

View File

@@ -0,0 +1,680 @@
/*******************************************************************************
* 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;
import org.luaj.vm2.lib.DebugLib.CallFrame;
/**
* Extension of {@link LuaFunction} which executes lua bytecode.
* <p>
* A {@link LuaClosure} is a combination of a {@link Prototype} and a
* {@link LuaValue} to use as an environment for execution. Normally the
* {@link LuaValue} is a {@link Globals} in which case the environment will
* contain standard lua libraries.
*
* <p>
* There are three main ways {@link LuaClosure} instances are created:
* <ul>
* <li>Construct an instance using {@link #LuaClosure(Prototype, LuaValue)}</li>
* <li>Construct it indirectly by loading a chunk via
* {@link Globals#load(java.io.Reader, String)}
* <li>Execute the lua bytecode {@link Lua#OP_CLOSURE} as part of bytecode
* processing
* </ul>
* <p>
* To construct it directly, the {@link Prototype} is typically created via a
* compiler such as {@link org.luaj.vm2.compiler.LuaC}:
*
* <pre>
* {
* &#64;code
* String script = "print( 'hello, world' )";
* InputStream is = new ByteArrayInputStream(script.getBytes());
* Prototype p = LuaC.instance.compile(is, "script");
* LuaValue globals = JsePlatform.standardGlobals();
* LuaClosure f = new LuaClosure(p, globals);
* f.call();
* }
* </pre>
* <p>
* To construct it indirectly, the {@link Globals#load(java.io.Reader, String)}
* method may be used:
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* LuaFunction f = globals.load(new StringReader(script), "script");
* LuaClosure c = f.checkclosure(); // This may fail if LuaJC is installed.
* c.call();
* }
* </pre>
* <p>
* In this example, the "checkclosure()" may fail if direct lua-to-java-bytecode
* compiling using LuaJC is installed, because no LuaClosure is created in that
* case and the value returned is a {@link LuaFunction} but not a
* {@link LuaClosure}.
* <p>
* Since a {@link LuaClosure} is a {@link LuaFunction} which is a
* {@link LuaValue}, all the value operations can be used directly such as:
* <ul>
* <li>{@link LuaValue#call()}</li>
* <li>{@link LuaValue#call(LuaValue)}</li>
* <li>{@link LuaValue#invoke()}</li>
* <li>{@link LuaValue#invoke(Varargs)}</li>
* <li>{@link LuaValue#method(String)}</li>
* <li>{@link LuaValue#method(String,LuaValue)}</li>
* <li>{@link LuaValue#invokemethod(String)}</li>
* <li>{@link LuaValue#invokemethod(String,Varargs)}</li>
* <li>...</li>
* </ul>
*
* @see LuaValue
* @see LuaFunction
* @see LuaValue#isclosure()
* @see LuaValue#checkclosure()
* @see LuaValue#optclosure(LuaClosure)
* @see LoadState
* @see Globals#compiler
*/
public class LuaClosure extends LuaFunction {
private static final UpValue[] NOUPVALUES = {};
public final Prototype p;
public UpValue[] upValues;
final Globals globals;
/**
* Create a closure around a Prototype with a specific environment. If the
* prototype has upvalues, the environment will be written into the first
* upvalue.
*
* @param p the Prototype to construct this Closure for.
* @param env the environment to associate with the closure.
*/
public LuaClosure(Prototype p, LuaValue env) {
this.p = p;
this.initupvalue1(env);
globals = env instanceof Globals? (Globals) env: null;
}
@Override
public void initupvalue1(LuaValue env) {
if (p.upvalues == null || p.upvalues.length == 0)
this.upValues = NOUPVALUES;
else {
this.upValues = new UpValue[p.upvalues.length];
this.upValues[0] = new UpValue(new LuaValue[] { env }, 0);
}
}
@Override
public boolean isclosure() {
return true;
}
@Override
public LuaClosure optclosure(LuaClosure defval) {
return this;
}
@Override
public LuaClosure checkclosure() {
return this;
}
@Override
public String tojstring() {
return "function: " + p.toString();
}
private LuaValue[] getNewStack() {
int max = p.maxstacksize;
LuaValue[] stack = new LuaValue[max];
System.arraycopy(NILS, 0, stack, 0, max);
return stack;
}
@Override
public final LuaValue call() {
LuaValue[] stack = getNewStack();
return execute(stack, NONE).arg1();
}
@Override
public final LuaValue call(LuaValue arg) {
LuaValue[] stack = getNewStack();
switch (p.numparams) {
default:
stack[0] = arg;
return execute(stack, NONE).arg1();
case 0:
return execute(stack, arg).arg1();
}
}
@Override
public final LuaValue call(LuaValue arg1, LuaValue arg2) {
LuaValue[] stack = getNewStack();
switch (p.numparams) {
default:
stack[0] = arg1;
stack[1] = arg2;
return execute(stack, NONE).arg1();
case 1:
stack[0] = arg1;
return execute(stack, arg2).arg1();
case 0:
return execute(stack, p.is_vararg != 0? varargsOf(arg1, arg2): NONE).arg1();
}
}
@Override
public final LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
LuaValue[] stack = getNewStack();
switch (p.numparams) {
default:
stack[0] = arg1;
stack[1] = arg2;
stack[2] = arg3;
return execute(stack, NONE).arg1();
case 2:
stack[0] = arg1;
stack[1] = arg2;
return execute(stack, arg3).arg1();
case 1:
stack[0] = arg1;
return execute(stack, p.is_vararg != 0? varargsOf(arg2, arg3): NONE).arg1();
case 0:
return execute(stack, p.is_vararg != 0? varargsOf(arg1, arg2, arg3): NONE).arg1();
}
}
@Override
public final Varargs invoke(Varargs varargs) {
return onInvoke(varargs).eval();
}
@Override
public final Varargs onInvoke(Varargs varargs) {
LuaValue[] stack = getNewStack();
for (int i = 0; i < p.numparams; i++)
stack[i] = varargs.arg(i+1);
return execute(stack, p.is_vararg != 0? varargs.subargs(p.numparams+1): NONE);
}
protected Varargs execute(LuaValue[] stack, Varargs varargs) {
// loop through instructions
int i, a, b, c, pc = 0, top = 0;
LuaValue o;
Varargs v = NONE;
int[] code = p.code;
LuaValue[] k = p.k;
// upvalues are only possible when closures create closures
// TODO: use linked list.
UpValue[] openups = p.p.length > 0? new UpValue[stack.length]: null;
// allow for debug hooks
if (globals != null && globals.debuglib != null)
globals.debuglib.onCall(this, varargs, stack);
// process instructions
try {
for (; true; ++pc) {
if (globals != null && globals.debuglib != null)
globals.debuglib.onInstruction(pc, v, top);
// pull out instruction
i = code[pc];
a = i>>6 & 0xff;
// process the op code
switch (i & 0x3f) {
case Lua.OP_MOVE:/* A B R(A):= R(B) */
stack[a] = stack[i>>>23];
continue;
case Lua.OP_LOADK:/* A Bx R(A):= Kst(Bx) */
stack[a] = k[i>>>14];
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++ */
stack[a] = i>>>23 != 0? LuaValue.TRUE: LuaValue.FALSE;
if ((i & 0x1ff<<14) != 0)
++pc; /* skip next instruction (if C) */
continue;
case Lua.OP_LOADNIL: /* A B R(A):= ...:= R(A+B):= nil */
for (b = i>>>23; b-- >= 0;)
stack[a++] = LuaValue.NIL;
continue;
case Lua.OP_GETUPVAL: /* A B R(A):= UpValue[B] */
stack[a] = upValues[i>>>23].getValue();
continue;
case Lua.OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
stack[a] = upValues[i>>>23].getValue().get((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_GETTABLE: /* A B C R(A):= R(B)[RK(C)] */
stack[a] = stack[i>>>23].get((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
upValues[a].getValue().set((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b],
(c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_SETUPVAL: /* A B UpValue[B]:= R(A) */
upValues[i>>>23].setValue(stack[a]);
continue;
case Lua.OP_SETTABLE: /* A B C R(A)[RK(B)]:= RK(C) */
stack[a].set((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b],
(c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_NEWTABLE: /* A B C R(A):= {} (size = B,C) */
stack[a] = new LuaTable(i>>>23, i>>14 & 0x1ff);
continue;
case Lua.OP_SELF: /* A B C R(A+1):= R(B): R(A):= R(B)[RK(C)] */
stack[a+1] = o = stack[i>>>23];
stack[a] = o.get((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_ADD: /* A B C R(A):= RK(B) + RK(C) */
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.add((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_SUB: /* A B C R(A):= RK(B) - RK(C) */
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.sub((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.mul((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.div((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.mod((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
stack[a] = ((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.pow((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]);
continue;
case Lua.OP_UNM: /* A B R(A):= -R(B) */
stack[a] = stack[i>>>23].neg();
continue;
case Lua.OP_NOT: /* A B R(A):= not R(B) */
stack[a] = stack[i>>>23].not();
continue;
case Lua.OP_LEN: /* A B R(A):= length of R(B) */
stack[a] = stack[i>>>23].len();
continue;
case Lua.OP_CONCAT: /* A B C R(A):= R(B).. ... ..R(C) */
b = i>>>23;
c = i>>14 & 0x1ff; {
if (c > b+1) {
Buffer sb = stack[c].buffer();
while ( --c >= b )
sb.concatTo(stack[c]);
stack[a] = sb.value();
} else {
stack[a] = stack[c-1].concat(stack[c]);
}
}
continue;
case Lua.OP_JMP: /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
pc += (i>>>14)-0x1ffff;
if (a > 0) {
for (--a, b = openups.length; --b >= 0;)
if (openups[b] != null && openups[b].index >= a) {
openups[b].close();
openups[b] = null;
}
}
continue;
case Lua.OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
if (((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.eq_b((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]) != (a != 0))
++pc;
continue;
case Lua.OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
if (((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.lt_b((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]) != (a != 0))
++pc;
continue;
case Lua.OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
if (((b = i>>>23) > 0xff? k[b & 0x0ff]: stack[b])
.lteq_b((c = i>>14 & 0x1ff) > 0xff? k[c & 0x0ff]: stack[c]) != (a != 0))
++pc;
continue;
case Lua.OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
if (stack[a].toboolean() != ((i & 0x1ff<<14) != 0))
++pc;
continue;
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A):= R(B) else pc++ */
/* note: doc appears to be reversed */
if ((o = stack[i>>>23]).toboolean() != ((i & 0x1ff<<14) != 0))
++pc;
else
stack[a] = o; // TODO: should be sBx?
continue;
case Lua.OP_CALL: /* A B C R(A), ... ,R(A+C-2):= R(A)(R(A+1), ... ,R(A+B-1)) */
switch (i & (Lua.MASK_B | Lua.MASK_C)) {
case 1<<Lua.POS_B | 0<<Lua.POS_C:
v = stack[a].invoke(NONE);
top = a+v.narg();
continue;
case 2<<Lua.POS_B | 0<<Lua.POS_C:
v = stack[a].invoke(stack[a+1]);
top = a+v.narg();
continue;
case 1<<Lua.POS_B | 1<<Lua.POS_C:
stack[a].call();
continue;
case 2<<Lua.POS_B | 1<<Lua.POS_C:
stack[a].call(stack[a+1]);
continue;
case 3<<Lua.POS_B | 1<<Lua.POS_C:
stack[a].call(stack[a+1], stack[a+2]);
continue;
case 4<<Lua.POS_B | 1<<Lua.POS_C:
stack[a].call(stack[a+1], stack[a+2], stack[a+3]);
continue;
case 1<<Lua.POS_B | 2<<Lua.POS_C:
stack[a] = stack[a].call();
continue;
case 2<<Lua.POS_B | 2<<Lua.POS_C:
stack[a] = stack[a].call(stack[a+1]);
continue;
case 3<<Lua.POS_B | 2<<Lua.POS_C:
stack[a] = stack[a].call(stack[a+1], stack[a+2]);
continue;
case 4<<Lua.POS_B | 2<<Lua.POS_C:
stack[a] = stack[a].call(stack[a+1], stack[a+2], stack[a+3]);
continue;
default:
b = i>>>23;
c = i>>14 & 0x1ff;
v = stack[a].invoke(b > 0? varargsOf(stack, a+1, b-1): // exact arg count
varargsOf(stack, a+1, top-v.narg()-(a+1), v)); // from prev top
if (c > 0) {
v.copyto(stack, a, c-1);
v = NONE;
} else {
top = a+v.narg();
v = v.dealias();
}
continue;
}
case Lua.OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
switch (i & Lua.MASK_B) {
case 1<<Lua.POS_B:
return new TailcallVarargs(stack[a], NONE);
case 2<<Lua.POS_B:
return new TailcallVarargs(stack[a], stack[a+1]);
case 3<<Lua.POS_B:
return new TailcallVarargs(stack[a], varargsOf(stack[a+1], stack[a+2]));
case 4<<Lua.POS_B:
return new TailcallVarargs(stack[a], varargsOf(stack[a+1], stack[a+2], stack[a+3]));
default:
b = i>>>23;
v = b > 0? varargsOf(stack, a+1, b-1): // exact arg count
varargsOf(stack, a+1, top-v.narg()-(a+1), v); // from prev top
return new TailcallVarargs(stack[a], v);
}
case Lua.OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
b = i>>>23;
switch (b) {
case 0:
return varargsOf(stack, a, top-v.narg()-a, v);
case 1:
return NONE;
case 2:
return stack[a];
default:
return varargsOf(stack, a, b-1);
}
case Lua.OP_FORLOOP: /* A sBx R(A)+=R(A+2): if R(A) <?= R(A+1) then { pc+=sBx: R(A+3)=R(A) }*/
{
LuaValue limit = stack[a+1];
LuaValue step = stack[a+2];
LuaValue idx = stack[a].add(step);
if (step.gt_b(0)? idx.lteq_b(limit): idx.gteq_b(limit)) {
stack[a] = idx;
stack[a+3] = idx;
pc += (i>>>14)-0x1ffff;
}
}
continue;
case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */
{
LuaValue init = stack[a].checknumber("'for' initial value must be a number");
LuaValue limit = stack[a+1].checknumber("'for' limit must be a number");
LuaValue step = stack[a+2].checknumber("'for' step must be a number");
stack[a] = init.sub(step);
stack[a+1] = limit;
stack[a+2] = step;
pc += (i>>>14)-0x1ffff;
}
continue;
case Lua.OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
v = stack[a].invoke(varargsOf(stack[a+1], stack[a+2]));
c = i>>14 & 0x1ff;
while ( --c >= 0 )
stack[a+3+c] = v.arg(c+1);
v = NONE;
continue;
case Lua.OP_TFORLOOP: /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx */
if (!stack[a+1].isnil()) { /* continue loop? */
stack[a] = stack[a+1]; /* save control varible. */
pc += (i>>>14)-0x1ffff;
}
continue;
case Lua.OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i]:= R(A+i), 1 <= i <= B */
{
if ((c = i>>14 & 0x1ff) == 0)
c = code[++pc];
int offset = (c-1)*Lua.LFIELDS_PER_FLUSH;
o = stack[a];
if ((b = i>>>23) == 0) {
b = top-a-1;
int m = b-v.narg();
int j = 1;
for (; j <= m; j++)
o.set(offset+j, stack[a+j]);
for (; j <= b; j++)
o.set(offset+j, v.arg(j-m));
} else {
o.presize(offset+b);
for (int j = 1; j <= b; j++)
o.set(offset+j, stack[a+j]);
}
}
continue;
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx]) */
{
Prototype newp = p.p[i>>>14];
LuaClosure ncl = new LuaClosure(newp, globals);
Upvaldesc[] uv = newp.upvalues;
for (int j = 0, nup = uv.length; j < nup; ++j) {
if (uv[j].instack) /* upvalue refes to local variable? */
ncl.upValues[j] = findupval(stack, uv[j].idx, openups);
else /* get upvalue from enclosing function */
ncl.upValues[j] = upValues[uv[j].idx];
}
stack[a] = ncl;
}
continue;
case Lua.OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
b = i>>>23;
if (b == 0) {
top = a+(b = varargs.narg());
v = varargs;
} else {
for (int j = 1; j < b; ++j)
stack[a+j-1] = varargs.arg(j);
}
continue;
case Lua.OP_EXTRAARG:
throw new java.lang.IllegalArgumentException("Uexecutable opcode: OP_EXTRAARG");
default:
throw new java.lang.IllegalArgumentException("Illegal opcode: " + (i & 0x3f));
}
}
} catch (LuaError le) {
if (le.traceback == null)
processErrorHooks(le, p, pc);
throw le;
} catch (Exception e) {
LuaError le = new LuaError(e);
processErrorHooks(le, p, pc);
throw le;
} finally {
if (openups != null)
for (int u = openups.length; --u >= 0;)
if (openups[u] != null)
openups[u].close();
if (globals != null && globals.debuglib != null)
globals.debuglib.onReturn();
}
}
/**
* Run the error hook if there is one
*
* @param msg the message to use in error hook processing.
*/
String errorHook(String msg, int level) {
if (globals == null)
return msg;
final LuaThread r = globals.running;
if (r.errorfunc == null)
return globals.debuglib != null? msg + "\n" + globals.debuglib.traceback(level): msg;
final LuaValue e = r.errorfunc;
r.errorfunc = null;
try {
return e.call(LuaValue.valueOf(msg)).tojstring();
} catch (Throwable t) {
return "error in error handling";
} finally {
r.errorfunc = e;
}
}
private void processErrorHooks(LuaError le, Prototype p, int pc) {
String file = "?";
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);
}
private UpValue findupval(LuaValue[] stack, short idx, UpValue[] openups) {
final int n = openups.length;
for (int i = 0; i < n; ++i)
if (openups[i] != null && openups[i].index == idx)
return openups[i];
for (int i = 0; i < n; ++i)
if (openups[i] == null)
return openups[i] = new UpValue(stack, idx);
error("No space for upvalue");
return null;
}
protected LuaValue getUpvalue(int i) {
return upValues[i].getValue();
}
protected void setUpvalue(int i, LuaValue v) {
upValues[i].setValue(v);
}
@Override
public String name() {
return "<" + p.shortsource() + ":" + p.linedefined + ">";
}
}

View File

@@ -21,6 +21,7 @@
******************************************************************************/
package org.luaj.vm2;
import org.luaj.vm2.compat.JavaCompat;
import org.luaj.vm2.lib.MathLib;
/**
@@ -33,8 +34,8 @@ import org.luaj.vm2.lib.MathLib;
* <p>
* Almost all API's implemented in LuaDouble are defined and documented in {@link LuaValue}.
* <p>
* However the constants {@link #NAN}, {@link #POSINF}, {@link #NEGINF},
* {@link #JSTR_NAN}, {@link #JSTR_POSINF}, and {@link #JSTR_NEGINF} may be useful
* However the constants {@link #NAN}, {@link #NEGNAN}, {@link #POSINF}, {@link #NEGINF},
* {@link #JSTR_NAN}, {@link #JSTR_NEGNAN}, {@link #JSTR_POSINF}, and {@link #JSTR_NEGINF} may be useful
* when dealing with Nan or Infinite values.
* <p>
* LuaDouble also defines functions for handling the unique math rules of lua devision and modulo in
@@ -56,6 +57,9 @@ public class LuaDouble extends LuaNumber {
/** Constant LuaDouble representing NaN (not a number) */
public static final LuaDouble NAN = new LuaDouble( Double.NaN );
/** Constant LuaDouble representing negative NaN (not a number) */
public static final LuaDouble NEGNAN = new LuaDouble( -Double.NaN );
/** Constant LuaDouble representing positive infinity */
public static final LuaDouble POSINF = new LuaDouble( Double.POSITIVE_INFINITY );
@@ -65,6 +69,9 @@ public class LuaDouble extends LuaNumber {
/** Constant String representation for NaN (not a number), "nan" */
public static final String JSTR_NAN = "nan";
/** Constant String representation for negative NaN (not a number), "-nan" */
public static final String JSTR_NEGNAN = "-nan";
/** Constant String representation for positive infinity, "inf" */
public static final String JSTR_POSINF = "inf";
@@ -206,28 +213,28 @@ public class LuaDouble extends LuaNumber {
}
// 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( 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( 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( 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( 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( 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( 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( 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( double rhs ) { return v >= rhs; }
@@ -235,17 +242,13 @@ public class LuaDouble extends LuaNumber {
public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; }
public String tojstring() {
/*
if ( v == 0.0 ) { // never occurs in J2me
long bits = Double.doubleToLongBits( v );
return ( bits >> 63 == 0 ) ? "0" : "-0";
}
*/
if ( v == 0.0 ) // never occurs on J2ME
return (JavaCompat.INSTANCE.doubleToRawLongBits(v)<0? "-0": "0");
long l = (long) v;
if ( l == v )
return Long.toString(l);
if ( Double.isNaN(v) )
return JSTR_NAN;
return (JavaCompat.INSTANCE.doubleToRawLongBits(v)<0? JSTR_NEGNAN: JSTR_NAN);
if ( Double.isInfinite(v) )
return (v<0? JSTR_NEGINF: JSTR_POSINF);
return Float.toString((float)v);

View File

@@ -21,22 +21,21 @@
******************************************************************************/
package org.luaj.vm2;
/**
* RuntimeException that is thrown and caught in response to a lua error.
* <p>
* {@link LuaError} is used wherever a lua call to {@code error()}
* would be used within a script.
* {@link LuaError} is used wherever a lua call to {@code error()} would be used
* within a script.
* <p>
* Since it is an unchecked exception inheriting from {@link RuntimeException},
* Java method signatures do notdeclare this exception, althoug it can
* be thrown on almost any luaj Java operation.
* This is analagous to the fact that any lua script can throw a lua error at any time.
* Java method signatures do notdeclare this exception, althoug it can be thrown
* on almost any luaj Java operation. This is analagous to the fact that any lua
* script can throw a lua error at any time.
* <p>
* The LuaError may be constructed with a message object, in which case the message
* is the string representation of that object. getMessageObject will get the object
* supplied at construct time, or a LuaString containing the message of an object
* was not supplied.
* The LuaError may be constructed with a message object, in which case the
* message is the string representation of that object. getMessageObject will
* get the object supplied at construct time, or a LuaString containing the
* message of an object was not supplied.
*/
public class LuaError extends RuntimeException {
private static final long serialVersionUID = 1L;
@@ -51,9 +50,11 @@ public class LuaError extends RuntimeException {
private LuaValue object;
/** Get the string message if it was supplied, or a string
* representation of the message object if that was supplied.
/**
* Get the string message if it was supplied, or a string representation of
* the message object if that was supplied.
*/
@Override
public String getMessage() {
if (traceback != null)
return traceback;
@@ -61,24 +62,29 @@ public class LuaError extends RuntimeException {
if (m == null)
return null;
if (fileline != null)
return fileline + " " + m;
return fileline + m;
return m;
}
/** Get the LuaValue that was provided in the constructor, or
* a LuaString containing the message if it was a string error argument.
/**
* Get the LuaValue that was provided in the constructor, or a LuaString
* containing the message if it was a string error argument.
*
* @return LuaValue which was used in the constructor, or a LuaString
* containing the message.
*/
public LuaValue getMessageObject() {
if (object != null) return object;
if (object != null)
return object;
String m = getMessage();
return m != null? LuaValue.valueOf(m): null;
}
/** Construct LuaError when a program exception occurs.
/**
* Construct LuaError when a program exception occurs.
* <p>
* All errors generated from lua code should throw LuaError(String) instead.
*
* @param cause the Throwable that caused the error, if known.
*/
public LuaError(Throwable cause) {
@@ -98,7 +104,9 @@ public class LuaError extends RuntimeException {
}
/**
* Construct a LuaError with a message, and level to draw line number information from.
* Construct a LuaError with a message, and level to draw line number
* information from.
*
* @param message message to supply
* @param level where to supply line info from in call stack
*/
@@ -108,8 +116,9 @@ public class LuaError extends RuntimeException {
}
/**
* Construct a LuaError with a LuaValue as the message object,
* and level to draw line number information from.
* Construct a LuaError with a LuaValue as the message object, and level to
* draw line number information from.
*
* @param message_object message string or object to supply
*/
public LuaError(LuaValue message_object) {
@@ -118,13 +127,10 @@ public class LuaError extends RuntimeException {
this.level = 1;
}
/**
* Get the cause, if any.
*/
public Throwable getCause() {
return cause;
}
@Override
public Throwable getCause() { return cause; }
}

View File

@@ -21,68 +21,86 @@
******************************************************************************/
package org.luaj.vm2;
/**
* Base class for functions implemented in Java.
* <p>
* Direct subclass include {@link org.luaj.vm2.lib.LibFunction}
* which is the base class for
* all built-in library functions coded in Java,
* and {@link LuaClosure}, which represents a lua closure
* whose bytecode is interpreted when the function is invoked.
* Direct subclass include {@link org.luaj.vm2.lib.LibFunction} which is the
* base class for all built-in library functions coded in Java, and
* {@link LuaClosure}, which represents a lua closure whose bytecode is
* interpreted when the function is invoked.
*
* @see LuaValue
* @see LuaClosure
* @see org.luaj.vm2.lib.LibFunction
*/
abstract
public class LuaFunction extends LuaValue {
abstract public class LuaFunction extends LuaValue {
/** Shared static metatable for all functions and closures. */
public static LuaValue s_metatable;
@Override
public int type() {
return TFUNCTION;
}
@Override
public String typename() {
return "function";
}
@Override
public boolean isfunction() {
return true;
}
@Override
public LuaFunction checkfunction() {
return this;
}
@Override
public LuaFunction optfunction(LuaFunction defval) {
return this;
}
@Override
public LuaValue getmetatable() {
return s_metatable;
}
@Override
public String tojstring() {
return "function: " + classnamestub();
}
@Override
public LuaString strvalue() {
return valueOf(tojstring());
}
/** 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 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 ($). If the first character is '_', it is
* skipped.
*/
public String classnamestub() {
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.
* Is overridden by LuaClosure to return the source file and line, and by LibFunctions to return the name.
* @return common name for this function. */
/**
* Return a human-readable name for this function. Returns the last part of
* the class name by default. Is overridden by LuaClosure to return the
* source file and line, and by LibFunctions to return the name.
*
* @return common name for this function.
*/
public String name() {
return classnamestub();
}

View File

@@ -0,0 +1,372 @@
/*******************************************************************************
* 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;
import org.luaj.vm2.lib.MathLib;
/**
* Extension of {@link LuaNumber} which can hold a Java int as its value.
* <p>
* These instance are not instantiated directly by clients, but indirectly via
* the static functions {@link LuaValue#valueOf(int)} or
* {@link LuaValue#valueOf(double)} functions. This ensures that policies
* regarding pooling of instances are encapsulated.
* <p>
* There are no API's specific to LuaInteger that are useful beyond what is
* already exposed in {@link LuaValue}.
*
* @see LuaValue
* @see LuaNumber
* @see LuaDouble
* @see LuaValue#valueOf(int)
* @see LuaValue#valueOf(double)
*/
public class LuaInteger extends LuaNumber {
private static final LuaInteger[] intValues = new LuaInteger[512];
static {
for (int i = 0; i < 512; i++)
intValues[i] = new LuaInteger(i-256);
}
public static LuaInteger valueOf(int i) {
return i <= 255 && i >= -256? intValues[i+256]: new LuaInteger(i);
}
// TODO consider moving this to LuaValue
/**
* Return a LuaNumber that represents the value provided
*
* @param l long value to represent.
* @return LuaNumber that is eithe LuaInteger or LuaDouble representing l
* @see LuaValue#valueOf(int)
* @see LuaValue#valueOf(double)
*/
public static LuaNumber valueOf(long l) {
int i = (int) l;
return l == i? i <= 255 && i >= -256? intValues[i+256]: (LuaNumber) new LuaInteger(i)
: (LuaNumber) LuaDouble.valueOf(l);
}
/** The value being held by this instance. */
public final int v;
/**
* Package protected constructor.
*
* @see LuaValue#valueOf(int)
**/
LuaInteger(int i) {
this.v = i;
}
@Override
public boolean isint() { return true; }
@Override
public boolean isinttype() { return true; }
@Override
public boolean islong() { return true; }
@Override
public byte tobyte() { return (byte) v; }
@Override
public char tochar() { return (char) v; }
@Override
public double todouble() { return v; }
@Override
public float tofloat() { return v; }
@Override
public int toint() { return v; }
@Override
public long tolong() { return v; }
@Override
public short toshort() { return (short) v; }
@Override
public double optdouble(double defval) { return v; }
@Override
public int optint(int defval) { return v; }
@Override
public LuaInteger optinteger(LuaInteger defval) { return this; }
@Override
public long optlong(long defval) { return v; }
@Override
public String tojstring() {
return Integer.toString(v);
}
@Override
public LuaString strvalue() {
return LuaString.valueOf(Integer.toString(v));
}
@Override
public LuaString optstring(LuaString defval) {
return LuaString.valueOf(Integer.toString(v));
}
@Override
public LuaValue tostring() {
return LuaString.valueOf(Integer.toString(v));
}
@Override
public String optjstring(String defval) {
return Integer.toString(v);
}
@Override
public LuaInteger checkinteger() {
return this;
}
@Override
public boolean isstring() {
return true;
}
@Override
public int hashCode() {
return v;
}
public static int hashCode(int x) {
return x;
}
// unary operators
@Override
public LuaValue neg() { return valueOf(-(long) v); }
// object equality, used for key comparison
@Override
public boolean equals(Object o) { return o instanceof LuaInteger? ((LuaInteger) o).v == v: false; }
// equality w/ metatable processing
@Override
public LuaValue eq(LuaValue val) { return val.raweq(v)? TRUE: FALSE; }
@Override
public boolean eq_b(LuaValue val) { return val.raweq(v); }
// equality w/o metatable processing
@Override
public boolean raweq(LuaValue val) { return val.raweq(v); }
@Override
public boolean raweq(double val) { return v == val; }
@Override
public boolean raweq(int val) { return v == val; }
// arithmetic operators
@Override
public LuaValue add(LuaValue rhs) { return rhs.add(v); }
@Override
public LuaValue add(double lhs) { return LuaDouble.valueOf(lhs+v); }
@Override
public LuaValue add(int lhs) { return LuaInteger.valueOf(lhs+(long) v); }
@Override
public LuaValue sub(LuaValue rhs) { return rhs.subFrom(v); }
@Override
public LuaValue sub(double rhs) { return LuaDouble.valueOf(v-rhs); }
@Override
public LuaValue sub(int rhs) { return LuaValue.valueOf(v-rhs); }
@Override
public LuaValue subFrom(double lhs) { return LuaDouble.valueOf(lhs-v); }
@Override
public LuaValue subFrom(int lhs) { return LuaInteger.valueOf(lhs-(long) v); }
@Override
public LuaValue mul(LuaValue rhs) { return rhs.mul(v); }
@Override
public LuaValue mul(double lhs) { return LuaDouble.valueOf(lhs*v); }
@Override
public LuaValue mul(int lhs) { return LuaInteger.valueOf(lhs*(long) v); }
@Override
public LuaValue pow(LuaValue rhs) { return rhs.powWith(v); }
@Override
public LuaValue pow(double rhs) { return MathLib.dpow(v, rhs); }
@Override
public LuaValue pow(int rhs) { return MathLib.dpow(v, rhs); }
@Override
public LuaValue powWith(double lhs) { return MathLib.dpow(lhs, v); }
@Override
public LuaValue powWith(int lhs) { return MathLib.dpow(lhs, v); }
@Override
public LuaValue div(LuaValue rhs) { return rhs.divInto(v); }
@Override
public LuaValue div(double rhs) { return LuaDouble.ddiv(v, rhs); }
@Override
public LuaValue div(int rhs) { return LuaDouble.ddiv(v, rhs); }
@Override
public LuaValue divInto(double lhs) { return LuaDouble.ddiv(lhs, v); }
@Override
public LuaValue mod(LuaValue rhs) { return rhs.modFrom(v); }
@Override
public LuaValue mod(double rhs) { return LuaDouble.dmod(v, rhs); }
@Override
public LuaValue mod(int rhs) { return LuaDouble.dmod(v, rhs); }
@Override
public LuaValue modFrom(double lhs) { return LuaDouble.dmod(lhs, v); }
// relational operators
@Override
public LuaValue lt(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gt_b(v)? TRUE: FALSE: super.lt(rhs); }
@Override
public LuaValue lt(double rhs) { return v < rhs? TRUE: FALSE; }
@Override
public LuaValue lt(int rhs) { return v < rhs? TRUE: FALSE; }
@Override
public boolean lt_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gt_b(v): super.lt_b(rhs); }
@Override
public boolean lt_b(int rhs) { return v < rhs; }
@Override
public boolean lt_b(double rhs) { return v < rhs; }
@Override
public LuaValue lteq(LuaValue rhs) {
return rhs instanceof LuaNumber? rhs.gteq_b(v)? TRUE: FALSE: super.lteq(rhs);
}
@Override
public LuaValue lteq(double rhs) { return v <= rhs? TRUE: FALSE; }
@Override
public LuaValue lteq(int rhs) { return v <= rhs? TRUE: FALSE; }
@Override
public boolean lteq_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.gteq_b(v): super.lteq_b(rhs); }
@Override
public boolean lteq_b(int rhs) { return v <= rhs; }
@Override
public boolean lteq_b(double rhs) { return v <= rhs; }
@Override
public LuaValue gt(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lt_b(v)? TRUE: FALSE: super.gt(rhs); }
@Override
public LuaValue gt(double rhs) { return v > rhs? TRUE: FALSE; }
@Override
public LuaValue gt(int rhs) { return v > rhs? TRUE: FALSE; }
@Override
public boolean gt_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lt_b(v): super.gt_b(rhs); }
@Override
public boolean gt_b(int rhs) { return v > rhs; }
@Override
public boolean gt_b(double rhs) { return v > rhs; }
@Override
public LuaValue gteq(LuaValue rhs) {
return rhs instanceof LuaNumber? rhs.lteq_b(v)? TRUE: FALSE: super.gteq(rhs);
}
@Override
public LuaValue gteq(double rhs) { return v >= rhs? TRUE: FALSE; }
@Override
public LuaValue gteq(int rhs) { return v >= rhs? TRUE: FALSE; }
@Override
public boolean gteq_b(LuaValue rhs) { return rhs instanceof LuaNumber? rhs.lteq_b(v): super.gteq_b(rhs); }
@Override
public boolean gteq_b(int rhs) { return v >= rhs; }
@Override
public boolean gteq_b(double rhs) { return v >= rhs; }
// string comparison
@Override
public int strcmp(LuaString rhs) { typerror("attempt to compare number with string"); return 0; }
@Override
public int checkint() {
return v;
}
@Override
public long checklong() {
return v;
}
@Override
public double checkdouble() {
return v;
}
@Override
public String checkjstring() {
return String.valueOf(v);
}
@Override
public LuaString checkstring() {
return valueOf(String.valueOf(v));
}
}

View File

@@ -24,16 +24,16 @@ package org.luaj.vm2;
/**
* Class to encapsulate behavior of the singleton instance {@code nil}
* <p>
* There will be one instance of this class, {@link LuaValue#NIL},
* per Java virtual machine.
* However, the {@link Varargs} instance {@link LuaValue#NONE}
* which is the empty list,
* is also considered treated as a nil value by default.
* There will be one instance of this class, {@link LuaValue#NIL}, per Java
* virtual machine. However, the {@link Varargs} instance {@link LuaValue#NONE}
* which is the empty list, is also considered treated as a nil value by
* default.
* <p>
* Although it is possible to test for nil using Java == operator,
* the recommended approach is to use the method {@link LuaValue#isnil()}
* instead. By using that any ambiguities between
* {@link LuaValue#NIL} and {@link LuaValue#NONE} are avoided.
* Although it is possible to test for nil using Java == operator, the
* recommended approach is to use the method {@link LuaValue#isnil()} instead.
* By using that any ambiguities between {@link LuaValue#NIL} and
* {@link LuaValue#NONE} are avoided.
*
* @see LuaValue
* @see LuaValue#NIL
*/
@@ -45,64 +45,104 @@ public class LuaNil extends LuaValue {
LuaNil() {}
@Override
public int type() {
return LuaValue.TNIL;
}
@Override
public String toString() {
return "nil";
}
@Override
public String typename() {
return "nil";
}
@Override
public String tojstring() {
return "nil";
}
@Override
public LuaValue not() {
return LuaValue.TRUE;
}
@Override
public boolean toboolean() {
return false;
}
@Override
public boolean isnil() {
return true;
}
@Override
public LuaValue getmetatable() {
return s_metatable;
}
@Override
public boolean equals(Object o) {
return o instanceof LuaNil;
}
@Override
public LuaValue checknotnil() {
return argerror("value");
}
@Override
public boolean isvalidkey() {
return false;
}
// optional argument conversions - nil alwas falls badk to default value
@Override
public boolean optboolean(boolean defval) { return defval; }
@Override
public LuaClosure optclosure(LuaClosure defval) { return defval; }
@Override
public double optdouble(double defval) { return defval; }
@Override
public LuaFunction optfunction(LuaFunction defval) { return defval; }
@Override
public int optint(int defval) { return defval; }
@Override
public LuaInteger optinteger(LuaInteger defval) { return defval; }
@Override
public long optlong(long defval) { return defval; }
@Override
public LuaNumber optnumber(LuaNumber defval) { return defval; }
@Override
public LuaTable opttable(LuaTable defval) { return defval; }
@Override
public LuaThread optthread(LuaThread defval) { return defval; }
@Override
public String optjstring(String defval) { return defval; }
@Override
public LuaString optstring(LuaString defval) { return defval; }
@Override
public Object optuserdata(Object defval) { return defval; }
@Override
public Object optuserdata(Class c, Object defval) { return defval; }
@Override
public LuaValue optvalue(LuaValue defval) { return defval; }
}

View File

@@ -24,58 +24,74 @@ package org.luaj.vm2;
/**
* Base class for representing numbers as lua values directly.
* <p>
* The main subclasses are {@link LuaInteger} which holds values that fit in a java int,
* and {@link LuaDouble} which holds all other number values.
* The main subclasses are {@link LuaInteger} which holds values that fit in a
* java int, and {@link LuaDouble} which holds all other number values.
*
* @see LuaInteger
* @see LuaDouble
* @see LuaValue
*
*/
abstract
public class LuaNumber extends LuaValue {
abstract public class LuaNumber extends LuaValue {
/** Shared static metatable for all number values represented in lua. */
public static LuaValue s_metatable;
@Override
public int type() {
return TNUMBER;
}
@Override
public String typename() {
return "number";
}
@Override
public LuaNumber checknumber() {
return this;
}
@Override
public LuaNumber checknumber(String errmsg) {
return this;
}
@Override
public LuaNumber optnumber(LuaNumber defval) {
return this;
}
@Override
public LuaValue tonumber() {
return this;
}
@Override
public boolean isnumber() {
return true;
}
@Override
public boolean isstring() {
return true;
}
@Override
public LuaValue getmetatable() {
return s_metatable;
}
@Override
public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
@Override
public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
@Override
public LuaValue concatTo(LuaNumber lhs) { return strvalue().concatTo(lhs.strvalue()); }
@Override
public LuaValue concatTo(LuaString lhs) { return strvalue().concatTo(lhs); }
}

View File

@@ -289,20 +289,20 @@ public class LuaString extends LuaValue {
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs, checkarith()); }
// relational operators, these only work with other strings
public LuaValue lt( LuaValue rhs ) { return rhs.strcmp(this)>0? LuaValue.TRUE: FALSE; }
public boolean lt_b( LuaValue rhs ) { return rhs.strcmp(this)>0; }
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.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( 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 boolean lteq_b( LuaValue rhs ) { return rhs.strcmp(this)>=0; }
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.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( 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 boolean gt_b( LuaValue rhs ) { return rhs.strcmp(this)<0; }
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.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( 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 boolean gteq_b( LuaValue rhs ) { return rhs.strcmp(this)<=0; }
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.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( double rhs ) { typerror("attempt to compare string with number"); return false; }
@@ -639,9 +639,15 @@ public class LuaString extends LuaValue {
public static String decodeAsUtf8(byte[] bytes, int offset, int length) {
int i,j,n,b;
for ( i=offset,j=offset+length,n=0; i<j; ++n ) {
switch ( 0xE0 & bytes[i++] ) {
case 0xE0: ++i;
case 0xC0: ++i;
byte v = bytes[i++];
if ((v & 0xC0) == 0xC0) {
++i;
if ((v & 0xE0) == 0xE0) {
++i;
if ((v & 0xF0) == 0xF0) {
++i;
}
}
}
}
char[] chars=new char[n];
@@ -665,9 +671,22 @@ public class LuaString extends LuaValue {
public static int lengthAsUtf8(char[] chars) {
int i, b;
char c;
for ( i=b=chars.length; --i>=0; )
if ( (c=chars[i]) >=0x80 )
b += (c>=0x800)? 2: 1;
for (i = 0, b = 0; i < chars.length; i++) {
if ((c = chars[i]) < 0x80 || (c >= 0xdc00 && c < 0xe000)) {
b += 1;
} else if (c < 0x800) {
b += 2;
} else if (c >= 0xd800 && c < 0xdc00) {
if (i + 1 < chars.length && chars[i+1] >= 0xdc00 && chars[i+1] < 0xe000) {
b += 4;
i++;
} else {
b += 1;
}
} else {
b += 3;
}
}
return b;
}
@@ -693,10 +712,22 @@ public class LuaString extends LuaValue {
if ((c = chars[i]) < 0x80) {
bytes[j++] = (byte) c;
} else if (c < 0x800) {
bytes[j++] = (byte) (0xC0 | ((c>>6) & 0x1f));
bytes[j++] = (byte) (0xC0 | ((c >> 6)));
bytes[j++] = (byte) (0x80 | (c & 0x3f));
} else if (c >= 0xd800 && c < 0xdc00) {
if (i + 1 < nchars && chars[i+1] >= 0xdc00 && chars[i+1] < 0xe000) {
int uc = 0x10000 + (((c & 0x3ff) << 10) | (chars[++i] & 0x3ff));
bytes[j++] = (byte) (0xF0 | ((uc >> 18)));
bytes[j++] = (byte) (0x80 | ((uc >> 12) & 0x3f));
bytes[j++] = (byte) (0x80 | ((uc >> 6) & 0x3f));
bytes[j++] = (byte) (0x80 | (uc & 0x3f));
} else {
bytes[j++] = (byte) (0xE0 | ((c>>12) & 0x0f));
bytes[j++] = (byte) '?';
}
} else if (c >= 0xdc00 && c < 0xe000) {
bytes[j++] = (byte) '?';
} else {
bytes[j++] = (byte) (0xE0 | ((c >> 12)));
bytes[j++] = (byte) (0x80 | ((c >> 6) & 0x3f));
bytes[j++] = (byte) (0x80 | (c & 0x3f));
}
@@ -713,14 +744,14 @@ public class LuaString extends LuaValue {
public boolean isValidUtf8() {
for (int i = m_offset, j = m_offset + m_length; i < j;) {
int c = m_bytes[i++];
if ( c >= 0 ) continue;
if ( ((c & 0xE0) == 0xC0)
&& i<j
&& (m_bytes[i++] & 0xC0) == 0x80) continue;
if ( ((c & 0xF0) == 0xE0)
&& i+1<j
&& (m_bytes[i++] & 0xC0) == 0x80
&& (m_bytes[i++] & 0xC0) == 0x80) continue;
if (c >= 0)
continue;
if (((c & 0xE0) == 0xC0) && i < j && (m_bytes[i++] & 0xC0) == 0x80)
continue;
if (((c & 0xF0) == 0xE0) && i + 1 < j && (m_bytes[i++] & 0xC0) == 0x80 && (m_bytes[i++] & 0xC0) == 0x80)
continue;
if (((c & 0xF8) == 0xF0) && i + 2 < j && (m_bytes[i++] & 0xC0) == 0x80 && (m_bytes[i++] & 0xC0) == 0x80 && (m_bytes[i++] & 0xC0) == 0x80)
continue;
return false;
}
return true;
@@ -750,6 +781,22 @@ public class LuaString extends LuaValue {
return Double.isNaN(d)? NIL: valueOf(d);
}
private boolean isspace(byte c) {
return c == ' ' || (c >= '\t' && c <= '\r');
}
private boolean isdigit(byte c) {
return (c >= '0' && c <= '9');
}
private boolean isxdigit(byte c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
private int hexvalue(byte c) {
return c <= '9' ? c - '0' : c <= 'F' ? c + 10 - 'A' : c + 10 - 'a';
}
/**
* Convert to a number in base 10, or base 16 if the string starts with '0x',
* or return Double.NaN if it cannot be converted to a number.
@@ -757,14 +804,63 @@ public class LuaString extends LuaValue {
*/
public double scannumber() {
int i = m_offset, j = m_offset + m_length;
while ( i<j && m_bytes[i]==' ' ) ++i;
while ( i<j && m_bytes[j-1]==' ' ) --j;
while (i < j && isspace(m_bytes[i]))
++i;
while (i < j && isspace(m_bytes[j - 1]))
--j;
if (i >= j)
return Double.NaN;
if ( m_bytes[i]=='0' && i+1<j && (m_bytes[i+1]=='x'||m_bytes[i+1]=='X'))
return scanlong(16, i+2, j);
double l = scanlong(10, i, j);
return Double.isNaN(l)? scandouble(i,j): l;
if (indexOf((byte) 'x', i - m_offset) != -1 || indexOf((byte) 'X', i - m_offset) != -1)
return strx2number(i, j);
return scandouble(i, j);
}
private double strx2number(int start, int end) {
double sgn = (m_bytes[start] == '-') ? -1.0 : 1.0;
if (sgn == -1.0 || m_bytes[start] == '+')
++start;
if (start + 2 >= end)
return Double.NaN;
if (m_bytes[start++] != '0')
return Double.NaN;
if (m_bytes[start] != 'x' && m_bytes[start] != 'X')
return Double.NaN;
++start;
double m = 0;
int e = 0;
boolean i = isxdigit(m_bytes[start]);
while (start < end && isxdigit(m_bytes[start]))
m = (m * 16) + hexvalue(m_bytes[start++]);
if (start < end && m_bytes[start] == '.') {
++start;
while (start < end && isxdigit(m_bytes[start])) {
m = (m * 16) + hexvalue(m_bytes[start++]);
e -= 4;
}
}
if (!i && e == 0)
return Double.NaN;
if (start < end && (m_bytes[start] == 'p' || m_bytes[start] == 'P')) {
++start;
int exp1 = 0;
boolean neg1 = false;
if (start < end) {
if (m_bytes[start] == '-')
neg1 = true;
if (neg1 || m_bytes[start] == '+')
++start;
}
if (start >= end || !isdigit(m_bytes[start]))
return Double.NaN;
while (start < end && isdigit(m_bytes[start]))
exp1 = exp1 * 10 + m_bytes[start++] - '0';
if (neg1)
exp1 = -exp1;
e += exp1;
}
if (start != end)
return Double.NaN;
return sgn * m * MathLib.dpow_d(2.0, e);
}
/**
@@ -776,8 +872,8 @@ public class LuaString extends LuaValue {
if ( base < 2 || base > 36 )
return Double.NaN;
int i=m_offset,j=m_offset+m_length;
while ( i<j && m_bytes[i]==' ' ) ++i;
while ( i<j && m_bytes[j-1]==' ' ) --j;
while ( i<j && isspace(m_bytes[i]) ) ++i;
while ( i<j && isspace(m_bytes[j-1]) ) --j;
if ( i>=j )
return Double.NaN;
return scanlong( base, i, j );
@@ -794,7 +890,8 @@ public class LuaString extends LuaValue {
private double scanlong( int base, int start, int end ) {
long x = 0;
boolean neg = (m_bytes[start] == '-');
for ( int i=(neg?start+1:start); i<end; i++ ) {
if (neg || m_bytes[start] == '+') start++;
for ( int i=start; i<end; i++ ) {
int digit = m_bytes[i] - (base<=10||(m_bytes[i]>='0'&&m_bytes[i]<='9')? '0':
m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10));
if ( digit < 0 || digit >= base )

View File

@@ -21,43 +21,41 @@
******************************************************************************/
package org.luaj.vm2;
import java.lang.ref.WeakReference;
/**
* Subclass of {@link LuaValue} that implements
* a lua coroutine thread using Java Threads.
* Subclass of {@link LuaValue} that implements a lua coroutine thread using
* Java Threads.
* <p>
* A LuaThread is typically created in response to a scripted call to
* {@code coroutine.create()}
* <p>
* The threads must be initialized with the globals, so that
* the global environment may be passed along according to rules of lua.
* This is done via the constructor arguments {@link #LuaThread(Globals)} or
* The threads must be initialized with the globals, so that the global
* environment may be passed along according to rules of lua. This is done via
* the constructor arguments {@link #LuaThread(Globals)} or
* {@link #LuaThread(Globals, LuaValue)}.
* <p>
* The utility classes {@link org.luaj.vm2.lib.jse.JsePlatform} and
* {@link org.luaj.vm2.lib.jme.JmePlatform}
* see to it that this {@link Globals} are initialized properly.
* {@link org.luaj.vm2.lib.jme.JmePlatform} see to it that this {@link Globals}
* are initialized properly.
* <p>
* The behavior of coroutine threads matches closely the behavior
* of C coroutine library. However, because of the use of Java threads
* to manage call state, it is possible to yield from anywhere in luaj.
* The behavior of coroutine threads matches closely the behavior of C coroutine
* library. However, because of the use of Java threads to manage call state, it
* is possible to yield from anywhere in luaj.
* <p>
* Each Java thread wakes up at regular intervals and checks a weak reference
* to determine if it can ever be resumed. If not, it throws
* {@link OrphanedThread} which is an {@link java.lang.Error}.
* Applications should not catch {@link OrphanedThread}, because it can break
* the thread safety of luaj. The value controlling the polling interval
* is {@link #thread_orphan_check_interval} and may be set by the user.
* Each Java thread wakes up at regular intervals and checks a weak reference to
* determine if it can ever be resumed. If not, it throws {@link OrphanedThread}
* which is an {@link java.lang.Error}. Applications should not catch
* {@link OrphanedThread}, because it can break the thread safety of luaj. The
* value controlling the polling interval is
* {@link #thread_orphan_check_interval} and may be set by the user.
* <p>
* There are two main ways to abandon a coroutine. The first is to call
* {@code yield()} from lua, or equivalently {@link Globals#yield(Varargs)},
* and arrange to have it never resumed possibly by values passed to yield.
* The second is to throw {@link OrphanedThread}, which should put the thread
* in a dead state. In either case all references to the thread must be
* dropped, and the garbage collector must run for the thread to be
* garbage collected.
* {@code yield()} from lua, or equivalently {@link Globals#yield(Varargs)}, and
* arrange to have it never resumed possibly by values passed to yield. The
* second is to throw {@link OrphanedThread}, which should put the thread in a
* dead state. In either case all references to the thread must be dropped, and
* the garbage collector must run for the thread to be garbage collected.
*
*
* @see LuaValue
@@ -73,12 +71,13 @@ public class LuaThread extends LuaValue {
/** The current number of coroutines. Should not be set. */
public static int coroutine_count = 0;
/** Polling interval, in milliseconds, which each thread uses while waiting to
* return from a yielded state to check if the lua threads is no longer
* referenced and therefore should be garbage collected.
* A short polling interval for many threads will consume server resources.
* Orphaned threads cannot be detected and collected unless garbage
* collection is run. This can be changed by Java startup code if desired.
/**
* Polling interval, in milliseconds, which each thread uses while waiting
* to return from a yielded state to check if the lua threads is no longer
* referenced and therefore should be garbage collected. A short polling
* interval for many threads will consume server resources. Orphaned threads
* cannot be detected and collected unless garbage collection is run. This
* can be changed by Java startup code if desired.
*/
public static long thread_orphan_check_interval = 5000;
@@ -87,19 +86,16 @@ public class LuaThread extends LuaValue {
public static final int STATUS_RUNNING = 2;
public static final int STATUS_NORMAL = 3;
public static final int STATUS_DEAD = 4;
public static final String[] STATUS_NAMES = {
"suspended",
"suspended",
"running",
"normal",
"dead",};
public static final String[] STATUS_NAMES = { "suspended", "suspended", "running", "normal", "dead", };
public final State state;
public static final int MAX_CALLSTACK = 256;
/** Thread-local used by DebugLib to store debugging state.
* This is an opaque value that should not be modified by applications. */
/**
* Thread-local used by DebugLib to store debugging state. This is an opaque
* value that should not be modified by applications.
*/
public Object callstack;
public final Globals globals;
@@ -116,6 +112,7 @@ public class LuaThread extends LuaValue {
/**
* Create a LuaThread around a function and environment
*
* @param func The function to execute
*/
public LuaThread(Globals globals, LuaValue func) {
@@ -124,43 +121,45 @@ public class LuaThread extends LuaValue {
this.globals = globals;
}
@Override
public int type() {
return LuaValue.TTHREAD;
}
@Override
public String typename() {
return "thread";
}
@Override
public boolean isthread() {
return true;
}
@Override
public LuaThread optthread(LuaThread defval) {
return this;
}
@Override
public LuaThread checkthread() {
return this;
}
@Override
public LuaValue getmetatable() {
return s_metatable;
}
public String getStatus() {
return STATUS_NAMES[state.status];
}
public String getStatus() { return STATUS_NAMES[state.status]; }
public boolean isMainThread() {
return this.state.function == null;
}
public boolean isMainThread() { return this.state.function == null; }
public Varargs resume(Varargs args) {
final LuaThread.State s = this.state;
if (s.status > LuaThread.STATUS_SUSPENDED)
return LuaValue.varargsOf(LuaValue.FALSE,
LuaValue.valueOf("cannot resume "+(s.status==LuaThread.STATUS_DEAD? "dead": "non-suspended")+" coroutine"));
return LuaValue.varargsOf(LuaValue.FALSE, LuaValue.valueOf(
"cannot resume " + (s.status == LuaThread.STATUS_DEAD? "dead": "non-suspended") + " coroutine"));
return s.lua_resume(this, args);
}
@@ -191,6 +190,7 @@ public class LuaThread extends LuaValue {
this.function = function;
}
@Override
public synchronized void run() {
try {
Varargs a = this.args;
@@ -219,9 +219,8 @@ public class LuaThread extends LuaValue {
previous_thread.state.status = STATUS_NORMAL;
this.status = STATUS_RUNNING;
this.wait();
return (this.error != null?
LuaValue.varargsOf(LuaValue.FALSE, LuaValue.valueOf(this.error)):
LuaValue.varargsOf(LuaValue.TRUE, this.result));
return this.error != null? LuaValue.varargsOf(LuaValue.FALSE, LuaValue.valueOf(this.error))
: LuaValue.varargsOf(LuaValue.TRUE, this.result);
} catch (InterruptedException ie) {
throw new OrphanedThread();
} finally {

View File

@@ -21,7 +21,6 @@
******************************************************************************/
package org.luaj.vm2;
public class LuaUserdata extends LuaValue {
public Object m_instance;
@@ -36,18 +35,22 @@ public class LuaUserdata extends LuaValue {
m_metatable = metatable;
}
@Override
public String tojstring() {
return String.valueOf(m_instance);
}
@Override
public int type() {
return LuaValue.TUSERDATA;
}
@Override
public String typename() {
return "userdata";
}
@Override
public int hashCode() {
return m_instance.hashCode();
}
@@ -56,45 +59,63 @@ public class LuaUserdata extends LuaValue {
return m_instance;
}
@Override
public boolean isuserdata() { return true; }
@Override
public boolean isuserdata(Class c) { return c.isAssignableFrom(m_instance.getClass()); }
@Override
public Object touserdata() { return m_instance; }
@Override
public Object touserdata(Class c) { return c.isAssignableFrom(m_instance.getClass())? m_instance: null; }
@Override
public Object optuserdata(Object defval) { return m_instance; }
@Override
public Object optuserdata(Class c, Object defval) {
if (!c.isAssignableFrom(m_instance.getClass()))
typerror(c.getName());
return m_instance;
}
@Override
public LuaValue getmetatable() {
return m_metatable;
}
@Override
public LuaValue setmetatable(LuaValue metatable) {
this.m_metatable = metatable;
return this;
}
@Override
public Object checkuserdata() {
return m_instance;
}
@Override
public Object checkuserdata(Class c) {
if (c.isAssignableFrom(m_instance.getClass()))
return m_instance;
return typerror(c.getName());
}
@Override
public LuaValue get(LuaValue key) {
return m_metatable != null? gettable(this, key): NIL;
}
@Override
public void set(LuaValue key, LuaValue value) {
if (m_metatable == null || !settable(this, key, value))
error("cannot set " + key + " for userdata");
}
@Override
public boolean equals(Object val) {
if (this == val)
return true;
@@ -105,22 +126,31 @@ public class LuaUserdata extends LuaValue {
}
// equality w/ metatable processing
@Override
public LuaValue eq(LuaValue val) { return eq_b(val)? TRUE: FALSE; }
@Override
public boolean eq_b(LuaValue val) {
if ( val.raweq(this) ) return true;
if ( m_metatable == null || !val.isuserdata() ) return false;
if (val.raweq(this))
return true;
if (m_metatable == null || !val.isuserdata())
return false;
LuaValue valmt = val.getmetatable();
return valmt != null && LuaValue.eqmtcall(this, m_metatable, val, valmt);
}
// equality w/o metatable processing
@Override
public boolean raweq(LuaValue val) { return val.raweq(this); }
@Override
public boolean raweq(LuaUserdata val) {
return this == val || (m_metatable == val.m_metatable && m_instance.equals(val.m_instance));
return this == val || m_metatable == val.m_metatable && m_instance.equals(val.m_instance);
}
// __eq metatag processing
public boolean eqmt(LuaValue val) {
return m_metatable!=null && val.isuserdata()? LuaValue.eqmtcall(this, m_metatable, val, val.getmetatable()): false;
return m_metatable != null && val.isuserdata()? LuaValue.eqmtcall(this, m_metatable, val, val.getmetatable())
: false;
}
}

View File

@@ -21,8 +21,6 @@
******************************************************************************/
package org.luaj.vm2;
import org.luaj.vm2.Varargs;
/**
* Base class for all concrete lua type values.
* <p>
@@ -101,7 +99,7 @@ import org.luaj.vm2.Varargs;
* {@link #INDEX}, {@link #NEWINDEX}, {@link #CALL}, {@link #MODE}, {@link #METATABLE},
* {@link #ADD}, {@link #SUB}, {@link #DIV}, {@link #MUL}, {@link #POW},
* {@link #MOD}, {@link #UNM}, {@link #LEN}, {@link #EQ}, {@link #LT},
* {@link #LE}, {@link #TOSTRING}, and {@link #CONCAT}.
* {@link #LE}, {@link #TOSTRING}, {@link #CONCAT}, {@link PAIRS} and {@link IPAIRS}.
*
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
@@ -245,6 +243,12 @@ public class LuaValue extends Varargs {
/** LuaString constant with value "__concat" for use as metatag */
public static final LuaString CONCAT = valueOf("__concat");
/** LuaString constant with value "__pairs" for use as metatag */
public static final LuaString PAIRS = valueOf("__pairs");
/** LuaString constant with value "__ipairs" for use as metatag */
public static final LuaString IPAIRS = valueOf("__ipairs");
/** LuaString constant with value "" */
public static final LuaString EMPTYSTRING = valueOf("");
@@ -531,7 +535,7 @@ public class LuaValue extends Varargs {
* @see #isstring()
* @see #TSTRING
*/
public String tojstring() { return typename() + ": " + Integer.toHexString(hashCode()); }
public String tojstring() { return typename() + ": 0x" + Integer.toHexString(hashCode()); }
/** Convert to userdata instance, or null.
* @return userdata instance if userdata, or null if not {@link LuaUserdata}
@@ -627,7 +631,7 @@ public class LuaValue extends Varargs {
* @see #isclosure()
* @see #TFUNCTION
*/
public LuaClosure optclosure(LuaClosure defval) { argerror("closure"); return null; }
public LuaClosure optclosure(LuaClosure defval) { argerror("function"); return null; }
/** Check that optional argument is a number or string convertible to number and return as double
* @param defval double to return if {@code this} is nil or none
@@ -739,7 +743,7 @@ public class LuaValue extends Varargs {
* @see #toString()
* @see #TSTRING
*/
public String optjstring(String defval) { argerror("String"); return null; }
public String optjstring(String defval) { argerror("string"); return null; }
/** Check that optional argument is a string or number and return as {@link LuaString}
* @param defval {@link LuaString} to return if {@code this} is nil or none
@@ -890,7 +894,7 @@ public class LuaValue extends Varargs {
* @see #optint(int)
* @see #TNUMBER
*/
public int checkint() { argerror("int"); return 0; }
public int checkint() { argerror("number"); return 0; }
/** Check that the value is numeric, and convert and cast value to int, or throw {@link LuaError} if not numeric
* <p>
@@ -1055,7 +1059,7 @@ public class LuaValue extends Varargs {
* @param expected String naming the type that was expected
* @throws LuaError in all cases
*/
protected LuaValue argerror(String expected) { throw new LuaError("bad argument: "+expected+" expected, got "+typename()); }
protected LuaValue argerror(String expected) { throw new LuaError("bad argument ("+expected+" expected, got "+typename()+")"); }
/**
* Throw a {@link LuaError} indicating an invalid argument was supplied to a function
@@ -2987,7 +2991,7 @@ public class LuaValue extends Varargs {
return h.call(this, op1);
if (LuaValue.LE.raweq(tag) && (!(h = metatag(LT)).isnil() || !(h = op1.metatag(LT)).isnil()))
return h.call(op1, this).not();
return error("attempt to compare "+tag+" on "+typename()+" and "+op1.typename());
return error("bad argument: attempt to compare "+tag+" on "+typename()+" and "+op1.typename());
}
/** Perform string comparison with another value
@@ -3362,7 +3366,7 @@ public class LuaValue extends Varargs {
protected LuaValue checkmetatag(LuaValue tag, String reason) {
LuaValue h = this.metatag(tag);
if ( h.isnil() )
throw new LuaError(reason+typename());
throw new LuaError(reason + "a " + typename() + " value");
return h;
}

View File

@@ -29,23 +29,23 @@ import org.luaj.vm2.LuaTable.Slot;
interface Metatable {
/** Return whether or not this table's keys are weak. */
public boolean useWeakKeys();
boolean useWeakKeys();
/** Return whether or not this table's values are weak. */
public boolean useWeakValues();
boolean useWeakValues();
/** Return this metatable as a LuaValue. */
public LuaValue toLuaValue();
LuaValue toLuaValue();
/** Return an instance of Slot appropriate for the given key and value. */
public Slot entry( LuaValue key, LuaValue value );
Slot entry(LuaValue key, LuaValue value);
/** Returns the given value wrapped in a weak reference if appropriate. */
public LuaValue wrap( LuaValue value );
LuaValue wrap(LuaValue value);
/**
* Returns the value at the given index in the array, or null if it is a weak reference that
* has been dropped.
* Returns the value at the given index in the array, or null if it is a
* weak reference that has been dropped.
*/
public LuaValue arrayget(LuaValue[] array, int index);
LuaValue arrayget(LuaValue[] array, int index);
}

View File

@@ -10,26 +10,32 @@ class NonTableMetatable implements Metatable {
this.value = value;
}
@Override
public boolean useWeakKeys() {
return false;
}
@Override
public boolean useWeakValues() {
return false;
}
@Override
public LuaValue toLuaValue() {
return value;
}
@Override
public Slot entry(LuaValue key, LuaValue value) {
return LuaTable.defaultEntry(key, value);
}
@Override
public LuaValue wrap(LuaValue value) {
return value;
}
@Override
public LuaValue arrayget(LuaValue[] array, int index) {
return array[index];
}

View File

@@ -29,7 +29,8 @@ package org.luaj.vm2;
* {@link LuaThread} being used as a coroutine that could not possibly be
* resumed again because there are no more references to the LuaThread with
* which it is associated. Rather than locking up resources forever, this error
* is thrown, and should fall through all the way to the thread's {@link Thread#run()} method.
* is thrown, and should fall through all the way to the thread's
* {@link Thread#run()} method.
* <p>
* Java code mixed with the luaj vm should not catch this error because it may
* occur when the coroutine is not running, so any processing done during error

View File

@@ -26,6 +26,7 @@ import java.io.PrintStream;
/**
* Debug helper class to pretty-print lua bytecodes.
*
* @see Prototype
* @see LuaClosure
*/
@@ -36,50 +37,10 @@ public class Print extends Lua {
public static PrintStream ps = System.out;
/** String names for each lua opcode value. */
public static final String[] OPNAMES = {
"MOVE",
"LOADK",
"LOADKX",
"LOADBOOL",
"LOADNIL",
"GETUPVAL",
"GETTABUP",
"GETTABLE",
"SETTABUP",
"SETUPVAL",
"SETTABLE",
"NEWTABLE",
"SELF",
"ADD",
"SUB",
"MUL",
"DIV",
"MOD",
"POW",
"UNM",
"NOT",
"LEN",
"CONCAT",
"JMP",
"EQ",
"LT",
"LE",
"TEST",
"TESTSET",
"CALL",
"TAILCALL",
"RETURN",
"FORLOOP",
"FORPREP",
"TFORCALL",
"TFORLOOP",
"SETLIST",
"CLOSURE",
"VARARG",
"EXTRAARG",
null,
};
public static final String[] OPNAMES = { "MOVE", "LOADK", "LOADKX", "LOADBOOL", "LOADNIL", "GETUPVAL", "GETTABUP",
"GETTABLE", "SETTABUP", "SETUPVAL", "SETTABLE", "NEWTABLE", "SELF", "ADD", "SUB", "MUL", "DIV", "MOD",
"POW", "UNM", "NOT", "LEN", "CONCAT", "JMP", "EQ", "LT", "LE", "TEST", "TESTSET", "CALL", "TAILCALL",
"RETURN", "FORLOOP", "FORPREP", "TFORCALL", "TFORLOOP", "SETLIST", "CLOSURE", "VARARG", "EXTRAARG", null, };
static void printString(PrintStream ps, final LuaString s) {
@@ -133,8 +94,11 @@ public class Print extends Lua {
return;
}
switch (v.type()) {
case LuaValue.TSTRING: printString( ps, (LuaString) v ); break;
default: ps.print( v.tojstring() );
case LuaValue.TSTRING:
printString(ps, (LuaString) v);
break;
default:
ps.print(v.tojstring());
}
}
@@ -150,6 +114,7 @@ public class Print extends Lua {
/**
* Print the code in a prototype
*
* @param f the {@link Prototype}
*/
public static void printCode(Prototype f) {
@@ -163,6 +128,7 @@ public class Print extends Lua {
/**
* Print an opcode in a prototype
*
* @param f the {@link Prototype}
* @param pc the program counter to look up and print
* @return pc same as above or changed
@@ -173,6 +139,7 @@ public class Print extends Lua {
/**
* Print an opcode in a prototype
*
* @param ps the {@link PrintStream} to print to
* @param f the {@link Prototype}
* @param pc the program counter to look up and print
@@ -201,15 +168,15 @@ public class Print extends Lua {
case iABC:
ps.print(a);
if (getBMode(o) != OpArgN)
ps.print(" "+(ISK(b) ? (-1 - INDEXK(b)) : b));
ps.print(" " + (ISK(b)? -1-INDEXK(b): b));
if (getCMode(o) != OpArgN)
ps.print(" "+(ISK(c) ? (-1 - INDEXK(c)) : c));
ps.print(" " + (ISK(c)? -1-INDEXK(c): c));
break;
case iABx:
if (getBMode(o) == OpArgK) {
ps.print(a + " " + (-1-bx));
} else {
ps.print(a + " " + (bx));
ps.print(a + " " + bx);
}
break;
case iAsBx:
@@ -307,9 +274,9 @@ public class Print extends Lua {
break;
case OP_SETLIST:
if (c == 0)
ps.print(" ; " + ((int) code[++pc]) + " (stored in the next OP)");
ps.print(" ; " + code[++pc] + " (stored in the next OP)");
else
ps.print(" ; " + ((int) c));
ps.print(" ; " + c);
break;
case OP_VARARG:
ps.print(" ; is_vararg=" + f.is_vararg);
@@ -333,14 +300,11 @@ public class Print extends Lua {
s = "(bstring)";
else
s = "(string)";
String a = (f.linedefined == 0) ? "main" : "function";
ps.print("\n%" + a + " <" + s + ":" + f.linedefined + ","
+ f.lastlinedefined + "> (" + f.code.length + " instructions, "
+ f.code.length * 4 + " bytes at " + id(f) + ")\n");
ps.print(f.numparams + " param, " + f.maxstacksize + " slot, "
+ f.upvalues.length + " upvalue, ");
ps.print(f.locvars.length + " local, " + f.k.length
+ " constant, " + f.p.length + " function\n");
String a = f.linedefined == 0? "main": "function";
ps.print("\n%" + a + " <" + s + ":" + f.linedefined + "," + f.lastlinedefined + "> (" + f.code.length
+ " instructions, " + f.code.length*4 + " bytes at " + id(f) + ")\n");
ps.print(f.numparams + " param, " + f.maxstacksize + " slot, " + f.upvalues.length + " upvalue, ");
ps.print(f.locvars.length + " local, " + f.k.length + " constant, " + f.p.length + " function\n");
}
static void printConstants(Prototype f) {
@@ -357,7 +321,8 @@ public class Print extends Lua {
int i, n = f.locvars.length;
ps.print("locals (" + n + ") for " + id(f) + ":\n");
for (i = 0; i < n; i++) {
ps.println(" "+i+" "+f.locvars[i].varname+" "+(f.locvars[i].startpc+1)+" "+(f.locvars[i].endpc+1));
ps.println(
" " + i + " " + f.locvars[i].varname + " " + (f.locvars[i].startpc+1) + " " + (f.locvars[i].endpc+1));
}
}
@@ -369,7 +334,8 @@ public class Print extends Lua {
}
}
/** Pretty-prints contents of a Prototype.
/**
* Pretty-prints contents of a Prototype.
*
* @param prototype Prototype to print.
*/
@@ -377,7 +343,8 @@ public class Print extends Lua {
printFunction(prototype, true);
}
/** Pretty-prints contents of a Prototype in short or long form.
/**
* Pretty-prints contents of a Prototype in short or long form.
*
* @param prototype Prototype to print.
* @param full true to print all fields, false to print short form.
@@ -409,6 +376,7 @@ public class Print extends Lua {
private static String id(Prototype f) {
return "Proto";
}
private void _assert(boolean b) {
if (!b)
throw new NullPointerException("_assert failed");
@@ -416,6 +384,7 @@ public class Print extends Lua {
/**
* Print the state of a {@link LuaClosure} that is being executed
*
* @param cl the {@link LuaClosure}
* @param pc the program counter
* @param stack the stack of {@link LuaValue}
@@ -443,12 +412,12 @@ public class Print extends Lua {
LuaValue v = stack[i];
if (v == null)
ps.print(STRING_FOR_NULL);
else switch ( v.type() ) {
else
switch (v.type()) {
case LuaValue.TSTRING:
LuaString s = v.checkstring();
ps.print( s.length() < 48?
s.tojstring():
s.substring(0, 32).tojstring()+"...+"+(s.length()-32)+"b");
ps.print(s.length() < 48? s.tojstring()
: s.substring(0, 32).tojstring() + "...+" + (s.length()-32) + "b");
break;
case LuaValue.TFUNCTION:
ps.print(v.tojstring());

View File

@@ -0,0 +1,180 @@
/*******************************************************************************
* Copyright (c) 2009-2011 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;
/**
* Prototype representing compiled lua code.
*
* <p>
* This is both a straight translation of the corresponding C type, and the main
* data structure for execution of compiled lua bytecode.
*
* <p>
* Generally, the {@link Prototype} is not constructed directly is an
* intermediate result as lua code is loaded using
* {@link Globals#load(java.io.Reader, String)}:
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.load(new StringReader("print 'hello'"), "main.lua").call();
* }
* </pre>
*
* <p>
* To create a {@link Prototype} directly, a compiler such as
* {@link org.luaj.vm2.compiler.LuaC} may be used:
*
* <pre>
* {
* &#64;code
* InputStream is = new ByteArrayInputStream("print('hello,world')".getBytes());
* Prototype p = LuaC.instance.compile(is, "script");
* }
* </pre>
*
* To simplify loading, the
* {@link Globals#compilePrototype(java.io.InputStream, String)} method may be
* used:
*
* <pre>
* {
* &#64;code
* Prototype p = globals.compileProtoytpe(is, "script");
* }
* </pre>
*
* It may also be loaded from a {@link java.io.Reader} via
* {@link Globals#compilePrototype(java.io.Reader, String)}:
*
* <pre>
* {
* &#64;code
* Prototype p = globals.compileProtoytpe(new StringReader(script), "script");
* }
* </pre>
*
* To un-dump a binary file known to be a binary lua file that has been dumped
* to a string, the {@link Globals.Undumper} interface may be used:
*
* <pre>
* {
* &#64;code
* FileInputStream lua_binary_file = new FileInputStream("foo.lc"); // Known to be compiled lua.
* Prototype p = globals.undumper.undump(lua_binary_file, "foo.lua");
* }
* </pre>
*
* To execute the code represented by the {@link Prototype} it must be supplied
* to the constructor of a {@link LuaClosure}:
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* LuaClosure f = new LuaClosure(p, globals);
* f.call();
* }
* </pre>
*
* To simplify the debugging of prototype values, the contents may be printed
* using {@link Print#print}:
*
* <pre>
* {@code
* Print.print(p);
* }
* </pre>
* <p>
*
* @see LuaClosure
* @see Globals
* @see Globals#undumper
* @see Globals#compiler
* @see Print#print
*/
public class Prototype {
/* constants used by the function */
public LuaValue[] k;
public int[] code;
/* functions defined inside the function */
public Prototype[] p;
/* map from opcodes to source lines */
public int[] lineinfo;
/* information about local variables */
public LocVars[] locvars;
/* upvalue information */
public Upvaldesc[] upvalues;
public LuaString source;
public int linedefined;
public int lastlinedefined;
public int numparams;
public int is_vararg;
public int maxstacksize;
private static final Upvaldesc[] NOUPVALUES = {};
private static final Prototype[] NOSUBPROTOS = {};
public Prototype() {
p = NOSUBPROTOS;
upvalues = NOUPVALUES;
}
public Prototype(int n_upvalues) {
p = NOSUBPROTOS;
upvalues = new Upvaldesc[n_upvalues];
}
@Override
public String toString() {
return source + ":" + linedefined + "-" + lastlinedefined;
}
/**
* Get the name of a local variable.
*
* @param number the local variable number to look up
* @param pc the program counter
* @return the name, or null if not found
*/
public LuaString getlocalname(int number, int pc) {
int i;
for (i = 0; i < locvars.length && locvars[i].startpc <= pc; i++) {
if (pc < locvars[i].endpc) { /* is variable active? */
number--;
if (number == 0)
return locvars[i].varname;
}
}
return null; /* not found */
}
public String shortsource() {
String name = source.tojstring();
if (name.startsWith("@") || name.startsWith("="))
name = name.substring(1);
else if (name.startsWith("\033"))
name = "binary string";
return name;
}
}

View File

@@ -22,21 +22,20 @@
package org.luaj.vm2;
/**
* Subclass of {@link Varargs} that represents a lua tail call
* in a Java library function execution environment.
* Subclass of {@link Varargs} that represents a lua tail call in a Java library
* function execution environment.
* <p>
* Since Java doesn't have direct support for tail calls,
* any lua function whose {@link Prototype} contains the
* {@link Lua#OP_TAILCALL} bytecode needs a mechanism
* for tail calls when converting lua-bytecode to java-bytecode.
* Since Java doesn't have direct support for tail calls, any lua function whose
* {@link Prototype} contains the {@link Lua#OP_TAILCALL} bytecode needs a
* mechanism for tail calls when converting lua-bytecode to java-bytecode.
* <p>
* The tail call holds the next function and arguments,
* and the client a call to {@link #eval()} executes the function
* repeatedly until the tail calls are completed.
* The tail call holds the next function and arguments, and the client a call to
* {@link #eval()} executes the function repeatedly until the tail calls are
* completed.
* <p>
* Normally, users of luaj need not concern themselves with the
* details of this mechanism, as it is built into the core
* execution framework.
* Normally, users of luaj need not concern themselves with the details of this
* mechanism, as it is built into the core execution framework.
*
* @see Prototype
* @see org.luaj.vm2.luajc.LuaJC
*/
@@ -56,10 +55,10 @@ public class TailcallVarargs extends Varargs {
this.args = LuaValue.varargsOf(object, args);
}
public boolean isTailcall() {
return true;
}
@Override
public boolean isTailcall() { return true; }
@Override
public Varargs eval() {
while ( result == null ) {
Varargs r = func.onInvoke(args);
@@ -67,8 +66,7 @@ public class TailcallVarargs extends Varargs {
TailcallVarargs t = (TailcallVarargs) r;
func = t.func;
args = t.args;
}
else {
} else {
result = r;
func = null;
args = null;
@@ -77,24 +75,28 @@ public class TailcallVarargs extends Varargs {
return result;
}
@Override
public LuaValue arg(int i) {
if (result == null)
eval();
return result.arg(i);
}
@Override
public LuaValue arg1() {
if (result == null)
eval();
return result.arg1();
}
@Override
public int narg() {
if (result == null)
eval();
return result.narg();
}
@Override
public Varargs subargs(int start) {
if (result == null)
eval();

View File

@@ -21,9 +21,10 @@
******************************************************************************/
package org.luaj.vm2;
/** Upvalue used with Closure formulation
/**
* Upvalue used with Closure formulation
* <p>
*
* @see LuaClosure
* @see Prototype
*/
@@ -34,6 +35,7 @@ public final class UpValue {
/**
* Create an upvalue relative to a stack
*
* @param stack the stack
* @param index the index on the stack for the upvalue
*/
@@ -42,12 +44,14 @@ public final class UpValue {
this.index = index;
}
@Override
public String toString() {
return index + "/" + array.length + " " + array[index];
}
/**
* Convert this upvalue to a Java String
*
* @return the Java String for this upvalue.
* @see LuaValue#tojstring()
*/
@@ -57,24 +61,22 @@ public final class UpValue {
/**
* Get the value of the upvalue
*
* @return the {@link LuaValue} for this upvalue
*/
public final LuaValue getValue() {
return array[index];
}
public LuaValue getValue() { return array[index]; }
/**
* Set the value of the upvalue
*
* @param value the {@link LuaValue} to set it to
*/
public final void setValue( LuaValue value ) {
array[index] = value;
}
public void setValue(LuaValue value) { array[index] = value; }
/**
* Close this upvalue so it is no longer on the stack
*/
public final void close() {
public void close() {
LuaValue[] old = array;
array = new LuaValue[] { old[index] };
old[index] = null;

View File

@@ -38,6 +38,7 @@ public class Upvaldesc {
this.idx = (short) idx;
}
@Override
public String toString() {
return idx+(instack? " instack ": " closed ")+String.valueOf(name);
}

View File

@@ -29,16 +29,16 @@ import org.luaj.vm2.LuaTable.StrongSlot;
/**
* Subclass of {@link LuaTable} that provides weak key and weak value semantics.
* <p>
* Normally these are not created directly, but indirectly when changing the mode
* of a {@link LuaTable} as lua script executes.
* Normally these are not created directly, but indirectly when changing the
* mode of a {@link LuaTable} as lua script executes.
* <p>
* However, calling the constructors directly when weak tables are required from
* Java will reduce overhead.
*/
public class WeakTable implements Metatable {
private boolean weakkeys, weakvalues;
private LuaValue backing;
private final boolean weakkeys, weakvalues;
private final LuaValue backing;
public static LuaTable make(boolean weakkeys, boolean weakvalues) {
LuaString mode;
@@ -49,16 +49,17 @@ public class WeakTable implements Metatable {
} else if (weakvalues) {
mode = LuaString.valueOf("v");
} else {
return LuaTable.tableOf();
return LuaValue.tableOf();
}
LuaTable table = LuaTable.tableOf();
LuaTable mt = LuaTable.tableOf(new LuaValue[] { LuaValue.MODE, mode });
LuaTable table = LuaValue.tableOf();
LuaTable mt = LuaValue.tableOf(new LuaValue[] { LuaValue.MODE, mode });
table.setmetatable(mt);
return table;
}
/**
* Construct a table with weak keys, weak values, or both
*
* @param weakkeys true to let the table have weak keys
* @param weakvalues true to let the table have weak values
*/
@@ -68,18 +69,22 @@ public class WeakTable implements Metatable {
this.backing = backing;
}
@Override
public boolean useWeakKeys() {
return weakkeys;
}
@Override
public boolean useWeakValues() {
return weakvalues;
}
@Override
public LuaValue toLuaValue() {
return backing;
}
@Override
public Slot entry(LuaValue key, LuaValue value) {
value = value.strongvalue();
if (value == null)
@@ -109,10 +114,12 @@ public class WeakTable implements Metatable {
this.next = next;
}
@Override
public abstract int keyindex(int hashMask);
public abstract Slot set(LuaValue value);
@Override
public StrongSlot first() {
LuaValue key = strongkey();
LuaValue value = strongvalue();
@@ -125,25 +132,30 @@ public class WeakTable implements Metatable {
}
}
@Override
public StrongSlot find(LuaValue key) {
StrongSlot first = first();
return ( first != null ) ? first.find( key ) : null;
return first != null? first.find(key): null;
}
@Override
public boolean keyeq(LuaValue key) {
StrongSlot first = first();
return ( first != null ) && first.keyeq( key );
return first != null && first.keyeq(key);
}
@Override
public Slot rest() {
return next;
}
@Override
public int arraykey(int max) {
// Integer keys can never be weak.
return 0;
}
@Override
public Slot set(StrongSlot target, LuaValue value) {
LuaValue key = strongkey();
if (key != null && target.find(key) != null) {
@@ -158,8 +170,9 @@ public class WeakTable implements Metatable {
}
}
@Override
public Slot add(Slot entry) {
next = ( next != null ) ? next.add( entry ) : entry;
next = next != null? next.add(entry): entry;
if (strongkey() != null && strongvalue() != null) {
return this;
} else {
@@ -167,6 +180,7 @@ public class WeakTable implements Metatable {
}
}
@Override
public Slot remove(StrongSlot target) {
LuaValue key = strongkey();
if (key == null) {
@@ -180,6 +194,7 @@ public class WeakTable implements Metatable {
}
}
@Override
public Slot relink(Slot rest) {
if (strongkey() != null && strongvalue() != null) {
if (rest == null && this.next == null) {
@@ -217,19 +232,23 @@ public class WeakTable implements Metatable {
this.keyhash = copyFrom.keyhash;
}
@Override
public int keyindex(int mask) {
return LuaTable.hashmod(keyhash, mask);
}
@Override
public Slot set(LuaValue value) {
this.value = value;
return this;
}
@Override
public LuaValue strongkey() {
return strengthen(key);
}
@Override
protected WeakSlot copy(Slot rest) {
return new WeakKeySlot(this, rest);
}
@@ -245,19 +264,23 @@ public class WeakTable implements Metatable {
super(copyFrom.key, copyFrom.value, next);
}
@Override
public int keyindex(int mask) {
return LuaTable.hashSlot(strongkey(), mask);
}
@Override
public Slot set(LuaValue value) {
this.value = weaken(value);
return this;
}
@Override
public LuaValue strongvalue() {
return strengthen(value);
}
@Override
protected WeakSlot copy(Slot next) {
return new WeakValueSlot(this, next);
}
@@ -277,23 +300,28 @@ public class WeakTable implements Metatable {
keyhash = copyFrom.keyhash;
}
@Override
public int keyindex(int hashMask) {
return LuaTable.hashmod(keyhash, hashMask);
}
@Override
public Slot set(LuaValue value) {
this.value = weaken(value);
return this;
}
@Override
public LuaValue strongkey() {
return strengthen(key);
}
@Override
public LuaValue strongvalue() {
return strengthen(value);
}
@Override
protected WeakSlot copy(Slot next) {
return new WeakKeyAndValueSlot(this, next);
}
@@ -301,8 +329,10 @@ public class WeakTable implements Metatable {
/**
* Self-sent message to convert a value to its weak counterpart
*
* @param value value to convert
* @return {@link LuaValue} that is a strong or weak reference, depending on type of {@code value}
* @return {@link LuaValue} that is a strong or weak reference, depending on
* type of {@code value}
*/
protected static LuaValue weaken(LuaValue value) {
switch (value.type()) {
@@ -319,6 +349,7 @@ public class WeakTable implements Metatable {
/**
* Unwrap a LuaValue from a WeakReference and/or WeakUserdata.
*
* @param ref reference to convert
* @return LuaValue or null
* @see #weaken(LuaValue)
@@ -333,7 +364,9 @@ public class WeakTable implements Metatable {
return (LuaValue) ref;
}
/** Internal class to implement weak values.
/**
* Internal class to implement weak values.
*
* @see WeakTable
*/
static class WeakValue extends LuaValue {
@@ -343,32 +376,39 @@ public class WeakTable implements Metatable {
ref = new WeakReference(value);
}
@Override
public int type() {
illegal("type", "weak value");
return 0;
}
@Override
public String typename() {
illegal("typename", "weak value");
return null;
}
@Override
public String toString() {
return "weak<" + ref.get() + ">";
}
@Override
public LuaValue strongvalue() {
Object o = ref.get();
return (LuaValue) o;
}
@Override
public boolean raweq(LuaValue rhs) {
Object o = ref.get();
return o != null && rhs.raweq((LuaValue) o);
}
}
/** Internal class to implement weak userdata values.
/**
* Internal class to implement weak userdata values.
*
* @see WeakTable
*/
static final class WeakUserdata extends WeakValue {
@@ -381,6 +421,7 @@ public class WeakTable implements Metatable {
mt = value.getmetatable();
}
@Override
public LuaValue strongvalue() {
Object u = ref.get();
if (u != null)
@@ -396,10 +437,12 @@ public class WeakTable implements Metatable {
}
}
@Override
public LuaValue wrap(LuaValue value) {
return weakvalues? weaken(value): value;
}
@Override
public LuaValue arrayget(LuaValue[] array, int index) {
LuaValue value = array[index];
if (value != null) {

View File

@@ -0,0 +1,19 @@
package org.luaj.vm2.compat;
public class JavaCompat {
public static final JavaCompat INSTANCE;
static {
JavaCompat instance;
try {
instance = (JavaCompat) Class.forName("org.luaj.vm2.lib.jse.JavaCompatJSE").newInstance();
} catch (Throwable t) {
instance = new JavaCompat();
}
INSTANCE = instance;
}
public long doubleToRawLongBits(double x) {
return Double.doubleToLongBits(x);
}
}

View File

@@ -44,48 +44,42 @@ public class Constants extends Lua {
static final int LUAI_MAXVARS = 200;
static final int NO_REG = MAXARG_A;
/* OpMode - basic instruction format */
static final int
iABC = 0,
iABx = 1,
iAsBx = 2;
static final int iABC = 0, iABx = 1, iAsBx = 2;
/* OpArgMask */
static final int
OpArgN = 0, /* argument is not used */
static final int OpArgN = 0, /* argument is not used */
OpArgU = 1, /* argument is used */
OpArgR = 2, /* argument is a register or a jump offset */
OpArgK = 3; /* argument is a constant or register/constant */
protected static void _assert(boolean b) {
if (!b)
throw new LuaError("compiler assert failed");
}
static void SET_OPCODE(InstructionPtr i, int o) {
i.set( ( i.get() & (MASK_NOT_OP)) | ((o << POS_OP) & MASK_OP) );
i.set(i.get() & MASK_NOT_OP | o<<POS_OP & MASK_OP);
}
static void SETARG_A(int[] code, int index, int u) {
code[index] = (code[index] & (MASK_NOT_A)) | ((u << POS_A) & MASK_A);
code[index] = code[index] & MASK_NOT_A | u<<POS_A & MASK_A;
}
static void SETARG_A(InstructionPtr i, int u) {
i.set( ( i.get() & (MASK_NOT_A)) | ((u << POS_A) & MASK_A) );
i.set(i.get() & MASK_NOT_A | u<<POS_A & MASK_A);
}
static void SETARG_B(InstructionPtr i, int u) {
i.set( ( i.get() & (MASK_NOT_B)) | ((u << POS_B) & MASK_B) );
i.set(i.get() & MASK_NOT_B | u<<POS_B & MASK_B);
}
static void SETARG_C(InstructionPtr i, int u) {
i.set( ( i.get() & (MASK_NOT_C)) | ((u << POS_C) & MASK_C) );
i.set(i.get() & MASK_NOT_C | u<<POS_C & MASK_C);
}
static void SETARG_Bx(InstructionPtr i, int u) {
i.set( ( i.get() & (MASK_NOT_Bx)) | ((u << POS_Bx) & MASK_Bx) );
i.set(i.get() & MASK_NOT_Bx | u<<POS_Bx & MASK_Bx);
}
static void SETARG_sBx(InstructionPtr i, int u) {
@@ -93,16 +87,15 @@ public class Constants extends Lua {
}
static int CREATE_ABC(int o, int a, int b, int c) {
return ((o << POS_OP) & MASK_OP) |
((a << POS_A) & MASK_A) |
((b << POS_B) & MASK_B) |
((c << POS_C) & MASK_C) ;
return o<<POS_OP & MASK_OP | a<<POS_A & MASK_A | b<<POS_B & MASK_B | c<<POS_C & MASK_C;
}
static int CREATE_ABx(int o, int a, int bc) {
return ((o << POS_OP) & MASK_OP) |
((a << POS_A) & MASK_A) |
((bc << POS_Bx) & MASK_Bx) ;
return o<<POS_OP & MASK_OP | a<<POS_A & MASK_A | 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

View File

@@ -28,39 +28,51 @@ import java.io.OutputStream;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LoadState;
import org.luaj.vm2.LocVars;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.LuaString;
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.
* <p>
* Generally, this class is not used directly, but rather indirectly via a command
* line interface tool such as {@link luac}.
* Generally, this class is not used directly, but rather indirectly via a
* command line interface tool such as {@link luac}.
* <p>
* A lua binary file is created via {@link DumpState#dump}:
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* Prototype p = globals.compilePrototype(new StringReader("print('hello, world')"), "main.lua");
* ByteArrayOutputStream o = new ByteArrayOutputStream();
* DumpState.dump(p, o, false);
* byte[] lua_binary_file_bytes = o.toByteArray();
* } </pre>
* }
* </pre>
*
* The {@link LoadState} may be used directly to undump these bytes:
* <pre> {@code
*
* <pre>
* {@code
* Prototypep = LoadState.instance.undump(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua");
* LuaClosure c = new LuaClosure(p, globals);
* c.call();
* } </pre>
* }
* </pre>
*
*
* More commonly, the {@link Globals#undumper} may be used to undump them:
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Prototype p = globals.loadPrototype(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua", "b");
* LuaClosure c = new LuaClosure(p, globals);
* c.call();
* } </pre>
* }
* </pre>
*
* @see luac
* @see LoadState
@@ -72,20 +84,26 @@ public class DumpState {
/** set true to allow integer compilation */
public static boolean ALLOW_INTEGER_CASTING = false;
/** format corresponding to non-number-patched lua, all numbers are floats or doubles */
/**
* format corresponding to non-number-patched lua, all numbers are floats or
* doubles
*/
public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0;
/** format corresponding to non-number-patched lua, all numbers are ints */
public static final int NUMBER_FORMAT_INTS_ONLY = 1;
/** format corresponding to number-patched lua, all numbers are 32-bit (4 byte) ints */
/**
* format corresponding to number-patched lua, all numbers are 32-bit (4
* byte) ints
*/
public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4;
/** default number format */
public static final int NUMBER_FORMAT_DEFAULT = NUMBER_FORMAT_FLOATS_OR_DOUBLES;
// header fields
private boolean IS_LITTLE_ENDIAN = false;
private boolean IS_LITTLE_ENDIAN = true;
private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT;
private int SIZEOF_LUA_NUMBER = 8;
private static final int SIZEOF_INT = 4;
@@ -113,9 +131,9 @@ public class DumpState {
void dumpInt(int x) throws IOException {
if (IS_LITTLE_ENDIAN) {
writer.writeByte(x & 0xff);
writer.writeByte((x>>8)&0xff);
writer.writeByte((x>>16)&0xff);
writer.writeByte((x>>24)&0xff);
writer.writeByte(x>>8 & 0xff);
writer.writeByte(x>>16 & 0xff);
writer.writeByte(x>>24 & 0xff);
} else {
writer.writeInt(x);
}
@@ -272,13 +290,17 @@ public class DumpState {
* @param f the function to dump
* @param w the output stream to dump to
* @param stripDebug true to strip debugging info, false otherwise
* @param numberFormat one of NUMBER_FORMAT_FLOATS_OR_DOUBLES, NUMBER_FORMAT_INTS_ONLY, NUMBER_FORMAT_NUM_PATCH_INT32
* @param littleendian true to use little endian for numbers, false for big endian
* @param numberFormat one of NUMBER_FORMAT_FLOATS_OR_DOUBLES,
* NUMBER_FORMAT_INTS_ONLY,
* NUMBER_FORMAT_NUM_PATCH_INT32
* @param littleendian true to use little endian for numbers, false for big
* endian
* @return 0 if dump succeeds
* @throws IOException
* @throws IllegalArgumentException if the number format it not supported
*/
public static int dump(Prototype f, OutputStream w, boolean stripDebug, int numberFormat, boolean littleendian) throws IOException {
public static int dump(Prototype f, OutputStream w, boolean stripDebug, int numberFormat, boolean littleendian)
throws IOException {
switch (numberFormat) {
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
case NUMBER_FORMAT_INTS_ONLY:
@@ -290,7 +312,7 @@ public class DumpState {
DumpState D = new DumpState(w, stripDebug);
D.IS_LITTLE_ENDIAN = littleendian;
D.NUMBER_FORMAT = numberFormat;
D.SIZEOF_LUA_NUMBER = (numberFormat==NUMBER_FORMAT_INTS_ONLY? 4: 8);
D.SIZEOF_LUA_NUMBER = numberFormat == NUMBER_FORMAT_INTS_ONLY? 4: 8;
D.dumpHeader();
D.dumpFunction(f);
return D.status;

View File

@@ -34,7 +34,6 @@ import org.luaj.vm2.Upvaldesc;
import org.luaj.vm2.compiler.LexState.ConsControl;
import org.luaj.vm2.compiler.LexState.expdesc;
public class FuncState extends Constants {
static class BlockCnt {
@@ -44,13 +43,12 @@ public class FuncState extends Constants {
short nactvar; /* # active locals outside the breakable structure */
boolean upval; /* true if some variable in the block is an upvalue */
boolean isloop; /* true if `block' is a loop */
};
}
Prototype f; /* current function header */
Hashtable h; /* table to find (and reuse) elements in `k' */
FuncState prev; /* enclosing function */
LexState ls; /* lexical state */
LuaC.CompileState L; /* compiler being invoked */
BlockCnt bl; /* chain of current blocks */
int pc; /* next position to code (equivalent to `ncode') */
int lasttarget; /* `pc' of last `jump target' */
@@ -66,7 +64,6 @@ public class FuncState extends Constants {
FuncState() {
}
// =============================================================
// from lcode.h
// =============================================================
@@ -87,7 +84,6 @@ public class FuncState extends Constants {
setreturns(e, LUA_MULTRET);
}
// =============================================================
// from lparser.c
// =============================================================
@@ -97,14 +93,12 @@ public class FuncState extends Constants {
int i;
for (i = bl.firstlabel; i < ll_n; i++) {
if (label.eq_b(ll[i].name)) {
String msg = ls.L.pushfstring(
"label '" + label + " already defined on line " + ll[i].line);
String msg = ls.L.pushfstring("label '" + label + " already defined on line " + ll[i].line);
ls.semerror(msg);
}
}
}
void checklimit(int v, int l, String msg) {
if (v > l)
errorlimit(l, msg);
@@ -112,9 +106,8 @@ public class FuncState extends Constants {
void errorlimit(int limit, String what) {
// TODO: report message logic.
String msg = (f.linedefined == 0) ?
L.pushfstring("main function has more than "+limit+" "+what) :
L.pushfstring("function at line "+f.linedefined+" has more than "+limit+" "+what);
String msg = f.linedefined == 0? ls.L.pushfstring("main function has more than " + limit + " " + what)
: ls.L.pushfstring("function at line " + f.linedefined + " has more than " + limit + " " + what);
ls.lexerror(msg, 0);
}
@@ -125,12 +118,11 @@ public class FuncState extends Constants {
}
void removevars(int tolevel) {
ls.dyd.n_actvar -= (nactvar - tolevel);
ls.dyd.n_actvar -= nactvar-tolevel;
while ( nactvar > tolevel )
getlocvar(--nactvar).endpc = pc;
}
int searchupvalue(LuaString name) {
int i;
Upvaldesc[] up = f.upvalues;
@@ -253,25 +245,26 @@ public class FuncState extends Constants {
}
boolean hasmultret(int k) {
return ((k) == LexState.VCALL || (k) == LexState.VVARARG);
return k == LexState.VCALL || k == LexState.VVARARG;
}
void lastlistfield(ConsControl cc) {
if (cc.tostore == 0) return;
if (cc.tostore == 0)
return;
if (hasmultret(cc.v.k)) {
this.setmultret(cc.v);
this.setlist(cc.t.u.info, cc.na, LUA_MULTRET);
cc.na--; /** do not count last expression (unknown number of elements) */
}
else {
cc.na--; /**
* do not count last expression (unknown number of
* elements)
*/
} else {
if (cc.v.k != LexState.VVOID)
this.exp2nextreg(cc.v);
this.setlist(cc.t.u.info, cc.na, cc.tostore);
}
}
// =============================================================
// from lcode.c
// =============================================================
@@ -283,8 +276,7 @@ public class FuncState extends Constants {
if (GET_OPCODE(previous_code) == OP_LOADNIL) {
int pfrom = GETARG_A(previous_code);
int pl = pfrom+GETARG_B(previous_code);
if ((pfrom <= from && from <= pl + 1)
|| (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
if (pfrom <= from && from <= pl+1 || from <= pfrom && pfrom <= l+1) { /* can connect both? */
if (pfrom < from)
from = pfrom; /* from = min(from, pfrom) */
if (pl > l)
@@ -299,7 +291,6 @@ public class FuncState extends Constants {
this.codeABC(OP_LOADNIL, from, n-1, 0);
}
int jump() {
int jpc = this.jpc.i; /* save list of jumps to here */
this.jpc.i = LexState.NO_JUMP;
@@ -326,7 +317,6 @@ public class FuncState extends Constants {
SETARG_sBx(jmp, offset);
}
/*
* * returns current `pc' and marks it as a jump target (to avoid wrong *
* optimizations with consecutive instructions not in the same basic block).
@@ -336,7 +326,6 @@ public class FuncState extends Constants {
return this.pc;
}
int getjump(int pc) {
int offset = GETARG_sBx(this.f.code[pc]);
/* point to itself represents end of list */
@@ -345,10 +334,9 @@ public class FuncState extends Constants {
return LexState.NO_JUMP;
else
/* turn offset into absolute position */
return (pc + 1) + offset;
return pc+1+offset;
}
InstructionPtr getjumpcontrol(int pc) {
InstructionPtr pi = new InstructionPtr(this.f.code, pc);
if (pc >= 1 && testTMode(GET_OPCODE(pi.code[pi.idx-1])))
@@ -357,7 +345,6 @@ public class FuncState extends Constants {
return pi;
}
/*
* * check whether list has any jump that do not produce a value * (or
* produce an inverted value)
@@ -371,7 +358,6 @@ public class FuncState extends Constants {
return false; /* not found */
}
boolean patchtestreg(int node, int reg) {
InstructionPtr i = this.getjumpcontrol(node);
if (GET_OPCODE(i.get()) != OP_TESTSET)
@@ -386,7 +372,6 @@ public class FuncState extends Constants {
return true;
}
void removevalues(int list) {
for (; list != LexState.NO_JUMP; list = this.getjump(list))
this.patchtestreg(list, NO_REG);
@@ -421,8 +406,8 @@ public class FuncState extends Constants {
level++; /* argument is +1 to reserve 0 as non-op */
while ( list != LexState.NO_JUMP ) {
int next = getjump(list);
_assert(GET_OPCODE(f.code[list]) == OP_JMP
&& (GETARG_A(f.code[list]) == 0 || GETARG_A(f.code[list]) >= level));
_assert(
GET_OPCODE(f.code[list]) == OP_JMP && (GETARG_A(f.code[list]) == 0 || GETARG_A(f.code[list]) >= level));
SETARG_A(f.code, list, level);
list = next;
}
@@ -473,6 +458,7 @@ public class FuncState extends Constants {
if (e.k == LexState.VNONRELOC)
this.freereg(e.u.info);
}
int addk(LuaValue v) {
if (this.h == null) {
this.h = new Hashtable();
@@ -480,7 +466,7 @@ public class FuncState extends Constants {
return ((Integer) h.get(v)).intValue();
}
final int idx = this.nk;
this.h.put(v, new Integer(idx));
this.h.put(v, Integer.valueOf(idx));
final Prototype f = this.f;
if (f.k == null || nk+1 >= f.k.length)
f.k = realloc(f.k, nk*2+1);
@@ -496,14 +482,14 @@ public class FuncState extends Constants {
if (r instanceof LuaDouble) {
double d = r.todouble();
int i = (int) d;
if ( d == (double) i )
if (d == i)
r = LuaInteger.valueOf(i);
}
return this.addk(r);
}
int boolK(boolean b) {
return this.addk((b ? LuaValue.TRUE : LuaValue.FALSE));
return this.addk(b? LuaValue.TRUE: LuaValue.FALSE);
}
int nilK() {
@@ -576,16 +562,15 @@ public class FuncState extends Constants {
}
case LexState.VFALSE:
case LexState.VTRUE: {
this.codeABC(OP_LOADBOOL, reg, (e.k == LexState.VTRUE ? 1 : 0),
0);
this.codeABC(OP_LOADBOOL, reg, e.k == LexState.VTRUE? 1: 0, 0);
break;
}
case LexState.VK: {
this.codeABx(OP_LOADK, reg, e.u.info);
this.codeK(reg, e.u.info);
break;
}
case LexState.VKNUM: {
this.codeABx(OP_LOADK, reg, this.numberK(e.u.nval()));
this.codeK(reg, this.numberK(e.u.nval()));
break;
}
case LexState.VRELOCABLE: {
@@ -623,8 +608,7 @@ public class FuncState extends Constants {
int p_f = LexState.NO_JUMP; /* position of an eventual LOAD false */
int p_t = LexState.NO_JUMP; /* position of an eventual LOAD true */
if (this.need_value(e.t.i) || this.need_value(e.f.i)) {
int fj = (e.k == LexState.VJMP) ? LexState.NO_JUMP : this
.jump();
int fj = e.k == LexState.VJMP? LexState.NO_JUMP: this.jump();
p_f = this.code_label(reg, 0, 1);
p_t = this.code_label(reg, 1, 0);
this.patchtohere(fj);
@@ -678,8 +662,7 @@ public class FuncState extends Constants {
case LexState.VFALSE:
case LexState.VNIL: {
if (this.nk <= MAXINDEXRK) { /* constant fit in RK operand? */
e.u.info = (e.k == LexState.VNIL) ? this.nilK()
: this.boolK((e.k == LexState.VTRUE));
e.u.info = e.k == LexState.VNIL? this.nilK(): this.boolK(e.k == LexState.VTRUE);
e.k = LexState.VK;
return RKASK(e.u.info);
} else
@@ -716,7 +699,7 @@ public class FuncState extends Constants {
break;
}
case LexState.VINDEXED: {
int op = (var.u.ind_vt == LexState.VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
int op = var.u.ind_vt == LexState.VLOCAL? OP_SETTABLE: OP_SETTABUP;
int e = this.exp2RK(ex);
this.codeABC(op, var.u.ind_t, var.u.ind_idx, e);
break;
@@ -743,12 +726,11 @@ public class FuncState extends Constants {
void invertjump(expdesc e) {
InstructionPtr pc = this.getjumpcontrol(e.u.info);
_assert (testTMode(GET_OPCODE(pc.get()))
&& GET_OPCODE(pc.get()) != OP_TESTSET && Lua
.GET_OPCODE(pc.get()) != OP_TEST);
_assert(testTMode(GET_OPCODE(pc.get())) && GET_OPCODE(pc.get()) != OP_TESTSET
&& Lua.GET_OPCODE(pc.get()) != OP_TEST);
// SETARG_A(pc, !(GETARG_A(pc.get())));
int a = GETARG_A(pc.get());
int nota = (a!=0? 0: 1);
int nota = a != 0? 0: 1;
SETARG_A(pc, nota);
}
@@ -757,7 +739,7 @@ public class FuncState extends Constants {
int ie = this.getcode(e);
if (GET_OPCODE(ie) == OP_NOT) {
this.pc--; /* remove previous OP_NOT */
return this.condjump(OP_TEST, GETARG_B(ie), 0, (cond!=0? 0: 1));
return this.condjump(OP_TEST, GETARG_B(ie), 0, cond != 0? 0: 1);
}
/* else go through */
}
@@ -856,14 +838,14 @@ public class FuncState extends Constants {
}
static boolean vkisinreg(int k) {
return ((k) == LexState.VNONRELOC || (k) == LexState.VLOCAL);
return k == LexState.VNONRELOC || k == LexState.VLOCAL;
}
void indexed(expdesc t, expdesc k) {
t.u.ind_t = (short) t.u.info;
t.u.ind_idx = (short) this.exp2RK(k);
LuaC._assert(t.k == LexState.VUPVAL || vkisinreg(t.k));
t.u.ind_vt = (short) ((t.k == LexState.VUPVAL) ? LexState.VUPVAL : LexState.VLOCAL);
Constants._assert(t.k == LexState.VUPVAL || vkisinreg(t.k));
t.u.ind_vt = (short) (t.k == LexState.VUPVAL? LexState.VUPVAL: LexState.VLOCAL);
t.k = LexState.VINDEXED;
}
@@ -913,11 +895,9 @@ public class FuncState extends Constants {
}
void codearith(int op, expdesc e1, expdesc e2, int line) {
if (constfolding(op, e1, e2))
return;
else {
int o2 = (op != OP_UNM && op != OP_LEN) ? this.exp2RK(e2)
: 0;
if (constfolding(op, e1, e2)) {
} else {
int o2 = op != OP_UNM && op != OP_LEN? this.exp2RK(e2): 0;
int o1 = this.exp2RK(e1);
if (o1 > o2) {
this.freeexp(e1);
@@ -1005,7 +985,6 @@ public class FuncState extends Constants {
}
}
void posfix(int op, expdesc e1, expdesc e2, int line) {
switch (op) {
case LexState.OPR_AND: {
@@ -1026,8 +1005,7 @@ public class FuncState extends Constants {
}
case LexState.OPR_CONCAT: {
this.exp2val(e2);
if (e2.k == LexState.VRELOCABLE
&& GET_OPCODE(this.getcode(e2)) == OP_CONCAT) {
if (e2.k == LexState.VRELOCABLE && GET_OPCODE(this.getcode(e2)) == OP_CONCAT) {
_assert(e1.u.info == GETARG_B(this.getcode(e2))-1);
this.freeexp(e1);
SETARG_B(this.getcodePtr(e2), e1.u.info);
@@ -1080,28 +1058,24 @@ public class FuncState extends Constants {
}
}
void fixline(int line) {
this.f.lineinfo[this.pc-1] = line;
}
int code(int instruction, int line) {
Prototype f = this.f;
this.dischargejpc(); /* `pc' will change */
/* put new instruction in code array */
if (f.code == null || this.pc+1 > f.code.length)
f.code = LuaC.realloc(f.code, this.pc * 2 + 1);
f.code = Constants.realloc(f.code, this.pc*2+1);
f.code[this.pc] = instruction;
/* save corresponding line information */
if (f.lineinfo == null || this.pc+1 > f.lineinfo.length)
f.lineinfo = LuaC.realloc(f.lineinfo,
this.pc * 2 + 1);
f.lineinfo = Constants.realloc(f.lineinfo, this.pc*2+1);
f.lineinfo[this.pc] = line;
return this.pc++;
}
int codeABC(int o, int a, int b, int c) {
_assert(getOpMode(o) == iABC);
_assert(getBMode(o) != OpArgN || b == 0);
@@ -1109,7 +1083,6 @@ public class FuncState extends Constants {
return this.code(CREATE_ABC(o, a, b, c), this.ls.lastline);
}
int codeABx(int o, int a, int bc) {
_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
_assert(getCMode(o) == OpArgN);
@@ -1117,10 +1090,24 @@ public class FuncState extends Constants {
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) {
int c = (nelems-1)/LFIELDS_PER_FLUSH+1;
int b = (tostore == LUA_MULTRET) ? 0 : tostore;
int b = tostore == LUA_MULTRET? 0: tostore;
_assert(tostore != 0);
if (c <= MAXARG_C)
this.codeABC(OP_SETLIST, base, b, c);

View File

@@ -24,13 +24,16 @@ package org.luaj.vm2.compiler;
class InstructionPtr {
final int[] code;
final int idx;
InstructionPtr(int[] code, int idx) {
this.code = code;
this.idx = idx;
}
int get() {
return code[idx];
}
void set(int value) {
code[idx] = value;
}

View File

@@ -23,8 +23,10 @@ package org.luaj.vm2.compiler;
public class IntPtr {
int i;
IntPtr() {
}
IntPtr(int value) {
this.i = value;
}

View File

@@ -35,7 +35,6 @@ import org.luaj.vm2.Prototype;
import org.luaj.vm2.compiler.FuncState.BlockCnt;
import org.luaj.vm2.lib.MathLib;
public class LexState extends Constants {
protected static final String RESERVED_LOCAL_VAR_FOR_CONTROL = "(for control)";
@@ -46,26 +45,22 @@ public class LexState extends Constants {
protected static final String RESERVED_LOCAL_VAR_FOR_INDEX = "(for index)";
// keywords array
protected static final String[] RESERVED_LOCAL_VAR_KEYWORDS = new String[] {
RESERVED_LOCAL_VAR_FOR_CONTROL,
RESERVED_LOCAL_VAR_FOR_GENERATOR,
RESERVED_LOCAL_VAR_FOR_INDEX,
RESERVED_LOCAL_VAR_FOR_LIMIT,
RESERVED_LOCAL_VAR_FOR_STATE,
RESERVED_LOCAL_VAR_FOR_STEP
};
protected static final String[] RESERVED_LOCAL_VAR_KEYWORDS = { RESERVED_LOCAL_VAR_FOR_CONTROL,
RESERVED_LOCAL_VAR_FOR_GENERATOR, RESERVED_LOCAL_VAR_FOR_INDEX, RESERVED_LOCAL_VAR_FOR_LIMIT,
RESERVED_LOCAL_VAR_FOR_STATE, RESERVED_LOCAL_VAR_FOR_STEP };
private static final Hashtable RESERVED_LOCAL_VAR_KEYWORDS_TABLE = new Hashtable();
static {
for ( int i=0; i<RESERVED_LOCAL_VAR_KEYWORDS.length; i++ )
RESERVED_LOCAL_VAR_KEYWORDS_TABLE.put( RESERVED_LOCAL_VAR_KEYWORDS[i], Boolean.TRUE );
for (String element : RESERVED_LOCAL_VAR_KEYWORDS)
RESERVED_LOCAL_VAR_KEYWORDS_TABLE.put(element, Boolean.TRUE);
}
private static final int EOZ = (-1);
private static final int EOZ = -1;
private static final int MAX_INT = Integer.MAX_VALUE-2;
private static final int UCHAR_MAX = 255; // TODO, convert to unicode CHAR_MAX?
private static final int LUAI_MAXCCALLS = 200;
private static final String LUA_QS(String s) { return "'" + s + "'"; }
private static final String LUA_QL(Object o) { return LUA_QS(String.valueOf(o)); }
private static final int LUA_COMPAT_LSTR = 1; // 1 for compatibility, 2 for old behavior
@@ -79,29 +74,20 @@ public class LexState extends Constants {
** Marks the end of a patch list. It is an invalid value both as an absolute
** address, and as a list link (would link an element to itself).
*/
static final int NO_JUMP = (-1);
static final int NO_JUMP = -1;
/*
** grep "ORDER OPR" if you change these enums
*/
static final int
OPR_ADD=0, OPR_SUB=1, OPR_MUL=2, OPR_DIV=3, OPR_MOD=4, OPR_POW=5,
OPR_CONCAT=6,
OPR_NE=7, OPR_EQ=8,
OPR_LT=9, OPR_LE=10, OPR_GT=11, OPR_GE=12,
OPR_AND=13, OPR_OR=14,
static final int OPR_ADD = 0, OPR_SUB = 1, OPR_MUL = 2, OPR_DIV = 3, OPR_MOD = 4, OPR_POW = 5, OPR_CONCAT = 6,
OPR_NE = 7, OPR_EQ = 8, OPR_LT = 9, OPR_LE = 10, OPR_GT = 11, OPR_GE = 12, OPR_AND = 13, OPR_OR = 14,
OPR_NOBINOPR = 15;
static final int
OPR_MINUS=0, OPR_NOT=1, OPR_LEN=2, OPR_NOUNOPR=3;
static final int OPR_MINUS = 0, OPR_NOT = 1, OPR_LEN = 2, OPR_NOUNOPR = 3;
/* exp kind */
static final int
VVOID = 0, /* no value */
VNIL = 1,
VTRUE = 2,
VFALSE = 3,
VK = 4, /* info = index of constant in `k' */
static final int VVOID = 0, /* no value */
VNIL = 1, VTRUE = 2, VFALSE = 3, VK = 4, /* info = index of constant in `k' */
VKNUM = 5, /* nval = numerical value */
VNONRELOC = 6, /* info = result register */
VLOCAL = 7, /* info = local register */
@@ -116,17 +102,18 @@ public class LexState extends Constants {
private static class SemInfo {
LuaValue r;
LuaString ts;
};
}
private static class Token {
int token;
final SemInfo seminfo = new SemInfo();
public void set(Token other) {
this.token = other.token;
this.seminfo.r = other.seminfo.r;
this.seminfo.ts = other.seminfo.ts;
}
};
}
int current; /* current character (charint) */
int linenumber; /* input line counter */
@@ -150,18 +137,18 @@ public class LexState extends Constants {
"in", "local", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while",
"..", "...", "==", ">=", "<=", "~=",
"::", "<eos>", "<number>", "<name>", "<string>", "<eof>",
"::", "<eof>", "<number>", "<name>", "<string>"
};
final static int
/* terminal symbols denoted by reserved words */
TK_AND=257, TK_BREAK=258, TK_DO=259, TK_ELSE=260, TK_ELSEIF=261,
TK_END=262, TK_FALSE=263, TK_FOR=264, TK_FUNCTION=265, TK_GOTO=266, TK_IF=267,
TK_IN=268, TK_LOCAL=269, TK_NIL=270, TK_NOT=271, TK_OR=272, TK_REPEAT=273,
TK_RETURN=274, TK_THEN=275, TK_TRUE=276, TK_UNTIL=277, TK_WHILE=278,
TK_AND = 257, TK_BREAK = 258, TK_DO = 259, TK_ELSE = 260, TK_ELSEIF = 261, TK_END = 262, TK_FALSE = 263,
TK_FOR = 264, TK_FUNCTION = 265, TK_GOTO = 266, TK_IF = 267, TK_IN = 268, TK_LOCAL = 269, TK_NIL = 270,
TK_NOT = 271, TK_OR = 272, TK_REPEAT = 273, TK_RETURN = 274, TK_THEN = 275, TK_TRUE = 276, TK_UNTIL = 277,
TK_WHILE = 278,
/* other terminal symbols */
TK_CONCAT=279, TK_DOTS=280, TK_EQ=281, TK_GE=282, TK_LE=283, TK_NE=284,
TK_DBCOLON=285, TK_EOS=286, TK_NUMBER=287, TK_NAME=288, TK_STRING=289;
TK_DBCOLON=285, TK_EOF=286, TK_NUMBER=287, TK_NAME=288, TK_STRING=289;
final static int FIRST_RESERVED = TK_AND;
final static int NUM_RESERVED = TK_WHILE+1-FIRST_RESERVED;
@@ -169,39 +156,32 @@ public class LexState extends Constants {
final static Hashtable RESERVED = new Hashtable();
static {
for (int i = 0; i < NUM_RESERVED; i++) {
LuaString ts = (LuaString) LuaValue.valueOf( luaX_tokens[i] );
RESERVED.put(ts, new Integer(FIRST_RESERVED+i));
LuaString ts = LuaValue.valueOf(luaX_tokens[i]);
RESERVED.put(ts, Integer.valueOf(FIRST_RESERVED+i));
}
}
private boolean isalnum(int c) {
return (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c == '_');
return c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_';
// return Character.isLetterOrDigit(c);
}
private boolean isalpha(int c) {
return (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z');
return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
}
private boolean isdigit(int c) {
return (c >= '0' && c <= '9');
return c >= '0' && c <= '9';
}
private boolean isxdigit(int c) {
return (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'f')
|| (c >= 'A' && c <= 'F');
return c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F';
}
private boolean isspace(int c) {
return (c <= ' ');
return c >= 0 && c <= ' ';
}
public LexState(LuaC.CompileState state, InputStream stream) {
this.z = stream;
this.buff = new char[32];
@@ -232,12 +212,9 @@ public class LexState extends Constants {
buff[nbuff++] = (char) c;
}
String token2str(int token) {
if (token < FIRST_RESERVED) {
return iscntrl(token)?
L.pushfstring( "char("+((int)token)+")" ):
L.pushfstring( String.valueOf( (char) token ) );
return iscntrl(token)? L.pushfstring("char(" + token + ")"): L.pushfstring(String.valueOf((char) token));
} else {
return luaX_tokens[token-FIRST_RESERVED];
}
@@ -292,7 +269,7 @@ public class LexState extends Constants {
void setinput(LuaC.CompileState L, int firstByte, InputStream z, LuaString source) {
this.decpoint = '.';
this.L = L;
this.lookahead.token = TK_EOS; /* no look-ahead token */
this.lookahead.token = TK_EOF; /* no look-ahead token */
this.z = z;
this.fs = null;
this.linenumber = 1;
@@ -310,15 +287,12 @@ public class LexState extends Constants {
nextChar();
}
/*
** =======================================================
** LEXICAL ANALYZER
** =======================================================
*/
boolean check_next(String set) {
if (set.indexOf(current) < 0)
return false;
@@ -329,7 +303,7 @@ public class LexState extends Constants {
void buffreplace(char from, char to) {
int n = nbuff;
char[] p = buff;
while ((--n) >= 0)
while ( --n >= 0 )
if (p[n] == from)
p[n] = to;
}
@@ -346,11 +320,7 @@ public class LexState extends Constants {
++s;
}
/* Check for "0x" */
if (s + 2 >= c.length )
return LuaValue.ZERO;
if (c[s++] != '0')
return LuaValue.ZERO;
if (c[s] != 'x' && c[s] != 'X')
if (s+2 >= c.length || c[s++] != '0' || c[s] != 'x' && c[s] != 'X')
return LuaValue.ZERO;
++s;
@@ -358,11 +328,11 @@ public class LexState extends Constants {
double m = 0;
int e = 0;
while ( s < c.length && isxdigit(c[s]) )
m = (m * 16) + hexvalue(c[s++]);
m = m*16+hexvalue(c[s++]);
if (s < c.length && c[s] == '.') {
++s; // skip dot
while ( s < c.length && isxdigit(c[s]) ) {
m = (m * 16) + hexvalue(c[s++]);
m = m*16+hexvalue(c[s++]);
e -= 4; // Each fractional part shifts right by 2^4
}
}
@@ -388,8 +358,13 @@ public class LexState extends Constants {
seminfo.r = LuaValue.ZERO;
else if (str.indexOf('x') >= 0 || str.indexOf('X') >= 0)
seminfo.r = strx2number(str, seminfo);
else
else {
try {
seminfo.r = LuaValue.valueOf(Double.parseDouble(str.trim()));
} catch (NumberFormatException e) {
lexerror("malformed number (" + e.getMessage() + ")", TK_NUMBER);
}
}
return true;
}
@@ -408,7 +383,6 @@ public class LexState extends Constants {
else
break;
}
save('\0');
String str = new String(buff, 0, nbuff);
str2d(str, seminfo);
}
@@ -422,7 +396,7 @@ public class LexState extends Constants {
save_and_next();
count++;
}
return (current == s) ? count : (-count) - 1;
return current == s? count: (-count)-1;
}
void read_long_string(SemInfo seminfo, int sep) {
@@ -434,7 +408,7 @@ public class LexState extends Constants {
switch (current) {
case EOZ:
lexerror((seminfo != null) ? "unfinished long string"
: "unfinished long comment", TK_EOS);
: "unfinished long comment", TK_EOF);
break; /* to avoid warnings */
case '[': {
if (skip_sep() == sep) {
@@ -489,7 +463,7 @@ public class LexState extends Constants {
nextChar();
int c2 = current;
if (!isxdigit(c1) || !isxdigit(c2))
lexerror("hexadecimal digit expected 'x"+((char)c1)+((char)c2), TK_STRING);
lexerror("hexadecimal digit expected 'x" + (char) c1 + (char) c2, TK_STRING);
return (hexvalue(c1)<<4)+hexvalue(c2);
}
@@ -498,7 +472,7 @@ public class LexState extends Constants {
while ( current != del ) {
switch (current) {
case EOZ:
lexerror("unfinished string", TK_EOS);
lexerror("unfinished string", TK_EOF);
continue; /* to avoid warnings */
case '\n':
case '\r':
@@ -542,8 +516,10 @@ public class LexState extends Constants {
case 'z': { /* zap following span of spaces */
nextChar(); /* skip the 'z' */
while ( isspace(current) ) {
if (currIsNewline()) inclinenumber();
else nextChar();
if (currIsNewline())
inclinenumber();
else
nextChar();
}
continue;
}
@@ -554,7 +530,7 @@ public class LexState extends Constants {
int i = 0;
c = 0;
do {
c = 10 * c + (current - '0');
c = 10*c+current-'0';
nextChar();
} while ( ++i < 3 && isdigit(current) );
if (c > UCHAR_MAX)
@@ -585,6 +561,13 @@ public class LexState extends Constants {
inclinenumber();
continue;
}
case ' ':
case '\f':
case '\t':
case 0x0B: /* \v */ {
nextChar();
continue;
}
case '-': {
nextChar();
if (current != '-')
@@ -685,22 +668,15 @@ public class LexState extends Constants {
return TK_NUMBER;
}
case EOZ: {
return TK_EOS;
return TK_EOF;
}
default: {
if (isspace(current)) {
_assert (!currIsNewline());
nextChar();
continue;
} else if (isdigit(current)) {
read_numeral(seminfo);
return TK_NUMBER;
} else if (isalpha(current) || current == '_') {
if (isalpha(current) || current == '_') {
/* identifier or reserved word */
LuaString ts;
do {
save_and_next();
} while (isalnum(current) || current == '_');
} while ( isalnum(current) );
ts = newstring(buff, 0, nbuff);
if (RESERVED.containsKey(ts))
return ((Integer) RESERVED.get(ts)).intValue();
@@ -720,15 +696,15 @@ public class LexState extends Constants {
void next() {
lastline = linenumber;
if (lookahead.token != TK_EOS) { /* is there a look-ahead token? */
if (lookahead.token != TK_EOF) { /* is there a look-ahead token? */
t.set( lookahead ); /* use this one */
lookahead.token = TK_EOS; /* and discharge it */
lookahead.token = TK_EOF; /* and discharge it */
} else
t.token = llex(t.seminfo); /* read next token */
}
void lookahead() {
_assert (lookahead.token == TK_EOS);
_assert (lookahead.token == TK_EOF);
lookahead.token = llex(lookahead.seminfo);
}
@@ -736,37 +712,39 @@ public class LexState extends Constants {
// from lcode.h
// =============================================================
// =============================================================
// from lparser.c
// =============================================================
static final boolean vkisvar(final int k) {
return (VLOCAL <= (k) && (k) <= VINDEXED);
return VLOCAL <= k && k <= VINDEXED;
}
static final boolean vkisinreg(final int k) {
return ((k) == VNONRELOC || (k) == VLOCAL);
return k == VNONRELOC || k == VLOCAL;
}
static class expdesc {
int k; // expkind, from enumerated list, above
static class U { // originally a union
short ind_idx; // index (R/K)
short ind_t; // table(register or upvalue)
short ind_vt; // whether 't' is register (VLOCAL) or (UPVALUE)
private LuaValue _nval;
int info;
public void setNval(LuaValue r) {
_nval = r;
}
public void setNval(LuaValue r) { _nval = r; }
public LuaValue nval() {
return (_nval == null? LuaInteger.valueOf(info): _nval);
return _nval == null? LuaInteger.valueOf(info): _nval;
}
};
}
final U u = new U();
final IntPtr t = new IntPtr(); /* patch list of `exit when true' */
final IntPtr f = new IntPtr(); /* patch list of `exit when false' */
void init(int k, int i) {
this.f.i = NO_JUMP;
this.t.i = NO_JUMP;
@@ -775,11 +753,11 @@ public class LexState extends Constants {
}
boolean hasjumps() {
return (t.i != f.i);
return t.i != f.i;
}
boolean isnumeral() {
return (k == VKNUM && t.i == NO_JUMP && f.i == NO_JUMP);
return k == VKNUM && t.i == NO_JUMP && f.i == NO_JUMP;
}
public void setvalue(expdesc other) {
@@ -794,15 +772,14 @@ public class LexState extends Constants {
}
}
/* description of active local variable */
static class Vardesc {
final short idx; /* variable index in stack */
Vardesc(int idx) {
this.idx = (short) idx;
}
};
}
/* description of pending goto statements and label statements */
static class Labeldesc {
@@ -810,14 +787,14 @@ public class LexState extends Constants {
int pc; /* position in code */
int line; /* line where it appeared */
short nactvar; /* local level where it appears in current block */
public Labeldesc(LuaString name, int pc, int line, short nactvar) {
this.name = name;
this.pc = pc;
this.line = line;
this.nactvar = nactvar;
}
};
}
/* dynamic structures used by the parser */
static class Dyndata {
@@ -827,11 +804,10 @@ public class LexState extends Constants {
int n_gt = 0;
Labeldesc[] label; /* list of active labels */
int n_label = 0;
};
}
boolean hasmultret(int k) {
return ((k) == VCALL || (k) == VVARARG);
return k == VCALL || k == VVARARG;
}
/*----------------------------------------------------------------------
@@ -839,8 +815,8 @@ public class LexState extends Constants {
------------------------------------------------------------------------*/
void anchor_token () {
/* last token from outer function must be EOS */
_assert(fs != null || t.token == TK_EOS);
/* last token from outer function must be EOF */
_assert(fs != null || t.token == TK_EOF);
if (t.token == TK_NAME || t.token == TK_STRING) {
LuaString ts = t.seminfo.ts;
// TODO: is this necessary?
@@ -877,18 +853,16 @@ public class LexState extends Constants {
}
void check_condition(boolean c, String msg) {
if (!(c))
if (!c)
syntaxerror(msg);
}
void check_match(int what, int who, int where) {
if (!testnext(what)) {
if (where == linenumber)
error_expected(what);
else {
syntaxerror(L.pushfstring(LUA_QS(token2str(what))
+ " expected " + "(to close " + LUA_QS(token2str(who))
syntaxerror(L.pushfstring(LUA_QS(token2str(what)) + " expected " + "(to close " + LUA_QS(token2str(who))
+ " at line " + where + ")"));
}
}
@@ -910,7 +884,6 @@ public class LexState extends Constants {
codestring(e, str_checkname());
}
int registerlocalvar(LuaString varname) {
FuncState fs = this.fs;
Prototype f = fs.f;
@@ -922,7 +895,7 @@ public class LexState extends Constants {
void new_localvar(LuaString name) {
int reg = registerlocalvar(name);
fs.checklimit(dyd.n_actvar + 1, FuncState.LUAI_MAXVARS, "local variables");
fs.checklimit(dyd.n_actvar+1, Constants.LUAI_MAXVARS, "local variables");
if (dyd.actvar == null || dyd.n_actvar+1 > dyd.actvar.length)
dyd.actvar = realloc(dyd.actvar, Math.max(1, dyd.n_actvar*2));
dyd.actvar[dyd.n_actvar++] = new Vardesc(reg);
@@ -999,8 +972,7 @@ public class LexState extends Constants {
_assert(gt.name.eq_b(label.name));
if (gt.nactvar < label.nactvar) {
LuaString vname = fs.getlocvar(gt.nactvar).varname;
String msg = L.pushfstring("<goto " + gt.name + "> at line "
+ gt.line + " jumps into the scope of local '"
String msg = L.pushfstring("<goto " + gt.name + "> at line " + gt.line + " jumps into the scope of local '"
+ vname.tojstring() + "'");
semerror(msg);
}
@@ -1022,8 +994,7 @@ public class LexState extends Constants {
for (i = bl.firstlabel; i < dyd.n_label; i++) {
Labeldesc lb = dyd.label[i];
if (lb.name.eq_b(gt.name)) { /* correct label? */
if (gt.nactvar > lb.nactvar &&
(bl.upval || dyd.n_label > bl.firstlabel))
if (gt.nactvar > lb.nactvar && (bl.upval || dyd.n_label > bl.firstlabel))
fs.patchclose(gt.pc, lb.nactvar);
closegoto(g, lb); /* close it */
return true;
@@ -1053,7 +1024,6 @@ public class LexState extends Constants {
}
}
/*
** create a label named "break" to resolve break statements
*/
@@ -1068,8 +1038,8 @@ public class LexState extends Constants {
** message when label name is a reserved word (which can only be 'break')
*/
void undefgoto(Labeldesc gt) {
String msg = L.pushfstring(isReservedKeyword(gt.name.tojstring())
? "<"+gt.name+"> at line "+gt.line+" not inside a loop"
String msg = L.pushfstring(
isReservedKeyword(gt.name.tojstring())? "<" + gt.name + "> at line " + gt.line + " not inside a loop"
: "no visible label '" + gt.name + "' for <goto> at line " + gt.line);
semerror(msg);
}
@@ -1149,22 +1119,19 @@ public class LexState extends Constants {
this.checknext(']');
}
/*
** {======================================================================
** Rules for Constructors
** =======================================================================
*/
static class ConsControl {
expdesc v = new expdesc(); /* last list item read */
expdesc t; /* table descriptor */
int nh; /* total number of `record' elements */
int na; /* total number of array elements */
int tostore; /* number of array elements pending to be stored */
};
}
void recfield(ConsControl cc) {
/* recfield -> (NAME | `['exp1`]') = exp1 */
@@ -1194,7 +1161,6 @@ public class LexState extends Constants {
cc.tostore++;
}
void constructor(expdesc t) {
/* constructor -> ?? */
FuncState fs = this.fs;
@@ -1246,14 +1212,15 @@ public class LexState extends Constants {
static int luaO_int2fb(int x) {
int e = 0; /* expoent */
while ( x >= 16 ) {
x = (x+1) >> 1;
x = x+1>>1;
e++;
}
if (x < 8) return x;
else return ((e+1) << 3) | (((int)x) - 8);
if (x < 8)
return x;
else
return e+1<<3 | x-8;
}
/* }====================================================================== */
void parlist() {
@@ -1275,16 +1242,16 @@ public class LexState extends Constants {
f.is_vararg = 1;
break;
}
default: this.syntaxerror("<name> or " + LUA_QL("...") + " expected");
default:
this.syntaxerror("<name> or " + LUA_QL("...") + " expected");
}
} while ((f.is_vararg==0) && this.testnext(','));
} while ( f.is_vararg == 0 && this.testnext(',') );
}
this.adjustlocalvars(nparams);
f.numparams = fs.nactvar;
fs.reserveregs(fs.nactvar); /* reserve register for parameters */
}
void body(expdesc e, boolean needself, int line) {
/* body -> `(' parlist `)' chunk END */
FuncState new_fs = new FuncState();
@@ -1318,7 +1285,6 @@ public class LexState extends Constants {
return n;
}
void funcargs(expdesc f, int line) {
FuncState fs = this.fs;
expdesc args = new expdesc();
@@ -1364,7 +1330,6 @@ public class LexState extends Constants {
* (unless changed) one result */
}
/*
** {======================================================================
** Expression parsing
@@ -1387,13 +1352,11 @@ public class LexState extends Constants {
return;
}
default: {
this.syntaxerror("unexpected symbol " + t.token + " (" + ((char) t.token) + ")");
return;
this.syntaxerror("unexpected symbol " + t.token + " (" + (char) t.token + ")");
}
}
}
void suffixedexp(expdesc v) {
/* suffixedexp ->
primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */
@@ -1433,7 +1396,6 @@ public class LexState extends Constants {
}
}
void simpleexp(expdesc v) {
/*
* simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor |
@@ -1463,8 +1425,7 @@ public class LexState extends Constants {
}
case TK_DOTS: { /* vararg */
FuncState fs = this.fs;
this.check_condition(fs.f.is_vararg!=0, "cannot use " + LUA_QL("...")
+ " outside a vararg function");
this.check_condition(fs.f.is_vararg != 0, "cannot use " + LUA_QL("...") + " outside a vararg function");
v.init(VVARARG, fs.codeABC(Lua.OP_VARARG, 0, 1, 0));
break;
}
@@ -1485,7 +1446,6 @@ public class LexState extends Constants {
this.next();
}
int getunopr(int op) {
switch (op) {
case TK_NOT:
@@ -1499,7 +1459,6 @@ public class LexState extends Constants {
}
}
int getbinopr(int op) {
switch (op) {
case '+':
@@ -1546,10 +1505,11 @@ public class LexState extends Constants {
left = (byte) i;
right = (byte) j;
}
};
}
static Priority[] priority = { /* ORDER OPR */
new Priority(6, 6), new Priority(6, 6), new Priority(7, 7), new Priority(7, 7), new Priority(7, 7), /* `+' `-' `/' `%' */
new Priority(6, 6), new Priority(6, 6), new Priority(7, 7), new Priority(7, 7),
new Priority(7, 7), /* `+' `-' `/' `%' */
new Priority(10, 9), new Priority(5, 4), /* power and concat (right associative) */
new Priority(3, 3), new Priority(3, 3), /* equality and inequality */
new Priority(3, 3), new Priority(3, 3), new Priority(3, 3), new Priority(3, 3), /* order */
@@ -1558,7 +1518,6 @@ public class LexState extends Constants {
static final int UNARY_PRIORITY = 8; /* priority for unary operators */
/*
** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
** where `binop' is any binary operator with a priority higher than `limit'
@@ -1597,18 +1556,15 @@ public class LexState extends Constants {
/* }==================================================================== */
/*
** {======================================================================
** Rules for Statements
** =======================================================================
*/
boolean block_follow(boolean withuntil) {
switch (t.token) {
case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_EOS:
case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_EOF:
return true;
case TK_UNTIL:
return withuntil;
@@ -1616,7 +1572,6 @@ public class LexState extends Constants {
}
}
void block() {
/* block -> chunk */
FuncState fs = this.fs;
@@ -1626,7 +1581,6 @@ public class LexState extends Constants {
fs.leaveblock();
}
/*
** structure to chain all variables in the left-hand side of an
** assignment
@@ -1635,8 +1589,7 @@ public class LexState extends Constants {
LHS_assign prev;
/* variable (global, local, upvalue, or indexed) */
expdesc v = new expdesc();
};
}
/*
** check whether, in an assignment to a local variable, the local variable
@@ -1646,7 +1599,7 @@ public class LexState extends Constants {
*/
void check_conflict(LHS_assign lh, expdesc v) {
FuncState fs = this.fs;
short extra = (short) fs.freereg; /* eventual position to save local variable */
short extra = fs.freereg; /* eventual position to save local variable */
boolean conflict = false;
for (; lh != null; lh = lh.prev) {
if (lh.v.k == VINDEXED) {
@@ -1665,17 +1618,15 @@ public class LexState extends Constants {
}
if (conflict) {
/* copy upvalue/local value to a temporary (in position 'extra') */
int op = (v.k == VLOCAL) ? Lua.OP_MOVE : Lua.OP_GETUPVAL;
int op = v.k == VLOCAL? Lua.OP_MOVE: Lua.OP_GETUPVAL;
fs.codeABC(op, extra, v.u.info, 0);
fs.reserveregs(1);
}
}
void assignment(LHS_assign lh, int nvars) {
expdesc e = new expdesc();
this.check_condition(VLOCAL <= lh.v.k && lh.v.k <= VINDEXED,
"syntax error");
this.check_condition(VLOCAL <= lh.v.k && lh.v.k <= VINDEXED, "syntax error");
if (this.testnext(',')) { /* assignment -> `,' primaryexp assignment */
LHS_assign nv = new LHS_assign();
nv.prev = lh;
@@ -1683,8 +1634,7 @@ public class LexState extends Constants {
if (nv.v.k != VINDEXED)
this.check_conflict(lh, nv.v);
this.assignment(nv, nvars+1);
}
else { /* assignment . `=' explist1 */
} else { /* assignment . `=' explist1 */
int nexps;
this.checknext('=');
nexps = this.explist(e);
@@ -1692,8 +1642,7 @@ public class LexState extends Constants {
this.adjust_assign(nvars, nexps, e);
if (nexps > nvars)
this.fs.freereg -= nexps-nvars; /* remove extra values */
}
else {
} else {
fs.setoneret(e); /* close last expression */
fs.storevar(lh.v, e);
return; /* avoid default */
@@ -1703,7 +1652,6 @@ public class LexState extends Constants {
fs.storevar(lh.v, e);
}
int cond() {
/* cond -> exp */
expdesc v = new expdesc();
@@ -1730,21 +1678,19 @@ public class LexState extends Constants {
findlabel(g); /* close it if label already defined */
}
/* skip no-op statements */
void skipnoopstat() {
while ( t.token == ';' || t.token == TK_DBCOLON )
statement();
}
void labelstat(LuaString label, int line) {
/* label -> '::' NAME '::' */
int l; /* index of new label being created */
fs.checkrepeated(dyd.label, dyd.n_label, label); /* check for repeated labels */
checknext(TK_DBCOLON); /* skip double colon */
/* 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 */
if (block_follow(false)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */
@@ -1753,7 +1699,6 @@ public class LexState extends Constants {
findgotos(dyd.label[l]);
}
void whilestat(int line) {
/* whilestat -> WHILE cond DO block END */
FuncState fs = this.fs;
@@ -1793,7 +1738,6 @@ public class LexState extends Constants {
fs.leaveblock(); /* finish loop */
}
int exp1() {
expdesc e = new expdesc();
int k;
@@ -1803,7 +1747,6 @@ public class LexState extends Constants {
return k;
}
void forbody(int base, int line, int nvars, boolean isnum) {
/* forbody -> DO block */
BlockCnt bl = new BlockCnt();
@@ -1829,7 +1772,6 @@ public class LexState extends Constants {
fs.fixline(line);
}
void fornum(LuaString varname, int line) {
/* fornum -> NAME = exp1,exp1[,exp1] forbody */
FuncState fs = this.fs;
@@ -1845,13 +1787,12 @@ public class LexState extends Constants {
if (this.testnext(','))
this.exp1(); /* optional step */
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);
}
this.forbody(base, line, 1, true);
}
void forlist(LuaString indexname) {
/* forlist -> NAME {,NAME} IN explist1 forbody */
FuncState fs = this.fs;
@@ -1876,7 +1817,6 @@ public class LexState extends Constants {
this.forbody(base, line, nvars-3, false);
}
void forstat(int line) {
/* forstat -> FOR (fornum | forlist) END */
FuncState fs = this.fs;
@@ -1900,7 +1840,6 @@ public class LexState extends Constants {
fs.leaveblock(); /* loop scope (`break' jumps to this point) */
}
void test_then_block(IntPtr escapelist) {
/* test_then_block -> [IF | ELSEIF] cond THEN block */
expdesc v = new expdesc();
@@ -1932,7 +1871,6 @@ public class LexState extends Constants {
fs.patchtohere(jf);
}
void ifstat(int line) {
IntPtr escapelist = new IntPtr(NO_JUMP); /* exit list for finished parts */
test_then_block(escapelist); /* IF cond THEN block */
@@ -1954,7 +1892,6 @@ public class LexState extends Constants {
fs.getlocvar(fs.nactvar-1).startpc = fs.pc;
}
void localstat() {
/* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
int nvars = 0;
@@ -1974,7 +1911,6 @@ public class LexState extends Constants {
this.adjustlocalvars(nvars);
}
boolean funcname(expdesc v) {
/* funcname -> NAME {field} [`:' NAME] */
boolean ismethod = false;
@@ -1988,7 +1924,6 @@ public class LexState extends Constants {
return ismethod;
}
void funcstat(int line) {
/* funcstat -> FUNCTION funcname body */
boolean needself;
@@ -2001,7 +1936,6 @@ public class LexState extends Constants {
fs.fixline(line); /* definition `happens' in the first line */
}
void exprstat() {
/* stat -> func | assignment */
FuncState fs = this.fs;
@@ -2010,8 +1944,7 @@ public class LexState extends Constants {
if (t.token == '=' || t.token == ',') { /* stat -> assignment ? */
v.prev = null;
assignment(v, 1);
}
else { /* stat -> func */
} else { /* stat -> func */
check_condition(v.v.k == VCALL, "syntax error");
SETARG_C(fs.getcodePtr(v.v), 1); /* call statement uses no results */
}
@@ -2110,8 +2043,7 @@ public class LexState extends Constants {
break;
}
}
_assert(fs.f.maxstacksize >= fs.freereg
&& fs.freereg >= fs.nactvar);
_assert(fs.f.maxstacksize >= fs.freereg && fs.freereg >= fs.nactvar);
fs.freereg = fs.nactvar; /* free registers */
leavelevel();
}
@@ -2140,7 +2072,7 @@ public class LexState extends Constants {
fs.newupvalue(envn, v); /* ...set environment upvalue */
next(); /* read first token */
statlist(); /* parse main body */
check(TK_EOS);
check(TK_EOF);
close_func();
}

View File

@@ -37,30 +37,37 @@ import org.luaj.vm2.lib.BaseLib;
* Compiler for Lua.
*
* <p>
* Compiles lua source files into lua bytecode within a {@link Prototype},
* loads lua binary files directly into a {@link Prototype},
* and optionaly instantiates a {@link LuaClosure} around the result
* using a user-supplied environment.
* Compiles lua source files into lua bytecode within a {@link Prototype}, loads
* lua binary files directly into a {@link Prototype}, and optionaly
* instantiates a {@link LuaClosure} around the result using a user-supplied
* environment.
*
* <p>
* Implements the {@link org.luaj.vm2.Globals.Compiler} interface for loading
* initialized chunks, which is an interface common to
* lua bytecode compiling and java bytecode compiling.
* initialized chunks, which is an interface common to lua bytecode compiling
* and java bytecode compiling.
*
* <p>
* The {@link LuaC} compiler is installed by default by both the
* {@link org.luaj.vm2.lib.jse.JsePlatform} and {@link org.luaj.vm2.lib.jme.JmePlatform} classes,
* so in the following example, the default {@link LuaC} compiler
* will be used:
* <pre> {@code
* {@link org.luaj.vm2.lib.jse.JsePlatform} and
* {@link org.luaj.vm2.lib.jme.JmePlatform} classes, so in the following
* example, the default {@link LuaC} compiler will be used:
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.load(new StringReader("print 'hello'"), "main.lua").call();
* } </pre>
* }
* </pre>
*
* To load the LuaC compiler manually, use the install method:
* <pre> {@code
*
* <pre>
* {@code
* LuaC.install(globals);
* } </pre>
* }
* </pre>
*
* @see #install(Globals)
* @see Globals#compiler
@@ -77,9 +84,10 @@ public class LuaC extends Constants implements Globals.Compiler, Globals.Loader
/** A sharable instance of the LuaC compiler. */
public static final LuaC instance = new LuaC();
/** Install the compiler so that LoadState will first
* try to use it when handed bytes that are
* not already a compiled lua chunk.
/**
* Install the compiler so that LoadState will first try to use it when
* handed bytes that are not already a compiled lua chunk.
*
* @param globals the Globals into which this is to be installed.
*/
public static void install(Globals globals) {
@@ -89,31 +97,39 @@ public class LuaC extends Constants implements Globals.Compiler, Globals.Loader
protected LuaC() {}
/** Compile lua source into a Prototype.
* @param stream InputStream representing the text source conforming to lua source syntax.
/**
* Compile lua source into a Prototype.
*
* @param stream InputStream representing the text source conforming to
* lua source syntax.
* @param chunkname String name of the chunk to use.
* @return Prototype representing the lua chunk for this source.
* @throws IOException
*/
@Override
public Prototype compile(InputStream stream, String chunkname) throws IOException {
return (new CompileState()).luaY_parser(stream, chunkname);
return new CompileState().luaY_parser(stream, chunkname);
}
@Override
public LuaFunction load(Prototype prototype, String chunkname, LuaValue env) throws IOException {
return new LuaClosure(prototype, env);
}
/** @deprecated
* Use Globals.load(InputString, String, String) instead,
* or LuaC.compile(InputStream, String) and construct LuaClosure directly.
/**
* @deprecated Use Globals.load(InputString, String, String) instead, or
* LuaC.compile(InputStream, String) and construct LuaClosure
* directly.
*/
@Deprecated
public LuaValue load(InputStream stream, String chunkname, Globals globals) throws IOException {
return new LuaClosure(compile(stream, chunkname), globals);
}
static class CompileState {
int nCcalls = 0;
private Hashtable strings = new Hashtable();
private final Hashtable strings = new Hashtable();
protected CompileState() {}
/** Parse the input */
@@ -122,15 +138,15 @@ public class LuaC extends Constants implements Globals.Compiler, Globals.Loader
FuncState funcstate = new FuncState();
// lexstate.buff = buff;
lexstate.fs = funcstate;
lexstate.setinput(this, z.read(), z, (LuaString) LuaValue.valueOf(name) );
lexstate.setinput(this, z.read(), z, LuaValue.valueOf(name));
/* main func. is always vararg */
funcstate.f = new Prototype();
funcstate.f.source = (LuaString) LuaValue.valueOf(name);
funcstate.f.source = LuaValue.valueOf(name);
lexstate.mainfunc(funcstate);
LuaC._assert (funcstate.prev == null);
Constants._assert(funcstate.prev == null);
/* all scopes should be correctly finished */
LuaC._assert (lexstate.dyd == null
|| (lexstate.dyd.n_actvar == 0 && lexstate.dyd.n_gt == 0 && lexstate.dyd.n_label == 0));
Constants._assert(lexstate.dyd == null
|| lexstate.dyd.n_actvar == 0 && lexstate.dyd.n_gt == 0 && lexstate.dyd.n_label == 0);
return funcstate.f;
}

View File

@@ -34,14 +34,14 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the lua basic library functions.
* Subclass of {@link LibFunction} which implements the lua basic library
* functions.
* <p>
* This contains all library functions listed as "basic functions" in the lua documentation for JME.
* The functions dofile and loadfile use the
* {@link Globals#finder} instance to find resource files.
* Since JME has no file system by default, {@link BaseLib} implements
* {@link ResourceFinder} using {@link Class#getResource(String)},
* which is the closest equivalent on JME.
* This contains all library functions listed as "basic functions" in the lua
* documentation for JME. The functions dofile and loadfile use the
* {@link Globals#finder} instance to find resource files. Since JME has no file
* system by default, {@link BaseLib} implements {@link ResourceFinder} using
* {@link Class#getResource(String)}, which is the closest equivalent on JME.
* The default loader chain in {@link PackageLib} will use these as well.
* <p>
* To use basic library functions that include a {@link ResourceFinder} based on
@@ -50,41 +50,55 @@ import org.luaj.vm2.Varargs;
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
* }
* </pre>
* <p>
* For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code
* For special cases where the smallest possible footprint is desired, a minimal
* set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
* using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
* Doing so will ensure the library is properly initialized
* and loaded into the globals table.
* }
* </pre>
*
* Doing so will ensure the library is properly initialized and loaded into the
* globals table.
* <p>
* This is a direct port of the corresponding library in C.
*
* @see org.luaj.vm2.lib.jse.JseBaseLib
* @see ResourceFinder
* @see Globals#finder
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.1">Lua 5.2 Base Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.1">Lua 5.2 Base Lib
* Reference</a>
*/
public class BaseLib extends TwoArgFunction implements ResourceFinder {
Globals globals;
/** Perform one-time initialization on the library by adding base functions
/**
* Perform one-time initialization on the library by adding base functions
* to the supplied environment, and returning it as the return value.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, which must be a Globals instance.
* @param env the environment to load into, which must be a Globals
* instance.
*/
@Override
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
globals.finder = this;
@@ -113,8 +127,8 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
next next;
env.set("next", next = new next());
env.set("pairs", new pairs(next));
env.set("ipairs", new ipairs());
env.set("pairs", new pairsbase(PAIRS, NIL, next));
env.set("ipairs", new pairsbase(IPAIRS, ZERO, new inext()));
return env;
}
@@ -152,7 +166,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
System.gc();
return LuaValue.TRUE;
} else {
this.argerror("gc op");
argerror(1, "invalid option '" + s + "'");
}
return NIL;
}
@@ -173,16 +187,16 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "error", // ( message [,level] ) -> ERR
static final class error extends TwoArgFunction {
public LuaValue call(LuaValue arg1, LuaValue arg2) {
throw arg1.isnil()? new LuaError(null, arg2.optint(1)):
arg1.isstring()? new LuaError(arg1.tojstring(), arg2.optint(1)):
new LuaError(arg1);
if (arg1.isnil()) throw new LuaError(NIL);
if (!arg1.isstring() || arg2.optint(1) == 0) throw new LuaError(arg1);
throw new LuaError(arg1.tojstring(), arg2.optint(1));
}
}
// "getmetatable", // ( object ) -> table
static final class getmetatable extends LibFunction {
public LuaValue call() {
return argerror(1, "value");
return argerror(1, "value expected");
}
public LuaValue call(LuaValue arg) {
LuaValue mt = arg.getmetatable();
@@ -193,7 +207,9 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
final class load extends VarArgFunction {
public Varargs invoke(Varargs args) {
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 mode = args.optjstring(3, "bt");
LuaValue env = args.optvalue(4, globals);
@@ -204,6 +220,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg
final class loadfile extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil");
String filename = args.isstring(1)? args.tojstring(1): null;
@@ -217,6 +234,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "pcall", // (f, arg1, ...) -> status, result1, ...
final class pcall extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
LuaValue func = args.checkvalue(1);
if (globals != null && globals.debuglib != null)
@@ -242,26 +260,27 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
print(BaseLib baselib) {
this.baselib = baselib;
}
@Override
public Varargs invoke(Varargs args) {
LuaValue tostring = globals.get("tostring");
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();
globals.STDOUT.print(s.tojstring());
}
globals.STDOUT.println();
globals.STDOUT.print('\n');
return NONE;
}
}
// "rawequal", // (v1, v2) -> boolean
static final class rawequal extends LibFunction {
public LuaValue call() {
return argerror(1, "value");
return argerror(1, "value expected");
}
public LuaValue call(LuaValue arg) {
return argerror(2, "value");
return argerror(2, "value expected");
}
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return valueOf(arg1.raweq(arg2));
@@ -269,12 +288,12 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
}
// "rawget", // (table, index) -> value
static final class rawget extends LibFunction {
static final class rawget extends TableLibFunction {
public LuaValue call() {
return argerror(1, "value");
return argerror(1, "value expected");
}
public LuaValue call(LuaValue arg) {
return argerror(2, "value");
return argerror(2, "value expected");
}
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return arg1.checktable().rawget(arg2);
@@ -290,16 +309,16 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
}
// "rawset", // (table, index, value) -> table
static final class rawset extends LibFunction {
static final class rawset extends TableLibFunction {
public LuaValue call(LuaValue table) {
return argerror(2,"value");
return argerror(2,"value expected");
}
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) {
LuaTable t = table.checktable();
if (!index.isvalidkey()) argerror(2, "value");
if (!index.isvalidkey()) argerror(2, "table index is nil");
t.rawset(index, value);
return t;
}
@@ -319,9 +338,9 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
}
// "setmetatable", // (table, metatable) -> table
static final class setmetatable extends LibFunction {
static final class setmetatable extends TableLibFunction {
public LuaValue call(LuaValue table) {
return argerror(2,"value");
return argerror(2,"nil or table expected");
}
public LuaValue call(LuaValue table, LuaValue metatable) {
final LuaValue mt0 = table.checktable().getmetatable();
@@ -350,8 +369,11 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
static final class tostring extends LibFunction {
public LuaValue call(LuaValue arg) {
LuaValue h = arg.metatag(TOSTRING);
if ( ! h.isnil() )
return h.call(arg);
if ( ! h.isnil() ) {
LuaValue v = h.call(arg);
LuaValue vs = v.tostring();
return !vs.isnil() ? vs : v;
}
LuaValue v = arg.tostring();
if ( ! v.isnil() )
return v;
@@ -361,6 +383,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "type", // (v) -> value
static final class type extends LibFunction {
@Override
public LuaValue call(LuaValue arg) {
return valueOf(arg.typename());
}
@@ -368,6 +391,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "xpcall", // (f, err) -> result1, ...
final class xpcall extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
final LuaThread t = globals.running;
final LuaValue preverror = t.errorfunc;
@@ -393,22 +417,25 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
}
}
// "pairs" (t) -> iter-func, t, nil
static final class pairs extends VarArgFunction {
final next next;
pairs(next next) {
this.next = next;
}
public Varargs invoke(Varargs args) {
return varargsOf( next, args.checktable(1), NIL );
}
// pairsbase, // (t) -> iter-func, t, initial
static final class pairsbase extends VarArgFunction {
final LuaString method;
final LuaValue initial;
final VarArgFunction iter;
pairsbase(LuaString method, LuaValue initial, VarArgFunction iter) {
this.method = method;
this.initial = initial;
this.iter = iter;
}
// // "ipairs", // (t) -> iter-func, t, 0
static final class ipairs extends VarArgFunction {
inext inext = new inext();
public Varargs invoke(Varargs args) {
return varargsOf( inext, args.checktable(1), ZERO );
LuaValue arg = args.arg1();
LuaValue t = arg.metatag(method);
if (!t.isnil())
// TODO: This can return more than 3 results.
return t.invoke(args.isvalue(1) ? arg : t);
return varargsOf(iter, args.checktable(1), initial);
}
}
@@ -421,6 +448,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "inext" ( table, [int-index] ) -> next-index, next-value
static final class inext extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
return args.checktable(1).inext(args.arg(2));
}
@@ -457,7 +485,6 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
}
}
private static class StringInputStream extends InputStream {
final LuaValue func;
byte[] bytes;
@@ -466,10 +493,12 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
this.func = func;
}
public int read() throws IOException {
if ( remaining <= 0 ) {
if ( remaining < 0 )
return -1;
if ( remaining == 0 ) {
LuaValue s = func.call();
if ( s.isnil() )
return -1;
return remaining = -1;
LuaString ls = s.strvalue();
bytes = ls.m_bytes;
offset = ls.m_offset;
@@ -478,7 +507,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
return -1;
}
--remaining;
return bytes[offset++];
return 0xFF & bytes[offset++];
}
}
}

View File

@@ -26,68 +26,88 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of LibFunction that implements the Lua standard {@code bit32} library.
* Subclass of LibFunction that implements the Lua standard {@code bit32}
* library.
* <p>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println(globals.get("bit32").get("bnot").call(LuaValue.valueOf(2)));
* } </pre>
* }
* </pre>
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new Bit32Lib());
* System.out.println(globals.get("bit32").get("bnot").call(LuaValue.valueOf(2)));
* } </pre>
* }
* </pre>
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.7">Lua 5.2 Bitwise Operation Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.7">Lua 5.2 Bitwise
* Operation Lib Reference</a>
*/
public class Bit32Lib extends TwoArgFunction {
public Bit32Lib() {
}
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, which must be a Globals instance.
* @param env the environment to load into, which must be a Globals
* instance.
*/
@Override
public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable t = new LuaTable();
bind(t, Bit32LibV.class, new String[] {
"band", "bnot", "bor", "btest", "bxor", "extract", "replace"
});
bind(t, Bit32Lib2.class, new String[] {
"arshift", "lrotate", "lshift", "rrotate", "rshift"
});
bind(t, Bit32LibV.class, new String[] { "band", "bnot", "bor", "btest", "bxor", "extract", "replace" });
bind(t, Bit32Lib2.class, new String[] { "arshift", "lrotate", "lshift", "rrotate", "rshift" });
env.set("bit32", t);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("bit32", t);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("bit32", t);
return t;
}
static final class Bit32LibV extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
switch (opcode) {
case 0: return Bit32Lib.band( args );
case 1: return Bit32Lib.bnot( args );
case 2: return Bit32Lib.bor( args );
case 3: return Bit32Lib.btest( args );
case 4: return Bit32Lib.bxor( args );
case 0:
return Bit32Lib.band(args);
case 1:
return Bit32Lib.bnot(args);
case 2:
return Bit32Lib.bor(args);
case 3:
return Bit32Lib.btest(args);
case 4:
return Bit32Lib.bxor(args);
case 5:
return Bit32Lib.extract(args.checkint(1), args.checkint(2), args.optint(3, 1));
case 6:
return Bit32Lib.replace( args.checkint(1), args.checkint(2),
args.checkint(3), args.optint(4, 1) );
return Bit32Lib.replace(args.checkint(1), args.checkint(2), args.checkint(3), args.optint(4, 1));
}
return NIL;
}
@@ -95,13 +115,19 @@ public class Bit32Lib extends TwoArgFunction {
static final class Bit32Lib2 extends TwoArgFunction {
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2) {
switch (opcode) {
case 0: return Bit32Lib.arshift(arg1.checkint(), arg2.checkint());
case 1: return Bit32Lib.lrotate(arg1.checkint(), arg2.checkint());
case 2: return Bit32Lib.lshift(arg1.checkint(), arg2.checkint());
case 3: return Bit32Lib.rrotate(arg1.checkint(), arg2.checkint());
case 4: return Bit32Lib.rshift(arg1.checkint(), arg2.checkint());
case 0:
return Bit32Lib.arshift(arg1.checkint(), arg2.checkint());
case 1:
return Bit32Lib.lrotate(arg1.checkint(), arg2.checkint());
case 2:
return Bit32Lib.lshift(arg1.checkint(), arg2.checkint());
case 3:
return Bit32Lib.rrotate(arg1.checkint(), arg2.checkint());
case 4:
return Bit32Lib.rshift(arg1.checkint(), arg2.checkint());
}
return NIL;
}
@@ -177,7 +203,7 @@ public class Bit32Lib extends TwoArgFunction {
return rrotate(x, -disp);
} else {
disp = disp & 31;
return bitsToValue((x << disp) | (x >>> (32 - disp)));
return bitsToValue(x<<disp | x>>>32-disp);
}
}
@@ -186,7 +212,7 @@ public class Bit32Lib extends TwoArgFunction {
return lrotate(x, -disp);
} else {
disp = disp & 31;
return bitsToValue((x >>> disp) | (x << (32 - disp)));
return bitsToValue(x>>>disp | x<<32-disp);
}
}
@@ -200,7 +226,7 @@ public class Bit32Lib extends TwoArgFunction {
if (field+width > 32) {
error("trying to access non-existent bits");
}
return bitsToValue((n >>> field) & (-1 >>> (32 - width)));
return bitsToValue(n>>>field & -1>>>32-width);
}
static LuaValue replace(int n, int v, int field, int width) {
@@ -213,12 +239,12 @@ public class Bit32Lib extends TwoArgFunction {
if (field+width > 32) {
error("trying to access non-existent bits");
}
int mask = (-1 >>> (32 - width)) << field;
n = (n & ~mask) | ((v << field) & mask);
int mask = -1>>>32-width<<field;
n = n & ~mask | v<<field & mask;
return bitsToValue(n);
}
private static LuaValue bitsToValue(int x) {
return ( x < 0 ) ? valueOf((double) ((long) x & 0xFFFFFFFFL)) : valueOf(x);
return x < 0? valueOf(x & 0xFFFFFFFFL): valueOf(x);
}
}

View File

@@ -28,37 +28,48 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the lua standard {@code coroutine}
* library.
* Subclass of {@link LibFunction} which implements the lua standard
* {@code coroutine} library.
* <p>
* The coroutine library in luaj has the same behavior as the
* coroutine library in C, but is implemented using Java Threads to maintain
* the call state between invocations. Therefore it can be yielded from anywhere,
* similar to the "Coco" yield-from-anywhere patch available for C-based lua.
* However, coroutines that are yielded but never resumed to complete their execution
* may not be collected by the garbage collector.
* The coroutine library in luaj has the same behavior as the coroutine library
* in C, but is implemented using Java Threads to maintain the call state
* between invocations. Therefore it can be yielded from anywhere, similar to
* the "Coco" yield-from-anywhere patch available for C-based lua. However,
* coroutines that are yielded but never resumed to complete their execution may
* not be collected by the garbage collector.
* <p>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println(globals.get("coroutine").get("running").call());
* } </pre>
* }
* </pre>
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new CoroutineLib());
* System.out.println(globals.get("coroutine").get("running").call());
* } </pre>
* }
* </pre>
* <p>
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.2">Lua 5.2 Coroutine Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.2">Lua 5.2
* Coroutine Lib Reference</a>
*/
public class CoroutineLib extends TwoArgFunction {
@@ -66,12 +77,17 @@ public class CoroutineLib extends TwoArgFunction {
Globals globals;
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, which must be a Globals instance.
* @param env the environment to load into, which must be a Globals
* instance.
*/
@Override
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
LuaTable coroutine = new LuaTable();
@@ -82,17 +98,20 @@ public class CoroutineLib extends TwoArgFunction {
coroutine.set("yield", new yield());
coroutine.set("wrap", new wrap());
env.set("coroutine", coroutine);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("coroutine", coroutine);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("coroutine", coroutine);
return coroutine;
}
final class create extends LibFunction {
@Override
public LuaValue call(LuaValue f) {
return new LuaThread(globals, f.checkfunction());
}
}
static final class resume extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
final LuaThread t = args.checkthread(1);
return t.resume(args.subargs(2));
@@ -100,6 +119,7 @@ public class CoroutineLib extends TwoArgFunction {
}
final class running extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
final LuaThread r = globals.running;
return varargsOf(r, valueOf(r.isMainThread()));
@@ -107,6 +127,7 @@ public class CoroutineLib extends TwoArgFunction {
}
static final class status extends LibFunction {
@Override
public LuaValue call(LuaValue t) {
LuaThread lt = t.checkthread();
return valueOf(lt.getStatus());
@@ -114,12 +135,14 @@ public class CoroutineLib extends TwoArgFunction {
}
final class yield extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
return globals.yield(args);
}
}
final class wrap extends LibFunction {
@Override
public LuaValue call(LuaValue f) {
final LuaValue func = f.checkfunction();
final LuaThread thread = new LuaThread(globals, func);
@@ -129,9 +152,12 @@ public class CoroutineLib extends TwoArgFunction {
static final class wrapper extends VarArgFunction {
final LuaThread luathread;
wrapper(LuaThread luathread) {
this.luathread = luathread;
}
@Override
public Varargs invoke(Varargs args) {
final Varargs result = luathread.resume(args);
if (result.arg1().toboolean()) {

View File

@@ -39,49 +39,64 @@ import org.luaj.vm2.Prototype;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the lua standard {@code debug}
* library.
* Subclass of {@link LibFunction} which implements the lua standard
* {@code debug} library.
* <p>
* The debug library in luaj tries to emulate the behavior of the corresponding C-based lua library.
* To do this, it must maintain a separate stack of calls to {@link LuaClosure} and {@link LibFunction}
* instances.
* Especially when lua-to-java bytecode compiling is being used
* via a {@link org.luaj.vm2.Globals.Compiler} such as {@link org.luaj.vm2.luajc.LuaJC},
* this cannot be done in all cases.
* The debug library in luaj tries to emulate the behavior of the corresponding
* C-based lua library. To do this, it must maintain a separate stack of calls
* to {@link LuaClosure} and {@link LibFunction} instances. Especially when
* lua-to-java bytecode compiling is being used via a
* {@link org.luaj.vm2.Globals.Compiler} such as
* {@link org.luaj.vm2.luajc.LuaJC}, this cannot be done in all cases.
* <p>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#debugGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#debugGlobals()}
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.debugGlobals();
* System.out.println(globals.get("debug").get("traceback").call());
* } </pre>
* }
* </pre>
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new DebugLib());
* System.out.println(globals.get("debug").get("traceback").call());
* } </pre>
* }
* </pre>
* <p>
* This library exposes the entire state of lua code, and provides method to see and modify
* all underlying lua values within a Java VM so should not be exposed to client code
* in a shared server environment.
* This library exposes the entire state of lua code, and provides method to see
* and modify all underlying lua values within a Java VM so should not be
* exposed to client code in a shared server environment.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.10">Lua 5.2 Debug Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.10">Lua 5.2 Debug
* Lib Reference</a>
*/
public class DebugLib extends TwoArgFunction {
public static boolean CALLS;
public static boolean TRACE;
static {
try { CALLS = (null != System.getProperty("CALLS")); } catch (Exception e) {}
try { TRACE = (null != System.getProperty("TRACE")); } catch (Exception e) {}
try {
CALLS = null != System.getProperty("CALLS");
} catch (Exception e) {
}
try {
TRACE = null != System.getProperty("TRACE");
} catch (Exception e) {
}
}
static final LuaString LUA = valueOf("Lua");
@@ -108,12 +123,17 @@ public class DebugLib extends TwoArgFunction {
Globals globals;
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, which must be a Globals instance.
* @param env the environment to load into, which must be a Globals
* instance.
*/
@Override
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
globals.debuglib = this;
@@ -135,12 +155,14 @@ public class DebugLib extends TwoArgFunction {
debug.set("upvalueid", new upvalueid());
debug.set("upvaluejoin", new upvaluejoin());
env.set("debug", debug);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("debug", debug);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("debug", debug);
return debug;
}
// debug.debug()
static final class debug extends ZeroArgFunction {
@Override
public LuaValue call() {
return NONE;
}
@@ -148,18 +170,18 @@ public class DebugLib extends TwoArgFunction {
// debug.gethook ([thread])
final class gethook extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
LuaThread t = args.narg() > 0? args.checkthread(1): globals.running;
LuaThread.State s = t.state;
return varargsOf(
s.hookfunc != null? s.hookfunc: NIL,
valueOf((s.hookcall?"c":"")+(s.hookline?"l":"")+(s.hookrtrn?"r":"")),
valueOf(s.hookcount));
return varargsOf(s.hookfunc != null? s.hookfunc: NIL,
valueOf((s.hookcall? "c": "")+(s.hookline? "l": "")+(s.hookrtrn? "r": "")), valueOf(s.hookcount));
}
}
// debug.getinfo ([thread,] f [, what])
final class getinfo extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
int a = 1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
@@ -223,18 +245,27 @@ public class DebugLib extends TwoArgFunction {
// debug.getlocal ([thread,] f, local)
final class getlocal extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
int a = 1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
int level = args.checkint(a++);
int local = args.checkint(a++);
CallFrame f = callstack(thread).getCallFrame(level);
return f != null? f.getLocal(local): NONE;
LuaValue func = args.arg(a++);
int local = args.checkint(a);
if (func.isfunction())
return func.checkclosure().p.getlocalname(local, 0);
// find the stack info
DebugLib.CallFrame frame = callstack(thread).getCallFrame(func.checkint());
if (frame == null)
return argerror(a, "level out of range");
return frame.getLocal(local);
}
}
// debug.getmetatable (value)
static final class getmetatable extends LibFunction {
@Override
public LuaValue call(LuaValue v) {
LuaValue mt = v.getmetatable();
return mt != null? mt: NIL;
@@ -243,6 +274,7 @@ public class DebugLib extends TwoArgFunction {
// debug.getregistry ()
final class getregistry extends ZeroArgFunction {
@Override
public LuaValue call() {
return globals;
}
@@ -250,6 +282,7 @@ public class DebugLib extends TwoArgFunction {
// debug.getupvalue (f, up)
static final class getupvalue extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
LuaValue func = args.checkfunction(1);
int up = args.checkint(2);
@@ -266,14 +299,15 @@ public class DebugLib extends TwoArgFunction {
// debug.getuservalue (u)
static final class getuservalue extends LibFunction {
@Override
public LuaValue call(LuaValue u) {
return u.isuserdata()? u: NIL;
}
}
// debug.sethook ([thread,] hook, mask [, count])
final class sethook extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
int a = 1;
LuaThread t = args.isthread(a)? args.checkthread(a++): globals.running;
@@ -283,9 +317,15 @@ public class DebugLib extends TwoArgFunction {
boolean call = false, line = false, rtrn = false;
for (int i = 0; i < str.length(); i++)
switch (str.charAt(i)) {
case 'c': call=true; break;
case 'l': line=true; break;
case 'r': rtrn=true; break;
case 'c':
call = true;
break;
case 'l':
line = true;
break;
case 'r':
rtrn = true;
break;
}
LuaThread.State s = t.state;
s.hookfunc = func;
@@ -299,6 +339,7 @@ public class DebugLib extends TwoArgFunction {
// debug.setlocal ([thread,] level, local, value)
final class setlocal extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
int a = 1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
@@ -312,16 +353,30 @@ public class DebugLib extends TwoArgFunction {
// debug.setmetatable (value, table)
static final class setmetatable extends TwoArgFunction {
@Override
public LuaValue call(LuaValue value, LuaValue table) {
LuaValue mt = table.opttable(null);
switch (value.type()) {
case TNIL: LuaNil.s_metatable = mt; break;
case TNUMBER: LuaNumber.s_metatable = mt; break;
case TBOOLEAN: LuaBoolean.s_metatable = mt; break;
case TSTRING: LuaString.s_metatable = mt; break;
case TFUNCTION: LuaFunction.s_metatable = mt; break;
case TTHREAD: LuaThread.s_metatable = mt; break;
default: value.setmetatable( mt );
case TNIL:
LuaNil.s_metatable = mt;
break;
case TNUMBER:
LuaNumber.s_metatable = mt;
break;
case TBOOLEAN:
LuaBoolean.s_metatable = mt;
break;
case TSTRING:
LuaString.s_metatable = mt;
break;
case TFUNCTION:
LuaFunction.s_metatable = mt;
break;
case TTHREAD:
LuaThread.s_metatable = mt;
break;
default:
value.setmetatable(mt);
}
return value;
}
@@ -329,10 +384,11 @@ public class DebugLib extends TwoArgFunction {
// debug.setupvalue (f, up, value)
static final class setupvalue extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
LuaValue func = args.checkfunction(1);
LuaValue value = args.checkvalue(3);
int up = args.checkint(2);
LuaValue value = args.arg(3);
LuaValue func = args.checkfunction(1);
if (func instanceof LuaClosure) {
LuaClosure c = (LuaClosure) func;
LuaString name = findupvalue(c, up);
@@ -347,6 +403,7 @@ public class DebugLib extends TwoArgFunction {
// debug.setuservalue (udata, value)
static final class setuservalue extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
Object o = args.checkuserdata(1);
LuaValue v = args.checkvalue(2);
@@ -359,6 +416,7 @@ public class DebugLib extends TwoArgFunction {
// debug.traceback ([thread,] [message [, level]])
final class traceback extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
int a = 1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): globals.running;
@@ -371,9 +429,10 @@ public class DebugLib extends TwoArgFunction {
// debug.upvalueid (f, n)
static final class upvalueid extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
LuaValue func = args.checkfunction(1);
int up = args.checkint(2);
LuaValue func = args.checkfunction(1);
if (func instanceof LuaClosure) {
LuaClosure c = (LuaClosure) func;
if (c.upValues != null && up > 0 && up <= c.upValues.length) {
@@ -386,11 +445,12 @@ public class DebugLib extends TwoArgFunction {
// debug.upvaluejoin (f1, n1, f2, n2)
static final class upvaluejoin extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
LuaClosure f1 = args.checkclosure(1);
int n1 = args.checkint(2);
LuaClosure f2 = args.checkclosure(3);
LuaClosure f1 = args.checkclosure(1);
int n2 = args.checkint(4);
LuaClosure f2 = args.checkclosure(3);
if (n1 < 1 || n1 > f1.upValues.length)
argerror("index out of range");
if (n2 < 1 || n2 > f2.upValues.length)
@@ -402,23 +462,29 @@ public class DebugLib extends TwoArgFunction {
public void onCall(LuaFunction f) {
LuaThread.State s = globals.running.state;
if (s.inhook) return;
if (s.inhook)
return;
callstack().onCall(f);
if (s.hookcall) callHook(s, CALL, NIL);
if (s.hookcall)
callHook(s, CALL, NIL);
}
public void onCall(LuaClosure c, Varargs varargs, LuaValue[] stack) {
LuaThread.State s = globals.running.state;
if (s.inhook) return;
if (s.inhook)
return;
callstack().onCall(c, varargs, stack);
if (s.hookcall) callHook(s, CALL, NIL);
if (s.hookcall)
callHook(s, CALL, NIL);
}
public void onInstruction(int pc, Varargs v, int top) {
LuaThread.State s = globals.running.state;
if (s.inhook) return;
if (s.inhook)
return;
callstack().onInstruction(pc, v, top);
if (s.hookfunc == null) return;
if (s.hookfunc == null)
return;
if (s.hookcount > 0)
if (++s.bytecodes%s.hookcount == 0)
callHook(s, COUNT, NIL);
@@ -433,17 +499,24 @@ public class DebugLib extends TwoArgFunction {
public void onReturn() {
LuaThread.State s = globals.running.state;
if (s.inhook) return;
if (s.inhook)
return;
callstack().onReturn();
if (s.hookrtrn) callHook(s, RETURN, NIL);
if (s.hookrtrn)
callHook(s, RETURN, NIL);
}
public String traceback(int level) {
return callstack().traceback(level);
}
public CallFrame getCallFrame(int level) {
return callstack().getCallFrame(level);
}
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;
try {
s.hookfunc.call(type, arg);
@@ -487,7 +560,7 @@ public class DebugLib extends TwoArgFunction {
this.source = p.source != null? p.source.tojstring(): "=?";
this.linedefined = p.linedefined;
this.lastlinedefined = p.lastlinedefined;
this.what = (this.linedefined == 0) ? "main" : "Lua";
this.what = this.linedefined == 0? "main": "Lua";
this.short_src = p.shortsource();
} else {
this.source = "=[Java]";
@@ -544,6 +617,7 @@ public class DebugLib extends TwoArgFunction {
/**
* Get the traceback starting at a specific level.
*
* @param level
* @return String containing the traceback.
*/
@@ -589,7 +663,6 @@ public class DebugLib extends TwoArgFunction {
return null;
}
synchronized DebugInfo auxgetinfo(String what, LuaFunction f, CallFrame ci) {
DebugInfo ar = new DebugInfo();
for (int i = 0, n = what.length(); i < n; ++i) {
@@ -645,29 +718,36 @@ public class DebugLib extends TwoArgFunction {
}
static class CallFrame {
public static class CallFrame {
static final LuaValue[] EMPTY = {};
LuaFunction f;
int pc;
int top;
Varargs v;
LuaValue[] stack;
LuaValue[] stack = EMPTY;
CallFrame previous;
void set(LuaClosure function, Varargs varargs, LuaValue[] stack) {
this.f = function;
this.v = varargs;
this.stack = stack;
}
public String shortsource() {
return f.isclosure()? f.checkclosure().p.shortsource(): "[Java]";
}
void set(LuaFunction function) {
this.f = function;
}
void reset() {
this.f = null;
this.v = null;
this.stack = null;
this.stack = EMPTY;
}
void instr(int pc, Varargs v, int top) {
this.pc = pc;
this.v = v;
@@ -675,6 +755,7 @@ public class DebugLib extends TwoArgFunction {
if (TRACE)
Print.printState(f.checkclosure(), pc, stack, top, v);
}
Varargs getLocal(int i) {
LuaString name = getlocalname(i);
if (i >= 1 && i <= stack.length && stack[i-1] != null)
@@ -682,6 +763,7 @@ public class DebugLib extends TwoArgFunction {
else
return NIL;
}
Varargs setLocal(int i, LuaValue value) {
LuaString name = getlocalname(i);
if (i >= 1 && i <= stack.length && stack[i-1] != null) {
@@ -691,20 +773,27 @@ public class DebugLib extends TwoArgFunction {
return NIL;
}
}
int currentline() {
if ( !f.isclosure() ) return -1;
public int currentline() {
if (!f.isclosure())
return -1;
int[] li = f.checkclosure().p.lineinfo;
return li == null || pc < 0 || pc >= li.length? -1: li[pc];
}
String sourceline() {
if ( !f.isclosure() ) return f.tojstring();
if (!f.isclosure())
return f.tojstring();
return f.checkclosure().p.shortsource() + ":" + currentline();
}
int linedefined() {
return f.isclosure()? f.checkclosure().p.linedefined: -1;
}
LuaString getlocalname(int index) {
if ( !f.isclosure() ) return null;
if (!f.isclosure())
return null;
return f.checkclosure().p.getlocalname(index, pc);
}
}
@@ -720,12 +809,14 @@ public class DebugLib extends TwoArgFunction {
}
static void lua_assert(boolean x) {
if (!x) throw new RuntimeException("lua_assert failed");
if (!x)
throw new RuntimeException("lua_assert failed");
}
static class NameWhat {
final String name;
final String namewhat;
NameWhat(String name, String namewhat) {
this.name = name;
this.namewhat = namewhat;
@@ -749,21 +840,49 @@ public class DebugLib extends TwoArgFunction {
/* all other instructions can call only through metamethods */
case Lua.OP_SELF:
case Lua.OP_GETTABUP:
case Lua.OP_GETTABLE: tm = LuaValue.INDEX; break;
case Lua.OP_GETTABLE:
tm = LuaValue.INDEX;
break;
case Lua.OP_SETTABUP:
case Lua.OP_SETTABLE: tm = LuaValue.NEWINDEX; break;
case Lua.OP_EQ: tm = LuaValue.EQ; break;
case Lua.OP_ADD: tm = LuaValue.ADD; break;
case Lua.OP_SUB: tm = LuaValue.SUB; break;
case Lua.OP_MUL: tm = LuaValue.MUL; break;
case Lua.OP_DIV: tm = LuaValue.DIV; break;
case Lua.OP_MOD: tm = LuaValue.MOD; break;
case Lua.OP_POW: tm = LuaValue.POW; break;
case Lua.OP_UNM: tm = LuaValue.UNM; break;
case Lua.OP_LEN: tm = LuaValue.LEN; break;
case Lua.OP_LT: tm = LuaValue.LT; break;
case Lua.OP_LE: tm = LuaValue.LE; break;
case Lua.OP_CONCAT: tm = LuaValue.CONCAT; break;
case Lua.OP_SETTABLE:
tm = LuaValue.NEWINDEX;
break;
case Lua.OP_EQ:
tm = LuaValue.EQ;
break;
case Lua.OP_ADD:
tm = LuaValue.ADD;
break;
case Lua.OP_SUB:
tm = LuaValue.SUB;
break;
case Lua.OP_MUL:
tm = LuaValue.MUL;
break;
case Lua.OP_DIV:
tm = LuaValue.DIV;
break;
case Lua.OP_MOD:
tm = LuaValue.MOD;
break;
case Lua.OP_POW:
tm = LuaValue.POW;
break;
case Lua.OP_UNM:
tm = LuaValue.UNM;
break;
case Lua.OP_LEN:
tm = LuaValue.LEN;
break;
case Lua.OP_LT:
tm = LuaValue.LT;
break;
case Lua.OP_LE:
tm = LuaValue.LE;
break;
case Lua.OP_CONCAT:
tm = LuaValue.CONCAT;
break;
default:
return null; /* else no useful name can be found */
}
@@ -793,21 +912,20 @@ public class DebugLib extends TwoArgFunction {
case Lua.OP_GETTABLE: {
int k = Lua.GETARG_C(i); /* key index */
int t = Lua.GETARG_B(i); /* table index */
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)
: (t < p.upvalues.length ? p.upvalues[t].name : QMARK);
name = kname(p, k);
return new NameWhat( name.tojstring(), vn != null && vn.eq_b(ENV)? "global": "field" );
: t < p.upvalues.length? p.upvalues[t].name: QMARK;
String jname = kname(p, pc, k);
return new NameWhat(jname, vn != null && vn.eq_b(ENV)? "global": "field");
}
case Lua.OP_GETUPVAL: {
int u = Lua.GETARG_B(i); /* upvalue index */
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_LOADKX: {
int b = (Lua.GET_OPCODE(i) == Lua.OP_LOADK) ? Lua.GETARG_Bx(i)
: Lua.GETARG_Ax(p.code[pc + 1]);
int b = Lua.GET_OPCODE(i) == Lua.OP_LOADK? Lua.GETARG_Bx(i): Lua.GETARG_Ax(p.code[pc+1]);
if (p.k[b].isstring()) {
name = p.k[b].strvalue();
return new NameWhat(name.tojstring(), "constant");
@@ -816,8 +934,8 @@ public class DebugLib extends TwoArgFunction {
}
case Lua.OP_SELF: {
int k = Lua.GETARG_C(i); /* key index */
name = kname(p, k);
return new NameWhat( name.tojstring(), "method" );
String jname = kname(p, pc, k);
return new NameWhat(jname, "method");
}
default:
break;
@@ -826,11 +944,20 @@ public class DebugLib extends TwoArgFunction {
return null; /* no useful name found */
}
static LuaString kname(Prototype p, int c) {
if (Lua.ISK(c) && p.k[Lua.INDEXK(c)].isstring())
return p.k[Lua.INDEXK(c)].strvalue();
else
return QMARK;
static String kname(Prototype p, int pc, int c) {
if (Lua.ISK(c)) { /* is 'c' a constant? */
LuaValue k = p.k[Lua.INDEXK(c)];
if (k.isstring()) { /* literal constant? */
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 */
}
/*
@@ -851,12 +978,14 @@ public class DebugLib extends TwoArgFunction {
break;
}
case Lua.OP_TFORCALL: {
if (reg >= a + 2) setreg = pc; /* affect all regs above its base */
if (reg >= a+2)
setreg = pc; /* affect all regs above its base */
break;
}
case Lua.OP_CALL:
case Lua.OP_TAILCALL: {
if (reg >= a) setreg = pc; /* affect all registers above base */
if (reg >= a)
setreg = pc; /* affect all registers above base */
break;
}
case Lua.OP_JMP: {
@@ -868,11 +997,13 @@ public class DebugLib extends TwoArgFunction {
break;
}
case Lua.OP_TEST: {
if (reg == a) setreg = pc; /* jumped code can change 'a' */
if (reg == a)
setreg = pc; /* jumped code can change 'a' */
break;
}
case Lua.OP_SETLIST: { // Lua.testAMode(Lua.OP_SETLIST) == false
if ( ((i>>14)&0x1ff) == 0 ) pc++; // if c == 0 then c stored in next op -> skip
if ((i>>14 & 0x1ff) == 0)
pc++; // if c == 0 then c stored in next op -> skip
break;
}
default:

View File

@@ -0,0 +1,748 @@
/*******************************************************************************
* Copyright (c) 2009-2011 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;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.IOException;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Abstract base class extending {@link LibFunction} which implements the core
* of the lua standard {@code io} library.
* <p>
* It contains the implementation of the io library support that is common to
* the JSE and JME platforms. In practice on of the concrete IOLib subclasses is
* chosen: {@link org.luaj.vm2.lib.jse.JseIoLib} for the JSE platform, and
* {@link org.luaj.vm2.lib.jme.JmeIoLib} for the JME platform.
* <p>
* The JSE implementation conforms almost completely to the C-based lua library,
* while the JME implementation follows closely except in the area of
* random-access files, which are difficult to support properly on JME.
* <p>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* }
* </pre>
*
* In this example the platform-specific {@link org.luaj.vm2.lib.jse.JseIoLib}
* library will be loaded, which will include the base functionality provided by
* this class, whereas the {@link org.luaj.vm2.lib.jse.JsePlatform} would load
* the {@link org.luaj.vm2.lib.jse.JseIoLib}.
* <p>
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new OsLib());
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* }
* </pre>
* <p>
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see org.luaj.vm2.lib.jse.JseIoLib
* @see org.luaj.vm2.lib.jme.JmeIoLib
* @see <a href=
* "http://www.lua.org/manual/5.1/manual.html#5.7">http://www.lua.org/manual/5.1/manual.html#5.7</a>
*/
public abstract class IoLib extends TwoArgFunction {
protected abstract class File extends LuaValue {
public abstract void write(LuaString string) throws IOException;
public abstract void flush() throws IOException;
public abstract boolean isstdfile();
public abstract void close() throws IOException;
public abstract boolean isclosed();
// returns new position
public abstract int seek(String option, int bytecount) throws IOException;
public abstract void setvbuf(String mode, int size);
// get length remaining to read
public abstract int remaining() throws IOException;
// peek ahead one character
public abstract int peek() throws IOException, EOFException;
// return char if read, -1 if eof, throw IOException on other exception
public abstract int read() throws IOException, EOFException;
// return number of bytes read if positive, false if eof, throw IOException on other exception
public abstract 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
@Override
public LuaValue get(LuaValue key) {
return filemethods.get(key);
}
// essentially a userdata instance
@Override
public int type() {
return LuaValue.TUSERDATA;
}
@Override
public String typename() {
return "userdata";
}
// displays as "file" type
@Override
public String tojstring() {
return "file: " + Integer.toHexString(hashCode());
}
@Override
public void finalize() {
if (!isclosed()) {
try {
close();
} catch (IOException ignore) {
}
}
}
}
/** Enumerated value representing stdin */
protected static final int FTYPE_STDIN = 0;
/** Enumerated value representing stdout */
protected static final int FTYPE_STDOUT = 1;
/** Enumerated value representing stderr */
protected static final int FTYPE_STDERR = 2;
/** Enumerated value representing a file type for a named file */
protected static final int FTYPE_NAMED = 3;
/**
* Wrap the standard input.
*
* @return File
* @throws IOException
*/
abstract protected File wrapStdin() throws IOException;
/**
* Wrap the standard output.
*
* @return File
* @throws IOException
*/
abstract protected File wrapStdout() throws IOException;
/**
* Wrap the standard error output.
*
* @return File
* @throws IOException
*/
abstract protected File wrapStderr() throws IOException;
/**
* Open a file in a particular mode.
*
* @param filename
* @param readMode true if opening in read mode
* @param appendMode true if opening in append mode
* @param updateMode true if opening in update mode
* @param binaryMode true if opening in binary mode
* @return File object if successful
* @throws IOException if could not be opened
*/
abstract protected File openFile(String filename, boolean readMode, boolean appendMode, boolean updateMode,
boolean binaryMode) throws IOException;
/**
* Open a temporary file.
*
* @return File object if successful
* @throws IOException if could not be opened
*/
abstract protected File tmpFile() throws IOException;
/**
* Start a new process and return a file for input or output
*
* @param prog the program to execute
* @param mode "r" to read, "w" to write
* @return File to read to or write from
* @throws IOException if an i/o exception occurs
*/
abstract protected File openProgram(String prog, String mode) throws IOException;
private File infile = null;
private File outfile = null;
private File errfile = null;
private static final LuaValue STDIN = valueOf("stdin");
private static final LuaValue STDOUT = valueOf("stdout");
private static final LuaValue STDERR = valueOf("stderr");
private static final LuaValue FILE = valueOf("file");
private static final LuaValue CLOSED_FILE = valueOf("closed file");
private static final int IO_CLOSE = 0;
private static final int IO_FLUSH = 1;
private static final int IO_INPUT = 2;
private static final int IO_LINES = 3;
private static final int IO_OPEN = 4;
private static final int IO_OUTPUT = 5;
private static final int IO_POPEN = 6;
private static final int IO_READ = 7;
private static final int IO_TMPFILE = 8;
private static final int IO_TYPE = 9;
private static final int IO_WRITE = 10;
private static final int FILE_CLOSE = 11;
private static final int FILE_FLUSH = 12;
private static final int FILE_LINES = 13;
private static final int FILE_READ = 14;
private static final int FILE_SEEK = 15;
private static final int FILE_SETVBUF = 16;
private static final int FILE_WRITE = 17;
private static final int IO_INDEX = 18;
private static final int LINES_ITER = 19;
public static final String[] IO_NAMES = { "close", "flush", "input", "lines", "open", "output", "popen", "read",
"tmpfile", "type", "write", };
public static final String[] FILE_NAMES = { "close", "flush", "lines", "read", "seek", "setvbuf", "write", };
LuaTable filemethods;
protected Globals globals;
@Override
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
// io lib functions
LuaTable t = new LuaTable();
bind(t, IoLibV.class, IO_NAMES);
// create file methods table
filemethods = new LuaTable();
bind(filemethods, IoLibV.class, FILE_NAMES, FILE_CLOSE);
// set up file metatable
LuaTable mt = new LuaTable();
bind(mt, IoLibV.class, new String[] { "__index" }, IO_INDEX);
t.setmetatable(mt);
// all functions link to library instance
setLibInstance(t);
setLibInstance(filemethods);
setLibInstance(mt);
// return the table
env.set("io", t);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("io", t);
return t;
}
private void setLibInstance(LuaTable t) {
LuaValue[] k = t.keys();
for (int i = 0, n = k.length; i < n; i++)
((IoLibV) t.get(k[i])).iolib = this;
}
static final class IoLibV extends VarArgFunction {
private File f;
public IoLib iolib;
private boolean toclose;
private Varargs args;
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) {
this.f = f;
this.name = name;
this.opcode = opcode;
this.iolib = iolib;
}
@Override
public Varargs invoke(Varargs args) {
try {
switch (opcode) {
case IO_FLUSH:
return iolib._io_flush();
case IO_TMPFILE:
return iolib._io_tmpfile();
case IO_CLOSE:
return iolib._io_close(args.arg1());
case IO_INPUT:
return iolib._io_input(args.arg1());
case IO_OUTPUT:
return iolib._io_output(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_OPEN:
return iolib._io_open(args.checkjstring(1), args.optjstring(2, "r"));
case IO_LINES:
return iolib._io_lines(args);
case IO_READ:
return iolib._io_read(args);
case IO_WRITE:
return iolib._io_write(args);
case FILE_CLOSE:
return iolib._file_close(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, 8192));
case FILE_LINES:
return iolib._file_lines(args);
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_WRITE:
return iolib._file_write(args.arg1(), args.subargs(2));
case IO_INDEX:
return iolib._io_index(args.arg(2));
case LINES_ITER:
return iolib._lines_iter(f, toclose, this.args);
}
} catch (IOException ioe) {
if (opcode == LINES_ITER) {
String s = ioe.getMessage();
error(s != null? s: ioe.toString());
}
return errorresult(ioe);
}
return NONE;
}
}
private File input() {
return infile != null? infile: (infile = ioopenfile(FTYPE_STDIN, "-", "r"));
}
// io.flush() -> bool
public Varargs _io_flush() throws IOException {
checkopen(output());
outfile.flush();
return LuaValue.TRUE;
}
// io.tmpfile() -> file
public Varargs _io_tmpfile() throws IOException {
return tmpFile();
}
// io.close([file]) -> void
public Varargs _io_close(LuaValue file) throws IOException {
File f = file.isnil()? output(): checkfile(file);
checkopen(f);
return ioclose(f);
}
// io.input([file]) -> file
public Varargs _io_input(LuaValue file) {
infile = file.isnil()? input()
: file.isstring()? ioopenfile(FTYPE_NAMED, file.checkjstring(), "r"): checkfile(file);
return infile;
}
// io.output(filename) -> file
public Varargs _io_output(LuaValue filename) {
outfile = filename.isnil()? output()
: filename.isstring()? ioopenfile(FTYPE_NAMED, filename.checkjstring(), "w"): checkfile(filename);
return outfile;
}
// io.type(obj) -> "file" | "closed file" | nil
public Varargs _io_type(LuaValue obj) {
File f = optfile(obj);
return f != null? f.isclosed()? CLOSED_FILE: FILE: NIL;
}
// io.popen(prog, [mode]) -> file
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);
}
// io.open(filename, [mode]) -> file | nil,err
public Varargs _io_open(String filename, String mode) throws IOException {
return rawopenfile(FTYPE_NAMED, filename, mode);
}
// io.lines(filename, ...) -> iterator
public Varargs _io_lines(Varargs args) {
String filename = args.optjstring(1, null);
File infile = filename == null? input(): ioopenfile(FTYPE_NAMED, filename, "r");
checkopen(infile);
return lines(infile, filename != null, args.subargs(2));
}
// io.read(...) -> (...)
public Varargs _io_read(Varargs args) throws IOException {
checkopen(input());
return ioread(infile, args);
}
// io.write(...) -> void
public Varargs _io_write(Varargs args) throws IOException {
checkopen(output());
return iowrite(outfile, args);
}
// file:close() -> void
public Varargs _file_close(LuaValue file) throws IOException {
return ioclose(checkfile(file));
}
// file:flush() -> void
public Varargs _file_flush(LuaValue file) throws IOException {
checkfile(file).flush();
return LuaValue.TRUE;
}
// file:setvbuf(mode,[size]) -> void
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);
return LuaValue.TRUE;
}
// file:lines(...) -> iterator
public Varargs _file_lines(Varargs args) {
return lines(checkfile(args.arg1()), false, args.subargs(2));
}
// file:read(...) -> (...)
public Varargs _file_read(LuaValue file, Varargs subargs) throws IOException {
return ioread(checkfile(file), subargs);
}
// file:seek([whence][,offset]) -> pos | nil,error
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));
}
// file:write(...) -> void
public Varargs _file_write(LuaValue file, Varargs subargs) throws IOException {
return iowrite(checkfile(file), subargs);
}
// __index, returns a field
public Varargs _io_index(LuaValue v) {
return v.equals(STDOUT)? output(): v.equals(STDIN)? input(): v.equals(STDERR)? errput(): NIL;
}
// lines iterator(s,var) -> var'
public Varargs _lines_iter(LuaValue file, boolean toclose, Varargs args) throws IOException {
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() {
return outfile != null? outfile: (outfile = ioopenfile(FTYPE_STDOUT, "-", "w"));
}
private File errput() {
return errfile != null? errfile: (errfile = ioopenfile(FTYPE_STDERR, "-", "w"));
}
private File ioopenfile(int filetype, String filename, String mode) {
try {
return rawopenfile(filetype, filename, mode);
} catch (Exception e) {
error("io error: " + e.getMessage());
return null;
}
}
private static Varargs ioclose(File f) throws IOException {
if (f.isstdfile())
return errorresult("cannot close standard file");
else {
f.close();
return successresult();
}
}
private static Varargs successresult() {
return LuaValue.TRUE;
}
static Varargs errorresult(Exception ioe) {
String s = ioe.getMessage();
return errorresult("io error: " + (s != null? s: ioe.toString()));
}
private static Varargs errorresult(String errortext) {
return varargsOf(NIL, valueOf(errortext));
}
private Varargs lines(final File f, boolean toclose, Varargs args) {
try {
return new IoLibV(f, "lnext", LINES_ITER, this, toclose, args);
} catch (Exception e) {
return error("lines: " + e);
}
}
private static Varargs iowrite(File f, Varargs args) throws IOException {
for (int i = 1, n = args.narg(); i <= n; i++)
f.write(args.checkstring(i));
return f;
}
private Varargs ioread(File f, Varargs args) throws IOException {
int i, n = args.narg();
if (n == 0)
return freadline(f, false);
LuaValue[] v = new LuaValue[n];
LuaValue ai, vi;
LuaString fmt;
for (i = 0; i < n;) {
item: switch ((ai = args.arg(i+1)).type()) {
case LuaValue.TNUMBER:
vi = freadbytes(f, ai.toint());
break item;
case LuaValue.TSTRING:
fmt = ai.checkstring();
if (fmt.m_length >= 2 && fmt.m_bytes[fmt.m_offset] == '*') {
switch (fmt.m_bytes[fmt.m_offset+1]) {
case 'n':
vi = freadnumber(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;
}
}
default:
return argerror(i+1, "(invalid format)");
}
if ((v[i++] = vi).isnil())
break;
}
return i == 0? NIL: varargsOf(v, 0, i);
}
private static File checkfile(LuaValue val) {
File f = optfile(val);
if (f == null)
argerror(1, "file");
checkopen(f);
return f;
}
private static File optfile(LuaValue val) {
return (val instanceof File)? (File) val: null;
}
private static File checkopen(File file) {
if (file.isclosed())
error("attempt to use a closed file");
return file;
}
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) || (i == 1 && ch == '+'))
continue;
if (i >= 1 && ch == 'b')
continue;
len = -1;
break;
}
if (len <= 0)
argerror(2, "invalid mode: '" + mode + "'");
switch (filetype) {
case FTYPE_STDIN:
return wrapStdin();
case FTYPE_STDOUT:
return wrapStdout();
case FTYPE_STDERR:
return wrapStderr();
}
boolean isreadmode = mode.startsWith("r");
boolean isappend = mode.startsWith("a");
boolean isupdate = mode.indexOf('+') > 0;
boolean isbinary = mode.endsWith("b");
return openFile(filename, isreadmode, isappend, isupdate, isbinary);
}
// ------------- file reading utilitied ------------------
public static LuaValue freadbytes(File f, int count) throws IOException {
if (count == 0)
return f.eof()? NIL: EMPTYSTRING;
byte[] b = new byte[count];
int r;
if ((r = f.read(b, 0, b.length)) < 0)
return NIL;
return LuaString.valueUsing(b, 0, r);
}
public static LuaValue freaduntil(File f, boolean lineonly, boolean withend) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c;
try {
if (lineonly) {
loop: while ( (c = f.read()) >= 0 ) {
switch (c) {
case '\r':
if (withend)
baos.write(c);
break;
case '\n':
if (withend)
baos.write(c);
break loop;
default:
baos.write(c);
break;
}
}
} else {
while ( (c = f.read()) >= 0 )
baos.write(c);
}
} catch (EOFException e) {
c = -1;
}
return (c < 0 && baos.size() == 0)? (LuaValue) NIL: (LuaValue) LuaString.valueUsing(baos.toByteArray());
}
public static LuaValue freadline(File f, boolean withend) throws IOException {
return freaduntil(f, true, withend);
}
public static LuaValue freadall(File f) throws IOException {
int n = f.remaining();
if (n >= 0) {
return n == 0? EMPTYSTRING: freadbytes(f, n);
} else {
return freaduntil(f, false, false);
}
}
public static LuaValue freadnumber(File f) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
freadchars(f, " \t\r\n", null);
freadchars(f, "-+", baos);
//freadchars(f,"0",baos);
//freadchars(f,"xX",baos);
freadchars(f, "0123456789", baos);
freadchars(f, ".", baos);
freadchars(f, "0123456789", baos);
//freadchars(f,"eEfFgG",baos);
// freadchars(f,"+-",baos);
//freadchars(f,"0123456789",baos);
String s = baos.toString();
return s.length() > 0? valueOf(Double.parseDouble(s)): NIL;
}
private static void freadchars(File f, String chars, ByteArrayOutputStream baos) throws IOException {
int c;
while ( true ) {
c = f.peek();
if (chars.indexOf(c) < 0) {
return;
}
f.read();
if (baos != null)
baos.write(c);
}
}
}

View File

@@ -29,20 +29,20 @@ import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LuaFunction} common to Java functions exposed to lua.
* <p>
* To provide for common implementations in JME and JSE,
* library functions are typically grouped on one or more library classes
* and an opcode per library function is defined and used to key the switch
* to the correct function within the library.
* To provide for common implementations in JME and JSE, library functions are
* typically grouped on one or more library classes and an opcode per library
* function is defined and used to key the switch to the correct function within
* the library.
* <p>
* Since lua functions can be called with too few or too many arguments,
* and there are overloaded {@link LuaValue#call()} functions with varying
* number of arguments, a Java function exposed in lua needs to handle the
* argument fixup when a function is called with a number of arguments
* differs from that expected.
* Since lua functions can be called with too few or too many arguments, and
* there are overloaded {@link LuaValue#call()} functions with varying number of
* arguments, a Java function exposed in lua needs to handle the argument fixup
* when a function is called with a number of arguments differs from that
* expected.
* <p>
* To simplify the creation of library functions,
* there are 5 direct subclasses to handle common cases based on number of
* argument values and number of return return values.
* To simplify the creation of library functions, there are 5 direct subclasses
* to handle common cases based on number of argument values and number of
* return return values.
* <ul>
* <li>{@link ZeroArgFunction}</li>
* <li>{@link OneArgFunction}</li>
@@ -51,13 +51,15 @@ import org.luaj.vm2.Varargs;
* <li>{@link VarArgFunction}</li>
* </ul>
* <p>
* To be a Java library that can be loaded via {@code require}, it should have
* a public constructor that returns a {@link LuaValue} that, when executed,
* To be a Java library that can be loaded via {@code require}, it should have a
* public constructor that returns a {@link LuaValue} that, when executed,
* initializes the library.
* <p>
* For example, the following code will implement a library called "hyperbolic"
* with two functions, "sinh", and "cosh":
<pre> {@code
*
* <pre>
* {@code
* import org.luaj.vm2.LuaValue;
* import org.luaj.vm2.lib.*;
*
@@ -85,18 +87,22 @@ import org.luaj.vm2.Varargs;
* }
* }
*}
*}</pre>
* The default constructor is used to instantiate the library
* in response to {@code require 'hyperbolic'} statement,
* provided it is on Java&quot;s class path.
* This instance is then invoked with 2 arguments: the name supplied to require(),
* and the environment for this function. The library may ignore these, or use
* them to leave side effects in the global environment, for example.
* In the previous example, two functions are created, 'sinh', and 'cosh', and placed
* into a global table called 'hyperbolic' using the supplied 'env' argument.
*}
* </pre>
*
* The default constructor is used to instantiate the library in response to
* {@code require 'hyperbolic'} statement, provided it is on Java&quot;s class
* path. This instance is then invoked with 2 arguments: the name supplied to
* require(), and the environment for this function. The library may ignore
* these, or use them to leave side effects in the global environment, for
* example. In the previous example, two functions are created, 'sinh', and
* 'cosh', and placed into a global table called 'hyperbolic' using the supplied
* 'env' argument.
* <p>
* To test it, a script such as this can be used:
* <pre> {@code
*
* <pre>
* {@code
* local t = require('hyperbolic')
* print( 't', t )
* print( 'hyperbolic', hyperbolic )
@@ -105,30 +111,38 @@ import org.luaj.vm2.Varargs;
* end
* print( 'sinh(.5)', hyperbolic.sinh(.5) )
* print( 'cosh(.5)', hyperbolic.cosh(.5) )
* }</pre>
* }
* </pre>
* <p>
* It should produce something like:
* <pre> {@code
*
* <pre>
* {@code
* t table: 3dbbd23f
* hyperbolic table: 3dbbd23f
* k,v cosh function: 3dbbd128
* k,v sinh function: 3dbbd242
* sinh(.5) 0.5210953
* cosh(.5) 1.127626
* }</pre>
* }
* </pre>
* <p>
* See the source code in any of the library functions
* such as {@link BaseLib} or {@link TableLib} for other examples.
* See the source code in any of the library functions such as {@link BaseLib}
* or {@link TableLib} for other examples.
*/
abstract public class LibFunction extends LuaFunction {
/** User-defined opcode to differentiate between instances of the library function class.
/**
* User-defined opcode to differentiate between instances of the library
* function class.
* <p>
* Subclass will typicall switch on this value to provide the specific behavior for each function.
* Subclass will typicall switch on this value to provide the specific
* behavior for each function.
*/
protected int opcode;
/** The common name for this function, useful for debugging.
/**
* The common name for this function, useful for debugging.
* <p>
* Binding functions initialize this to the name to which it is bound.
*/
@@ -138,6 +152,7 @@ abstract public class LibFunction extends LuaFunction {
protected LibFunction() {
}
@Override
public String tojstring() {
return name != null? "function: " + name: super.tojstring();
}
@@ -145,8 +160,9 @@ abstract public class LibFunction extends LuaFunction {
/**
* Bind a set of library functions.
* <p>
* An array of names is provided, and the first name is bound
* with opcode = 0, second with 1, etc.
* An array of names is provided, and the first name is bound with opcode =
* 0, second with 1, etc.
*
* @param env The environment to apply to each bound function
* @param factory the Class to instantiate for each bound function
* @param names array of String names, one for each function.
@@ -159,8 +175,9 @@ abstract public class LibFunction extends LuaFunction {
/**
* Bind a set of library functions, with an offset
* <p>
* An array of names is provided, and the first name is bound
* with opcode = {@code firstopcode}, second with {@code firstopcode+1}, etc.
* An array of names is provided, and the first name is bound with opcode =
* {@code firstopcode}, second with {@code firstopcode+1}, etc.
*
* @param env The environment to apply to each bound function
* @param factory the Class to instantiate for each bound function
* @param names array of String names, one for each function.
@@ -180,43 +197,67 @@ abstract public class LibFunction extends LuaFunction {
}
}
/** Java code generation utility to allocate storage for upvalue, leave it empty */
/**
* Java code generation utility to allocate storage for upvalue, leave it
* empty
*/
protected static LuaValue[] newupe() {
return new LuaValue[1];
}
/** Java code generation utility to allocate storage for upvalue, initialize with nil */
/**
* Java code generation utility to allocate storage for upvalue, initialize
* with nil
*/
protected static LuaValue[] newupn() {
return new LuaValue[] { NIL };
}
/** Java code generation utility to allocate storage for upvalue, initialize with value */
/**
* Java code generation utility to allocate storage for upvalue, initialize
* with value
*/
protected static LuaValue[] newupl(LuaValue v) {
return new LuaValue[] { v };
}
@Override
public LuaValue call() {
return argerror(1,"value");
return argerror(1, "value expected");
}
@Override
public LuaValue call(LuaValue a) {
return call();
}
@Override
public LuaValue call(LuaValue a, LuaValue b) {
return call(a);
}
@Override
public LuaValue call(LuaValue a, LuaValue b, LuaValue c) {
return call(a, b);
}
public LuaValue call(LuaValue a, LuaValue b, LuaValue c, LuaValue d) {
return call(a, b, c);
}
@Override
public Varargs invoke(Varargs args) {
switch (args.narg()) {
case 0: return call();
case 1: return call(args.arg1());
case 2: return call(args.arg1(),args.arg(2));
case 3: return call(args.arg1(),args.arg(2),args.arg(3));
default: return call(args.arg1(),args.arg(2),args.arg(3),args.arg(4));
case 0:
return call();
case 1:
return call(args.arg1());
case 2:
return call(args.arg1(), args.arg(2));
case 3:
return call(args.arg1(), args.arg(2), args.arg(3));
default:
return call(args.arg1(), args.arg(2), args.arg(3), args.arg(4));
}
}
}

View File

@@ -29,13 +29,13 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the lua standard {@code math}
* library.
* Subclass of {@link LibFunction} which implements the lua standard
* {@code math} library.
* <p>
* It contains only the math library support that is possible on JME.
* For a more complete implementation based on math functions specific to JSE
* use {@link org.luaj.vm2.lib.jse.JseMathLib}.
* In Particular the following math functions are <b>not</b> implemented by this library:
* It contains only the math library support that is possible on JME. For a more
* complete implementation based on math functions specific to JSE use
* {@link org.luaj.vm2.lib.jse.JseMathLib}. In Particular the following math
* functions are <b>not</b> implemented by this library:
* <ul>
* <li>acos</li>
* <li>asin</li>
@@ -48,58 +48,80 @@ import org.luaj.vm2.Varargs;
* </ul>
* <p>
* The implementations of {@code exp()} and {@code pow()} are constructed by
* hand for JME, so will be slower and less accurate than when executed on the JSE platform.
* hand for JME, so will be slower and less accurate than when executed on the
* JSE platform.
* <p>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2)));
* } </pre>
* When using {@link org.luaj.vm2.lib.jse.JsePlatform} as in this example,
* the subclass {@link org.luaj.vm2.lib.jse.JseMathLib} will
* be included, which also includes this base functionality.
* }
* </pre>
*
* When using {@link org.luaj.vm2.lib.jse.JsePlatform} as in this example, the
* subclass {@link org.luaj.vm2.lib.jse.JseMathLib} will be included, which also
* includes this base functionality.
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new MathLib());
* System.out.println(globals.get("math").get("sqrt").call(LuaValue.valueOf(2)));
* } </pre>
* Doing so will ensure the library is properly initialized
* and loaded into the globals table.
* }
* </pre>
*
* Doing so will ensure the library is properly initialized and loaded into the
* globals table.
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see org.luaj.vm2.lib.jse.JseMathLib
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.6">Lua 5.2 Math Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.6">Lua 5.2 Math Lib
* Reference</a>
*/
public class MathLib extends TwoArgFunction {
/** Pointer to the latest MathLib instance, used only to dispatch
* math.exp to tha correct platform math library.
/**
* Pointer to the latest MathLib instance, used only to dispatch math.exp to
* tha correct platform math library.
*/
public static MathLib MATHLIB = null;
/** Construct a MathLib, which can be initialized by calling it with a
/**
* Construct a MathLib, which can be initialized by calling it with a
* modname string, and a global environment table as arguments using
* {@link #call(LuaValue, LuaValue)}. */
* {@link #call(LuaValue, LuaValue)}.
*/
public MathLib() {
MATHLIB = this;
}
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, typically a Globals instance.
* @param env the environment to load into, typically a Globals
* instance.
*/
@Override
public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable math = new LuaTable(0, 30);
math.set("abs", new abs());
@@ -125,105 +147,163 @@ public class MathLib extends TwoArgFunction {
math.set("sqrt", new sqrt());
math.set("tan", new tan());
env.set("math", math);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("math", math);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("math", math);
return math;
}
abstract protected static class UnaryOp extends OneArgFunction {
@Override
public LuaValue call(LuaValue arg) {
return valueOf(call(arg.checkdouble()));
}
abstract protected double call(double d);
}
abstract protected static class BinaryOp extends TwoArgFunction {
@Override
public LuaValue call(LuaValue x, LuaValue y) {
return valueOf(call(x.checkdouble(), y.checkdouble()));
}
abstract protected double call(double x, double y);
}
static final class abs extends UnaryOp { protected double call(double d) { return Math.abs(d); } }
static final class ceil extends UnaryOp { protected double call(double d) { return Math.ceil(d); } }
static final class cos extends UnaryOp { protected double call(double d) { return Math.cos(d); } }
static final class deg extends UnaryOp { protected double call(double d) { return Math.toDegrees(d); } }
static final class floor extends UnaryOp { protected double call(double d) { return Math.floor(d); } }
static final class rad extends UnaryOp { protected double call(double d) { return Math.toRadians(d); } }
static final class sin extends UnaryOp { protected double call(double d) { return Math.sin(d); } }
static final class sqrt extends UnaryOp { protected double call(double d) { return Math.sqrt(d); } }
static final class tan extends UnaryOp { protected double call(double d) { return Math.tan(d); } }
static final class abs extends UnaryOp {
@Override
protected double call(double d) { return Math.abs(d); }
}
static final class ceil extends UnaryOp {
@Override
protected double call(double d) { return Math.ceil(d); }
}
static final class cos extends UnaryOp {
@Override
protected double call(double d) { return Math.cos(d); }
}
static final class deg extends UnaryOp {
@Override
protected double call(double d) { return Math.toDegrees(d); }
}
static final class floor extends UnaryOp {
@Override
protected double call(double d) { return Math.floor(d); }
}
static final class rad extends UnaryOp {
@Override
protected double call(double d) { return Math.toRadians(d); }
}
static final class sin extends UnaryOp {
@Override
protected double call(double d) { return Math.sin(d); }
}
static final class sqrt extends UnaryOp {
@Override
protected double call(double d) { return Math.sqrt(d); }
}
static final class tan extends UnaryOp {
@Override
protected double call(double d) { return Math.tan(d); }
}
static final class exp extends UnaryOp {
final MathLib mathlib;
exp(MathLib mathlib) {
this.mathlib = mathlib;
}
@Override
protected double call(double d) {
return mathlib.dpow_lib(Math.E, d);
}
}
static final class fmod extends TwoArgFunction {
@Override
public LuaValue call(LuaValue xv, LuaValue yv) {
if (yv.checkdouble() == 0.0d)
return LuaDouble.NAN;
if (xv.islong() && yv.islong()) {
return valueOf(xv.tolong()%yv.tolong());
}
return valueOf(xv.checkdouble()%yv.checkdouble());
}
}
static final class ldexp extends BinaryOp {
@Override
protected double call(double x, double y) {
// This is the behavior on os-x, windows differs in rounding behavior.
return x * Double.longBitsToDouble((((long) y) + 1023) << 52);
return x*Double.longBitsToDouble((long) y+1023<<52);
}
}
static final class pow extends BinaryOp {
@Override
protected double call(double x, double y) {
return MathLib.dpow_default(x, y);
}
}
static class frexp extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
double x = args.checkdouble(1);
if ( x == 0 ) return varargsOf(ZERO,ZERO);
if (x == 0)
return varargsOf(ZERO, ZERO);
long bits = Double.doubleToLongBits(x);
double m = ((bits & (~(-1L<<52))) + (1L<<52)) * ((bits >= 0)? (.5 / (1L<<52)): (-.5 / (1L<<52)));
double e = (((int) (bits >> 52)) & 0x7ff) - 1022;
double m = ((bits & ~(-1L<<52))+(1L<<52))*(bits >= 0? .5/(1L<<52): -.5/(1L<<52));
double e = ((int) (bits>>52) & 0x7ff)-1022;
return varargsOf(valueOf(m), valueOf(e));
}
}
static class max extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
LuaValue m = args.checkvalue(1);
LuaValue m = args.checknumber(1);
for (int i = 2, n = args.narg(); i <= n; ++i) {
LuaValue v = args.checkvalue(i);
if (m.lt_b(v)) m = v;
LuaValue v = args.checknumber(i);
if (m.lt_b(v))
m = v;
}
return m;
}
}
static class min extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
LuaValue m = args.checkvalue(1);
LuaValue m = args.checknumber(1);
for (int i = 2, n = args.narg(); i <= n; ++i) {
LuaValue v = args.checkvalue(i);
if (v.lt_b(m)) m = v;
LuaValue v = args.checknumber(i);
if (v.lt_b(m))
m = v;
}
return m;
}
}
static class modf extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
LuaValue n = args.arg1();
/* number is its own integer part, no fractional part */
if (n.islong()) return varargsOf(n, valueOf(0.0));
if (n.islong())
return varargsOf(n.tonumber(), valueOf(0.0));
double x = n.checkdouble();
/* integer part (rounds toward zero) */
double intPart = ( x > 0 ) ? Math.floor( x ) : Math.ceil( x );
double intPart = x > 0? Math.floor(x): Math.ceil(x);
/* fractional part (test needed for inf/-inf) */
double fracPart = x == intPart? 0.0: x-intPart;
return varargsOf(valueOf(intPart), valueOf(fracPart));
@@ -232,18 +312,26 @@ public class MathLib extends TwoArgFunction {
static class random extends LibFunction {
Random random = new Random();
@Override
public LuaValue call() {
return valueOf(random.nextDouble());
}
@Override
public LuaValue call(LuaValue a) {
int m = a.checkint();
if (m<1) argerror(1, "interval is empty");
if (m < 1)
argerror(1, "interval is empty");
return valueOf(1+random.nextInt(m));
}
@Override
public LuaValue call(LuaValue a, LuaValue b) {
int m = a.checkint();
int n = b.checkint();
if (n<m) argerror(2, "interval is empty");
if (n < m)
argerror(2, "interval is empty");
return valueOf(m+random.nextInt(n+1-m));
}
@@ -251,9 +339,12 @@ public class MathLib extends TwoArgFunction {
static class randomseed extends OneArgFunction {
final random random;
randomseed(random random) {
this.random = random;
}
@Override
public LuaValue call(LuaValue arg) {
long seed = arg.checklong();
random.random = new Random(seed);
@@ -261,17 +352,16 @@ public class MathLib extends TwoArgFunction {
}
}
/** compute power using installed math library, or default if there is no math library installed */
/**
* compute power using installed math library, or default if there is no
* math library installed
*/
public static LuaValue dpow(double a, double b) {
return LuaDouble.valueOf(
MATHLIB!=null?
MATHLIB.dpow_lib(a,b):
dpow_default(a,b) );
return LuaDouble.valueOf(MATHLIB != null? MATHLIB.dpow_lib(a, b): dpow_default(a, b));
}
public static double dpow_d(double a, double b) {
return MATHLIB!=null?
MATHLIB.dpow_lib(a,b):
dpow_default(a,b);
return MATHLIB != null? MATHLIB.dpow_lib(a, b): dpow_default(a, b);
}
/**

View File

@@ -24,21 +24,23 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/** Abstract base class for Java function implementations that take one argument and
* return one value.
/**
* Abstract base class for Java function implementations that take one argument
* and return one value.
* <p>
* Subclasses need only implement {@link LuaValue#call(LuaValue)} to complete this class,
* simplifying development.
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
* are routed through this method by this class,
* Subclasses need only implement {@link LuaValue#call(LuaValue)} to complete
* this class, simplifying development. All other uses of {@link #call()},
* {@link #invoke(Varargs)},etc, are routed through this method by this class,
* dropping or extending arguments with {@code nil} values as required.
* <p>
* If more than one argument are required, or no arguments are required,
* or variable argument or variable return values,
* then use one of the related function
* {@link ZeroArgFunction}, {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
* If more than one argument are required, or no arguments are required, or
* variable argument or variable return values, then use one of the related
* function {@link ZeroArgFunction}, {@link TwoArgFunction},
* {@link ThreeArgFunction}, or {@link VarArgFunction}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* See {@link LibFunction} for more information on implementation libraries and
* library functions.
*
* @see #call(LuaValue)
* @see LibFunction
* @see ZeroArgFunction
@@ -48,24 +50,29 @@ import org.luaj.vm2.Varargs;
*/
abstract public class OneArgFunction extends LibFunction {
@Override
abstract public LuaValue call(LuaValue arg);
/** Default constructor */
public OneArgFunction() {
}
@Override
public final LuaValue call() {
return call(NIL);
}
@Override
public final LuaValue call(LuaValue arg1, LuaValue arg2) {
return call(arg1);
}
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return call(arg1);
}
@Override
public Varargs invoke(Varargs varargs) {
return call(varargs.arg1());
}

View File

@@ -0,0 +1,522 @@
/*******************************************************************************
* 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;
import java.io.IOException;
import java.time.format.TextStyle;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.luaj.vm2.Buffer;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the standard lua {@code os}
* library.
* <p>
* It is a usable base with simplified stub functions for library functions that
* cannot be implemented uniformly on Jse and Jme.
* <p>
* This can be installed as-is on either platform, or extended and refined to be
* used in a complete Jse implementation.
* <p>
* Because the nature of the {@code os} library is to encapsulate os-specific
* features, the behavior of these functions varies considerably from their
* counterparts in the C platform.
* <p>
* The following functions have limited implementations of features that are not
* supported well on Jme:
* <ul>
* <li>{@code execute()}</li>
* <li>{@code remove()}</li>
* <li>{@code rename()}</li>
* <li>{@code tmpname()}</li>
* </ul>
* <p>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println(globals.get("os").get("time").call());
* }
* </pre>
*
* In this example the platform-specific {@link org.luaj.vm2.lib.jse.JseOsLib}
* library will be loaded, which will include the base functionality provided by
* this class.
* <p>
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new OsLib());
* System.out.println(globals.get("os").get("time").call());
* }
* </pre>
* <p>
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JseOsLib
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href=
* "http://www.lua.org/manual/5.1/manual.html#5.8">http://www.lua.org/manual/5.1/manual.html#5.8</a>
*/
public class OsLib extends TwoArgFunction {
public static final String TMP_PREFIX = ".luaj";
public static final String TMP_SUFFIX = "tmp";
private static final int CLOCK = 0;
private static final int DATE = 1;
private static final int DIFFTIME = 2;
private static final int EXECUTE = 3;
private static final int EXIT = 4;
private static final int GETENV = 5;
private static final int REMOVE = 6;
private static final int RENAME = 7;
private static final int SETLOCALE = 8;
private static final int TIME = 9;
private static final int TMPNAME = 10;
private static final String[] NAMES = { "clock", "date", "difftime", "execute", "exit", "getenv", "remove",
"rename", "setlocale", "time", "tmpname", };
private static final long t0 = System.currentTimeMillis();
private static long tmpnames = t0;
protected Globals globals;
/**
* Create and OsLib instance.
*/
public OsLib() {
}
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, typically a Globals
* instance.
*/
@Override
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
LuaTable os = new LuaTable();
for (int i = 0; i < NAMES.length; ++i)
os.set(NAMES[i], new OsLibFunc(i, NAMES[i]));
env.set("os", os);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("os", os);
return os;
}
class OsLibFunc extends VarArgFunction {
public OsLibFunc(int opcode, String name) {
this.opcode = opcode;
this.name = name;
}
@Override
public Varargs invoke(Varargs args) {
try {
switch (opcode) {
case CLOCK:
return valueOf(clock());
case DATE: {
String s = args.optjstring(1, "%c");
long t = args.isnumber(2)? args.tolong(2): time(null);
if (s.equals("*t")) {
Calendar d = Calendar.getInstance();
d.setTime(new Date(t*1000));
LuaTable tbl = LuaValue.tableOf();
tbl.set("year", LuaValue.valueOf(d.get(Calendar.YEAR)));
tbl.set("month", LuaValue.valueOf(d.get(Calendar.MONTH)+1));
tbl.set("day", LuaValue.valueOf(d.get(Calendar.DAY_OF_MONTH)));
tbl.set("hour", LuaValue.valueOf(d.get(Calendar.HOUR_OF_DAY)));
tbl.set("min", LuaValue.valueOf(d.get(Calendar.MINUTE)));
tbl.set("sec", LuaValue.valueOf(d.get(Calendar.SECOND)));
tbl.set("wday", LuaValue.valueOf(d.get(Calendar.DAY_OF_WEEK)));
tbl.set("yday", LuaValue.valueOf(d.get(0x6))); // Day of year
tbl.set("isdst", LuaValue.valueOf(isDaylightSavingsTime(d)));
return tbl;
}
return valueOf(date(s, t == -1? time(null): t));
}
case DIFFTIME:
return valueOf(difftime(args.checkdouble(1), args.checkdouble(2)));
case EXECUTE:
return execute(args.optjstring(1, null));
case EXIT:
exit(args.optint(1, 0));
return NONE;
case GETENV: {
final String val = getenv(args.checkjstring(1));
return val != null? valueOf(val): NIL;
}
case REMOVE:
remove(args.checkjstring(1));
return LuaValue.TRUE;
case RENAME:
rename(args.checkjstring(1), args.checkjstring(2));
return LuaValue.TRUE;
case SETLOCALE: {
String s = setlocale(args.optjstring(1, null), args.optjstring(2, "all"));
return s != null? valueOf(s): NIL;
}
case TIME:
return valueOf(time(args.opttable(1, null)));
case TMPNAME:
return valueOf(tmpname());
}
return NONE;
} catch (IOException e) {
return varargsOf(NIL, valueOf(e.getMessage()));
}
}
}
/**
* @return an approximation of the amount in seconds of CPU time used by the
* program. For luaj this simple returns the elapsed time since the
* OsLib class was loaded.
*/
protected double clock() {
return (System.currentTimeMillis()-t0)/1000.;
}
/**
* Returns the number of seconds from time t1 to time t2. In POSIX, Windows,
* and some other systems, this value is exactly t2-t1.
*
* @param t2
* @param t1
* @return diffeence in time values, in seconds
*/
protected double difftime(double t2, double t1) {
return t2-t1;
}
/**
* If the time argument is present, this is the time to be formatted (see
* the os.time function for a description of this value). Otherwise, date
* formats the current time.
*
* Date returns the date as a string, formatted according to the same rules
* as ANSII strftime, but without support for %g, %G, or %V.
*
* When called without arguments, date returns a reasonable date and time
* representation that depends on the host system and on the current locale
* (that is, os.date() is equivalent to os.date("%c")).
*
* @param format
* @param timeInSec time since epoch, or -1 if not supplied
* @return a LString or a LTable containing date and time, formatted
* according to the given string format.
*/
private static String date(String format, long timeInSec) {
Calendar d = Calendar.getInstance();
d.setTime(new Date(timeInSec*1000));
if (format.startsWith("!")) {
timeInSec -= timeZoneOffset(d);
d.setTime(new Date(timeInSec*1000));
format = format.substring(1);
}
byte[] fmt = format.getBytes();
final int n = fmt.length;
Buffer result = new Buffer(n);
for (int i = 0; i < n; i++) {
byte c = fmt[i];
switch (c) {
case '\n':
result.append("\n");
break;
case '%':
if (++i >= n)
break;
String conv = Character.toString((char) fmt[i]);
if (CONVERTERS.containsKey(conv)) {
result.append(CONVERTERS.get(conv).convert(d));
} else {
LuaValue.argerror(1, "invalid conversion specifier '%" + conv + "'");
}
break;
default:
result.append(c);
break;
}
}
return result.tojstring();
}
private static final String[] WeekdayNameAbbrev = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
private static final String[] WeekdayName = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday" };
private static final String[] MonthNameAbbrev = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec" };
private static final String[] MonthName = { "January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December" };
private static interface DateConversion {
public String convert(Calendar d);
}
private static final Map<String, DateConversion> CONVERTERS = new HashMap<>();
static {
CONVERTERS.put("%", d -> "%");
CONVERTERS.put("a", d -> WeekdayNameAbbrev[d.get(Calendar.DAY_OF_WEEK)-1]);
CONVERTERS.put("A", d -> WeekdayName[d.get(Calendar.DAY_OF_WEEK)-1]);
CONVERTERS.put("b", d -> MonthNameAbbrev[d.get(Calendar.MONTH)]);
CONVERTERS.put("B", d -> MonthName[d.get(Calendar.MONTH)]);
CONVERTERS.put("c", d -> date("%a %b %e %H:%M:%S %Y", d.getTimeInMillis()/1000L));
CONVERTERS.put("C", d -> String.valueOf(d.get(Calendar.YEAR)).substring(0, 2));
CONVERTERS.put("d", d -> String.valueOf(100+d.get(Calendar.DAY_OF_MONTH)).substring(1));
CONVERTERS.put("D", d -> date("%m/%d/%y", d.getTimeInMillis()/1000L));
CONVERTERS.put("e", d -> String.format("%2d", d.get(Calendar.DAY_OF_MONTH)));
CONVERTERS.put("F", d -> date("%Y-%m-%d", d.getTimeInMillis()/1000L));
CONVERTERS.put("g", d -> String.valueOf(d.get(Calendar.YEAR)).substring(2));
CONVERTERS.put("G", d -> String.valueOf(d.get(Calendar.YEAR)));
CONVERTERS.put("h", d -> MonthNameAbbrev[d.get(Calendar.MONTH)]);
CONVERTERS.put("H", d -> String.valueOf(100+d.get(Calendar.HOUR_OF_DAY)).substring(1));
CONVERTERS.put("I", d -> String.valueOf(100+d.get(Calendar.HOUR_OF_DAY)%12).substring(1));
// day of year
CONVERTERS.put("j", d -> {
Calendar y0 = beginningOfYear(d);
int dayOfYear = (int) ((d.getTimeInMillis()-y0.getTimeInMillis())/(24*3600L*1000L));
return String.valueOf(1001+dayOfYear).substring(1);
});
CONVERTERS.put("m", d -> String.valueOf(101+d.get(Calendar.MONTH)).substring(1));
CONVERTERS.put("M", d -> String.valueOf(100+d.get(Calendar.MINUTE)).substring(1));
CONVERTERS.put("n", d -> "\n");
CONVERTERS.put("p", d -> d.get(Calendar.HOUR_OF_DAY) < 12? "AM": "PM");
CONVERTERS.put("r", d -> date("%I:%M:%S %p", d.getTimeInMillis()/1000L));
CONVERTERS.put("R", d -> date("%H:%M", d.getTimeInMillis()/1000L));
CONVERTERS.put("S", d -> String.valueOf(100+d.get(Calendar.SECOND)).substring(1));
CONVERTERS.put("t", d -> "\t");
CONVERTERS.put("T", d -> date("%H:%M:%S", d.getTimeInMillis()/1000L));
CONVERTERS.put("u", d -> String.valueOf((d.get(Calendar.DAY_OF_WEEK)+6)%7));
CONVERTERS.put("U", d -> String.valueOf(weekNumber(d, 0)));
CONVERTERS.put("V", d -> String.valueOf(weekNumber(d, 0)));
CONVERTERS.put("w", d -> String.valueOf((d.get(Calendar.DAY_OF_WEEK)+6)%7));
CONVERTERS.put("W", d -> String.valueOf(weekNumber(d, 1)));
CONVERTERS.put("x", d -> date("%m/%d/%y", d.getTimeInMillis()/1000L));
CONVERTERS.put("X", d -> date("%H:%M:%S", d.getTimeInMillis()/1000L));
CONVERTERS.put("y", d -> String.valueOf(d.get(Calendar.YEAR)).substring(2));
CONVERTERS.put("Y", d -> String.valueOf(d.get(Calendar.YEAR)));
CONVERTERS.put("z", d -> {
final int tzo = timeZoneOffset(d)/60;
final int a = Math.abs(tzo);
final String h = String.valueOf(100+a/60).substring(1);
final String m = String.valueOf(100+a%60).substring(1);
return (tzo >= 0? "+": "-")+h+m;
});
CONVERTERS.put("Z", d -> d.getTimeZone().toZoneId().getDisplayName(TextStyle.SHORT, Locale.getDefault()));
}
private static Calendar beginningOfYear(Calendar d) {
Calendar y0 = Calendar.getInstance();
y0.setTime(d.getTime());
y0.set(Calendar.MONTH, 0);
y0.set(Calendar.DAY_OF_MONTH, 1);
y0.set(Calendar.HOUR_OF_DAY, 0);
y0.set(Calendar.MINUTE, 0);
y0.set(Calendar.SECOND, 0);
y0.set(Calendar.MILLISECOND, 0);
return y0;
}
private static int weekNumber(Calendar d, int startDay) {
Calendar y0 = beginningOfYear(d);
y0.set(Calendar.DAY_OF_MONTH, 1+(startDay+8-y0.get(Calendar.DAY_OF_WEEK))%7);
if (y0.after(d)) {
y0.set(Calendar.YEAR, y0.get(Calendar.YEAR)-1);
y0.set(Calendar.DAY_OF_MONTH, 1+(startDay+8-y0.get(Calendar.DAY_OF_WEEK))%7);
}
long dt = d.getTime().getTime()-y0.getTime().getTime();
return 1+(int) (dt/(7L*24L*3600L*1000L));
}
private static int timeZoneOffset(Calendar d) {
int localStandarTimeMillis = (d.get(Calendar.HOUR_OF_DAY)*3600+d.get(Calendar.MINUTE)*60+d.get(Calendar.SECOND))
*1000;
return d.getTimeZone().getOffset(1, d.get(Calendar.YEAR), d.get(Calendar.MONTH), d.get(Calendar.DAY_OF_MONTH),
d.get(Calendar.DAY_OF_WEEK), localStandarTimeMillis)/1000;
}
private boolean isDaylightSavingsTime(Calendar d) {
return timeZoneOffset(d) != d.getTimeZone().getRawOffset()/1000;
}
/**
* This function is equivalent to the C function system. It passes command
* to be executed by an operating system shell. It returns a status code,
* which is system-dependent. If command is absent, then it returns nonzero
* if a shell is available and zero otherwise.
*
* @param command command to pass to the system
*/
protected Varargs execute(String command) {
return varargsOf(NIL, valueOf("exit"), ONE);
}
/**
* Calls the C function exit, with an optional code, to terminate the host
* program.
*
* @param code
*/
protected void exit(int code) {
System.exit(code);
}
/**
* Returns the value of the process environment variable varname, or the
* System property value for varname, or null if the variable is not defined
* in either environment.
*
* The default implementation, which is used by the JmePlatform, only
* queryies System.getProperty().
*
* The JsePlatform overrides this behavior and returns the environment
* variable value using System.getenv() if it exists, or the System property
* value if it does not.
*
* A SecurityException may be thrown if access is not allowed for 'varname'.
*
* @param varname
* @return String value, or null if not defined
*/
protected String getenv(String varname) {
return System.getProperty(varname);
}
/**
* Deletes the file or directory with the given name. Directories must be
* empty to be removed. If this function fails, it throws and IOException
*
* @param filename
* @throws IOException if it fails
*/
protected void remove(String filename) throws IOException {
throw new IOException("not implemented");
}
/**
* Renames file or directory named oldname to newname. If this function
* fails,it throws and IOException
*
* @param oldname old file name
* @param newname new file name
* @throws IOException if it fails
*/
protected void rename(String oldname, String newname) throws IOException {
throw new IOException("not implemented");
}
/**
* Sets the current locale of the program. locale is a string specifying a
* locale; category is an optional string describing which category to
* change: "all", "collate", "ctype", "monetary", "numeric", or "time"; the
* default category is "all".
*
* If locale is the empty string, the current locale is set to an
* implementation- defined native locale. If locale is the string "C", the
* current locale is set to the standard C locale.
*
* When called with null as the first argument, this function only returns
* the name of the current locale for the given category.
*
* @param locale
* @param category
* @return the name of the new locale, or null if the request cannot be
* honored.
*/
protected String setlocale(String locale, String category) {
return "C";
}
/**
* Returns the current time when called without arguments, or a time
* representing the date and time specified by the given table. This table
* must have fields year, month, and day, and may have fields hour, min,
* sec, and isdst (for a description of these fields, see the os.date
* function).
*
* @param table
* @return long value for the time
*/
protected long time(LuaTable table) {
java.util.Date d;
if (table == null) {
d = new java.util.Date();
} else {
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, table.get("year").checkint());
c.set(Calendar.MONTH, table.get("month").checkint()-1);
c.set(Calendar.DAY_OF_MONTH, table.get("day").checkint());
c.set(Calendar.HOUR_OF_DAY, table.get("hour").optint(12));
c.set(Calendar.MINUTE, table.get("min").optint(0));
c.set(Calendar.SECOND, table.get("sec").optint(0));
c.set(Calendar.MILLISECOND, 0);
d = c.getTime();
}
return d.getTime()/1000L;
}
/**
* Returns a string with a file name that can be used for a temporary file.
* The file must be explicitly opened before its use and explicitly removed
* when no longer needed.
*
* On some systems (POSIX), this function also creates a file with that
* name, to avoid security risks. (Someone else might create the file with
* wrong permissions in the time between getting the name and creating the
* file.) You still have to open the file to use it and to remove it (even
* if you do not use it).
*
* @return String filename to use
*/
protected String tmpname() {
synchronized (OsLib.class) {
return TMP_PREFIX+tmpnames+++TMP_SUFFIX;
}
}
}

View File

@@ -22,6 +22,7 @@
package org.luaj.vm2.lib;
import java.io.InputStream;
import java.nio.file.FileSystems;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaFunction;
@@ -31,56 +32,73 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the lua standard package and module
* library functions.
* Subclass of {@link LibFunction} which implements the lua standard package and
* module library functions.
*
* <h3>Lua Environment Variables</h3>
* The following variables are available to lua scrips when this library has been loaded:
* <h3>Lua Environment Variables</h3> The following variables are available to
* lua scrips when this library has been loaded:
* <ul>
* <li><code>"package.loaded"</code> Lua table of loaded modules.
* <li><code>"package.path"</code> Search path for lua scripts.
* <li><code>"package.preload"</code> Lua table of uninitialized preload functions.
* <li><code>"package.searchers"</code> Lua table of functions that search for object to load.
* <li><code>"package.preload"</code> Lua table of uninitialized preload
* functions.
* <li><code>"package.searchers"</code> Lua table of functions that search for
* object to load.
* </ul>
*
* <h3>Java Environment Variables</h3>
* These Java environment variables affect the library behavior:
* <h3>Java Environment Variables</h3> These Java environment variables affect
* the library behavior:
* <ul>
* <li><code>"luaj.package.path"</code> Initial value for <code>"package.path"</code>. Default value is <code>"?.lua"</code>
* <li><code>"luaj.package.path"</code> Initial value for
* <code>"package.path"</code>. Default value is <code>"?.lua"</code>
* </ul>
*
* <h3>Loading</h3>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
* <h3>Loading</h3> Typically, this library is included as part of a call to
* either {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {@code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println( globals.get("require").call"foo") );
* } </pre>
* }
* </pre>
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* System.out.println(globals.get("require").call("foo"));
* } </pre>
* <h3>Limitations</h3>
* This library has been implemented to match as closely as possible the behavior in the corresponding library in C.
* However, the default filesystem search semantics are different and delegated to the bas library
* as outlined in the {@link BaseLib} and {@link org.luaj.vm2.lib.jse.JseBaseLib} documentation.
* }
* </pre>
*
* <h3>Limitations</h3> This library has been implemented to match as closely as
* possible the behavior in the corresponding library in C. However, the default
* filesystem search semantics are different and delegated to the bas library as
* outlined in the {@link BaseLib} and {@link org.luaj.vm2.lib.jse.JseBaseLib}
* documentation.
* <p>
*
* @see LibFunction
* @see BaseLib
* @see org.luaj.vm2.lib.jse.JseBaseLib
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.3">Lua 5.2 Package Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.3">Lua 5.2 Package
* Lib Reference</a>
*/
public class PackageLib extends TwoArgFunction {
/** The default value to use for package.path. This can be set with the system property
* <code>"luaj.package.path"</code>, and is <code>"?.lua"</code> by default. */
/**
* The default value to use for package.path. This can be set with the
* system property <code>"luaj.package.path"</code>, and is
* <code>"?.lua"</code> by default.
*/
public static final String DEFAULT_LUA_PATH;
static {
String path = null;
@@ -101,6 +119,7 @@ public class PackageLib extends TwoArgFunction {
static final LuaString _PATH = valueOf("path");
static final LuaString _SEARCHPATH = valueOf("searchpath");
static final LuaString _SEARCHERS = valueOf("searchers");
static final LuaString _SEEALL = valueOf("seeall");
/** The globals that were used to load this library. */
Globals globals;
@@ -111,25 +130,35 @@ public class PackageLib extends TwoArgFunction {
/** Loader that loads from {@code preload} table if found there */
public preload_searcher preload_searcher;
/** Loader that loads as a lua script using the lua path currently in {@link path} */
/**
* Loader that loads as a lua script using the lua path currently in
* {@link path}
*/
public lua_searcher lua_searcher;
/** Loader that loads as a Java class. Class must have public constructor and be a LuaValue. */
/**
* Loader that loads as a Java class. Class must have public constructor and
* be a LuaValue.
*/
public java_searcher java_searcher;
private static final LuaString _SENTINEL = valueOf("\u0001");
private static final String FILE_SEP = System.getProperty("file.separator");
private static final String FILE_SEP = FileSystems.getDefault().getSeparator();
public PackageLib() {}
/** Perform one-time initialization on the library by adding package functions
* to the supplied environment, and returning it as the return value.
* It also creates the package.preload and package.loaded tables for use by
* other libraries.
/**
* Perform one-time initialization on the library by adding package
* functions to the supplied environment, and returning it as the return
* value. It also creates the package.preload and package.loaded tables for
* use by other libraries.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, typically a Globals instance.
* @param env the environment to load into, typically a Globals
* instance.
*/
@Override
public LuaValue call(LuaValue modname, LuaValue env) {
globals = env.checkglobals();
globals.set("require", new require());
@@ -139,11 +168,13 @@ public class PackageLib extends TwoArgFunction {
package_.set(_PATH, LuaValue.valueOf(DEFAULT_LUA_PATH));
package_.set(_LOADLIB, new loadlib());
package_.set(_SEARCHPATH, new searchpath());
package_.set(_SEEALL, new seeall());
LuaTable searchers = new LuaTable();
searchers.set(1, preload_searcher = new preload_searcher());
searchers.set(2, lua_searcher = new lua_searcher());
searchers.set(3, java_searcher = new java_searcher());
package_.set(_SEARCHERS, searchers);
package_.set("config", FILE_SEP + "\n;\n?\n!\n-\n");
package_.get(_LOADED).set("package", package_);
env.set("package", package_);
globals.package_ = this;
@@ -155,13 +186,15 @@ public class PackageLib extends TwoArgFunction {
package_.get(_LOADED).set(name, value);
}
/** Set the lua path used by this library instance to a new value.
* Merely sets the value of {@link path} to be used in subsequent searches. */
/**
* Set the lua path used by this library instance to a new value. Merely
* sets the value of {@link path} to be used in subsequent searches.
*/
public void setLuaPath(String newLuaPath) {
package_.set(_PATH, LuaValue.valueOf(newLuaPath));
}
@Override
public String tojstring() {
return "package";
}
@@ -171,31 +204,37 @@ public class PackageLib extends TwoArgFunction {
/**
* require (modname)
*
* Loads the given module. The function starts by looking into the package.loaded table
* to determine whether modname is already loaded. If it is, then require returns the value
* stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module.
* Loads the given module. The function starts by looking into the
* package.loaded table to determine whether modname is already loaded. If
* it is, then require returns the value stored at package.loaded[modname].
* Otherwise, it tries to find a loader for the module.
*
* To find a loader, require is guided by the package.searchers sequence.
* By changing this sequence, we can change how require looks for a module.
* The following explanation is based on the default configuration for package.searchers.
* To find a loader, require is guided by the package.searchers sequence. By
* changing this sequence, we can change how require looks for a module. The
* following explanation is based on the default configuration for
* package.searchers.
*
* First require queries package.preload[modname]. If it has a value, this value
* (which should be a function) is the loader. Otherwise require searches for a Lua loader using
* the path stored in package.path. If that also fails, it searches for a Java loader using
* the classpath, using the public default constructor, and casting the instance to LuaFunction.
* First require queries package.preload[modname]. If it has a value, this
* value (which should be a function) is the loader. Otherwise require
* searches for a Lua loader using the path stored in package.path. If that
* also fails, it searches for a Java loader using the classpath, using the
* public default constructor, and casting the instance to LuaFunction.
*
* Once a loader is found, require calls the loader with two arguments: modname and an extra value
* dependent on how it got the loader. If the loader came from a file, this extra value is the file name.
* If the loader is a Java instance of LuaFunction, this extra value is the environment.
* If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname].
* If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname],
* then require assigns true to this entry.
* In any case, require returns the final value of package.loaded[modname].
* Once a loader is found, require calls the loader with two arguments:
* modname and an extra value dependent on how it got the loader. If the
* loader came from a file, this extra value is the file name. If the loader
* is a Java instance of LuaFunction, this extra value is the environment.
* If the loader returns any non-nil value, require assigns the returned
* value to package.loaded[modname]. If the loader does not return a non-nil
* value and has not assigned any value to package.loaded[modname], then
* require assigns true to this entry. In any case, require returns the
* final value of package.loaded[modname].
*
* If there is any error loading or running the module, or if it cannot find any loader for the module,
* then require raises an error.
* If there is any error loading or running the module, or if it cannot find
* any loader for the module, then require raises an error.
*/
public class require extends OneArgFunction {
@Override
public LuaValue call(LuaValue arg) {
LuaString name = arg.checkstring();
LuaValue loaded = package_.get(_LOADED);
@@ -236,23 +275,24 @@ public class PackageLib extends TwoArgFunction {
}
public static class loadlib extends VarArgFunction {
public Varargs loadlib( Varargs args ) {
@Override
public Varargs invoke(Varargs args) {
args.checkstring(1);
return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent"));
}
}
public class preload_searcher extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
LuaString name = args.checkstring(1);
LuaValue val = package_.get(_PRELOAD).get(name);
return val.isnil()?
valueOf("\n\tno field package.preload['"+name+"']"):
val;
return val.isnil()? valueOf("\n\tno field package.preload['" + name + "']"): val;
}
}
public class lua_searcher extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
LuaString name = args.checkstring(1);
@@ -280,6 +320,7 @@ public class PackageLib extends TwoArgFunction {
}
public class searchpath extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
String name = args.checkjstring(1);
String path = args.checkjstring(2);
@@ -310,7 +351,10 @@ public class PackageLib extends TwoArgFunction {
// try opening the file
InputStream is = globals.finder.findResource(filename);
if (is != null) {
try { is.close(); } catch ( java.io.IOException ioe ) {}
try {
is.close();
} catch (java.io.IOException ioe) {
}
return valueOf(filename);
}
@@ -323,7 +367,18 @@ public class PackageLib extends TwoArgFunction {
}
}
public class seeall extends OneArgFunction {
@Override
public LuaValue call(LuaValue arg) {
LuaTable mt = new LuaTable();
mt.set(LuaValue.INDEX, globals);
arg.checktable().setmetatable(mt);
return LuaValue.NONE;
}
}
public class java_searcher extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
String name = args.checkjstring(1);
String classname = toClassname(name);
@@ -351,13 +406,11 @@ public class PackageLib extends TwoArgFunction {
j -= 4;
for (int k = 0; k < j; k++) {
char c = filename.charAt(k);
if ( (!isClassnamePart(c)) || (c=='/') || (c=='\\') ) {
if (!isClassnamePart(c) || c == '/' || c == '\\') {
StringBuffer sb = new StringBuffer(j);
for (int i = 0; i < j; i++) {
c = filename.charAt(i);
sb.append(
(isClassnamePart(c))? c:
((c=='/') || (c=='\\'))? '.': '_' );
sb.append(isClassnamePart(c)? c: c == '/' || c == '\\'? '.': '_');
}
return sb.toString();
}
@@ -366,7 +419,7 @@ public class PackageLib extends TwoArgFunction {
}
private static final boolean isClassnamePart(char c) {
if ( (c>='a'&&c<='z') || (c>='A'&&c<='Z') || (c>='0'&&c<='9') )
if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9')
return true;
switch (c) {
case '.':

View File

@@ -28,16 +28,17 @@ import org.luaj.vm2.Globals;
/**
* Interface for opening application resource files such as scripts sources.
* <p>
* This is used by required to load files that are part of
* the application, and implemented by BaseLib
* for both the Jme and Jse platforms.
* This is used by required to load files that are part of the application, and
* implemented by BaseLib for both the Jme and Jse platforms.
* <p>
* The Jme version of base lib {@link BaseLib}
* implements {@link Globals#finder} via {@link Class#getResourceAsStream(String)},
* while the Jse version {@link org.luaj.vm2.lib.jse.JseBaseLib} implements it using {@link java.io.File#File(String)}.
* The Jme version of base lib {@link BaseLib} implements {@link Globals#finder}
* via {@link Class#getResourceAsStream(String)}, while the Jse version
* {@link org.luaj.vm2.lib.jse.JseBaseLib} implements it using
* {@link java.io.File#File(String)}.
* <p>
* The io library does not use this API for file manipulation.
* <p>
*
* @see BaseLib
* @see Globals#finder
* @see org.luaj.vm2.lib.jse.JseBaseLib
@@ -55,5 +56,5 @@ public interface ResourceFinder {
* @param filename
* @return InputStream, or null if not found.
*/
public InputStream findResource( String filename );
InputStream findResource(String filename);
}

View File

@@ -24,12 +24,8 @@ package org.luaj.vm2.lib;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.luaj.vm2.Buffer;
import org.luaj.vm2.LuaClosure;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
import org.luaj.vm2.*;
import org.luaj.vm2.compat.JavaCompat;
import org.luaj.vm2.compiler.DumpState;
/**
@@ -83,8 +79,8 @@ public class StringLib extends TwoArgFunction {
*/
public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable string = new LuaTable();
string.set("byte", new byte_());
string.set("char", new char_());
string.set("byte", new _byte());
string.set("char", new _char());
string.set("dump", new dump());
string.set("find", new find());
string.set("format", new format());
@@ -117,7 +113,7 @@ public class StringLib extends TwoArgFunction {
*
* @param args the calling args
*/
static final class byte_ extends VarArgFunction {
static final class _byte extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaString s = args.checkstring(1);
int l = s.m_length;
@@ -148,7 +144,7 @@ public class StringLib extends TwoArgFunction {
*
* @param args the calling VM
*/
static final class char_ extends VarArgFunction {
static final class _char extends VarArgFunction {
public Varargs invoke(Varargs args) {
int n = args.narg();
byte[] bytes = new byte[n];
@@ -274,16 +270,63 @@ public class StringLib extends TwoArgFunction {
case 'f':
case 'g':
case 'G':
case 'a':
case 'A':
double j = args.checkdouble(arg);
if (Double.isNaN(j) || Double.isInfinite(j)) {
String nprefix = "";
if (JavaCompat.INSTANCE.doubleToRawLongBits(j) < 0)
nprefix = "-";
else if (fdsc.explicitPlus)
nprefix = "+";
else if (fdsc.space)
nprefix = " ";
String bstr = Double.isNaN(j) ? LuaDouble.JSTR_NAN : LuaDouble.JSTR_POSINF;
if (fdsc.conversion == 'E' || fdsc.conversion == 'G')
bstr = bstr.toUpperCase();
fdsc.precision = -1;
fdsc.zeroPad = false;
fdsc.format(result, valueOf(nprefix + bstr));
} else if ((fdsc.conversion == 'g' || fdsc.conversion == 'G') && fdsc.precision == -1) {
//TODO: This gives a slightly different format but is better than nothing
String nprefix = "";
if (j >= 0) {
if (fdsc.explicitPlus)
nprefix = "+";
else if (fdsc.space)
nprefix = " ";
}
String bstr = Double.toString(j);
if (fdsc.conversion == 'G')
bstr = bstr.toUpperCase();
else
bstr = bstr.toLowerCase();
fdsc.format(result, valueOf(nprefix + bstr));
} else
fdsc.format(result, args.checkdouble(arg));
break;
case 'q':
addquoted( result, args.checkstring( arg ) );
break;
case 's': {
LuaString s = args.checkstring( arg );
LuaValue argv = args.checkvalue( arg );
LuaString s;
LuaValue h = argv.metatag(TOSTRING);
if ( ! h.isnil() ) {
LuaValue v = h.call(argv).tostring();
return !v.isnil() ? v : StringLib.valueOf("(null)");
} else {
LuaValue v = argv.tostring();
if ( ! v.isnil() ) {
s = v.checkstring();
} else {
s = StringLib.valueOf(argv.tojstring());
}
}
if ( fdsc.precision == -1 && s.length() >= 100 ) {
result.append( s );
} else {
fdsc.zeroPad = false;
fdsc.format( result, s );
}
} break;
@@ -375,8 +418,8 @@ public class StringLib extends TwoArgFunction {
}
}
precision = -1;
if ( c == '.' ) {
precision = 0;
c = ( (p < n) ? strfrmt.luaByte( p++ ) : 0 );
if ( Character.isDigit( (char) c ) ) {
precision = c - '0';
@@ -386,20 +429,32 @@ public class StringLib extends TwoArgFunction {
c = ( (p < n) ? strfrmt.luaByte( p++ ) : 0 );
}
}
}
} else
precision = -1;
if ( Character.isDigit( (char) c ) )
error("invalid format (width or precision too long)");
if ( width == -1 ) {
// default width overrides '-' and '0'
leftAdjust = false;
zeroPad = false;
} else
zeroPad &= !leftAdjust; // '-' overrides '0'
space &= !explicitPlus; // '+' overrides ' '
conversion = c;
length = p - start;
src = strfrmt.substring(start - 1, p).tojstring();
}
public void format(Buffer buf, byte c) {
// TODO: not clear that any of width, precision, or flags apply here.
if (!leftAdjust)
pad(buf, ' ', width - 1);
buf.append(c);
if (leftAdjust)
pad(buf, ' ', width - 1);
}
public void format(Buffer buf, long number) {
@@ -430,9 +485,11 @@ public class StringLib extends TwoArgFunction {
int ndigits = minwidth;
int nzeros;
boolean allowPlusSpace = conversion == 'd' || conversion == 'i';
if ( number < 0 ) {
ndigits--;
} else if ( explicitPlus || space ) {
} else if ( allowPlusSpace && (explicitPlus || space) ) {
minwidth++;
}
@@ -454,12 +511,26 @@ public class StringLib extends TwoArgFunction {
buf.append( (byte)'-' );
digits = digits.substring( 1 );
}
} else if ( explicitPlus ) {
} else if ( allowPlusSpace && explicitPlus ) {
buf.append( (byte)'+' );
} else if ( space ) {
} else if ( allowPlusSpace && space ) {
buf.append( (byte)' ' );
}
if (alternateForm) {
switch (conversion) {
case 'o':
buf.append((byte) '0');
break;
case 'x':
buf.append("0x");
break;
case 'X':
buf.append("0X");
break;
}
}
if ( nzeros > 0 )
pad( buf, '0', nzeros );
@@ -470,14 +541,40 @@ public class StringLib extends TwoArgFunction {
}
public void format(Buffer buf, double x) {
buf.append( StringLib.this.format(src, x) );
// TODO: Java does not support alternateForm with 'g'
String sFormat = "%";
if (leftAdjust)
sFormat += ("-");
if (explicitPlus)
sFormat += ("+");
if (space)
sFormat += (" ");
if (alternateForm && conversion != 'g' && conversion != 'G')
sFormat += ("#");
if (zeroPad)
sFormat += ("0");
if (width != -1)
sFormat += (width);
if (precision != -1)
sFormat += (".") + (precision);
sFormat += ((char) conversion);
buf.append( StringLib.this.format(sFormat, x) );
}
public void format(Buffer buf, LuaString s) {
int nullindex = s.indexOf( (byte)'\0', 0 );
if ( nullindex != -1 )
s = s.substring( 0, nullindex );
int newLength = precision == -1 ? s.length() : Math.min(precision, s.length());
if (!leftAdjust)
pad(buf, zeroPad ? '0' : ' ', width - newLength);
buf.append(s);
if (leftAdjust)
pad(buf, ' ', width - newLength);
}
public final void pad(Buffer buf, char c, int n) {
@@ -527,19 +624,20 @@ public class StringLib extends TwoArgFunction {
private final int srclen;
private final MatchState ms;
private int soffset;
private int lastmatch;
public GMatchAux(Varargs args, LuaString src, LuaString pat) {
this.srclen = src.length();
this.ms = new MatchState(args, src, pat);
this.soffset = 0;
this.lastmatch = -1;
}
public Varargs invoke(Varargs args) {
for ( ; soffset<=srclen; soffset++ ) {
ms.reset();
int res = ms.match(soffset, 0);
if ( res >=0 ) {
if ( res >=0 && res != lastmatch ) {
int soff = soffset;
soffset = res;
if (soff == res) soffset++; /* empty match? go at least one position */
lastmatch = soffset = res;
return ms.push_captures( true, soff, res );
}
}
@@ -598,8 +696,11 @@ public class StringLib extends TwoArgFunction {
LuaString src = args.checkstring( 1 );
final int srclen = src.length();
LuaString p = args.checkstring( 2 );
int lastmatch = -1; /* end of last match */
LuaValue repl = args.arg( 3 );
int max_s = args.optint( 4, srclen + 1 );
if (max_s < 0)
max_s = srclen+1;
final boolean anchor = p.length() > 0 && p.charAt( 0 ) == '^';
Buffer lbuf = new Buffer( srclen );
@@ -610,18 +711,15 @@ public class StringLib extends TwoArgFunction {
while ( n < max_s ) {
ms.reset();
int res = ms.match( soffset, anchor ? 1 : 0 );
if ( res != -1 ) {
if ( res != -1 && res != lastmatch ) { /* match? */
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 )
soffset = res;
else if ( soffset < srclen )
else if ( soffset < srclen ) /* otherwise, skip one character */
lbuf.append( (byte) src.luaByte( soffset++ ) );
else
break;
if ( anchor )
break;
else break; /* end of subject */
if ( anchor ) break;
}
lbuf.append( src.substring( soffset, srclen ) );
return varargsOf(lbuf.tostring(), valueOf(n));
@@ -669,19 +767,32 @@ public class StringLib extends TwoArgFunction {
}
/**
* string.rep (s, n)
* string.rep (s, n [, sep])
*
* Returns a string that is the concatenation of n copies of the string s.
* Returns a string that is the concatenation of n copies of the string s
* separated by the string sep. The default value for sep is the empty
* string (that is, no separator).
*/
static final class rep extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaString s = args.checkstring(1);
int n = args.checkint(2);
final byte[] bytes = new byte[ s.length() * n ];
LuaString sep = args.optstring(3, EMPTYSTRING);
if (n <= 0)
return EMPTYSTRING;
int len = s.length();
for ( int offset = 0; offset < bytes.length; offset += len ) {
int lsep = sep.length();
final byte[] bytes = new byte[len * n + lsep * (n - 1)];
int offset = 0;
while (n-- > 1) {
s.copyInto(0, bytes, offset, len);
offset += len;
if (lsep > 0) {
sep.copyInto(0, bytes, offset, lsep);
offset += lsep;
}
}
s.copyInto(0, bytes, offset, len);
return LuaString.valueUsing(bytes);
}
}
@@ -804,6 +915,8 @@ public class StringLib extends TwoArgFunction {
private static final LuaString SPECIALS = valueOf("^$*+?.([%-");
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_POSITION = -2;
@@ -821,7 +934,7 @@ public class StringLib extends TwoArgFunction {
static {
CHAR_TABLE = new byte[256];
for ( int i = 0; i < 256; ++i ) {
for ( int i = 0; i < 128; ++i ) {
final char c = (char) i;
CHAR_TABLE[i] = (byte)( ( Character.isDigit( c ) ? MASK_DIGIT : 0 ) |
( Character.isLowerCase( c ) ? MASK_LOWERCASE : 0 ) |
@@ -830,7 +943,7 @@ public class StringLib extends TwoArgFunction {
if ( ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) || ( c >= '0' && c <= '9' ) ) {
CHAR_TABLE[i] |= MASK_HEXDIGIT;
}
if ( ( c >= '!' && c <= '/' ) || ( c >= ':' && c <= '@' ) ) {
if ( ( c >= '!' && c <= '/' ) || ( c >= ':' && c <= '@' ) || ( c >= '[' && c <= '`' ) || ( c >= '{' && c <= '~' ) ) {
CHAR_TABLE[i] |= MASK_PUNCT;
}
if ( ( CHAR_TABLE[i] & ( MASK_LOWERCASE | MASK_UPPERCASE ) ) != 0 ) {
@@ -842,11 +955,12 @@ public class StringLib extends TwoArgFunction {
CHAR_TABLE['\r'] |= MASK_SPACE;
CHAR_TABLE['\n'] |= MASK_SPACE;
CHAR_TABLE['\t'] |= MASK_SPACE;
CHAR_TABLE[0x0C /* '\v' */ ] |= MASK_SPACE;
CHAR_TABLE[0x0B /* '\v' */ ] |= MASK_SPACE;
CHAR_TABLE['\f'] |= MASK_SPACE;
};
static class MatchState {
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
final LuaString s;
final LuaString p;
final Varargs args;
@@ -861,10 +975,12 @@ public class StringLib extends TwoArgFunction {
this.level = 0;
this.cinit = new int[ MAX_CAPTURES ];
this.clen = new int[ MAX_CAPTURES ];
this.matchdepth = MAXCCALLS;
}
void reset() {
level = 0;
this.matchdepth = MAXCCALLS;
}
private void add_s( Buffer lbuf, LuaString news, int soff, int e ) {
@@ -939,7 +1055,7 @@ public class StringLib extends TwoArgFunction {
if ( i == 0 ) {
return s.substring( soff, end );
} else {
return error( "invalid capture index" );
return error( "invalid capture index %" + (i + 1) );
}
} else {
int l = clen[i];
@@ -958,7 +1074,7 @@ public class StringLib extends TwoArgFunction {
private int check_capture( int l ) {
l -= '1';
if ( l < 0 || l >= level || this.clen[l] == CAP_UNFINISHED ) {
error("invalid capture index");
error("invalid capture index %" + (l + 1));
}
return l;
}
@@ -1008,9 +1124,10 @@ public class StringLib extends TwoArgFunction {
case 'c': res = ( cdata & MASK_CONTROL ) != 0; break;
case 'p': res = ( cdata & MASK_PUNCT ) != 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 '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;
}
return ( lcl == cl ) ? res : !res;
@@ -1052,6 +1169,8 @@ public class StringLib extends TwoArgFunction {
* where match ends, otherwise returns -1.
*/
int match( int soffset, int poffset ) {
if (matchdepth-- == 0) error("pattern too complex");
try {
while ( true ) {
// Check if we are at the end of the pattern -
// equivalent to the '\0' case in the C version, but our pattern
@@ -1078,7 +1197,7 @@ public class StringLib extends TwoArgFunction {
case 'f': {
poffset += 2;
if ( poffset == p.length() || p.luaByte( poffset ) != '[' ) {
error("Missing '[' after '%f' in pattern");
error("missing '[' after '%f' in pattern");
}
int ep = classend( poffset );
int previous = ( soffset == 0 ) ? '\0' : s.luaByte( soffset - 1 );
@@ -1128,6 +1247,9 @@ public class StringLib extends TwoArgFunction {
continue;
}
}
} finally {
matchdepth++;
}
}
int max_expand( int soff, int poff, int ep ) {
@@ -1191,7 +1313,7 @@ public class StringLib extends TwoArgFunction {
int matchbalance( int soff, int poff ) {
final int plen = p.length();
if ( poff == plen || poff + 1 == plen ) {
error( "unbalanced pattern" );
error( "malformed pattern (missing arguments to '%b')" );
}
final int slen = s.length();
if ( soff >= slen )

View File

@@ -26,41 +26,58 @@ import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the lua standard {@code table}
* library.
* Subclass of {@link LibFunction} which implements the lua standard
* {@code table} library.
*
* <p>
* Typically, this library is included as part of a call to either
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
* {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
*
* <pre>
* {
* &#64;code
* Globals globals = JsePlatform.standardGlobals();
* System.out.println(globals.get("table").get("length").call(LuaValue.tableOf()));
* } </pre>
* }
* </pre>
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* To instantiate and use it directly, link it into your globals table via
* {@link LuaValue#load(LuaValue)} using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JseBaseLib());
* globals.load(new PackageLib());
* globals.load(new TableLib());
* System.out.println(globals.get("table").get("length").call(LuaValue.tableOf()));
* } </pre>
* }
* </pre>
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.5">Lua 5.2 Table Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.5">Lua 5.2 Table
* Lib Reference</a>
*/
public class TableLib extends TwoArgFunction {
/** Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied environment,
* adding the table to package.loaded, and returning table as the return value.
/**
* Perform one-time initialization on the library by creating a table
* containing the library functions, adding that table to the supplied
* environment, adding the table to package.loaded, and returning table as
* the return value.
*
* @param modname the module name supplied if this is loaded via 'require'.
* @param env the environment to load into, typically a Globals instance.
* @param env the environment to load into, typically a Globals
* instance.
*/
@Override
public LuaValue call(LuaValue modname, LuaValue env) {
LuaTable table = new LuaTable();
table.set("concat", new concat());
@@ -70,27 +87,29 @@ public class TableLib extends TwoArgFunction {
table.set("sort", new sort());
table.set("unpack", new unpack());
env.set("table", table);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("table", table);
if (!env.get("package").isnil())
env.get("package").get("loaded").set("table", table);
return NIL;
}
static class TableLibFunction extends LibFunction {
public LuaValue call() {
return argerror(1, "table expected, got no value");
}
}
// "concat" (table [, sep [, i [, j]]]) -> string
static class concat extends TableLibFunction {
@Override
public LuaValue call(LuaValue list) {
return list.checktable().concat(EMPTYSTRING, 1, list.length());
}
@Override
public LuaValue call(LuaValue list, LuaValue sep) {
return list.checktable().concat(sep.checkstring(), 1, list.length());
}
@Override
public LuaValue call(LuaValue list, LuaValue sep, LuaValue i) {
return list.checktable().concat(sep.checkstring(), i.checkint(), list.length());
}
@Override
public LuaValue call(LuaValue list, LuaValue sep, LuaValue i, LuaValue j) {
return list.checktable().concat(sep.checkstring(), i.checkint(), j.checkint());
}
@@ -98,26 +117,33 @@ public class TableLib extends TwoArgFunction {
// "insert" (table, [pos,] value)
static class insert extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
switch (args.narg()) {
case 0: case 1: {
return argerror(2, "value expected");
}
case 2: {
LuaTable table = args.arg1().checktable();
LuaTable table = args.checktable(1);
table.insert(table.length()+1, args.arg(2));
return NONE;
}
default: {
args.arg1().checktable().insert(args.checkint(2),args.arg(3));
case 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;
}
default: {
return error("wrong number of arguments to 'table.insert': " + args.narg() + " (must be 2 or 3)");
}
}
}
}
// "pack" (...) -> table
static class pack extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
LuaValue t = tableOf(args, 1);
t.set("n", args.narg());
@@ -127,30 +153,35 @@ public class TableLib extends TwoArgFunction {
// "remove" (table [, pos]) -> removed-ele
static class remove extends VarArgFunction {
@Override
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])
static class sort extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
args.arg1().checktable().sort(
args.arg(2).isnil()? NIL: args.arg(2).checkfunction());
args.checktable(1).sort(args.isnil(2)? NIL: args.checkfunction(2));
return NONE;
}
}
// "unpack", // (list [,i [,j]]) -> result1, ...
static class unpack extends VarArgFunction {
@Override
public Varargs invoke(Varargs args) {
LuaTable t = args.checktable(1);
switch (args.narg()) {
case 1: return t.unpack();
case 2: return t.unpack(args.checkint(2));
default: return t.unpack(args.checkint(2), args.checkint(3));
}
// do not waste resource for calc rawlen if arg3 is not nil
int len = args.arg(3).isnil()? t.length(): 0;
return t.unpack(args.optint(2, 1), args.optint(3, len));
}
}
}

View File

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

View File

@@ -24,21 +24,24 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/** Abstract base class for Java function implementations that take two arguments and
* return one value.
/**
* Abstract base class for Java function implementations that take two arguments
* and return one value.
* <p>
* Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue,LuaValue)} to complete this class,
* simplifying development.
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
* are routed through this method by this class,
* Subclasses need only implement
* {@link LuaValue#call(LuaValue,LuaValue,LuaValue)} to complete this class,
* simplifying development. All other uses of {@link #call()},
* {@link #invoke(Varargs)},etc, are routed through this method by this class,
* dropping or extending arguments with {@code nil} values as required.
* <p>
* If more or less than three arguments are required,
* or variable argument or variable return values,
* then use one of the related function
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or {@link VarArgFunction}.
* If more or less than three arguments are required, or variable argument or
* variable return values, then use one of the related function
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or
* {@link VarArgFunction}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* See {@link LibFunction} for more information on implementation libraries and
* library functions.
*
* @see #call(LuaValue,LuaValue,LuaValue)
* @see LibFunction
* @see ZeroArgFunction
@@ -48,24 +51,29 @@ import org.luaj.vm2.Varargs;
*/
abstract public class ThreeArgFunction extends LibFunction {
@Override
abstract public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3);
/** Default constructor */
public ThreeArgFunction() {
}
@Override
public final LuaValue call() {
return call(NIL, NIL, NIL);
}
@Override
public final LuaValue call(LuaValue arg) {
return call(arg, NIL, NIL);
}
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return call(arg1, arg2, NIL);
}
@Override
public Varargs invoke(Varargs varargs) {
return call(varargs.arg1(), varargs.arg(2), varargs.arg(3));
}

View File

@@ -24,21 +24,24 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/** Abstract base class for Java function implementations that take two arguments and
* return one value.
/**
* Abstract base class for Java function implementations that take two arguments
* and return one value.
* <p>
* Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue)} to complete this class,
* simplifying development.
* All other uses of {@link #call()}, {@link #invoke(Varargs)},etc,
* are routed through this method by this class,
* dropping or extending arguments with {@code nil} values as required.
* Subclasses need only implement {@link LuaValue#call(LuaValue,LuaValue)} to
* complete this class, simplifying development. All other uses of
* {@link #call()}, {@link #invoke(Varargs)},etc, are routed through this method
* by this class, dropping or extending arguments with {@code nil} values as
* required.
* <p>
* If more or less than two arguments are required,
* or variable argument or variable return values,
* then use one of the related function
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
* If more or less than two arguments are required, or variable argument or
* variable return values, then use one of the related function
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link ThreeArgFunction}, or
* {@link VarArgFunction}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* See {@link LibFunction} for more information on implementation libraries and
* library functions.
*
* @see #call(LuaValue,LuaValue)
* @see LibFunction
* @see ZeroArgFunction
@@ -48,24 +51,29 @@ import org.luaj.vm2.Varargs;
*/
abstract public class TwoArgFunction extends LibFunction {
@Override
abstract public LuaValue call(LuaValue arg1, LuaValue arg2);
/** Default constructor */
public TwoArgFunction() {
}
@Override
public final LuaValue call() {
return call(NIL, NIL);
}
@Override
public final LuaValue call(LuaValue arg) {
return call(arg, NIL);
}
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return call(arg1, arg2);
}
@Override
public Varargs invoke(Varargs varargs) {
return call(varargs.arg1(), varargs.arg(2));
}

View File

@@ -24,20 +24,23 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/** Abstract base class for Java function implementations that takes varaiable arguments and
* returns multiple return values.
/**
* Abstract base class for Java function implementations that takes varaiable
* arguments and returns multiple return values.
* <p>
* Subclasses need only implement {@link LuaValue#invoke(Varargs)} to complete this class,
* simplifying development.
* All other uses of {@link #call(LuaValue)}, {@link #invoke()},etc,
* are routed through this method by this class,
* converting arguments to {@link Varargs} and
* dropping or extending return values with {@code nil} values as required.
* Subclasses need only implement {@link LuaValue#invoke(Varargs)} to complete
* this class, simplifying development. All other uses of
* {@link #call(LuaValue)}, {@link #invoke()},etc, are routed through this
* method by this class, converting arguments to {@link Varargs} and dropping or
* extending return values with {@code nil} values as required.
* <p>
* If between one and three arguments are required, and only one return value is returned,
* {@link ZeroArgFunction}, {@link OneArgFunction}, {@link TwoArgFunction}, or {@link ThreeArgFunction}.
* If between one and three arguments are required, and only one return value is
* returned, {@link ZeroArgFunction}, {@link OneArgFunction},
* {@link TwoArgFunction}, or {@link ThreeArgFunction}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* See {@link LibFunction} for more information on implementation libraries and
* library functions.
*
* @see #invoke(Varargs)
* @see LibFunction
* @see ZeroArgFunction
@@ -50,33 +53,39 @@ abstract public class VarArgFunction extends LibFunction {
public VarArgFunction() {
}
@Override
public LuaValue call() {
return invoke(NONE).arg1();
}
@Override
public LuaValue call(LuaValue arg) {
return invoke(arg).arg1();
}
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return invoke(varargsOf(arg1, arg2)).arg1();
}
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return invoke(varargsOf(arg1, arg2, arg3)).arg1();
}
/**
* Subclass responsibility.
* May not have expected behavior for tail calls.
* Should not be used if:
* - function has a possibility of returning a TailcallVarargs
* Subclass responsibility. May not have expected behavior for tail calls.
* Should not be used if: - function has a possibility of returning a
* TailcallVarargs
*
* @param args the arguments to the function call.
*/
@Override
public Varargs invoke(Varargs args) {
return onInvoke(args).eval();
}
@Override
public Varargs onInvoke(Varargs args) {
return invoke(args);
}

View File

@@ -24,19 +24,21 @@ package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/** Abstract base class for Java function implementations that take no arguments and
* return one value.
/**
* Abstract base class for Java function implementations that take no arguments
* and return one value.
* <p>
* Subclasses need only implement {@link LuaValue#call()} to complete this class,
* simplifying development.
* All other uses of {@link #call(LuaValue)}, {@link #invoke(Varargs)},etc,
* are routed through this method by this class.
* Subclasses need only implement {@link LuaValue#call()} to complete this
* class, simplifying development. All other uses of {@link #call(LuaValue)},
* {@link #invoke(Varargs)},etc, are routed through this method by this class.
* <p>
* If one or more arguments are required, or variable argument or variable return values,
* then use one of the related function
* {@link OneArgFunction}, {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
* If one or more arguments are required, or variable argument or variable
* return values, then use one of the related function {@link OneArgFunction},
* {@link TwoArgFunction}, {@link ThreeArgFunction}, or {@link VarArgFunction}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* See {@link LibFunction} for more information on implementation libraries and
* library functions.
*
* @see #call()
* @see LibFunction
* @see OneArgFunction
@@ -46,24 +48,29 @@ import org.luaj.vm2.Varargs;
*/
abstract public class ZeroArgFunction extends LibFunction {
@Override
abstract public LuaValue call();
/** Default constructor */
public ZeroArgFunction() {
}
@Override
public LuaValue call(LuaValue arg) {
return call();
}
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return call();
}
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return call();
}
@Override
public Varargs invoke(Varargs varargs) {
return call();
}

View File

@@ -21,33 +21,29 @@
******************************************************************************/
package org.luaj.vm2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.ByteArrayInputStream;
import junit.framework.TestCase;
import org.junit.jupiter.api.Test;
import org.luaj.vm2.Globals.BufferedStream;
public class BufferedStreamTest extends TestCase {
public BufferedStreamTest() {}
class BufferedStreamTest {
private BufferedStream NewBufferedStream(int buflen, String contents) {
return new BufferedStream(buflen, new ByteArrayInputStream(contents.getBytes()));
}
protected void setUp() throws Exception {
super.setUp();
}
public void testReadEmptyStream() throws java.io.IOException {
@Test
void testReadEmptyStream() throws java.io.IOException {
BufferedStream bs = NewBufferedStream(4, "");
assertEquals(-1, bs.read());
assertEquals(-1, bs.read(new byte[10]));
assertEquals(-1, bs.read(new byte[10], 0, 10));
}
public void testReadByte() throws java.io.IOException {
@Test
void testReadByte() throws java.io.IOException {
BufferedStream bs = NewBufferedStream(2, "abc");
assertEquals('a', bs.read());
assertEquals('b', bs.read());
@@ -55,7 +51,8 @@ public class BufferedStreamTest extends TestCase {
assertEquals(-1, bs.read());
}
public void testReadByteArray() throws java.io.IOException {
@Test
void testReadByteArray() throws java.io.IOException {
byte[] array = new byte[3];
BufferedStream bs = NewBufferedStream(4, "abcdef");
assertEquals(3, bs.read(array));
@@ -67,7 +64,8 @@ public class BufferedStreamTest extends TestCase {
assertEquals(-1, bs.read());
}
public void testReadByteArrayOffsetLength() throws java.io.IOException {
@Test
void testReadByteArrayOffsetLength() throws java.io.IOException {
byte[] array = new byte[10];
BufferedStream bs = NewBufferedStream(8, "abcdefghijklmn");
assertEquals(4, bs.read(array, 0, 4));
@@ -79,7 +77,8 @@ public class BufferedStreamTest extends TestCase {
assertEquals(-1, bs.read());
}
public void testMarkOffsetBeginningOfStream() throws java.io.IOException {
@Test
void testMarkOffsetBeginningOfStream() throws java.io.IOException {
byte[] array = new byte[4];
BufferedStream bs = NewBufferedStream(8, "abcdefghijkl");
assertEquals(true, bs.markSupported());
@@ -96,7 +95,8 @@ public class BufferedStreamTest extends TestCase {
assertEquals(-1, bs.read());
}
public void testMarkOffsetMiddleOfStream() throws java.io.IOException {
@Test
void testMarkOffsetMiddleOfStream() throws java.io.IOException {
byte[] array = new byte[4];
BufferedStream bs = NewBufferedStream(8, "abcdefghijkl");
assertEquals(true, bs.markSupported());

View File

@@ -0,0 +1,135 @@
/*******************************************************************************
* 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;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import java.lang.reflect.InvocationTargetException;
import org.junit.jupiter.api.Test;
import org.luaj.vm2.TypeTest.MyData;
import org.luaj.vm2.lib.ZeroArgFunction;
class LuaOperationsTest {
private final int sampleint = 77;
private final long samplelong = 123400000000L;
private final double sampledouble = 55.25;
private final String samplestringstring = "abcdef";
private final String samplestringint = String.valueOf(sampleint);
private final String samplestringlong = String.valueOf(samplelong);
private final String samplestringdouble = String.valueOf(sampledouble);
private final Object sampleobject = new Object();
private final MyData sampledata = new MyData();
private final LuaValue somenil = LuaValue.NIL;
private final LuaValue sometrue = LuaValue.TRUE;
private final LuaValue somefalse = LuaValue.FALSE;
private final LuaValue zero = LuaValue.ZERO;
private final LuaValue intint = LuaValue.valueOf(sampleint);
private final LuaValue longdouble = LuaValue.valueOf(samplelong);
private final LuaValue doubledouble = LuaValue.valueOf(sampledouble);
private final LuaValue stringstring = LuaValue.valueOf(samplestringstring);
private final LuaValue stringint = LuaValue.valueOf(samplestringint);
private final LuaValue stringlong = LuaValue.valueOf(samplestringlong);
private final LuaValue stringdouble = LuaValue.valueOf(samplestringdouble);
private final LuaTable table = LuaValue
.listOf(new LuaValue[] { LuaValue.valueOf("aaa"), LuaValue.valueOf("bbb") });
private final LuaValue somefunc = new ZeroArgFunction() {
@Override
public LuaValue call() { return NONE; }
};
private final LuaThread thread = new LuaThread(new Globals(), somefunc);
private final Prototype proto = new Prototype(1);
private final LuaClosure someclosure = new LuaClosure(proto, table);
private final LuaUserdata userdataobj = LuaValue.userdataOf(sampleobject);
private final LuaUserdata userdatacls = LuaValue.userdataOf(sampledata);
private void throwsLuaError(String methodName, Object obj) {
try {
LuaValue.class.getMethod(methodName).invoke(obj);
fail("failed to throw LuaError as required");
} catch (InvocationTargetException e) {
if (!(e.getTargetException() instanceof LuaError))
fail("not a LuaError: " + e.getTargetException());
return; // pass
} catch (Exception e) {
fail("bad exception: " + e);
}
}
private void throwsLuaError(String methodName, Object obj, Object arg) {
try {
LuaValue.class.getMethod(methodName, LuaValue.class).invoke(obj, arg);
fail("failed to throw LuaError as required");
} catch (InvocationTargetException e) {
if (!(e.getTargetException() instanceof LuaError))
fail("not a LuaError: " + e.getTargetException());
return; // pass
} catch (Exception e) {
fail("bad exception: " + e);
}
}
@Test
void testLen() {
throwsLuaError("len", somenil);
throwsLuaError("len", sometrue);
throwsLuaError("len", somefalse);
throwsLuaError("len", zero);
throwsLuaError("len", intint);
throwsLuaError("len", longdouble);
throwsLuaError("len", doubledouble);
assertEquals(LuaInteger.valueOf(samplestringstring.length()), stringstring.len());
assertEquals(LuaInteger.valueOf(samplestringint.length()), stringint.len());
assertEquals(LuaInteger.valueOf(samplestringlong.length()), stringlong.len());
assertEquals(LuaInteger.valueOf(samplestringdouble.length()), stringdouble.len());
assertEquals(LuaInteger.valueOf(2), table.len());
throwsLuaError("len", somefunc);
throwsLuaError("len", thread);
throwsLuaError("len", someclosure);
throwsLuaError("len", userdataobj);
throwsLuaError("len", userdatacls);
}
@Test
void testLength() {
throwsLuaError("length", somenil);
throwsLuaError("length", sometrue);
throwsLuaError("length", somefalse);
throwsLuaError("length", zero);
throwsLuaError("length", intint);
throwsLuaError("length", longdouble);
throwsLuaError("length", doubledouble);
assertEquals(samplestringstring.length(), stringstring.length());
assertEquals(samplestringint.length(), stringint.length());
assertEquals(samplestringlong.length(), stringlong.length());
assertEquals(samplestringdouble.length(), stringdouble.length());
assertEquals(2, table.length());
throwsLuaError("length", somefunc);
throwsLuaError("length", thread);
throwsLuaError("length", someclosure);
throwsLuaError("length", userdataobj);
throwsLuaError("length", userdatacls);
}
}

View File

@@ -0,0 +1,372 @@
/*******************************************************************************
* 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;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.luaj.vm2.TypeTest.MyData;
import org.luaj.vm2.lib.StringLib;
import org.luaj.vm2.lib.ThreeArgFunction;
import org.luaj.vm2.lib.TwoArgFunction;
import org.luaj.vm2.lib.ZeroArgFunction;
class MetatableTest {
private final String samplestring = "abcdef";
private final Object sampleobject = new Object();
private final MyData sampledata = new MyData();
private final LuaValue string = LuaValue.valueOf(samplestring);
private final LuaTable table = LuaValue.tableOf();
private final LuaFunction function = new ZeroArgFunction() {
@Override
public LuaValue call() { return NONE; }
};
private final LuaThread thread = new LuaThread(new Globals(), function);
private final LuaClosure closure = new LuaClosure(new Prototype(), new LuaTable());
private final LuaUserdata userdata = LuaValue.userdataOf(sampleobject);
private final LuaUserdata userdatamt = LuaValue.userdataOf(sampledata, table);
@BeforeEach
protected void setUp() throws Exception {
// needed for metatable ops to work on strings
new StringLib();
}
@AfterEach
protected void tearDown() throws Exception {
LuaBoolean.s_metatable = null;
LuaFunction.s_metatable = null;
LuaNil.s_metatable = null;
LuaNumber.s_metatable = null;
// LuaString.s_metatable = null;
LuaThread.s_metatable = null;
}
@Test
void testGetMetatable() {
assertEquals(null, LuaValue.NIL.getmetatable());
assertEquals(null, LuaValue.TRUE.getmetatable());
assertEquals(null, LuaValue.ONE.getmetatable());
// assertEquals( null, string.getmetatable() );
assertEquals(null, table.getmetatable());
assertEquals(null, function.getmetatable());
assertEquals(null, thread.getmetatable());
assertEquals(null, closure.getmetatable());
assertEquals(null, userdata.getmetatable());
assertEquals(table, userdatamt.getmetatable());
}
@Test
void testSetMetatable() {
LuaValue mt = LuaValue.tableOf();
assertEquals(null, table.getmetatable());
assertEquals(null, userdata.getmetatable());
assertEquals(table, userdatamt.getmetatable());
assertEquals(table, table.setmetatable(mt));
assertEquals(userdata, userdata.setmetatable(mt));
assertEquals(userdatamt, userdatamt.setmetatable(mt));
assertEquals(mt, table.getmetatable());
assertEquals(mt, userdata.getmetatable());
assertEquals(mt, userdatamt.getmetatable());
// these all get metatable behind-the-scenes
assertEquals(null, LuaValue.NIL.getmetatable());
assertEquals(null, LuaValue.TRUE.getmetatable());
assertEquals(null, LuaValue.ONE.getmetatable());
// assertEquals( null, string.getmetatable() );
assertEquals(null, function.getmetatable());
assertEquals(null, thread.getmetatable());
assertEquals(null, closure.getmetatable());
LuaNil.s_metatable = mt;
assertEquals(mt, LuaValue.NIL.getmetatable());
assertEquals(null, LuaValue.TRUE.getmetatable());
assertEquals(null, LuaValue.ONE.getmetatable());
// assertEquals( null, string.getmetatable() );
assertEquals(null, function.getmetatable());
assertEquals(null, thread.getmetatable());
assertEquals(null, closure.getmetatable());
LuaBoolean.s_metatable = mt;
assertEquals(mt, LuaValue.TRUE.getmetatable());
assertEquals(null, LuaValue.ONE.getmetatable());
// assertEquals( null, string.getmetatable() );
assertEquals(null, function.getmetatable());
assertEquals(null, thread.getmetatable());
assertEquals(null, closure.getmetatable());
LuaNumber.s_metatable = mt;
assertEquals(mt, LuaValue.ONE.getmetatable());
assertEquals(mt, LuaValue.valueOf(1.25).getmetatable());
// assertEquals( null, string.getmetatable() );
assertEquals(null, function.getmetatable());
assertEquals(null, thread.getmetatable());
assertEquals(null, closure.getmetatable());
// LuaString.s_metatable = mt;
// assertEquals( mt, string.getmetatable() );
assertEquals(null, function.getmetatable());
assertEquals(null, thread.getmetatable());
assertEquals(null, closure.getmetatable());
LuaFunction.s_metatable = mt;
assertEquals(mt, function.getmetatable());
assertEquals(null, thread.getmetatable());
LuaThread.s_metatable = mt;
assertEquals(mt, thread.getmetatable());
}
@Test
void testMetatableIndex() {
assertEquals(table, table.setmetatable(null));
assertEquals(userdata, userdata.setmetatable(null));
assertEquals(userdatamt, userdatamt.setmetatable(null));
assertEquals(LuaValue.NIL, table.get(1));
assertEquals(LuaValue.NIL, userdata.get(1));
assertEquals(LuaValue.NIL, userdatamt.get(1));
// empty metatable
LuaValue mt = LuaValue.tableOf();
assertEquals(table, table.setmetatable(mt));
assertEquals(userdata, userdata.setmetatable(mt));
LuaBoolean.s_metatable = mt;
LuaFunction.s_metatable = mt;
LuaNil.s_metatable = mt;
LuaNumber.s_metatable = mt;
// LuaString.s_metatable = mt;
LuaThread.s_metatable = mt;
assertEquals(mt, table.getmetatable());
assertEquals(mt, userdata.getmetatable());
assertEquals(mt, LuaValue.NIL.getmetatable());
assertEquals(mt, LuaValue.TRUE.getmetatable());
assertEquals(mt, LuaValue.ONE.getmetatable());
// assertEquals( StringLib.instance, string.getmetatable() );
assertEquals(mt, function.getmetatable());
assertEquals(mt, thread.getmetatable());
// plain metatable
LuaValue abc = LuaValue.valueOf("abc");
mt.set(LuaValue.INDEX, LuaValue.listOf(new LuaValue[] { abc }));
assertEquals(abc, table.get(1));
assertEquals(abc, userdata.get(1));
assertEquals(abc, LuaValue.NIL.get(1));
assertEquals(abc, LuaValue.TRUE.get(1));
assertEquals(abc, LuaValue.ONE.get(1));
// assertEquals( abc, string.get(1) );
assertEquals(abc, function.get(1));
assertEquals(abc, thread.get(1));
// plain metatable
mt.set(LuaValue.INDEX, new TwoArgFunction() {
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return LuaValue.valueOf(arg1.typename() + "[" + arg2.tojstring() + "]=xyz");
}
});
assertEquals("table[1]=xyz", table.get(1).tojstring());
assertEquals("userdata[1]=xyz", userdata.get(1).tojstring());
assertEquals("nil[1]=xyz", LuaValue.NIL.get(1).tojstring());
assertEquals("boolean[1]=xyz", LuaValue.TRUE.get(1).tojstring());
assertEquals("number[1]=xyz", LuaValue.ONE.get(1).tojstring());
// assertEquals( "string[1]=xyz", string.get(1).tojstring() );
assertEquals("function[1]=xyz", function.get(1).tojstring());
assertEquals("thread[1]=xyz", thread.get(1).tojstring());
}
@Test
void testMetatableNewIndex() {
// empty metatable
LuaValue mt = LuaValue.tableOf();
assertEquals(table, table.setmetatable(mt));
assertEquals(userdata, userdata.setmetatable(mt));
LuaBoolean.s_metatable = mt;
LuaFunction.s_metatable = mt;
LuaNil.s_metatable = mt;
LuaNumber.s_metatable = mt;
// LuaString.s_metatable = mt;
LuaThread.s_metatable = mt;
// plain metatable
final LuaValue fallback = LuaValue.tableOf();
LuaValue abc = LuaValue.valueOf("abc");
mt.set(LuaValue.NEWINDEX, fallback);
table.set(2, abc);
userdata.set(3, abc);
LuaValue.NIL.set(4, abc);
LuaValue.TRUE.set(5, abc);
LuaValue.ONE.set(6, abc);
// string.set(7,abc);
function.set(8, abc);
thread.set(9, abc);
assertEquals(abc, fallback.get(2));
assertEquals(abc, fallback.get(3));
assertEquals(abc, fallback.get(4));
assertEquals(abc, fallback.get(5));
assertEquals(abc, fallback.get(6));
// assertEquals( abc, StringLib.instance.get(7) );
assertEquals(abc, fallback.get(8));
assertEquals(abc, fallback.get(9));
// metatable with function call
mt.set(LuaValue.NEWINDEX, new ThreeArgFunction() {
@Override
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
fallback.rawset(arg2, LuaValue.valueOf("via-func-" + arg3));
return NONE;
}
});
table.set(12, abc);
userdata.set(13, abc);
LuaValue.NIL.set(14, abc);
LuaValue.TRUE.set(15, abc);
LuaValue.ONE.set(16, abc);
// string.set(17,abc);
function.set(18, abc);
thread.set(19, abc);
LuaValue via = LuaValue.valueOf("via-func-abc");
assertEquals(via, fallback.get(12));
assertEquals(via, fallback.get(13));
assertEquals(via, fallback.get(14));
assertEquals(via, fallback.get(15));
assertEquals(via, fallback.get(16));
// assertEquals( via, StringLib.instance.get(17) );
assertEquals(via, fallback.get(18));
assertEquals(via, fallback.get(19));
}
private void checkTable(LuaValue t, LuaValue aa, LuaValue bb, LuaValue cc, LuaValue dd, LuaValue ee, LuaValue ff,
LuaValue gg, LuaValue ra, LuaValue rb, LuaValue rc, LuaValue rd, LuaValue re, LuaValue rf, LuaValue rg) {
assertEquals(aa, t.get("aa"));
assertEquals(bb, t.get("bb"));
assertEquals(cc, t.get("cc"));
assertEquals(dd, t.get("dd"));
assertEquals(ee, t.get("ee"));
assertEquals(ff, t.get("ff"));
assertEquals(gg, t.get("gg"));
assertEquals(ra, t.rawget("aa"));
assertEquals(rb, t.rawget("bb"));
assertEquals(rc, t.rawget("cc"));
assertEquals(rd, t.rawget("dd"));
assertEquals(re, t.rawget("ee"));
assertEquals(rf, t.rawget("ff"));
assertEquals(rg, t.rawget("gg"));
}
private LuaValue makeTable(String key1, String val1, String key2, String val2) {
return LuaValue.tableOf(new LuaValue[] { LuaValue.valueOf(key1), LuaValue.valueOf(val1), LuaValue.valueOf(key2),
LuaValue.valueOf(val2), });
}
@Test
void testRawsetMetatableSet() {
// set up tables
LuaValue m = makeTable("aa", "aaa", "bb", "bbb");
m.set(LuaValue.INDEX, m);
m.set(LuaValue.NEWINDEX, m);
LuaValue s = makeTable("cc", "ccc", "dd", "ddd");
LuaValue t = makeTable("cc", "ccc", "dd", "ddd");
t.setmetatable(m);
LuaValue aaa = LuaValue.valueOf("aaa");
LuaValue bbb = LuaValue.valueOf("bbb");
LuaValue ccc = LuaValue.valueOf("ccc");
LuaValue ddd = LuaValue.valueOf("ddd");
LuaValue ppp = LuaValue.valueOf("ppp");
LuaValue qqq = LuaValue.valueOf("qqq");
LuaValue rrr = LuaValue.valueOf("rrr");
LuaValue sss = LuaValue.valueOf("sss");
LuaValue ttt = LuaValue.valueOf("ttt");
LuaValue www = LuaValue.valueOf("www");
LuaValue xxx = LuaValue.valueOf("xxx");
LuaValue yyy = LuaValue.valueOf("yyy");
LuaValue zzz = LuaValue.valueOf("zzz");
LuaValue nil = LuaValue.NIL;
// check initial values
// values via "bet()" values via "rawget()"
checkTable(s, nil, nil, ccc, ddd, nil, nil, nil, nil, nil, ccc, ddd, nil, nil, nil);
checkTable(t, aaa, bbb, ccc, ddd, nil, nil, nil, nil, nil, ccc, ddd, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, nil, nil, aaa, bbb, nil, nil, nil, nil, nil);
// rawset()
s.rawset("aa", www);
checkTable(s, www, nil, ccc, ddd, nil, nil, nil, www, nil, ccc, ddd, nil, nil, nil);
checkTable(t, aaa, bbb, ccc, ddd, nil, nil, nil, nil, nil, ccc, ddd, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, nil, nil, aaa, bbb, nil, nil, nil, nil, nil);
s.rawset("cc", xxx);
checkTable(s, www, nil, xxx, ddd, nil, nil, nil, www, nil, xxx, ddd, nil, nil, nil);
checkTable(t, aaa, bbb, ccc, ddd, nil, nil, nil, nil, nil, ccc, ddd, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, nil, nil, aaa, bbb, nil, nil, nil, nil, nil);
t.rawset("bb", yyy);
checkTable(s, www, nil, xxx, ddd, nil, nil, nil, www, nil, xxx, ddd, nil, nil, nil);
checkTable(t, aaa, yyy, ccc, ddd, nil, nil, nil, nil, yyy, ccc, ddd, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, nil, nil, aaa, bbb, nil, nil, nil, nil, nil);
t.rawset("dd", zzz);
checkTable(s, www, nil, xxx, ddd, nil, nil, nil, www, nil, xxx, ddd, nil, nil, nil);
checkTable(t, aaa, yyy, ccc, zzz, nil, nil, nil, nil, yyy, ccc, zzz, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, nil, nil, aaa, bbb, nil, nil, nil, nil, nil);
// set() invoking metatables
s.set("ee", ppp);
checkTable(s, www, nil, xxx, ddd, ppp, nil, nil, www, nil, xxx, ddd, ppp, nil, nil);
checkTable(t, aaa, yyy, ccc, zzz, nil, nil, nil, nil, yyy, ccc, zzz, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, nil, nil, aaa, bbb, nil, nil, nil, nil, nil);
s.set("cc", qqq);
checkTable(s, www, nil, qqq, ddd, ppp, nil, nil, www, nil, qqq, ddd, ppp, nil, nil);
checkTable(t, aaa, yyy, ccc, zzz, nil, nil, nil, nil, yyy, ccc, zzz, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, nil, nil, aaa, bbb, nil, nil, nil, nil, nil);
t.set("ff", rrr);
checkTable(s, www, nil, qqq, ddd, ppp, nil, nil, www, nil, qqq, ddd, ppp, nil, nil);
checkTable(t, aaa, yyy, ccc, zzz, nil, rrr, nil, nil, yyy, ccc, zzz, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, rrr, nil, aaa, bbb, nil, nil, nil, rrr, nil);
t.set("dd", sss);
checkTable(s, www, nil, qqq, ddd, ppp, nil, nil, www, nil, qqq, ddd, ppp, nil, nil);
checkTable(t, aaa, yyy, ccc, sss, nil, rrr, nil, nil, yyy, ccc, sss, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, rrr, nil, aaa, bbb, nil, nil, nil, rrr, nil);
m.set("gg", ttt);
checkTable(s, www, nil, qqq, ddd, ppp, nil, nil, www, nil, qqq, ddd, ppp, nil, nil);
checkTable(t, aaa, yyy, ccc, sss, nil, rrr, ttt, nil, yyy, ccc, sss, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, rrr, ttt, aaa, bbb, nil, nil, nil, rrr, ttt);
// make s fall back to t
s.setmetatable(LuaValue.tableOf(new LuaValue[] { LuaValue.INDEX, t, LuaValue.NEWINDEX, t }));
checkTable(s, www, yyy, qqq, ddd, ppp, rrr, ttt, www, nil, qqq, ddd, ppp, nil, nil);
checkTable(t, aaa, yyy, ccc, sss, nil, rrr, ttt, nil, yyy, ccc, sss, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, rrr, ttt, aaa, bbb, nil, nil, nil, rrr, ttt);
s.set("aa", www);
checkTable(s, www, yyy, qqq, ddd, ppp, rrr, ttt, www, nil, qqq, ddd, ppp, nil, nil);
checkTable(t, aaa, yyy, ccc, sss, nil, rrr, ttt, nil, yyy, ccc, sss, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, rrr, ttt, aaa, bbb, nil, nil, nil, rrr, ttt);
s.set("bb", zzz);
checkTable(s, www, zzz, qqq, ddd, ppp, rrr, ttt, www, nil, qqq, ddd, ppp, nil, nil);
checkTable(t, aaa, zzz, ccc, sss, nil, rrr, ttt, nil, zzz, ccc, sss, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, rrr, ttt, aaa, bbb, nil, nil, nil, rrr, ttt);
s.set("ee", xxx);
checkTable(s, www, zzz, qqq, ddd, xxx, rrr, ttt, www, nil, qqq, ddd, xxx, nil, nil);
checkTable(t, aaa, zzz, ccc, sss, nil, rrr, ttt, nil, zzz, ccc, sss, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, rrr, ttt, aaa, bbb, nil, nil, nil, rrr, ttt);
s.set("ff", yyy);
checkTable(s, www, zzz, qqq, ddd, xxx, yyy, ttt, www, nil, qqq, ddd, xxx, nil, nil);
checkTable(t, aaa, zzz, ccc, sss, nil, yyy, ttt, nil, zzz, ccc, sss, nil, nil, nil);
checkTable(m, aaa, bbb, nil, nil, nil, yyy, ttt, aaa, bbb, nil, nil, nil, yyy, ttt);
}
}

View File

@@ -1,20 +1,21 @@
package org.luaj.vm2;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import junit.framework.TestCase;
import org.junit.jupiter.api.Test;
import org.luaj.vm2.lib.jse.JsePlatform;
class StringTest {
public class StringTest extends TestCase {
protected void setUp() throws Exception {
JsePlatform.standardGlobals();
}
public void testToInputStream() throws IOException {
@Test
void testToInputStream() throws IOException {
LuaString str = LuaString.valueOf("Hello");
InputStream is = str.toInputStream();
@@ -53,7 +54,6 @@ public class StringTest extends TestCase {
assertEquals('e', is.read());
}
private static final String userFriendly(String s) {
StringBuffer sb = new StringBuffer();
for (int i = 0, n = s.length(); i < n; i++) {
@@ -67,7 +67,8 @@ public class StringTest extends TestCase {
return sb.toString();
}
public void testUtf820482051() throws UnsupportedEncodingException {
@Test
void testUtf820482051() throws UnsupportedEncodingException {
int i = 2048;
char[] c = { (char) (i+0), (char) (i+1), (char) (i+2), (char) (i+3) };
String before = new String(c) + " " + i + "-" + (i+4);
@@ -76,8 +77,10 @@ public class StringTest extends TestCase {
assertEquals(userFriendly(before), userFriendly(after));
}
public void testUtf8() {
@Test
void testUtf8() {
for (int i = 4; i < 0xffff; i += 4) {
if (i == 0xd800) i = 0xe000;
char[] c = { (char) (i+0), (char) (i+1), (char) (i+2), (char) (i+3) };
String before = new String(c) + " " + i + "-" + (i+4);
LuaString ls = LuaString.valueOf(before);
@@ -91,8 +94,10 @@ public class StringTest extends TestCase {
assertEquals(userFriendly(before), userFriendly(after));
}
public void testSpotCheckUtf8() throws UnsupportedEncodingException {
byte[] bytes = {(byte)194,(byte)160,(byte)194,(byte)161,(byte)194,(byte)162,(byte)194,(byte)163,(byte)194,(byte)164};
@Test
void testSpotCheckUtf8() throws UnsupportedEncodingException {
byte[] bytes = { (byte) 194, (byte) 160, (byte) 194, (byte) 161, (byte) 194, (byte) 162, (byte) 194, (byte) 163,
(byte) 194, (byte) 164 };
String expected = new String(bytes, "UTF8");
String actual = LuaString.valueOf(bytes).tojstring();
char[] d = actual.toCharArray();
@@ -104,7 +109,8 @@ public class StringTest extends TestCase {
assertEquals(expected, actual);
}
public void testNullTerminated() {
@Test
void testNullTerminated() {
char[] c = { 'a', 'b', 'c', '\0', 'd', 'e', 'f' };
String before = new String(c);
LuaString ls = LuaString.valueOf(before);
@@ -112,7 +118,8 @@ public class StringTest extends TestCase {
assertEquals(userFriendly("abc\0def"), userFriendly(after));
}
public void testRecentStringsCacheDifferentHashcodes() {
@Test
void testRecentStringsCacheDifferentHashcodes() {
final byte[] abc = { 'a', 'b', 'c' };
final byte[] xyz = { 'x', 'y', 'z' };
final LuaString abc1 = LuaString.valueOf(abc);
@@ -125,7 +132,8 @@ public class StringTest extends TestCase {
assertSame(xyz1, xyz2);
}
public void testRecentStringsCacheHashCollisionCacheHit() {
@Test
void testRecentStringsCacheHashCollisionCacheHit() {
final byte[] abc = { 'a', 'b', 'c' };
final byte[] lyz = { 'l', 'y', 'z' }; // chosen to have hash collision with 'abc'
final LuaString abc1 = LuaString.valueOf(abc);
@@ -140,7 +148,8 @@ public class StringTest extends TestCase {
assertSame(lyz1, lyz2);
}
public void testRecentStringsCacheHashCollisionCacheMiss() {
@Test
void testRecentStringsCacheHashCollisionCacheMiss() {
final byte[] abc = { 'a', 'b', 'c' };
final byte[] lyz = { 'l', 'y', 'z' }; // chosen to have hash collision with 'abc'
final LuaString abc1 = LuaString.valueOf(abc);
@@ -155,7 +164,8 @@ public class StringTest extends TestCase {
assertNotSame(lyz1, lyz2);
}
public void testRecentStringsLongStrings() {
@Test
void testRecentStringsLongStrings() {
byte[] abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes();
assertTrue(abc.length > LuaString.RECENT_STRINGS_MAX_LENGTH);
LuaString abc1 = LuaString.valueOf(abc);
@@ -163,7 +173,8 @@ public class StringTest extends TestCase {
assertNotSame(abc1, abc2);
}
public void testRecentStringsUsingJavaStrings() {
@Test
void testRecentStringsUsingJavaStrings() {
final String abc = "abc";
final String lyz = "lyz"; // chosen to have hash collision with 'abc'
final String xyz = "xyz";
@@ -193,7 +204,8 @@ public class StringTest extends TestCase {
assertSame(xyz3, xyz4); // because hashes do not collide
}
public void testLongSubstringGetsOldBacking() {
@Test
void testLongSubstringGetsOldBacking() {
LuaString src = LuaString.valueOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
LuaString sub1 = src.substring(10, 40);
assertSame(src.m_bytes, sub1.m_bytes);
@@ -201,7 +213,8 @@ public class StringTest extends TestCase {
assertEquals(sub1.m_length, 30);
}
public void testShortSubstringGetsNewBacking() {
@Test
void testShortSubstringGetsNewBacking() {
LuaString src = LuaString.valueOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
LuaString sub1 = src.substring(10, 20);
LuaString sub2 = src.substring(10, 20);
@@ -211,10 +224,10 @@ public class StringTest extends TestCase {
assertFalse(src.m_bytes == sub1.m_bytes);
}
public void testShortSubstringOfVeryLongStringGetsNewBacking() {
LuaString src = LuaString.valueOf(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" );
@Test
void testShortSubstringOfVeryLongStringGetsNewBacking() {
LuaString src = LuaString.valueOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
LuaString sub1 = src.substring(10, 50);
LuaString sub2 = src.substring(10, 50);
assertEquals(sub1.m_offset, 0);
@@ -223,7 +236,8 @@ public class StringTest extends TestCase {
assertFalse(src.m_bytes == sub1.m_bytes);
}
public void testIndexOfByteInSubstring() {
@Test
void testIndexOfByteInSubstring() {
LuaString str = LuaString.valueOf("abcdef:ghi");
LuaString sub = str.substring(2, 10);
assertEquals(10, str.m_length);
@@ -256,7 +270,8 @@ public class StringTest extends TestCase {
assertEquals(-1, sub.indexOf((byte) 'z', 7));
}
public void testIndexOfPatternInSubstring() {
@Test
void testIndexOfPatternInSubstring() {
LuaString str = LuaString.valueOf("abcdef:ghi");
LuaString sub = str.substring(2, 10);
assertEquals(10, str.m_length);
@@ -293,7 +308,8 @@ public class StringTest extends TestCase {
assertEquals(-1, sub.indexOf(xyz, 7));
}
public void testLastIndexOfPatternInSubstring() {
@Test
void testLastIndexOfPatternInSubstring() {
LuaString str = LuaString.valueOf("abcdef:ghi");
LuaString sub = str.substring(2, 10);
assertEquals(10, str.m_length);
@@ -314,7 +330,8 @@ public class StringTest extends TestCase {
assertEquals(-1, sub.lastIndexOf(xyz));
}
public void testIndexOfAnyInSubstring() {
@Test
void testIndexOfAnyInSubstring() {
LuaString str = LuaString.valueOf("abcdef:ghi");
LuaString sub = str.substring(2, 10);
assertEquals(10, str.m_length);
@@ -349,33 +366,4 @@ public class StringTest extends TestCase {
assertEquals(1, sub.indexOfAny(CdEFGHIJ));
assertEquals(-1, sub.indexOfAny(EFGHIJKL));
}
public void testMatchShortPatterns() {
LuaValue[] args = { LuaString.valueOf("%bxy") };
LuaString _ = LuaString.valueOf("");
LuaString a = LuaString.valueOf("a");
LuaString ax = LuaString.valueOf("ax");
LuaString axb = LuaString.valueOf("axb");
LuaString axby = LuaString.valueOf("axby");
LuaString xbya = LuaString.valueOf("xbya");
LuaString bya = LuaString.valueOf("bya");
LuaString xby = LuaString.valueOf("xby");
LuaString axbya = LuaString.valueOf("axbya");
LuaValue nil = LuaValue.NIL;
assertEquals(nil, _.invokemethod("match", args));
assertEquals(nil, a.invokemethod("match", args));
assertEquals(nil, ax.invokemethod("match", args));
assertEquals(nil, axb.invokemethod("match", args));
assertEquals(xby, axby.invokemethod("match", args));
assertEquals(xby, xbya.invokemethod("match", args));
assertEquals(nil, bya.invokemethod("match", args));
assertEquals(xby, xby.invokemethod("match", args));
assertEquals(xby, axbya.invokemethod("match", args));
assertEquals(xby, axbya.substring(0,4).invokemethod("match", args));
assertEquals(nil, axbya.substring(0,3).invokemethod("match", args));
assertEquals(xby, axbya.substring(1,5).invokemethod("match", args));
assertEquals(nil, axbya.substring(2,5).invokemethod("match", args));
}
}

View File

@@ -0,0 +1,325 @@
/*******************************************************************************
* 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;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import org.luaj.vm2.lib.TwoArgFunction;
/**
* Tests for tables used as lists.
*/
public class TableHashTest {
protected LuaTable new_Table() {
return new LuaTable();
}
protected LuaTable new_Table(int n, int m) {
return new LuaTable(n, m);
}
@Test
void testSetRemove() {
LuaTable t = new_Table();
assertEquals(0, t.getHashLength());
assertEquals(0, t.length());
assertEquals(0, t.keyCount());
String[] keys = { "abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "wxy", "z01", "cd", "ef", "g", "hi", "jk",
"lm", "no", "pq", "rs", };
int[] capacities = { 0, 2, 2, 4, 4, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32 };
for (int i = 0; i < keys.length; ++i) {
assertEquals(capacities[i], t.getHashLength());
String si = "Test Value! " + i;
t.set(keys[i], si);
assertEquals(0, t.length());
assertEquals(i+1, t.keyCount());
}
assertEquals(capacities[keys.length], t.getHashLength());
for (int i = 0; i < keys.length; ++i) {
LuaValue vi = LuaString.valueOf("Test Value! " + i);
assertEquals(vi, t.get(keys[i]));
assertEquals(vi, t.get(LuaString.valueOf(keys[i])));
assertEquals(vi, t.rawget(keys[i]));
assertEquals(vi, t.rawget(keys[i]));
}
// replace with new values
for (int i = 0; i < keys.length; ++i) {
t.set(keys[i], LuaString.valueOf("Replacement Value! " + i));
assertEquals(0, t.length());
assertEquals(keys.length, t.keyCount());
assertEquals(capacities[keys.length], t.getHashLength());
}
for (int i = 0; i < keys.length; ++i) {
LuaValue vi = LuaString.valueOf("Replacement Value! " + i);
assertEquals(vi, t.get(keys[i]));
}
// remove
for (int i = 0; i < keys.length; ++i) {
t.set(keys[i], LuaValue.NIL);
assertEquals(0, t.length());
assertEquals(keys.length-i-1, t.keyCount());
if (i < keys.length-1)
assertEquals(capacities[keys.length], t.getHashLength());
else
assertTrue(0 <= t.getHashLength());
}
for (int i = 0; i < keys.length; ++i) {
assertEquals(LuaValue.NIL, t.get(keys[i]));
}
}
@Test
void testIndexMetatag() {
LuaTable t = new_Table();
LuaTable mt = new_Table();
LuaTable fb = new_Table();
// set basic values
t.set("ppp", "abc");
t.set(123, "def");
mt.set(LuaValue.INDEX, fb);
fb.set("qqq", "ghi");
fb.set(456, "jkl");
// check before setting metatable
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("nil", t.get("qqq").tojstring());
assertEquals("nil", t.get(456).tojstring());
assertEquals("nil", fb.get("ppp").tojstring());
assertEquals("nil", fb.get(123).tojstring());
assertEquals("ghi", fb.get("qqq").tojstring());
assertEquals("jkl", fb.get(456).tojstring());
assertEquals("nil", mt.get("ppp").tojstring());
assertEquals("nil", mt.get(123).tojstring());
assertEquals("nil", mt.get("qqq").tojstring());
assertEquals("nil", mt.get(456).tojstring());
// check before setting metatable
t.setmetatable(mt);
assertEquals(mt, t.getmetatable());
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("ghi", t.get("qqq").tojstring());
assertEquals("jkl", t.get(456).tojstring());
assertEquals("nil", fb.get("ppp").tojstring());
assertEquals("nil", fb.get(123).tojstring());
assertEquals("ghi", fb.get("qqq").tojstring());
assertEquals("jkl", fb.get(456).tojstring());
assertEquals("nil", mt.get("ppp").tojstring());
assertEquals("nil", mt.get(123).tojstring());
assertEquals("nil", mt.get("qqq").tojstring());
assertEquals("nil", mt.get(456).tojstring());
// set metatable to metatable without values
t.setmetatable(fb);
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("nil", t.get("qqq").tojstring());
assertEquals("nil", t.get(456).tojstring());
// set metatable to null
t.setmetatable(null);
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("nil", t.get("qqq").tojstring());
assertEquals("nil", t.get(456).tojstring());
}
@Test
void testIndexFunction() {
final LuaTable t = new_Table();
final LuaTable mt = new_Table();
final TwoArgFunction fb = new TwoArgFunction() {
@Override
public LuaValue call(LuaValue tbl, LuaValue key) {
assertEquals(tbl, t);
return valueOf("from mt: " + key);
}
};
// set basic values
t.set("ppp", "abc");
t.set(123, "def");
mt.set(LuaValue.INDEX, fb);
// check before setting metatable
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("nil", t.get("qqq").tojstring());
assertEquals("nil", t.get(456).tojstring());
// check before setting metatable
t.setmetatable(mt);
assertEquals(mt, t.getmetatable());
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("from mt: qqq", t.get("qqq").tojstring());
assertEquals("from mt: 456", t.get(456).tojstring());
// use raw set
t.rawset("qqq", "alt-qqq");
t.rawset(456, "alt-456");
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("alt-qqq", t.get("qqq").tojstring());
assertEquals("alt-456", t.get(456).tojstring());
// remove using raw set
t.rawset("qqq", LuaValue.NIL);
t.rawset(456, LuaValue.NIL);
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("from mt: qqq", t.get("qqq").tojstring());
assertEquals("from mt: 456", t.get(456).tojstring());
// set metatable to null
t.setmetatable(null);
assertEquals("abc", t.get("ppp").tojstring());
assertEquals("def", t.get(123).tojstring());
assertEquals("nil", t.get("qqq").tojstring());
assertEquals("nil", t.get(456).tojstring());
}
@Test
void testNext() {
final LuaTable t = new_Table();
assertEquals(LuaValue.NIL, t.next(LuaValue.NIL));
// insert array elements
t.set(1, "one");
assertEquals(LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1));
assertEquals(LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2));
assertEquals(LuaValue.NIL, t.next(LuaValue.ONE));
t.set(2, "two");
assertEquals(LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1));
assertEquals(LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2));
assertEquals(LuaValue.valueOf(2), t.next(LuaValue.ONE).arg(1));
assertEquals(LuaValue.valueOf("two"), t.next(LuaValue.ONE).arg(2));
assertEquals(LuaValue.NIL, t.next(LuaValue.valueOf(2)));
// insert hash elements
t.set("aa", "aaa");
assertEquals(LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1));
assertEquals(LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2));
assertEquals(LuaValue.valueOf(2), t.next(LuaValue.ONE).arg(1));
assertEquals(LuaValue.valueOf("two"), t.next(LuaValue.ONE).arg(2));
assertEquals(LuaValue.valueOf("aa"), t.next(LuaValue.valueOf(2)).arg(1));
assertEquals(LuaValue.valueOf("aaa"), t.next(LuaValue.valueOf(2)).arg(2));
assertEquals(LuaValue.NIL, t.next(LuaValue.valueOf("aa")));
t.set("bb", "bbb");
assertEquals(LuaValue.valueOf(1), t.next(LuaValue.NIL).arg(1));
assertEquals(LuaValue.valueOf("one"), t.next(LuaValue.NIL).arg(2));
assertEquals(LuaValue.valueOf(2), t.next(LuaValue.ONE).arg(1));
assertEquals(LuaValue.valueOf("two"), t.next(LuaValue.ONE).arg(2));
assertEquals(LuaValue.valueOf("aa"), t.next(LuaValue.valueOf(2)).arg(1));
assertEquals(LuaValue.valueOf("aaa"), t.next(LuaValue.valueOf(2)).arg(2));
assertEquals(LuaValue.valueOf("bb"), t.next(LuaValue.valueOf("aa")).arg(1));
assertEquals(LuaValue.valueOf("bbb"), t.next(LuaValue.valueOf("aa")).arg(2));
assertEquals(LuaValue.NIL, t.next(LuaValue.valueOf("bb")));
}
@Test
void testLoopWithRemoval() {
final LuaTable t = new_Table();
t.set(LuaValue.valueOf(1), LuaValue.valueOf("1"));
t.set(LuaValue.valueOf(3), LuaValue.valueOf("3"));
t.set(LuaValue.valueOf(8), LuaValue.valueOf("4"));
t.set(LuaValue.valueOf(17), LuaValue.valueOf("5"));
t.set(LuaValue.valueOf(26), LuaValue.valueOf("6"));
t.set(LuaValue.valueOf(35), LuaValue.valueOf("7"));
t.set(LuaValue.valueOf(42), LuaValue.valueOf("8"));
t.set(LuaValue.valueOf(60), LuaValue.valueOf("10"));
t.set(LuaValue.valueOf(63), LuaValue.valueOf("11"));
Varargs entry = t.next(LuaValue.NIL);
while ( !entry.isnil(1) ) {
LuaValue k = entry.arg1();
LuaValue v = entry.arg(2);
if ((k.toint() & 1) == 0) {
t.set(k, LuaValue.NIL);
}
entry = t.next(k);
}
int numEntries = 0;
entry = t.next(LuaValue.NIL);
while ( !entry.isnil(1) ) {
LuaValue k = entry.arg1();
// Only odd keys should remain
assertTrue((k.toint() & 1) == 1);
numEntries++;
entry = t.next(k);
}
assertEquals(5, numEntries);
}
@Test
void testLoopWithRemovalAndSet() {
final LuaTable t = new_Table();
t.set(LuaValue.valueOf(1), LuaValue.valueOf("1"));
t.set(LuaValue.valueOf(3), LuaValue.valueOf("3"));
t.set(LuaValue.valueOf(8), LuaValue.valueOf("4"));
t.set(LuaValue.valueOf(17), LuaValue.valueOf("5"));
t.set(LuaValue.valueOf(26), LuaValue.valueOf("6"));
t.set(LuaValue.valueOf(35), LuaValue.valueOf("7"));
t.set(LuaValue.valueOf(42), LuaValue.valueOf("8"));
t.set(LuaValue.valueOf(60), LuaValue.valueOf("10"));
t.set(LuaValue.valueOf(63), LuaValue.valueOf("11"));
Varargs entry = t.next(LuaValue.NIL);
Varargs entry2 = entry;
while ( !entry.isnil(1) ) {
LuaValue k = entry.arg1();
LuaValue v = entry.arg(2);
if ((k.toint() & 1) == 0) {
t.set(k, LuaValue.NIL);
} else {
t.set(k, v.tonumber());
entry2 = t.next(entry2.arg1());
}
entry = t.next(k);
}
int numEntries = 0;
entry = t.next(LuaValue.NIL);
while ( !entry.isnil(1) ) {
LuaValue k = entry.arg1();
// Only odd keys should remain
assertTrue((k.toint() & 1) == 1);
assertTrue(entry.arg(2).type() == LuaValue.TNUMBER);
numEntries++;
entry = t.next(k);
}
assertEquals(5, numEntries);
}
}

View File

@@ -0,0 +1,437 @@
/*******************************************************************************
* 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;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import org.junit.jupiter.api.Test;
class TableTest {
protected LuaTable new_Table() {
return new LuaTable();
}
protected LuaTable new_Table(int n, int m) {
return new LuaTable(n, m);
}
private int keyCount(LuaTable t) {
return keys(t).length;
}
private LuaValue[] keys(LuaTable t) {
ArrayList<LuaValue> l = new ArrayList<LuaValue>();
LuaValue k = LuaValue.NIL;
while ( true ) {
Varargs n = t.next(k);
if ((k = n.arg1()).isnil())
break;
l.add(k);
}
return l.toArray(new LuaValue[t.length()]);
}
@Test
void testInOrderIntegerKeyInsertion() {
LuaTable t = new_Table();
for (int i = 1; i <= 32; ++i) {
t.set(i, LuaValue.valueOf("Test Value! " + i));
}
// Ensure all keys are still there.
for (int i = 1; i <= 32; ++i) {
assertEquals("Test Value! " + i, t.get(i).tojstring());
}
// Ensure capacities make sense
assertEquals(0, t.getHashLength());
assertTrue(t.getArrayLength() >= 32);
assertTrue(t.getArrayLength() <= 64);
}
@Test
void testRekeyCount() {
LuaTable t = new_Table();
// NOTE: This order of insertion is important.
t.set(3, LuaInteger.valueOf(3));
t.set(1, LuaInteger.valueOf(1));
t.set(5, LuaInteger.valueOf(5));
t.set(4, LuaInteger.valueOf(4));
t.set(6, LuaInteger.valueOf(6));
t.set(2, LuaInteger.valueOf(2));
for (int i = 1; i < 6; ++i) {
assertEquals(LuaInteger.valueOf(i), t.get(i));
}
assertTrue(t.getArrayLength() >= 3);
assertTrue(t.getArrayLength() <= 12);
assertTrue(t.getHashLength() <= 3);
}
@Test
void testOutOfOrderIntegerKeyInsertion() {
LuaTable t = new_Table();
for (int i = 32; i > 0; --i) {
t.set(i, LuaValue.valueOf("Test Value! " + i));
}
// Ensure all keys are still there.
for (int i = 1; i <= 32; ++i) {
assertEquals("Test Value! " + i, t.get(i).tojstring());
}
// Ensure capacities make sense
assertEquals(32, t.getArrayLength());
assertEquals(0, t.getHashLength());
}
@Test
void testStringAndIntegerKeys() {
LuaTable t = new_Table();
for (int i = 0; i < 10; ++i) {
LuaString str = LuaValue.valueOf(String.valueOf(i));
t.set(i, str);
t.set(str, LuaInteger.valueOf(i));
}
assertTrue(t.getArrayLength() >= 8); // 1, 2, ..., 9
assertTrue(t.getArrayLength() <= 16);
assertTrue(t.getHashLength() >= 11); // 0, "0", "1", ..., "9"
assertTrue(t.getHashLength() <= 33);
LuaValue[] keys = keys(t);
int intKeys = 0;
int stringKeys = 0;
assertEquals(20, keys.length);
for (int i = 0; i < keys.length; ++i) {
LuaValue k = keys[i];
if (k instanceof LuaInteger) {
final int ik = k.toint();
assertTrue(ik >= 0 && ik < 10);
final int mask = 1<<ik;
assertTrue((intKeys & mask) == 0);
intKeys |= mask;
} else if (k instanceof LuaString) {
final int ik = Integer.parseInt(k.strvalue().tojstring());
assertEquals(String.valueOf(ik), k.strvalue().tojstring());
assertTrue(ik >= 0 && ik < 10);
final int mask = 1<<ik;
assertTrue((stringKeys & mask) == 0, "Key \"" + ik + "\" found more than once");
stringKeys |= mask;
} else {
fail("Unexpected type of key found");
}
}
assertEquals(0x03FF, intKeys);
assertEquals(0x03FF, stringKeys);
}
@Test
void testBadInitialCapacity() {
LuaTable t = new_Table(0, 1);
t.set("test", LuaValue.valueOf("foo"));
t.set("explode", LuaValue.valueOf("explode"));
assertEquals(2, keyCount(t));
}
@Test
void testRemove0() {
LuaTable t = new_Table(2, 0);
t.set(1, LuaValue.valueOf("foo"));
t.set(2, LuaValue.valueOf("bah"));
assertNotSame(LuaValue.NIL, t.get(1));
assertNotSame(LuaValue.NIL, t.get(2));
assertEquals(LuaValue.NIL, t.get(3));
t.set(1, LuaValue.NIL);
t.set(2, LuaValue.NIL);
t.set(3, LuaValue.NIL);
assertEquals(LuaValue.NIL, t.get(1));
assertEquals(LuaValue.NIL, t.get(2));
assertEquals(LuaValue.NIL, t.get(3));
}
@Test
void testRemove1() {
LuaTable t = new_Table(0, 1);
t.set("test", LuaValue.valueOf("foo"));
t.set("explode", LuaValue.NIL);
t.set(42, LuaValue.NIL);
t.set(new_Table(), LuaValue.NIL);
t.set("test", LuaValue.NIL);
assertEquals(0, keyCount(t));
t.set(10, LuaInteger.valueOf(5));
t.set(10, LuaValue.NIL);
assertEquals(0, keyCount(t));
}
@Test
void testRemove2() {
LuaTable t = new_Table(0, 1);
t.set("test", LuaValue.valueOf("foo"));
t.set("string", LuaInteger.valueOf(10));
assertEquals(2, keyCount(t));
t.set("string", LuaValue.NIL);
t.set("three", LuaValue.valueOf(3.14));
assertEquals(2, keyCount(t));
t.set("test", LuaValue.NIL);
assertEquals(1, keyCount(t));
t.set(10, LuaInteger.valueOf(5));
assertEquals(2, keyCount(t));
t.set(10, LuaValue.NIL);
assertEquals(1, keyCount(t));
t.set("three", LuaValue.NIL);
assertEquals(0, keyCount(t));
}
@Test
void testShrinkNonPowerOfTwoArray() {
LuaTable t = new_Table(6, 2);
t.set(1, "one");
t.set(2, "two");
t.set(3, "three");
t.set(4, "four");
t.set(5, "five");
t.set(6, "six");
t.set("aa", "aaa");
t.set("bb", "bbb");
t.set(3, LuaValue.NIL);
t.set(4, LuaValue.NIL);
t.set(6, LuaValue.NIL);
t.set("cc", "ccc");
t.set("dd", "ddd");
assertEquals(4, t.getArrayLength());
assertTrue(t.getHashLength() < 10);
assertEquals(5, t.hashEntries);
assertEquals("one", t.get(1).tojstring());
assertEquals("two", t.get(2).tojstring());
assertEquals(LuaValue.NIL, t.get(3));
assertEquals(LuaValue.NIL, t.get(4));
assertEquals("five", t.get(5).tojstring());
assertEquals(LuaValue.NIL, t.get(6));
assertEquals("aaa", t.get("aa").tojstring());
assertEquals("bbb", t.get("bb").tojstring());
assertEquals("ccc", t.get("cc").tojstring());
assertEquals("ddd", t.get("dd").tojstring());
}
@Test
void testInOrderLuaLength() {
LuaTable t = new_Table();
for (int i = 1; i <= 32; ++i) {
t.set(i, LuaValue.valueOf("Test Value! " + i));
assertEquals(i, t.length());
}
}
@Test
void testOutOfOrderLuaLength() {
LuaTable t = new_Table();
for (int j = 8; j < 32; j += 8) {
for (int i = j; i > 0; --i) {
t.set(i, LuaValue.valueOf("Test Value! " + i));
}
assertEquals(j, t.length());
}
}
@Test
void testStringKeysLuaLength() {
LuaTable t = new_Table();
for (int i = 1; i <= 32; ++i) {
t.set("str-" + i, LuaValue.valueOf("String Key Test Value! " + i));
assertEquals(0, t.length());
}
}
@Test
void testMixedKeysLuaLength() {
LuaTable t = new_Table();
for (int i = 1; i <= 32; ++i) {
t.set("str-" + i, LuaValue.valueOf("String Key Test Value! " + i));
t.set(i, LuaValue.valueOf("Int Key Test Value! " + i));
assertEquals(i, t.length());
}
}
private static final void compareLists(LuaTable t, Vector<LuaString> v) {
int n = v.size();
assertEquals(v.size(), t.length());
for (int j = 0; j < n; j++) {
LuaString vj = v.elementAt(j);
String tj = t.get(j+1).tojstring();
assertEquals(vj.tojstring(), tj);
}
}
@Test
void testInsertBeginningOfList() {
LuaTable t = new_Table();
Vector<LuaString> v = new Vector<>();
for (int i = 1; i <= 32; ++i) {
LuaString test = LuaValue.valueOf("Test Value! " + i);
t.insert(1, test);
v.insertElementAt(test, 0);
compareLists(t, v);
}
}
@Test
void testInsertEndOfList() {
LuaTable t = new_Table();
Vector<LuaString> v = new Vector<>();
for (int i = 1; i <= 32; ++i) {
LuaString test = LuaValue.valueOf("Test Value! " + i);
t.insert(0, test);
v.insertElementAt(test, v.size());
compareLists(t, v);
}
}
@Test
void testInsertMiddleOfList() {
LuaTable t = new_Table();
Vector<LuaString> v = new Vector<>();
for (int i = 1; i <= 32; ++i) {
LuaString test = LuaValue.valueOf("Test Value! " + i);
int m = i/2;
t.insert(m+1, test);
v.insertElementAt(test, m);
compareLists(t, v);
}
}
private static final void prefillLists(LuaTable t, Vector<LuaString> v) {
for (int i = 1; i <= 32; ++i) {
LuaString test = LuaValue.valueOf("Test Value! " + i);
t.insert(0, test);
v.insertElementAt(test, v.size());
}
}
@Test
void testRemoveBeginningOfList() {
LuaTable t = new_Table();
Vector<LuaString> v = new Vector<>();
prefillLists(t, v);
for (int i = 1; i <= 32; ++i) {
t.remove(1);
v.removeElementAt(0);
compareLists(t, v);
}
}
@Test
void testRemoveEndOfList() {
LuaTable t = new_Table();
Vector<LuaString> v = new Vector<>();
prefillLists(t, v);
for (int i = 1; i <= 32; ++i) {
t.remove(0);
v.removeElementAt(v.size()-1);
compareLists(t, v);
}
}
@Test
void testRemoveMiddleOfList() {
LuaTable t = new_Table();
Vector<LuaString> v = new Vector<>();
prefillLists(t, v);
for (int i = 1; i <= 32; ++i) {
int m = v.size()/2;
t.remove(m+1);
v.removeElementAt(m);
compareLists(t, v);
}
}
@Test
void testRemoveWhileIterating() {
LuaTable t = LuaValue.tableOf(
new LuaValue[] { LuaValue.valueOf("a"), LuaValue.valueOf("aa"), LuaValue.valueOf("b"),
LuaValue.valueOf("bb"), LuaValue.valueOf("c"), LuaValue.valueOf("cc"), LuaValue.valueOf("d"),
LuaValue.valueOf("dd"), LuaValue.valueOf("e"), LuaValue.valueOf("ee"), },
new LuaValue[] { LuaValue.valueOf("11"), LuaValue.valueOf("22"), LuaValue.valueOf("33"),
LuaValue.valueOf("44"), LuaValue.valueOf("55"), });
// Find expected order after removal.
List<String> expected = new ArrayList<>();
Varargs n;
int i;
for (n = t.next(LuaValue.NIL), i = 0; !n.arg1().isnil(); n = t.next(n.arg1()), ++i) {
if (i%2 == 0)
expected.add(n.arg1() + "=" + n.arg(2));
}
// Remove every other key while iterating over the table.
for (n = t.next(LuaValue.NIL), i = 0; !n.arg1().isnil(); n = t.next(n.arg1()), ++i) {
if (i%2 != 0)
t.set(n.arg1(), LuaValue.NIL);
}
// Iterate over remaining table, and form list of entries still in table.
List<String> actual = new ArrayList<>();
for (n = t.next(LuaValue.NIL); !n.arg1().isnil(); n = t.next(n.arg1())) {
actual.add(n.arg1() + "=" + n.arg(2));
}
assertEquals(expected, actual);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -21,12 +21,15 @@
******************************************************************************/
package org.luaj.vm2;
import junit.framework.TestCase;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.Test;
/**
* Tests of basic unary and binary operators on main value types.
*/
public class VarargsTest extends TestCase {
class VarargsTest {
static LuaValue A = LuaValue.valueOf("a");
static LuaValue B = LuaValue.valueOf("b");
@@ -57,7 +60,7 @@ public class VarargsTest extends TestCase {
static Varargs FG_alt = new Varargs.PairVarargs(F, G);
static Varargs NONE = LuaValue.NONE;
static void expectEquals(Varargs x, Varargs y) {
private void expectEquals(Varargs x, Varargs y) {
assertEquals(x.narg(), y.narg());
assertEquals(x.arg1(), y.arg1());
assertEquals(x.arg(0), y.arg(0));
@@ -68,7 +71,8 @@ public class VarargsTest extends TestCase {
assertEquals(x.arg(i), y.arg(i));
}
public void testSanity() {
@Test
void testSanity() {
expectEquals(A_G, A_G);
expectEquals(A_G_alt, A_G_alt);
expectEquals(A_G, A_G_alt);
@@ -86,7 +90,8 @@ public class VarargsTest extends TestCase {
expectEquals(NIL, NIL);
}
public void testNegativeIndices() {
@Test
void testNegativeIndices() {
expectNegSubargsError(A_G);
expectNegSubargsError(A_G_alt);
expectNegSubargsError(B_E);
@@ -106,7 +111,7 @@ public class VarargsTest extends TestCase {
expectNegSubargsError(NIL);
}
static void standardTestsA_G(Varargs a_g) {
private void standardTestsA_G(Varargs a_g) {
expectEquals(A_G, a_g);
expectEquals(A_G, a_g.subargs(1));
expectEquals(C_G, a_g.subargs(3).subargs(1));
@@ -121,7 +126,7 @@ public class VarargsTest extends TestCase {
standardTestsC_G(A_G.subargs(3));
}
static void standardTestsC_G(Varargs c_g) {
private void standardTestsC_G(Varargs c_g) {
expectEquals(C_G, c_g.subargs(1));
expectEquals(E_G, c_g.subargs(3));
expectEquals(E_G, c_g.subargs(3).subargs(1));
@@ -134,7 +139,7 @@ public class VarargsTest extends TestCase {
standardTestsE_G(c_g.subargs(3));
}
static void standardTestsE_G(Varargs e_g) {
private void standardTestsE_G(Varargs e_g) {
expectEquals(E_G, e_g.subargs(1));
expectEquals(FG, e_g.subargs(2));
expectEquals(FG, e_g.subargs(2).subargs(1));
@@ -145,7 +150,7 @@ public class VarargsTest extends TestCase {
standardTestsFG(e_g.subargs(2));
}
static void standardTestsFG(Varargs fg) {
private void standardTestsFG(Varargs fg) {
expectEquals(FG, fg.subargs(1));
expectEquals(G, fg.subargs(2));
expectEquals(G, fg.subargs(2).subargs(1));
@@ -153,12 +158,13 @@ public class VarargsTest extends TestCase {
expectEquals(NONE, fg.subargs(3).subargs(1));
}
static void standardTestsNone(Varargs none) {
private void standardTestsNone(Varargs none) {
expectEquals(NONE, none.subargs(1));
expectEquals(NONE, none.subargs(2));
}
public void testVarargsSubargs() {
@Test
void testVarargsSubargs() {
standardTestsA_G(A_G);
standardTestsA_G(A_G_alt);
standardTestsC_G(C_G);
@@ -170,7 +176,8 @@ public class VarargsTest extends TestCase {
standardTestsNone(NONE);
}
public void testVarargsMore() {
@Test
void testVarargsMore() {
Varargs a_g;
a_g = LuaValue.varargsOf(new LuaValue[] { A, }, LuaValue.varargsOf(new LuaValue[] { B, C, D, E, F, G }));
standardTestsA_G(a_g);
@@ -186,17 +193,15 @@ public class VarargsTest extends TestCase {
standardTestsA_G(a_g);
}
public void testPairVarargsMore() {
Varargs a_g = new Varargs.PairVarargs(A,
new Varargs.PairVarargs(B,
new Varargs.PairVarargs(C,
new Varargs.PairVarargs(D,
new Varargs.PairVarargs(E,
new Varargs.PairVarargs(F, G))))));
@Test
void testPairVarargsMore() {
Varargs a_g = new Varargs.PairVarargs(A, new Varargs.PairVarargs(B, new Varargs.PairVarargs(C,
new Varargs.PairVarargs(D, new Varargs.PairVarargs(E, new Varargs.PairVarargs(F, G))))));
standardTestsA_G(a_g);
}
public void testArrayPartMore() {
@Test
void testArrayPartMore() {
Varargs a_g;
a_g = new Varargs.ArrayPartVarargs(Z_H_array, 1, 1, new Varargs.ArrayPartVarargs(Z_H_array, 2, 6));
standardTestsA_G(a_g);
@@ -212,7 +217,7 @@ public class VarargsTest extends TestCase {
standardTestsA_G(a_g);
}
static void expectNegSubargsError(Varargs v) {
private void expectNegSubargsError(Varargs v) {
String expected_msg = "bad argument #1: start must be > 0";
try {
v.subargs(0);

View File

@@ -0,0 +1,262 @@
/*******************************************************************************
* 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;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.ref.WeakReference;
import org.junit.jupiter.api.Test;
class WeakTableTest {
@Test
void testWeakValuesTable() {
LuaTable t = WeakTable.make(false, true);
Object obj = new Object();
LuaTable tableValue = new LuaTable();
LuaString stringValue = LuaString.valueOf("this is a test");
LuaTable tableValue2 = new LuaTable();
t.set("table", tableValue);
t.set("userdata", LuaValue.userdataOf(obj, null));
t.set("string", stringValue);
t.set("string2", LuaValue.valueOf("another string"));
t.set(1, tableValue2);
assertTrue(t.getHashLength() >= 4, "table must have at least 4 elements");
// TODO fix assert
// assertTrue(t.getArrayLength() >= 1, "array part must have 1 element");
// check that table can be used to get elements
assertEquals(tableValue, t.get("table"));
assertEquals(stringValue, t.get("string"));
assertEquals(obj, t.get("userdata").checkuserdata());
assertEquals(tableValue2, t.get(1));
// nothing should be collected, since we have strong references here
collectGarbage();
// check that elements are still there
assertEquals(tableValue, t.get("table"));
assertEquals(stringValue, t.get("string"));
assertEquals(obj, t.get("userdata").checkuserdata());
assertEquals(tableValue2, t.get(1));
// drop our strong references
obj = null;
tableValue = null;
tableValue2 = null;
stringValue = null;
// Garbage collection should cause weak entries to be dropped.
collectGarbage();
// check that they are dropped
assertEquals(LuaValue.NIL, t.get("table"));
assertEquals(LuaValue.NIL, t.get("userdata"));
assertEquals(LuaValue.NIL, t.get(1));
assertFalse(t.get("string").isnil(), "strings should not be in weak references");
}
@Test
void testWeakKeysTable() {
LuaTable t = WeakTable.make(true, false);
LuaValue key = LuaValue.userdataOf(new MyData(111));
LuaValue val = LuaValue.userdataOf(new MyData(222));
// set up the table
t.set(key, val);
assertEquals(val, t.get(key));
System.gc();
assertEquals(val, t.get(key));
// drop key and value references, replace them with new ones
WeakReference<LuaValue> origkey = new WeakReference<>(key);
WeakReference<LuaValue> origval = new WeakReference<>(val);
key = LuaValue.userdataOf(new MyData(111));
val = LuaValue.userdataOf(new MyData(222));
// new key and value should be interchangeable (feature of this test class)
assertEquals(key, origkey.get());
assertEquals(val, origval.get());
assertEquals(val, t.get(key));
assertEquals(val, t.get(origkey.get()));
assertEquals(origval.get(), t.get(key));
// value should not be reachable after gc
collectGarbage();
assertEquals(null, origkey.get());
assertEquals(LuaValue.NIL, t.get(key));
collectGarbage();
assertEquals(null, origval.get());
}
@Test
void testNext() {
LuaTable t = WeakTable.make(true, true);
LuaValue key = LuaValue.userdataOf(new MyData(111));
LuaValue val = LuaValue.userdataOf(new MyData(222));
LuaValue key2 = LuaValue.userdataOf(new MyData(333));
LuaValue val2 = LuaValue.userdataOf(new MyData(444));
LuaValue key3 = LuaValue.userdataOf(new MyData(555));
LuaValue val3 = LuaValue.userdataOf(new MyData(666));
// set up the table
t.set(key, val);
t.set(key2, val2);
t.set(key3, val3);
// forget one of the keys
key2 = null;
val2 = null;
collectGarbage();
// table should have 2 entries
int size = 0;
for (LuaValue k = t.next(LuaValue.NIL).arg1(); !k.isnil(); k = t.next(k).arg1()) {
size++;
}
assertEquals(2, size);
}
@Test
void testWeakKeysValuesTable() {
LuaTable t = WeakTable.make(true, true);
LuaValue key = LuaValue.userdataOf(new MyData(111));
LuaValue val = LuaValue.userdataOf(new MyData(222));
LuaValue key2 = LuaValue.userdataOf(new MyData(333));
LuaValue val2 = LuaValue.userdataOf(new MyData(444));
LuaValue key3 = LuaValue.userdataOf(new MyData(555));
LuaValue val3 = LuaValue.userdataOf(new MyData(666));
// set up the table
t.set(key, val);
t.set(key2, val2);
t.set(key3, val3);
assertEquals(val, t.get(key));
assertEquals(val2, t.get(key2));
assertEquals(val3, t.get(key3));
System.gc();
assertEquals(val, t.get(key));
assertEquals(val2, t.get(key2));
assertEquals(val3, t.get(key3));
// drop key and value references, replace them with new ones
WeakReference<LuaValue> origkey = new WeakReference<>(key);
WeakReference<LuaValue> origval = new WeakReference<>(val);
WeakReference<LuaValue> origkey2 = new WeakReference<>(key2);
WeakReference<LuaValue> origval2 = new WeakReference<>(val2);
WeakReference<LuaValue> origkey3 = new WeakReference<>(key3);
WeakReference<LuaValue> origval3 = new WeakReference<>(val3);
key = LuaValue.userdataOf(new MyData(111));
val = LuaValue.userdataOf(new MyData(222));
key2 = LuaValue.userdataOf(new MyData(333));
// don't drop val2, or key3
val3 = LuaValue.userdataOf(new MyData(666));
// no values should be reachable after gc
collectGarbage();
assertEquals(null, origkey.get());
assertEquals(null, origval.get());
assertEquals(null, origkey2.get());
assertEquals(null, origval3.get());
assertEquals(LuaValue.NIL, t.get(key));
assertEquals(LuaValue.NIL, t.get(key2));
assertEquals(LuaValue.NIL, t.get(key3));
// all originals should be gone after gc, then access
val2 = null;
key3 = null;
collectGarbage();
assertEquals(null, origval2.get());
assertEquals(null, origkey3.get());
}
@Test
void testReplace() {
LuaTable t = WeakTable.make(true, true);
LuaValue key = LuaValue.userdataOf(new MyData(111));
LuaValue val = LuaValue.userdataOf(new MyData(222));
LuaValue key2 = LuaValue.userdataOf(new MyData(333));
LuaValue val2 = LuaValue.userdataOf(new MyData(444));
LuaValue key3 = LuaValue.userdataOf(new MyData(555));
LuaValue val3 = LuaValue.userdataOf(new MyData(666));
// set up the table
t.set(key, val);
t.set(key2, val2);
t.set(key3, val3);
LuaValue val4 = LuaValue.userdataOf(new MyData(777));
t.set(key2, val4);
// table should have 3 entries
int size = 0;
for (LuaValue k = t.next(LuaValue.NIL).arg1(); !k.isnil() && size < 1000; k = t.next(k).arg1()) {
size++;
}
assertEquals(3, size);
}
public static class MyData {
public final int value;
public MyData(int value) {
this.value = value;
}
@Override
public int hashCode() {
return value;
}
@Override
public boolean equals(Object o) {
return (o instanceof MyData) && ((MyData) o).value == value;
}
@Override
public String toString() {
return "mydata-" + value;
}
}
static void collectGarbage() {
Runtime rt = Runtime.getRuntime();
rt.gc();
try {
Thread.sleep(20);
rt.gc();
Thread.sleep(20);
} catch (Exception e) {
e.printStackTrace();
}
rt.gc();
}
}

BIN
luaj-jme-3.0.2.jar Normal file

Binary file not shown.

39
luaj-jme/pom.xml Normal file
View File

@@ -0,0 +1,39 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.luaj</groupId>
<artifactId>luaj-parent</artifactId>
<version>3.0-SNAPSHOT</version>
</parent>
<artifactId>luaj-jme</artifactId>
<name>luaj-jme</name>
<description>LuaJ for Java ME</description>
<dependencies>
<dependency>
<groupId>org.luaj</groupId>
<artifactId>luaj-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.bcel</groupId>
<artifactId>bcel</artifactId>
</dependency>
<dependency>
<groupId>com.github.mcpat.apistubs</groupId>
<artifactId>cldc-1.1-stub</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -35,60 +35,76 @@ import org.luaj.vm2.lib.IoLib;
import org.luaj.vm2.lib.LibFunction;
/**
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io}
* library for the JSE platform.
* Subclass of {@link IoLib} and therefore {@link LibFunction} which implements
* the lua standard {@code io} library for the JSE platform.
* <p>
* The implementation of the is based on CLDC 1.0 and StreamConnection.
* However, seek is not supported.
* The implementation of the is based on CLDC 1.0 and StreamConnection. However,
* seek is not supported.
* <p>
* Typically, this library is included as part of a call to
* {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()}
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals globals = JmePlatform.standardGlobals();
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </pre>
* }
* </pre>
* <p>
* For special cases where the smallest possible footprint is desired,
* a minimal set of libraries could be loaded
* directly via {@link Globals#load(LuaValue)} using code such as:
* <pre> {@code
* For special cases where the smallest possible footprint is desired, a minimal
* set of libraries could be loaded directly via {@link Globals#load(LuaValue)}
* using code such as:
*
* <pre>
* {
* &#64;code
* Globals globals = new Globals();
* globals.load(new JmeBaseLib());
* globals.load(new PackageLib());
* globals.load(new JmeIoLib());
* globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </pre>
* <p>However, other libraries such as <em>MathLib</em> are not loaded in this case.
* }
* </pre>
* <p>
* This has been implemented to match as closely as possible the behavior in the corresponding library in C.
* However, other libraries such as <em>MathLib</em> are not loaded in this
* case.
* <p>
* This has been implemented to match as closely as possible the behavior in the
* corresponding library in C.
*
* @see LibFunction
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform
* @see IoLib
* @see org.luaj.vm2.lib.jse.JseIoLib
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.8">Lua 5.2 I/O Lib Reference</a>
* @see <a href="http://www.lua.org/manual/5.2/manual.html#6.8">Lua 5.2 I/O Lib
* Reference</a>
*/
public class JmeIoLib extends IoLib {
@Override
protected File wrapStdin() throws IOException {
return new FileImpl(globals.STDIN);
}
@Override
protected File wrapStdout() throws IOException {
return new FileImpl(globals.STDOUT);
}
@Override
protected File wrapStderr() throws IOException {
return new FileImpl(globals.STDERR);
}
protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException {
@Override
protected File openFile(String filename, boolean readMode, boolean appendMode, boolean updateMode,
boolean binaryMode) throws IOException {
String url = "file:///" + filename;
int mode = readMode? Connector.READ: Connector.READ_WRITE;
StreamConnection conn = (StreamConnection) Connector.open(url, mode);
File f = readMode?
new FileImpl(conn, conn.openInputStream(), null):
new FileImpl(conn, conn.openInputStream(), conn.openOutputStream());
/*
if ( appendMode ) {
f.seek("end",0);
@@ -97,18 +113,21 @@ public class JmeIoLib extends IoLib {
conn.truncate(0);
}
*/
return f;
return readMode? new FileImpl(conn, conn.openInputStream(), null)
: new FileImpl(conn, conn.openInputStream(), conn.openOutputStream());
}
private static void notimplemented() throws IOException {
throw new IOException("not implemented");
}
@Override
protected File openProgram(String prog, String mode) throws IOException {
notimplemented();
return null;
}
@Override
protected File tmpFile() throws IOException {
notimplemented();
return null;
@@ -121,33 +140,46 @@ public class JmeIoLib extends IoLib {
private boolean closed = false;
private boolean nobuffer = false;
private int lookahead = -1;
private FileImpl(StreamConnection conn, InputStream is, OutputStream os) {
this.conn = conn;
this.is = is;
this.os = os;
}
private FileImpl(InputStream i) {
this(null, i, null);
}
private FileImpl(OutputStream o) {
this(null, null, o);
}
@Override
public String tojstring() {
return "file (" + this.hashCode() + ")";
}
@Override
public boolean isstdfile() {
return conn == null;
}
@Override
public void close() throws IOException {
closed = true;
if (conn != null) {
conn.close();
}
}
@Override
public void flush() throws IOException {
if (os != null)
os.flush();
}
@Override
public void write(LuaString s) throws IOException {
if (os != null)
os.write(s.m_bytes, s.m_offset, s.m_length);
@@ -156,9 +188,13 @@ public class JmeIoLib extends IoLib {
if (nobuffer)
flush();
}
@Override
public boolean isclosed() {
return closed;
}
@Override
public int seek(String option, int pos) throws IOException {
/*
if ( conn != null ) {
@@ -177,16 +213,20 @@ public class JmeIoLib extends IoLib {
notimplemented();
return 0;
}
@Override
public void setvbuf(String mode, int size) {
nobuffer = "no".equals(mode);
}
// get length remaining to read
@Override
public int remaining() throws IOException {
return -1;
}
// peek ahead one character
@Override
public int peek() throws IOException {
if (lookahead < 0)
lookahead = is.read();
@@ -194,6 +234,7 @@ public class JmeIoLib extends IoLib {
}
// return char if read, -1 if eof, throw IOException on other exception
@Override
public int read() throws IOException {
if (lookahead >= 0) {
int c = lookahead;
@@ -207,6 +248,7 @@ public class JmeIoLib extends IoLib {
}
// return number of bytes read if positive, -1 if eof, throws IOException
@Override
public int read(byte[] bytes, int offset, int length) throws IOException {
int n, i = 0;
if (is != null) {
@@ -218,7 +260,7 @@ public class JmeIoLib extends IoLib {
for (; i < length;) {
n = is.read(bytes, offset+i, length-i);
if (n < 0)
return ( i > 0 ? i : -1 );
return i > 0? i: -1;
i += n;
}
} else {

View File

@@ -23,8 +23,6 @@ package org.luaj.vm2.lib.jme;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LoadState;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.lib.BaseLib;
import org.luaj.vm2.lib.Bit32Lib;
@@ -37,40 +35,60 @@ import org.luaj.vm2.lib.ResourceFinder;
import org.luaj.vm2.lib.StringLib;
import org.luaj.vm2.lib.TableLib;
/** The {@link org.luaj.vm2.lib.jme.JmePlatform} class is a convenience class to standardize
* how globals tables are initialized for the JME platform.
/**
* The {@link org.luaj.vm2.lib.jme.JmePlatform} class is a convenience class to
* standardize how globals tables are initialized for the JME platform.
* <p>
* The JME platform, being limited, cannot implement all libraries in all aspects. The main limitations are
* The JME platform, being limited, cannot implement all libraries in all
* aspects. The main limitations are
* <ul>
* <li>Some math functions are not implemented, see {@link MathLib} for details</li>
* <li>Scripts are loaded via Class.getResourceAsStream(), see {@link BaseLib} for details</li>
* <li>OS functions execute(), remove(), rename(), and tmpname() vary, see {@link OsLib} for details</li>
* <li>I/O seek is not implemented, see {@link org.luaj.vm2.lib.jme.JmeIoLib} for details</li>
* <li>luajava is not available, see {@link org.luaj.vm2.lib.jse.LuajavaLib} for details</li>
* <li>Some math functions are not implemented, see {@link MathLib} for
* details</li>
* <li>Scripts are loaded via Class.getResourceAsStream(), see {@link BaseLib}
* for details</li>
* <li>OS functions execute(), remove(), rename(), and tmpname() vary, see
* {@link OsLib} for details</li>
* <li>I/O seek is not implemented, see {@link org.luaj.vm2.lib.jme.JmeIoLib}
* for details</li>
* <li>luajava is not available, see {@link org.luaj.vm2.lib.jse.LuajavaLib} for
* details</li>
* </ul>
* <p>
* It is used to allocate either a set of standard globals using
* {@link #standardGlobals()} or debug globals using {@link #debugGlobals()}
* <p>
* A simple example of initializing globals and using them from Java is:
* <pre> {@code
*
* <pre>
* {
* &#64;code
* Globals global = JmePlatform.standardGlobals();
* global.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
* }
* </pre>
* <p>
* Once globals are created, a simple way to load and run a script is:
* <pre> {@code
*
* <pre>
* {@code
* LoadState.load( getClass().getResourceAsStream("main.lua"), "main.lua", globals ).call();
* } </pre>
* }
* </pre>
* <p>
* although {@code require} could also be used:
* <pre> {@code
*
* <pre>
* {@code
* globals.get("require").call(LuaValue.valueOf("main"));
* } </pre>
* For this to succeed, the file "main.lua" must be a resource in the class path.
* See {@link BaseLib} for details on finding scripts using {@link ResourceFinder}.
* }
* </pre>
*
* For this to succeed, the file "main.lua" must be a resource in the class
* path. See {@link BaseLib} for details on finding scripts using
* {@link ResourceFinder}.
* <p>
* The standard globals will contain all standard libraries in their JME flavors:
* The standard globals will contain all standard libraries in their JME
* flavors:
* <ul>
* <li>{@link Globals}</li>
* <li>{@link BaseLib}</li>
@@ -83,9 +101,11 @@ import org.luaj.vm2.lib.TableLib;
* <li>{@link org.luaj.vm2.lib.jme.JmeIoLib}</li>
* <li>{@link OsLib}</li>
* </ul>
* In addition, the {@link LuaC} compiler is installed so lua files may be loaded in their source form.
* In addition, the {@link LuaC} compiler is installed so lua files may be
* loaded in their source form.
* <p>
* The debug globals are simply the standard globals plus the {@code debug} library {@link DebugLib}.
* The debug globals are simply the standard globals plus the {@code debug}
* library {@link DebugLib}.
* <p>
* <p>
* The class ensures that initialization is done in the correct order.
@@ -119,9 +139,11 @@ public class JmePlatform {
return globals;
}
/** Create standard globals including the {@link DebugLib} library.
/**
* Create standard globals including the {@link DebugLib} library.
*
* @return Table of globals initialized with the standard JSE and debug libraries
* @return Table of globals initialized with the standard JSE and debug
* libraries
* @see #standardGlobals()
* @see org.luaj.vm2.lib.jse.JsePlatform
* @see org.luaj.vm2.lib.jme.JmePlatform

View File

View File

@@ -0,0 +1,136 @@
package org.luaj.vm2.lib.jme;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.luaj.vm2.LuaValue;
class OsLibTest {
LuaValue jme_lib;
double time;
@BeforeEach
public void setUp() {
jme_lib = JmePlatform.standardGlobals().get("os");
time = 998571302000L/1000.0;
}
void test(String format, String expected) {
String actual = jme_lib.get("date").call(LuaValue.valueOf(format), LuaValue.valueOf(time)).tojstring();
assertEquals(expected, actual);
}
@Test
void testStringDateChars() { test("foo", "foo"); }
@Test
void testStringDate_a() { test("%a", "Thu"); }
@Test
void testStringDate_A() { test("%A", "Thursday"); }
@Test
void testStringDate_b() { test("%b", "Aug"); }
@Test
void testStringDate_B() { test("%B", "August"); }
@Test
void testStringDate_c() { test("%c", "Thu Aug 23 14:55:02 2001"); }
@Test
void testStringDate_d() { test("%d", "23"); }
@Test
void testStringDate_H() { test("%H", "14"); }
@Test
void testStringDate_I() { test("%I", "02"); }
@Test
void testStringDate_j() { test("%j", "235"); }
@Test
void testStringDate_m() { test("%m", "08"); }
@Test
void testStringDate_M() { test("%M", "55"); }
@Test
void testStringDate_p() { test("%p", "PM"); }
@Test
void testStringDate_S() { test("%S", "02"); }
@Test
void testStringDate_U() { test("%U", "33"); }
@Test
void testStringDate_w() { test("%w", "4"); }
@Test
void testStringDate_W() { test("%W", "34"); }
@Test
void testStringDate_x() { test("%x", "08/23/01"); }
@Test
void testStringDate_X() { test("%X", "14:55:02"); }
@Test
void testStringDate_y() { test("%y", "01"); }
@Test
void testStringDate_Y() { test("%Y", "2001"); }
@Test
void testStringDate_Pct() { test("%%", "%"); }
static final double DAY = 24.*3600.;
@Test
void testStringDate_UW_neg4() { time -= 4*DAY; test("%c %U %W", "Sun Aug 19 14:55:02 2001 33 33"); }
@Test
void testStringDate_UW_neg3() { time -= 3*DAY; test("%c %U %W", "Mon Aug 20 14:55:02 2001 33 34"); }
@Test
void testStringDate_UW_neg2() { time -= 2*DAY; test("%c %U %W", "Tue Aug 21 14:55:02 2001 33 34"); }
@Test
void testStringDate_UW_neg1() { time -= DAY; test("%c %U %W", "Wed Aug 22 14:55:02 2001 33 34"); }
@Test
void testStringDate_UW_pos0() { time += 0; test("%c %U %W", "Thu Aug 23 14:55:02 2001 33 34"); }
@Test
void testStringDate_UW_pos1() { time += DAY; test("%c %U %W", "Fri Aug 24 14:55:02 2001 33 34"); }
@Test
void testStringDate_UW_pos2() { time += 2*DAY; test("%c %U %W", "Sat Aug 25 14:55:02 2001 33 34"); }
@Test
void testStringDate_UW_pos3() { time += 3*DAY; test("%c %U %W", "Sun Aug 26 14:55:02 2001 34 34"); }
@Test
void testStringDate_UW_pos4() { time += 4*DAY; test("%c %U %W", "Mon Aug 27 14:55:02 2001 34 35"); }
@Test
void testJseOsGetenvForEnvVariables() {
LuaValue USER = LuaValue.valueOf("USER");
LuaValue jme_user = jme_lib.get("getenv").call(USER);
assertTrue(jme_user.isnil());
System.out.println("User: " + jme_user);
}
void testJseOsGetenvForSystemProperties() {
// System.setProperty("test.key.foo", "test.value.bar");
LuaValue key = LuaValue.valueOf("test.key.foo");
LuaValue value = LuaValue.valueOf("test.value.bar");
LuaValue jme_value = jme_lib.get("getenv").call(key);
assertEquals(value, jme_value);
}
}

View File

BIN
luaj-jse-3.0.2.jar Normal file

Binary file not shown.

77
luaj-jse/pom.xml Normal file
View File

@@ -0,0 +1,77 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.luaj</groupId>
<artifactId>luaj-parent</artifactId>
<version>3.0-SNAPSHOT</version>
</parent>
<artifactId>luaj-jse</artifactId>
<name>luaj-jse</name>
<description>LuaJ for Java SE</description>
<dependencies>
<dependency>
<groupId>org.luaj</groupId>
<artifactId>luaj-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.bcel</groupId>
<artifactId>bcel</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.helger.maven</groupId>
<artifactId>ph-javacc-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-grammar</id>
<phase>generate-sources</phase>
<goals>
<goal>javacc</goal>
</goals>
<configuration>
<jdkVersion>1.8</jdkVersion>
<javadocFriendlyComments>true</javadocFriendlyComments>
<packageName>org.luaj.vm2.parser</packageName>
<sourceDirectory>src/main/javacc</sourceDirectory>
<outputDirectory>${project.build.directory}/generated-sources/javacc</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/javacc</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,3 +1,4 @@
/*******************************************************************************
* Copyright (c) 2009-2012 Luaj.org. All rights reserved.
*
@@ -38,26 +39,19 @@ import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.luajc.LuaJC;
/**
* lua command for use in JSE environments.
*/
public class lua {
private static final String version = Lua._VERSION + " Copyright (c) 2012 Luaj.org.org";
private static final String usage =
"usage: java -cp luaj-jse.jar lua [options] [script [args]].\n" +
"Available options are:\n" +
" -e stat execute string 'stat'\n" +
" -l name require library 'name'\n" +
" -i enter interactive mode after executing 'script'\n" +
" -v show version information\n" +
" -b use luajc bytecode-to-bytecode compiler (requires bcel on class path)\n" +
" -n nodebug - do not load debug library by default\n" +
" -p print the prototype\n" +
" -c enc use the supplied encoding 'enc' for input files\n" +
" -- stop handling options\n" +
" - execute stdin and stop handling options";
private static final String usage = "usage: java -cp luaj-jse.jar lua [options] [script [args]].\n"
+ "Available options are:\n" + " -e stat execute string 'stat'\n" + " -l name require library 'name'\n"
+ " -i enter interactive mode after executing 'script'\n" + " -v show version information\n"
+ " -b use luajc bytecode-to-bytecode compiler (requires bcel on class path)\n"
+ " -n nodebug - do not load debug library by default\n" + " -p print the prototype\n"
+ " -c enc use the supplied encoding 'enc' for input files\n" + " -- stop handling options\n"
+ " - execute stdin and stop handling options";
private static void usageExit() {
System.out.println(usage);
@@ -71,7 +65,7 @@ public class lua {
public static void main(String[] args) throws IOException {
// process args
boolean interactive = (args.length == 0);
boolean interactive = args.length == 0;
boolean versioninfo = false;
boolean processing = true;
boolean nodebug = false;
@@ -137,7 +131,8 @@ public class lua {
// new lua state
globals = nodebug? JsePlatform.standardGlobals(): JsePlatform.debugGlobals();
if ( luajc ) LuaJC.install(globals);
if (luajc)
LuaJC.install(globals);
for (int i = 0, n = libs != null? libs.size(): 0; i < n; i++)
loadLibrary((String) libs.elementAt(i));
@@ -192,14 +187,14 @@ public class lua {
}
}
private static void processScript( InputStream script, String chunkname, String[] args, int firstarg ) throws IOException {
private static void processScript(InputStream script, String chunkname, String[] args, int firstarg)
throws IOException {
try {
LuaValue c;
try {
script = new BufferedInputStream(script);
c = encoding != null?
globals.load(new InputStreamReader(script, encoding), chunkname):
globals.load(script, chunkname, "bt", globals);
c = encoding != null? globals.load(new InputStreamReader(script, encoding), chunkname)
: globals.load(script, chunkname, "bt", globals);
} finally {
script.close();
}

View File

@@ -1,3 +1,4 @@
/*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved.
*
@@ -35,26 +36,19 @@ import org.luaj.vm2.Prototype;
import org.luaj.vm2.compiler.DumpState;
import org.luaj.vm2.lib.jse.JsePlatform;
/**
* Compiler for lua files to lua bytecode.
*/
public class luac {
private static final String version = Lua._VERSION + "Copyright (C) 2009 luaj.org";
private static final String usage =
"usage: java -cp luaj-jse.jar luac [options] [filenames].\n" +
"Available options are:\n" +
" - process stdin\n" +
" -l list\n" +
" -o name output to file 'name' (default is \"luac.out\")\n" +
" -p parse only\n" +
" -s strip debug information\n" +
" -e little endian format for numbers\n" +
" -i<n> number format 'n', (n=0,1 or 4, default="+DumpState.NUMBER_FORMAT_DEFAULT+")\n" +
" -v show version information\n" +
" -c enc use the supplied encoding 'enc' for input files\n" +
" -- stop handling options\n";
private static final String usage = "usage: java -cp luaj-jse.jar luac [options] [filenames].\n"
+ "Available options are:\n" + " - process stdin\n" + " -l list\n"
+ " -o name output to file 'name' (default is \"luac.out\")\n" + " -p parse only\n"
+ " -s strip debug information\n" + " -e little endian format for numbers\n"
+ " -i<n> number format 'n', (n=0,1 or 4, default=" + DumpState.NUMBER_FORMAT_DEFAULT + ")\n"
+ " -v show version information\n" + " -c enc use the supplied encoding 'enc' for input files\n"
+ " -- stop handling options\n";
private static void usageExit() {
System.out.println(usage);
@@ -134,10 +128,8 @@ public class luac {
System.out.println(version);
// open output file
OutputStream fos = new FileOutputStream( output );
// process input files
try {
try (OutputStream fos = new FileOutputStream(output)) {
Globals globals = JsePlatform.standardGlobals();
processing = true;
for (int i = 0; i < args.length; i++) {
@@ -158,8 +150,6 @@ public class luac {
}
}
}
} finally {
fos.close();
}
} catch (IOException ioe) {
@@ -168,13 +158,14 @@ public class luac {
}
}
private void processScript( Globals globals, InputStream script, String chunkname, OutputStream out ) throws IOException {
private void processScript(Globals globals, InputStream script, String chunkname, OutputStream out)
throws IOException {
try {
// create the chunk
script = new BufferedInputStream(script);
Prototype chunk = encoding != null?
globals.compilePrototype(new InputStreamReader(script, encoding), chunkname):
globals.compilePrototype(script, chunkname);
Prototype chunk = encoding != null
? globals.compilePrototype(new InputStreamReader(script, encoding), chunkname)
: globals.compilePrototype(script, chunkname);
// list the chunk
if (list)

View File

@@ -0,0 +1,270 @@
/*******************************************************************************
* Copyright (c) 2009-2012 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.
******************************************************************************/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import org.luaj.vm2.Globals;
import org.luaj.vm2.Lua;
import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.luajc.LuaJC;
/**
* Compiler for lua files to compile lua sources or lua binaries into java
* classes.
*/
public class luajc {
private static final String version = Lua._VERSION + " Copyright (C) 2012 luaj.org";
private static final String usage = "usage: java -cp luaj-jse.jar,bcel-5.2.jar luajc [options] fileordir [, fileordir ...]\n"
+ "Available options are:\n" + " - process stdin\n" + " -s src source directory\n"
+ " -d dir destination directory\n" + " -p pkg package prefix to apply to all classes\n"
+ " -m generate main(String[]) function for JSE\n" + " -r recursively compile all\n"
+ " -l load classes to verify generated bytecode\n"
+ " -c enc use the supplied encoding 'enc' for input files\n" + " -v verbose\n";
private static void usageExit() {
System.out.println(usage);
System.exit(-1);
}
private String srcdir = ".";
private String destdir = ".";
private boolean genmain = false;
private boolean recurse = false;
private boolean verbose = false;
private boolean loadclasses = false;
private String encoding = null;
private String pkgprefix = null;
private final List files = new ArrayList();
private final Globals globals;
public static void main(String[] args) throws IOException {
new luajc(args);
}
private luajc(String[] args) throws IOException {
// process args
List seeds = new ArrayList();
// get stateful args
for (int i = 0; i < args.length; i++) {
if (!args[i].startsWith("-")) {
seeds.add(args[i]);
} else {
switch (args[i].charAt(1)) {
case 's':
if (++i >= args.length)
usageExit();
srcdir = args[i];
break;
case 'd':
if (++i >= args.length)
usageExit();
destdir = args[i];
break;
case 'l':
loadclasses = true;
break;
case 'p':
if (++i >= args.length)
usageExit();
pkgprefix = args[i];
break;
case 'm':
genmain = true;
break;
case 'r':
recurse = true;
break;
case 'c':
if (++i >= args.length)
usageExit();
encoding = args[i];
break;
case 'v':
verbose = true;
break;
default:
usageExit();
break;
}
}
}
// echo version
if (verbose) {
System.out.println(version);
System.out.println("srcdir: " + srcdir);
System.out.println("destdir: " + destdir);
System.out.println("files: " + seeds);
System.out.println("recurse: " + recurse);
}
// need at least one seed
if (seeds.size() <= 0) {
System.err.println(usage);
System.exit(-1);
}
// collect up files to process
for (Object seed : seeds)
collectFiles(srcdir + "/" + seed);
// check for at least one file
if (files.size() <= 0) {
System.err.println("no files found in " + seeds);
System.exit(-1);
}
// process input files
globals = JsePlatform.standardGlobals();
for (Object file : files)
processFile((InputFile) file);
}
private void collectFiles(String path) {
File f = new File(path);
if (f.isDirectory() && recurse)
scandir(f, pkgprefix);
else if (f.isFile()) {
File dir = f.getAbsoluteFile().getParentFile();
if (dir != null)
scanfile(dir, f, pkgprefix);
}
}
private void scandir(File dir, String javapackage) {
File[] f = dir.listFiles();
for (File element : f)
scanfile(dir, element, javapackage);
}
private void scanfile(File dir, File f, String javapackage) {
if (f.exists()) {
if (f.isDirectory() && recurse)
scandir(f, javapackage != null? javapackage + "." + f.getName(): f.getName());
else if (f.isFile() && f.getName().endsWith(".lua"))
files.add(new InputFile(dir, f, javapackage));
}
}
private static final class LocalClassLoader extends ClassLoader {
private final Hashtable t;
private LocalClassLoader(Hashtable t) {
this.t = t;
}
@Override
public Class findClass(String classname) throws ClassNotFoundException {
byte[] bytes = (byte[]) t.get(classname);
if (bytes != null)
return defineClass(classname, bytes, 0, bytes.length);
return super.findClass(classname);
}
}
class InputFile {
public String luachunkname;
public String srcfilename;
public File infile;
public File outdir;
public String javapackage;
public InputFile(File dir, File f, String javapackage) {
this.infile = f;
String subdir = javapackage != null? javapackage.replace('.', '/'): null;
String outdirpath = subdir != null? destdir + "/" + subdir: destdir;
this.javapackage = javapackage;
this.srcfilename = (subdir != null? subdir + "/": "")+infile.getName();
this.luachunkname = (subdir != null? subdir + "/": "")
+infile.getName().substring(0, infile.getName().lastIndexOf('.'));
this.infile = f;
this.outdir = new File(outdirpath);
}
}
private void processFile(InputFile inf) {
inf.outdir.mkdirs();
try {
if (verbose)
System.out.println("chunk=" + inf.luachunkname + " srcfile=" + inf.srcfilename);
// create the chunk
FileInputStream fis = new FileInputStream(inf.infile);
final Hashtable t = encoding != null
? LuaJC.instance.compileAll(new InputStreamReader(fis, encoding), inf.luachunkname, inf.srcfilename,
globals, genmain)
: LuaJC.instance.compileAll(fis, inf.luachunkname, inf.srcfilename, globals, genmain);
fis.close();
// write out the chunk
for (Enumeration e = t.keys(); e.hasMoreElements();) {
String key = (String) e.nextElement();
byte[] bytes = (byte[]) t.get(key);
if (key.indexOf('/') >= 0) {
String d = (destdir != null? destdir + "/": "")+key.substring(0, key.lastIndexOf('/'));
new File(d).mkdirs();
}
String destpath = (destdir != null? destdir + "/": "") + key + ".class";
if (verbose)
System.out.println(" " + destpath + " (" + bytes.length + " bytes)");
FileOutputStream fos = new FileOutputStream(destpath);
fos.write(bytes);
fos.close();
}
// try to load the files
if (loadclasses) {
ClassLoader loader = new LocalClassLoader(t);
for (Enumeration e = t.keys(); e.hasMoreElements();) {
String classname = (String) e.nextElement();
try {
Class c = loader.loadClass(classname);
Object o = c.newInstance();
if (verbose)
System.out.println(" loaded " + classname + " as " + o);
} catch (Exception ex) {
System.out.flush();
System.err.println(" failed to load " + classname + ": " + ex);
System.err.flush();
}
}
}
} catch (Exception e) {
System.err.println(" failed to load " + inf.srcfilename + ": " + e);
e.printStackTrace(System.err);
System.err.flush();
}
}
}

View File

@@ -26,7 +26,7 @@ import java.util.List;
public class Block extends Stat {
public List<Stat> stats = new ArrayList<Stat>();
public List<Stat> stats = new ArrayList<>();
public NameScope scope;
public void add(Stat s) {
@@ -35,6 +35,7 @@ public class Block extends Stat {
stats.add(s);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}

View File

@@ -24,8 +24,7 @@ package org.luaj.vm2.ast;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaValue;
abstract
public class Exp extends SyntaxElement {
abstract public class Exp extends SyntaxElement {
abstract public void accept(Visitor visitor);
public static Exp constant(LuaValue value) {
@@ -63,14 +62,12 @@ public class Exp extends SyntaxElement {
// TODO: constant folding
if (lhs instanceof BinopExp) {
BinopExp b = (BinopExp) lhs;
if ( (precedence(op) > precedence(b.op)) ||
((precedence(op) == precedence(b.op)) && isrightassoc(op)) )
if (precedence(op) > precedence(b.op) || precedence(op) == precedence(b.op) && isrightassoc(op))
return binaryexp(b.lhs, b.op, binaryexp(b.rhs, op, rhs));
}
if (rhs instanceof BinopExp) {
BinopExp b = (BinopExp) rhs;
if ( (precedence(op) > precedence(b.op)) ||
((precedence(op) == precedence(b.op)) && ! isrightassoc(op)) )
if (precedence(op) > precedence(b.op) || precedence(op) == precedence(b.op) && !isrightassoc(op))
return binaryexp(binaryexp(lhs, op, b.lhs), b.op, b.rhs);
}
return new BinopExp(lhs, op, rhs);
@@ -79,22 +76,43 @@ public class Exp extends SyntaxElement {
static boolean isrightassoc(int op) {
switch (op) {
case Lua.OP_CONCAT:
case Lua.OP_POW: return true;
default: return false;
case Lua.OP_POW:
return true;
default:
return false;
}
}
static int precedence(int op) {
switch (op) {
case Lua.OP_OR: return 0;
case Lua.OP_AND: return 1;
case Lua.OP_LT: case Lua.OP_GT: case Lua.OP_LE: case Lua.OP_GE: case Lua.OP_NEQ: case Lua.OP_EQ: return 2;
case Lua.OP_CONCAT: return 3;
case Lua.OP_ADD: case Lua.OP_SUB: return 4;
case Lua.OP_MUL: case Lua.OP_DIV: case Lua.OP_MOD: return 5;
case Lua.OP_NOT: case Lua.OP_UNM: case Lua.OP_LEN: return 6;
case Lua.OP_POW: return 7;
default: throw new IllegalStateException("precedence of bad op "+op);
case Lua.OP_OR:
return 0;
case Lua.OP_AND:
return 1;
case Lua.OP_LT:
case Lua.OP_GT:
case Lua.OP_LE:
case Lua.OP_GE:
case Lua.OP_NEQ:
case Lua.OP_EQ:
return 2;
case Lua.OP_CONCAT:
return 3;
case Lua.OP_ADD:
case Lua.OP_SUB:
return 4;
case Lua.OP_MUL:
case Lua.OP_DIV:
case Lua.OP_MOD:
return 5;
case Lua.OP_NOT:
case Lua.OP_UNM:
case Lua.OP_LEN:
return 6;
case Lua.OP_POW:
return 7;
default:
throw new IllegalStateException("precedence of bad op " + op);
}
}
@@ -145,30 +163,40 @@ public class Exp extends SyntaxElement {
}
abstract public static class PrimaryExp extends Exp {
@Override
public boolean isvarexp() {
return false;
}
@Override
public boolean isfunccall() {
return false;
}
}
abstract public static class VarExp extends PrimaryExp {
@Override
public boolean isvarexp() {
return true;
}
public void markHasAssignment() {
}
}
public static class NameExp extends VarExp {
public final Name name;
public NameExp(String name) {
this.name = new Name(name);
}
@Override
public void markHasAssignment() {
name.variable.hasassignments = true;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -176,10 +204,12 @@ public class Exp extends SyntaxElement {
public static class ParensExp extends PrimaryExp {
public final Exp exp;
public ParensExp(Exp exp) {
this.exp = exp;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -188,11 +218,13 @@ public class Exp extends SyntaxElement {
public static class FieldExp extends VarExp {
public final PrimaryExp lhs;
public final Name name;
public FieldExp(PrimaryExp lhs, String name) {
this.lhs = lhs;
this.name = new Name(name);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -201,11 +233,13 @@ public class Exp extends SyntaxElement {
public static class IndexExp extends VarExp {
public final PrimaryExp lhs;
public final Exp exp;
public IndexExp(PrimaryExp lhs, Exp exp) {
this.lhs = lhs;
this.exp = exp;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -220,14 +254,17 @@ public class Exp extends SyntaxElement {
this.args = args;
}
@Override
public boolean isfunccall() {
return true;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public boolean isvarargexp() {
return true;
}
@@ -241,10 +278,12 @@ public class Exp extends SyntaxElement {
this.name = new String(name);
}
@Override
public boolean isfunccall() {
return true;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -252,10 +291,12 @@ public class Exp extends SyntaxElement {
public static class Constant extends Exp {
public final LuaValue value;
public Constant(LuaValue value) {
this.value = value;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -263,10 +304,12 @@ public class Exp extends SyntaxElement {
public static class VarargsExp extends Exp {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public boolean isvarargexp() {
return true;
}
@@ -275,11 +318,13 @@ public class Exp extends SyntaxElement {
public static class UnopExp extends Exp {
public final int op;
public final Exp rhs;
public UnopExp(int op, Exp rhs) {
this.op = op;
this.rhs = rhs;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -288,12 +333,14 @@ public class Exp extends SyntaxElement {
public static class BinopExp extends Exp {
public final Exp lhs, rhs;
public final int op;
public BinopExp(Exp lhs, int op, Exp rhs) {
this.lhs = lhs;
this.op = op;
this.rhs = rhs;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@@ -301,10 +348,12 @@ public class Exp extends SyntaxElement {
public static class AnonFuncDef extends Exp {
public final FuncBody body;
public AnonFuncDef(FuncBody funcbody) {
this.body = funcbody;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}

View File

@@ -50,12 +50,12 @@ public class FuncArgs extends SyntaxElement {
}
public FuncArgs(LuaString string) {
this.exps = new ArrayList<Exp>();
this.exps = new ArrayList<>();
this.exps.add(Exp.constant(string));
}
public FuncArgs(TableConstructor table) {
this.exps = new ArrayList<Exp>();
this.exps = new ArrayList<>();
this.exps.add(table);
}

View File

@@ -30,6 +30,7 @@ public class FuncBody extends SyntaxElement {
this.parlist = parlist != null? parlist: ParList.EMPTY_PARLIST;
this.block = block;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}

View File

@@ -42,7 +42,7 @@ public class FuncName extends SyntaxElement {
public void adddot(String dot) {
if (dots == null)
dots = new ArrayList<String>();
dots = new ArrayList<>();
dots.add(dot);
}

Some files were not shown because too many files have changed in this diff Show More