1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-15 14:07:38 +00:00

Compare commits

...

502 Commits

Author SHA1 Message Date
SquidDev
08d22fd3df Fix changelog being out-of-sync 2019-08-04 11:05:14 +01:00
SquidDev
e6c691a8f8 Fix rom's location
This isn't going to get annoying or anything
2019-08-04 11:02:07 +01:00
SquidDev
4b0e5c445c Merge branch 'master' into mc-1.14.x 2019-08-04 10:57:20 +01:00
SquidDev
eb5cff1045 Alright, let's do this one last time 2019-08-04 09:27:48 +01:00
SquidDev
35c7792aa2 Limit the titles of printed pages
Just enforce the same restrictions as we do for computer/disk labels.
2019-08-04 08:59:44 +01:00
Jonathan Coates
521688d630 Merge pull request #183 from SquidDev-CC/feature/thread-safe-inventories 2019-08-01 14:30:32 +01:00
SquidDev
75e2845c01 Remove synchronized from turtle inventory code
These should never be called off the server thread, so this doesn't make
much difference.
2019-08-01 14:09:57 +01:00
SquidDev
2f96283286 Make disk drives thread-safe 2019-08-01 13:48:03 +01:00
SquidDev
cbe6e9b5f5 Make printers thread-safe 2019-08-01 13:48:03 +01:00
SquidDev
2ab79cf474 Version bumps 'n stuff 2019-07-30 15:48:05 +01:00
SquidDev
6ce34aba79 A quick attempt at fixing Travis
Oracle JDK 8 is EOL (I think at least).
2019-07-30 15:25:14 +01:00
SquidDev
5eeb320b60 Include all mods within a resource mount
This is the behaviour on 1.14 already, so it makes sense to backport to
1.12.

Any mod may now insert files into assets/computercraft/lua/rom, and
they'll be automatically added to the default ROM mount. This allows
other mods to easily register new programs or autorun files.

See #242
2019-07-30 15:20:08 +01:00
SquidDev
93310850d2 Use the "cc" module namespace instead of "craftos"
This is what we actually discussed in the issue, and I failed to
remember.
2019-07-27 11:34:59 +01:00
powerboat9
a2880b12ca Do not refuel beyond the turtle limit (#274) 2019-07-24 08:15:02 +01:00
SquidDev
cef2657048 Fix turtles being replaced by leaves
And logs. Well, hopefully at least.

Fixes #278
2019-07-21 10:28:22 +01:00
SquidDev
ccd85eb055 Bump Forge version 2019-07-21 09:41:58 +01:00
powerboat9
303b57779a Fix turtles harvesting blocks when they shouldn't (#276)
harvestBlock should only be called when removedByPlayer and canHarvestBlock
return true, otherwise we run the risk of causing dupe bugs.

See #273.
2019-07-17 09:23:14 +01:00
SquidDev
6279816ecc Try using the HTTP one instead 2019-07-15 08:45:22 +01:00
SquidDev
4ae77261fa Petty changes because I'm petty 2019-07-13 08:29:28 +01:00
liquid
4b7d843b78 Removed term.getLine 2019-07-13 01:45:16 -05:00
liquid
1c28df65c3 Fixed style errors 2019-07-12 23:56:49 -05:00
liquid
85b740f484 Added term.getLine and window.getLine 2019-07-12 22:54:37 -05:00
SquidDev
f9929cb27d Fix the signature of loadfile
Lua 5.2+ uses loadfile(filename, mode, env), not loadfile(filename,
env). While this is a minor incompatibility, it'd be nice to be
consistent as much as possible.

We try to handle the incorrect case too, as obviously we don't want to
break existing programs.
2019-07-12 22:04:28 +01:00
SquidDev
bafab1ac07 Expose expect as a module (#267)
This moves expect from the bios into a new craftos.expect module,
removing the internal _G["~expect"] definition. Apparently people were
using this irrespective of the "don't use this" comment, so we need to
find another solution.

While this does introduce some ugliness (having to load the module in
weird ways for programs, duplicating the expect function in memory), it
does allow people to use the function in a supported way, and removes
the global ugliness.
2019-07-09 08:04:49 +01:00
JakobDev
e05c262468 Add more tests (#253)
I'm not entirely sure how useful all of these will be yet - still
trying to work out what/when to test things, but hopefully this'll
be a useful datapoint.
2019-07-08 09:24:05 +01:00
SquidDev
acfb72246c Bump JEI version 2019-07-07 15:52:52 +01:00
SquidDev
9d51c4c340 Use world-specific collider entity
This is equally an ugly hack, but means we're at least not constructing
entities with null worlds any more.

Ideally we could always use the turtle entity, but this will require a
bit more of a refactor.

Fixes #265
2019-07-05 22:09:42 +01:00
SquidDev
18068effec Use reflection to get the record's sound
getSound is client side only - I could have sworn it became shared at
some point, but that may have been reverted again (or I imagined it).

Fixes #263
2019-07-05 21:51:54 +01:00
SquidDev
7a3f7d3bba I'm a muppet
Even worse, I enabled branch protection for some reason, and so can't
force push and pretend this never happened.
2019-06-29 15:49:14 +01:00
SquidDev
95aa48c456 Allow running expectations against stubbed functions
Co-authored-by: hydraz <urn@semi.works>
2019-06-29 15:37:41 +01:00
SquidDev
6ea8ca991b Bump Forge to 1.14.3
Guess it's time for another release?
2019-06-26 08:25:32 +01:00
SquidDev
f1e551b960 Bump Forge version
Turtle models now work (though texture registration is still broken).
2019-06-23 15:30:29 +01:00
SquidDev
772c54ec74 Copy the item stack before merging
Otherwise we would mutate the stack, and so the current mount was
considered empty. Closes #240 (though would be nice to improve this).
2019-06-21 22:00:21 +01:00
SquidDev
13cb789c18 Fix "can deploy" check being entirely incorrect
Closes #258
2019-06-21 21:51:22 +01:00
SquidDev
42220c4268 Fix several other client-only methods 2019-06-21 21:32:15 +01:00
SquidDev
3052506e2e Reload configs from the file 2019-06-21 21:32:02 +01:00
SquidDev
0741daa7eb Fix usage of a client-only method
Should probably run forge-lint on this at some point, but it's a good
start.

Fixes #255
2019-06-21 21:02:09 +01:00
SquidDev
b4aa554279 Do not fetch the current block within onLoad
The chunk has not been fully loaded when onLoad is called, which means
we try to load it again, and so the server deadlocks.
2019-06-21 20:57:38 +01:00
SquidDev
8fe2abe0ae Forward tab key directly to the terminal
Fixes #256
2019-06-21 20:31:28 +01:00
SquidDev
5af789ae11 Bump Forge version 2019-06-21 20:31:17 +01:00
SquidDev
904a168d5c Fix incorrect explosion check
We should block explosions if the turtle is advanced /or/ if it's from
a fireball or entity, not if both.

Fixes #257
2019-06-21 18:53:28 +01:00
JakobDev
724441eddc Change URLs in build.gradle to https (#259) 2019-06-21 16:51:55 +01:00
SquidDev
f68ab3edd1 Minor tweaks to build script
Mostly just rearranging. Bump JUnit version in an attempt to fix test
outputs, but it appears this is a mix of gradle/gradle#5975 and
gradle/gradle#4438.
2019-06-15 11:05:45 +01:00
SquidDev
68542aca3a Fix cable breaking rendering
Texture locations have changed a little
2019-06-15 09:19:41 +01:00
SquidDev
594bc4203c Fix block drops for computers and turtles 2019-06-15 09:07:31 +01:00
SquidDev
57318b022d Merge branch 'master' into mc-1.14.x 2019-06-15 08:00:20 +01:00
SquidDev
761159aa93 Bump Forge version 2019-06-15 07:40:27 +01:00
SquidDev
29dce26bf6 Clean up checkstyle warning
Fixes #251, closes #252
2019-06-14 20:55:32 +01:00
JakobDev
717ab69093 Add a few Checks (#248)
- Add some basic tests for several built-in programs.
 - Preserve the state of the shell between tests
2019-06-14 08:15:12 +01:00
SquidDev
138a2cf08f Merge branches 'copycheck' and 'renamefix' 2019-06-13 08:03:35 +01:00
JakobDev
81daf82647 Add Checks to copy.lua 2019-06-13 08:03:01 +01:00
JakobDev
f3798bfb63 Improve rename.lua's argument validation 2019-06-13 08:00:06 +01:00
SquidDev
bc07dfad2e Make sure all writeDescription methods are pure
We don't want to be firing block updates or anything from here! That
runs the ricks of causing CMEs and the like.

Fixes #245
2019-06-12 21:03:11 +01:00
SquidDev
8dd1c2a6cc Finish off containers, somewhat fix block drops
- Add Forge's "name" field to the loot tables. This doesn't resolve all
   our missing loot providers, but it's a start.
 - Add back GUIs for pocket computers, printouts, view computer, etc...
2019-06-12 08:40:20 +01:00
SquidDev
d10b657a54 Initial work on GUIs
Needs a bit of a cleanup, but it's a start!
2019-06-11 21:03:40 +01:00
SquidDev
f90da739eb And bump Forge again 2019-06-09 10:15:53 +01:00
SquidDev
d9cadf64e8 Get the build working I guess? 2019-06-09 09:07:31 +01:00
SquidDev
15d4a55cd8 Bump mappings and Forge versions
Things are shaping up nicely!
2019-06-09 08:58:49 +01:00
JakobDev
309cbdb8be Add wget run (#218)
Equivalent to `pastebin run`, but allows running arbitrary URLs
instead.

Is this a little questionable? Yes - people shouldn't be downloading
and running code from the internet. But hey, people do that already,
so we might as well make it convenient.
2019-06-08 14:49:42 +01:00
SquidDev
39a9ad0ce7 Initial update to 1.14
So very little works, but it compiles and runs.

Things to resolve over the next few days:
 - Horrible mappings (should largely be resolved by tomorrow).
 - Cannot send extra data over containers - we'll have to see what Forge
   does here.
 - Turtle models are broken
 - No block drops yet - this will largely be cherry-picking whatever I
   did on Fabric.
 - Weird inventory desyncs (items don't show up initially when
   interacting with a CC inventory).
 - Probably lots of other things.
2019-06-08 13:36:31 +01:00
SquidDev
0f3c44c926 Merge branch 'master' into mc-1.13.x 2019-06-08 08:21:08 +01:00
SquidDev
a0e7c4a74c Add a little bit of source code checking to Gradle
- Adds a CheckStyle configuration which is pretty similar to CC's
   existing one.
 - Add the Gradle license plugin.
 - Ensure the existing source code is compatible with these additional
   checks.

See #239
2019-06-08 00:28:03 +01:00
Lignum
7d428030df Fix some warnings (#235)
Remove some unused code and fix a bunch of warnings
2019-06-07 14:35:17 +01:00
JakobDev
00c395f689 Add Check to delete.lua (#236) 2019-06-06 16:43:48 +01:00
SquidDev
d8e1c73d26 Ensure files cannot be closed multiple times
Also fix an NPE if we try to close them twice.

Fixes #230
2019-06-04 21:34:19 +01:00
SquidDev
ffa4cc241b Add a test utility for capturing program output
- Make mcfly's stubbing system a little more fault-tolerant.
 - Add a small utility function which redirects print, printError and
   write to capture their output, rather than printing to the terminal.
   This can then be matched against in order to determine a program's
   output.
   It's a little flakey - you can't use it multiple times in an it
   block, etc... but it's a nice feature.
 - Add a small couple of tests to delete as a proof-of-concept.
2019-06-03 20:33:09 +01:00
SquidDev
6f1b740c8f Un-localise paths in mount error messages
This is probably a little more complex than it needs to be, as we try to
handle the mounts as well (which generally don't error).

Fixes #229
2019-06-03 19:58:16 +01:00
SquidDev
3406ba3ebf Fix a build from a clean state failing 2019-06-02 18:48:36 +01:00
SquidDev
b6715bd812 Fix a couple of build failures 2019-06-02 18:36:34 +01:00
SquidDev
18aee02221 Mark CurseForge builds as release
They're almost definitely not, but I've had no bug reports so they must
work!
2019-06-02 17:28:13 +01:00
SquidDev
401bbf2e6a Fix turtle block placing failing 2019-06-02 17:25:49 +01:00
SquidDev
7467b7f88a Fix several deprecated warnings 2019-06-02 17:23:33 +01:00
SquidDev
c82d8a7c2a Merge branch 'master' into mc-1.13.x 2019-06-02 16:46:45 +01:00
SquidDev
6b81bcf334 Bump version 2019-06-02 16:20:15 +01:00
SquidDev
3d67421d98 Bump Forge version 2019-06-02 16:18:44 +01:00
SquidDev
acac70675d Add link to CF on the README
Not sure how useful this is - people are far more likely to come across
the CurseForge page than the GH one, but there's no harm I guess.

Closes #227
2019-06-01 15:15:39 +01:00
JakobDev
56434259c1 Add Checks for Turtle and Pocket programs (#226)
Error if turtle and pocket computers programs are not run on
their respective devices.
2019-06-01 12:48:33 +01:00
JakobDev
da7e4b9016 Add more MOTD messages. (#225) 2019-06-01 12:41:01 +01:00
SquidDev
d4b8650d21 Use select('#', ...) instead of ipairs on varargs
This means we don't discard any value after nil, meaning that
calls such as colors.combine(nil, 1, 2, 3) will error, rather
than returning 0.
2019-06-01 10:12:10 +01:00
SquidDev
17645a79f0 Fix type check on rednet.lookup
Fixes #224
2019-06-01 09:23:18 +01:00
SquidDev
ce1f14a010 Fix a couple of problems in the release buildscript
Otherwise that went pretty smoothly!
2019-05-31 13:56:48 +01:00
SquidDev
43050426de Bump version
First time using the new changelog tooling, let's see how this goes.
2019-05-31 13:53:15 +01:00
SquidDev
b05f60c98b Add small task to verify changelog is correct
Also use the changelog contents as the GH release notes
2019-05-31 10:19:24 +01:00
SquidDev
c44c560f96 Update changelog and whatsnew
- Convert existing changelog over to use Markdown. This mostly involves
   wrapping code in backticks, and marking things as headers where
   appropriate.
 - Copy all of CC:T's release notes over to the changelog. This is
   somewhat more verbose than Dan's notes, but keeping them in sync
   seems reasonable (and allows for automation!).
2019-05-31 09:35:45 +01:00
SquidDev
e839ef54af Forbid mutating empty_json_array
It's definitely still possible (rawset), but should prevent people
accidentally trying to modify it when they shouldn't.
2019-05-30 20:01:09 +01:00
SquidDev
0cb659d78c Ensure require is usable within the REPL
As 'require' operates relative to the current program's directory,
rather than the current directory, it meant we were trying to load files
from /rom/programs.

This is never a good idea, so we add the current directory to the
package path, allowing you to use require as one'd expect.
2019-05-30 19:52:55 +01:00
hydraz
9048deeb95 Add a function for type-checking arguments (#207)
- Define an expect(index, actual_value, types...) helper function which
   takes an argument index, value and list of permissable types and
   ensures the value is of one of those types.
   If not, it will produce an error message with the expected and actual
   type, as well as the argument number and (if available) the function
   name.
 - Expose expect in the global scope as _G["~expect"], hopefully making
   it clear it is internal.
 - Replace most manual type checks with this helper method.
 - Write tests to ensure this argument validation works as expected

Also fix a couple of bugs exposed by this refactor and the subsequent
tests:
 - Make rednet checks a little more strict - rednet.close(false) is no
   longer valid.
 - Error when attempting to redirect the terminal to itself 
   (term.redirect(term)).
2019-05-30 19:36:28 +01:00
SquidDev
5592ebae7d A small bit of housekeeping
- Add a link to discord and the forums. Oh goodness, I hope this
   doesn't count as making things official.
   I've had a couple of people email me with support requests, which is
   /fine/, but there's better channels for it!
 - Add a couple of PR templates
   - Ask people to write tests for CraftOS changes. This is a standard
     I'm trying to impose on myself, so seems reasonable to impose on
     everyone. Sorry!
   - Require same levels of explanation for PRs as we do for issues.
 - Try to expand on the feature request "rationale" section a little.
   Just trying to explan my process a little bit more.
2019-05-30 08:44:15 +01:00
SquidDev
b076c32fd1 Merge remote-tracking branch 'origin' 2019-05-30 07:57:30 +01:00
SquidDev
a48f1e310f Add a custom renderer for monitor block highlights (#220)
This only renders the bounding box on non-screen edges of the monitor,
meaning you have an uninterrupted view of the screen when hovering
hover.

Closes #219
2019-05-30 07:51:35 +01:00
SquidDev
19aca001d7 A couple of stability improvements to ComputerThread
- Be more generous in what errors we catch, handling some of the more
   "recoverable" ones.
 - Should a runner crash, attempt to restart it.
2019-05-29 09:03:31 +01:00
SquidDev
114f913bf8 Rework rendering of in-hand pocket computers (#215)
Rendering an item worked in principle, but had several caveats:
 - The terminal did not fit well within the item's texture, so we had a
   rather large border.
 - The "correctness" of this was very tied to Minecraft's item rendering
   code. This changed a little in 1.13, causing problems like #208.

Instead we effectively reuse the computer GUI rendering code, though
also handling coloured pocket computers and rendering the modem light.

This fixes #208, and hopefully fixes #212.
2019-05-26 15:24:37 +01:00
Daniel Ratcliffe
1c9810890a Merge pull request #577 from SquidDev-CC/feature/get-blink
Add .getCursorBlink to monitors and terminals
2019-05-26 00:14:02 +01:00
SquidDev
b11beb508b Convert mkdir motd note to plural
*shrug*
2019-05-25 19:17:10 +01:00
SquidDev
af8d4da594 Ensure the test name is ASCII
Gradle really doesn't like unicode apparently
2019-05-25 18:11:14 +01:00
JakobDev
a81db2cda6 Allow multiple arguments for mkdir (#216) 2019-05-25 18:04:56 +01:00
SquidDev
99bdff0f92 Automatically label issues created with templates 2019-05-25 14:53:48 +01:00
SquidDev
bb138326df Use correct model for blinking pocket computers
Fixes #211211211211211211211211211211211211211211211211211211211211211
2019-05-25 09:28:15 +01:00
hydraz
5b0ce7410d Make delete delete many files (#210)
Actually, many *globs*. It additionally prints the glob if no files
matched it, since that's clearer.

Also move the ComputerTestDelegate's filesystem to be disk-based. This
is what actual computers use, and the MemoryMount is a little broken.
2019-05-25 09:02:42 +01:00
SquidDev
d5ea22d1a0 Jolly good job 2019-05-24 22:43:59 +01:00
SquidDev
210f3fa9e2 Add mostly standard compliant os.time/os.date
- os.time, when given a table, will act the same as PUC Lua - returning
   the seconds since the epoch. We preserve the previous string/nil
   behaviour though - os.epoch("local") is equivalent to PUC's
   os.time().

 - os.date will now act accept a string and (optional) time, returning
   an appropriate table.

Somewhat resolves the madness which was dan200/ComputerCraft#183, and
hopefully (though probably not) makes @Vexatos happy.
2019-05-24 22:33:56 +01:00
SquidDev
d661cfa88b Set the arg table within shell.run
This makes us a little more compatible with Lua
2019-05-24 18:42:19 +01:00
SquidDev
68bf3a71dc Lazilly instantiate the terminal packet
This means we don't create an NBT tag every tick if the screen is
updating, unless we actually need to.
2019-05-24 18:32:56 +01:00
SquidDev
3cdb12d293 Stop shipping jars with GH releases
The build appears to be a little bit broken, I haven't got willpower to
look into it, and it's not really used anyway.
2019-05-14 07:44:19 +01:00
Wilma456 (Jakob0815)
ad33acd7d1 Add MOTD (#175) 2019-05-13 16:54:19 +01:00
SquidDev
0ec3884e98 Handle websockets which close while receiving
This changes the previous behaviour a little, but hopefully is more
sane:

 - Only require the socket to be open when first calling receive. This
   means if it closes while receving, you won't get an error.

   This behaviour is still not perfect - the socket could have closed,
   but the event not reached the user yet, but it's better.

 - Listen to websocket_close events while receiving, and return null
   should it match ours.

See #201
2019-05-08 08:16:21 +01:00
SquidDev
7f2471d6b2 Fix list-like config options not reloading
Closes #199
2019-05-08 08:00:07 +01:00
xuyu0v0
e0660b1dab Create zh_cn.json 2019-05-06 21:47:43 +01:00
SquidDev
2182cfbeb7 Merge branch 'master' into mc-1.13.x 2019-05-06 21:32:56 +01:00
SquidDev
8fafec4915 Fix budget growing too much
We were using += instead of =, meaning the budget always grew,
rather than growing while there was still space. As a result, computers
were never correctly rate limited.

Further more, if a computer went into a deficit, we would continue to
increase the budget by a negative amount, exponentially decreasing until
overflowing!

Yes, this is a very embarrassing mistake. I'd been aware that rate
limiting wasn't working as expected for a while, I hadn't realised
the problem would be this stupid.
2019-05-01 17:24:30 +01:00
SquidDev
b9fd690ecb Mark CC:T as incompatible with ComputerCraft
Just so people using the Twitch client don't try to use both.
2019-05-01 17:24:30 +01:00
xuyu0v0
2f2ada4416 Create zh_cn.lang (#186) 2019-04-24 15:41:13 +01:00
SquidDev
9c951c58d9 Revert "Switch over to Curse maven for now"
This reverts commit 4b4b47e231.

Didn't need it for that long. Woops.
2019-04-24 15:17:13 +01:00
SquidDev
4b4b47e231 Switch over to Curse maven for now
It stinks, but it's a suitable workaround.

Closes #184
2019-04-24 14:48:11 +01:00
SquidDev
2c027adb68 Fix advancements
Looks like these were never properly updated. Woops.
2019-04-24 12:15:03 +01:00
SquidDev
4a25e7a178 Fix GH release uploading 2019-04-24 10:40:44 +01:00
SquidDev
55d54fec63 Bump versions 2019-04-24 10:33:50 +01:00
SquidDev
220e4bd660 Merge branch 'master' into mc-1.13.x 2019-04-24 10:15:33 +01:00
SquidDev
978c28a686 Bump version 2019-04-24 09:48:28 +01:00
SquidDev
b867ada5e5 Merge pull request #182 from SquidDev-CC/hotfix/redstone-checks
Redstone behaviour tweaks
2019-04-24 09:45:28 +01:00
SquidDev
7071cc972b Make redstone behaviour consistent with repeaters
This uses the same behaviour that repeaters and comparators do for
determining their input, meaning that redstone directly connected to the
computer is read (as you would expect).

It's worth noting that this is a shift from previous behaviour.
Therefore, it runs the (small) risk of breaking existing builds.
However, I believe it is more consistent with the expected behaviour.
2019-04-22 11:52:53 +01:00
SquidDev
6898f932a0 Remove redstone blocked checks
This has been returning false for almost 2 years (since
8abff95441). At this point, it's probably
worth just dropping it entirely.
2019-04-22 11:40:19 +01:00
SquidDev
2e0ef6385d Fix TurtleCompareCommand throwing exceptions
Originally introduced in 173ea72001, but
the underlying cause has been happening for much longer.

 - Fix order of method name parameters. Looks like this has been broken
   since 1.11. Woops.
 - Catch RuntimeExceptions too, as Forge converts checked into unchecked
   ones.

Fixes #179
2019-04-19 18:57:12 +01:00
SquidDev
f93da7ea51 Bump Cobalt version
I promise! The joys of using -SNAPSHOT I guess...

This will now correctly cause orphaned threads to be cleaned up,
reducing the risk of thread saturation.
2019-04-18 09:49:52 +01:00
SquidDev
1210bb8a4d Fix Gradle dependencies
I'm not entirely sure why it didn't like the previous version, but there
we go.
2019-04-16 10:43:11 +01:00
SquidDev
48a71e96eb Bump version 2019-04-16 10:35:15 +01:00
SquidDev
3bf47b5290 Make refuelling a little more flexible
This removes the link between item size and refuel limit, meaning
working with other items (such as FE items) is a little easier.
2019-04-16 10:28:10 +01:00
SquidDev
9e9f199e55 Remove a couple of over-eager error logs 2019-04-16 10:08:12 +01:00
SquidDev
5a8a111857 You didn't see nothing 2019-04-15 18:33:59 +01:00
SquidDev
48ba247ab4 Create an IMultipartTile for all BlockPeripheral tiles
Fixes #176
2019-04-15 09:21:10 +01:00
SquidDev
362dbd97ac Correctly handle capability creation & invalidation
Also make cable part detection more consistent.
2019-04-09 17:29:23 +01:00
SquidDev
aa0e1883d1 Add check for if item/block registration has failed
If mod loading fails, we'll continue to load colour handlers. As
blocks/items have not been registered, then we'll throw an NPE.

See MinecraftForge/MinecraftForge#5682. Somewhat fixes #168.
2019-04-09 16:32:20 +01:00
SquidDev
9cdbcb4332 Use int instead of long for configs
Forge's config system will read the default values as integers, meaning
it fails to validate against the config spec. Ideally this'd be fixed in
forge, but this is a suitable work around.
2019-04-09 16:31:00 +01:00
SquidDev
23ddd4feb5 Fix several deprecation warnings 2019-04-09 16:30:44 +01:00
SquidDev
fcaa777c95 Merge branch 'master' into mc-1.13.x 2019-04-09 11:11:12 +01:00
SquidDev
b195cab6a7 Add a couple of colours unit tests 2019-04-09 10:35:23 +01:00
SquidDev
63dc0daa09 Convert computer sides to an enum
Previously we just relied on magic int values, which was confusing and
potentially error-prone. We could use EnumFacing, but that's a)
dependent on MC and b) incorrect, as we're referring to local
coordinates.
2019-04-09 10:02:54 +01:00
SquidDev
34602ec4be Move null checks from Preconditions to Objects 2019-04-08 14:54:57 +01:00
SquidDev
f3ce44042f Update all inputs if the block is not a neighbour
Fixes #172, and acts as a workaround for MrTJP/ProjectRed#1472.
2019-04-08 14:52:24 +01:00
SquidDev
4205f18f0c Publish jar files to GH too
I'm not sure if I'll keep this, as it's a little redundant. We're on an
older version of the plugin, as 2.2.7 seems to fail for me.

Closes #165.
2019-04-07 15:30:27 +01:00
SquidDev
6be330ae8d Expose Computer.getRootMount again
It's a little evil, but we need it for CCEmuX. There's other ways of
achieving this, but not with supporting CC and CC:T.
2019-04-07 14:58:25 +01:00
SquidDev
4569af2130 Bump version 2019-04-06 22:42:44 +01:00
SquidDev
765c31315a Make redstone updates identical to how MC does it
Also fixes rather embarassing bug with redstone not updating.
2019-04-06 22:42:03 +01:00
Wilma456 (Jakob0815)
0e191e42a0 Update de_de.lang (#166) 2019-04-03 14:58:04 +01:00
SquidDev
ca34b2a1b8 Update the dependency info a little 2019-04-02 21:37:19 +01:00
SquidDev
7afc3e5260 And fix the build failing 2019-04-02 21:33:55 +01:00
SquidDev
f9e13ca67a Update CC: Tweaked to 1.13
Look, I originally had this split into several commits, but lots of
other cleanups got mixed in. I then backported some of the cleanups to
1.12, did other tidy ups there, and eventually the web of merges was
unreadable.

Yes, this is a horrible mess, but it's still nicer than it was. Anyway,
changes:

 - Flatten everything. For instance, there are now three instances of
   BlockComputer, two BlockTurtle, ItemPocketComputer. There's also no
   more BlockPeripheral (thank heavens) - there's separate block classes
   for each peripheral type.

 - Remove pretty much all legacy code. As we're breaking world
   compatibility anyway, we can remove all the code to load worlds from
   1.4 days.
 - The command system is largely rewriten to take advantage of 1.13's
   new system. It's very fancy!

 - WidgetTerminal now uses Minecraft's "GUI listener" system.

 - BREAKING CHANGE: All the codes in keys.lua are different, due to the
   move to LWJGL 3. Hopefully this won't have too much of an impact.

   I don't want to map to the old key codes on the Java side, as there
   always ends up being small but slight inconsistencies. IMO it's
   better to make a clean break - people should be using keys rather
   than hard coding the constants anyway.

 - commands.list now allows fetching sub-commands. The ROM has already
   been updated to allow fancy usage such as commands.time.set("noon").

 - Turtles, modems and cables can be waterlogged.
2019-04-02 20:59:48 +01:00
SquidDev
810258e9b8 Update and rename all resources
- Languages are converted to JSON
 - Rename most *(_advanced) blocks to *_{advanced,normal}. It's more
   verbose, but means they're sorted together.
 - A couple of changes to the ROM to work with some Java changes.
 - Update recipes and advancements to not use damage values.
2019-04-02 13:18:43 +01:00
SquidDev
5e462adc5c Relocate all resource files
- textures/{block,item}s -> textures/{block,item}
 - assets/*/{advancements,lua,recipes} -> data/*/...
2019-04-02 13:18:43 +01:00
SquidDev
1fd0b40776 Fix printing not updating the output display state 2019-04-02 12:21:59 +01:00
SquidDev
2965fb666f Some further cleanup and 1.13 cherry-picks
Are most of these changes small and petty? Yes. However, IMO they do
make the code more readable. Anyway, a summary of some of the more
interesting changes:

 - Expose Abstract*Upgrade classes in the API
 - Fix the spelling of Jonathan in the API docs (*shakes fist*)
 - Fix bug with printout not working in the offhand.
 - Rename any argments/variables accidentally named "m_*", and add an
   inspection to prevent it happening again.
 - Remove most of the Block*.Properties classes - just inline them in
   the parent class.
 - Return super.writeToNBT instead of reassigning at the top.
2019-04-02 12:08:03 +01:00
Luca S
390575ab4d rednet.send now returns if the message was send (#164)
This makes use of the "sent" variable, which would otherwise go unused. It also makes rednet.send compliant to the behaviour specified in the Wiki: http://www.computercraft.info/wiki/Rednet.send
2019-04-01 19:31:21 +01:00
SquidDev
e4ef92ca2d Expose a stub "cctweaked" mod
This is largely invisible (it's marked as a child of the main
"computercraft" mod), but allows other mods (such as Plethora) to add
hard/soft dependencies on CC:T in a user-friendly manner.
2019-03-30 16:41:45 +00:00
SquidDev
9bf586b018 Make turtle crafting more consistent with vanilla
- Fire all the appropriate Forge hooks
 - Crafting will now attempt to craft one item at a time in a loop,
   instead of multiplying the resulting stack by the number of crafts.
   This means we function as expected on recipes which consume
   durability instead.
 - Cache the recipe between crafting and getting the remainder (and each
   craft loop). This should reduce any performance hit we would
   otherwise get.
2019-03-30 16:12:49 +00:00
SquidDev
173ea72001 Turn inspections up to 11
OK, so let's get this out of the way, there's some actual changes mixed
in here too. I'm really sorry:
 - Turtles can now not be renamed with unnamed item tags (previously it
   would clear the name, this seemed a little unideal).
 - commands.getBlock(s)Data will also include NBT.

Now, onto the horror story which is these inspection changes:
 - Make a lot of methods static
 - Typo fixes
 - Make utility classes final + private constructor
 - Lots of reformatting (ifs -> ternary, invert control flow, etc...)
 - ???
 - Profit!

I'm so going to regret this - can pretty much guarantee this is going to
break something.
2019-03-29 21:26:21 +00:00
SquidDev
1230cabcb0 Add an event for inspecting items too
We've had one for blocks for ever after all.
2019-03-27 20:58:14 +00:00
SquidDev
6ed03e1fcd Convert turtle refuelling into an event
This should allow us (or other mods) to register custom refuel handlers
should they so wish.
2019-03-27 20:38:39 +00:00
SquidDev
c4b371b124 Cherry pick several improvements from 1.13
- Move container opening (and gui handling) into a separate class
 - Move turtle/computer placement code onto the block
 - GUIs now use gui{Left,Top} instead of calculating it manually.
 - IPeripheralTile is now exposed in the API.
2019-03-27 19:20:59 +00:00
SquidDev
a600213b00 Merge pull request #153 from SquidDev-CC/feature/main-thread-limits 2019-03-26 11:28:35 +00:00
SquidDev
7799b8d4cb Convert MainThread into a priority queue
This uses a similar approach to ComputerThread: executors store how long
they've spent executing tasks. We then use that time to prioritise
executors.

One should note that we use the current runtime at the point of adding
to the queue - external tasks will not contribute towards it until a
later execution.
2019-03-26 11:21:40 +00:00
SquidDev
245bf26480 Expose max computer/global times as config options
These do have a direct impact on server performance, so are definitely
worthwhile exposing.
2019-03-26 11:21:40 +00:00
SquidDev
5d05205d69 Introduce IWorkMonitor into the public API
This effectively acts as a public interface to canExecuteExternal() and
consumeTime(). It's hopefully sufficiently general that we can mess
around with the backend as much as we like in the future.

One thing to note here is that this is based on a polling API, as it's
largely intended for people running work every tick. It would be
possible to adapt this with callbacks for when work is available,
etc..., but that was not needed immediately.

This also removes IComputerOwned, as Plethora no longer needs it.
2019-03-26 11:21:16 +00:00
SquidDev
853e2622a1 An initial prototype of main thread rate limiting
Unlike ComputerThread, we do not have a single source of tasks, and so
need a smarter way to handle scheduling and rate limiting. This
introduces a cooldown system, which works on both a global and
per-computer level:

Each computer is allowed to do some work for 5ms. If they go over that
budget, then they are marked as "hot", and will not execute work on the
next tick, until they have cooled down. This ensures that _on average_
computers perform at most 5ms of work per tick.

Obviously this is a rather large time span, so we also apply a global
10ms to all computers. This uses the same cooldown principle, meaning we
keep to an average of 10ms, even if we go over budget.
2019-03-26 11:21:16 +00:00
SquidDev
d0bf9e9cd7 Fix config reloading not working as expected
We were not updating the property instances, so we never actually used
the new values. This changes the syncing method to just copy values from
the new config file, meaning comments and structure are preserved from
the old one.

Note, we cannot just call Config.load(File) again, as the defaults are
no longer accurate.
2019-03-26 11:06:33 +00:00
SquidDev
7a7951ae68 Keep track of the current input state on the server
- We send special packets for key and mouse events, which are then
   processed by the container's InputState.
 - InputState keeps track of currently held keys and mouse buttons.
 - When closing the container, we queue key_up/mouse_up events for any
   pending buttons.
2019-03-24 21:58:13 +00:00
SquidDev
bd28955c8e Fix ComputerThread not updating the minimumVirtualRuntime
We attempted to simplify this 0bfb7049b0,
but that change now means that minimumVirtualRuntime is not updated. As
a result, new tasks will have a runtime of 0 when the queue is empty.
2019-03-24 18:13:00 +00:00
SquidDev
e46f09a939 Several recipe improvements
- Some performance improvements to JEI recipe resolver
   - Use a shared map for upgrade items, meaning we only need one map
     lookup.
   - Cache the basic upgrade recipes.
 - Use the MC version within project rather than version name.
2019-03-19 11:59:23 +00:00
daelvn
71b1f8138d Localize ComputerCraft for es_ES
Español de España (Castellano)
2019-03-19 09:50:21 +00:00
Wilma456 (Jakob0815)
1d82a1c98c Update German translation (#145) 2019-03-19 09:43:32 +00:00
Wilma456 (Jakob0815)
b5f60f3f11 Correct typo within en_us.lang (#144) 2019-03-16 17:00:26 +00:00
SquidDev
259665d9f1 Add a more strict form of IPocketAccess.getEntity
Before IPocketAccess.getEntity would return the entity which last held
fthis computer, even if not holding it any more. As
ba823bae13 describes, this caused
pocket.equip/pocket.unequip to dupe items.

We move the validation from the PocketAPI into the main IPocketAccess
implementation, to ensure this issue does not occur elsewhere. Note, we
require a separate method, as this is no longer thread-safe.

We also now return ok, err instead of throwing an exception, in order to
be consistent with the turtle functions. See dan200/ComputerCraft#328.
2019-03-16 11:18:03 +00:00
Iunius118
ba823bae13 Fix Pocket API working outside of player inventory
This makes Pocket API not equip/unequip upgrades when the pocket
computer is outside of the player inventory (e.g. dragging,
dropped, placed in a chest).
2019-03-16 11:08:44 +00:00
SquidDev
1290a4402c Add a tool to verify language files are well formed
I'm not going to pretend this is a beautiful script, but it's good
enough for basic validation of language files.
2019-03-16 11:04:37 +00:00
absolument
379076a5e2 Localize ComputerCraft for fr_fr
Following #488
Here is my translation in french fr_fr
2019-03-16 11:00:41 +00:00
SquidDev
d12bdf50d8 Remove most instances of non-translatable strings
Oh goodness, this is going to painful to update to 1.13.

We now translate:
 - Computer/Disk ID tooltips
 - /computercraft descriptions, synopsises and usages. The last of these
   may not always be translated when in SMP, as it is sometimes done on
   the server, but the alternative would be more complex than I'm happy
   with.
 - Tracking field names. Might be worth adding descriptions too in the
   future.

Also cleanup a couple of other translation keys, so they're more
consistent with Minecraft.

Closes #141
2019-03-16 10:26:40 +00:00
SquidDev
cbfd5aeeee Use Minecraft's "can use command blocks" check
Just means we're a little more consistent, and hopefully can remove
canPlayerUseCommands in the future, once Plethora stops using it.
2019-03-16 01:55:38 +00:00
SquidDev
41429bdc0b Improve our JEI integration a little bit
- Turtle and pocket computers provide a "creator mod id" based on their
   upgrade(s).
   We track which mod was active when the upgrade was registered, and
   use that to determine the owner. Technically we could use the
   RegistryLocation ID, but this is not always correct (such as
   Plethora's vanilla modules).
 - We show all upgraded turtles/pocket computers in JEI now, rather than
   just CC ones.
 - We provide a custom IRecipeRegistryPlugin for upgrades, which
   provides custom usage/recipes for any upgrade or upgraded item. We
   also hide our generated turtle/pocket computer recipes in order to
   prevent duplicates.
2019-03-16 01:51:12 +00:00
SquidDev
54b9966feb Make upgrade crafting even more lenient
This now allows items with empty tags to equal those with no tag.
2019-03-16 01:51:00 +00:00
SquidDev
105c66127c Automatically generate impostor recipes
Previously we would register the recipes within our code, but the
advancements were written manually. This now generates JSON files for
both the advancement and recipe.

While this does mean we're shipping even more JSON, we'll need to do
this for 1.13 anyway, and means our advancements are guaranteed to be
consistent.

On a side note, a couple of other changes:
 - Turtle upgrades are now mounted on the right in the creative
   menu/fake recipes. This means the upgrade is now clearly visible in
   the inventory.
 - We no longer generate legacy turtle items at all: we'll always
   construct turtle_expanded.
 - Several peripheral items are no longer registered as having sub-types
   (namely advanced and full-block modems).
 - We only have one disk advancement now, which unlocks all 16 recipes.
 - We have removed the disk conversion recipes - these can be
   exposed through JEI if needed.
2019-03-16 00:15:31 +00:00
SquidDev
765ad0bd3f Some basic integration with MCMP
This allows wireless modems (advanced and normal) to be used in
multiparts. There's a very limited set of uses for this (mostly allows
using Chisel and Bits with them), but it's very simple to do.

I'd like to look into MCMP support for wired modems/cables in the
future, but this will be somewhat harder due to their pre-existing
multiblock structure.

Similarly, might be fun to look into CBMP compatibility.
2019-03-14 22:14:47 +00:00
Linus Ramneborg
dd05478483 Localize for Swedish (#139) 2019-03-14 22:14:13 +00:00
hydraz
5d028dea39 Add pt_BR lang file 2019-03-14 17:15:34 +00:00
SquidDev
629c51d260 Fix language silliness 2019-03-14 17:15:05 +00:00
Alessandro
9ea57961af Added Italian language (#138) 2019-03-14 16:55:38 +00:00
Luca
07b9b1c9c7 os.time() and os.day() join the "Finally Case-Insensitive Party" 2019-03-13 15:42:39 +00:00
SquidDev
5b942ff9c1 Some changes to Lua machines and string loading
- Share the ILuaContext across all method calls, as well as shifting it
   into an anonymous class.
 - Move the load/loadstring prefixing into bios.lua
 - Be less militant in prefixing chunk names:
   - load will no longer do any auto-prefixing.
   - loadstring will not prefix when there no chunk name is supplied.
     Before we would do `"=" .. supplied_program`, which made no sense.
2019-03-10 12:24:55 +00:00
SquidDev
7b5a918941 Improve AddressPredicate error messages a little
See #134.
2019-03-10 11:22:11 +00:00
SquidDev
47721bf76b Allow running pastebin with the URL
For instance, `pastebin run https://pastebin.com/LYAxmSby` will now
extract the code and download appropriately. Also add an error message
when we received something which is not a valid pastebin code.

See #134.
2019-03-10 11:11:49 +00:00
SquidDev
35ce0974cd Fix NPE when checking URLs
If the host was null due to a malformed URL, we'd try to verify that it
was allowed, throwing an NPE.

Fixes #135
2019-03-10 10:45:30 +00:00
SquidDev
52e1906d42 Add a basic test framework for CraftOS
This runs tests on CraftOS using a tiny test runner that I originally
knocked up for LuaDash. It can be run both from JUnit (so IDEA and
Gradle) and in-game in the shell, so is pretty accessible to work with.

I also add a very basic POC test for the io library. I'd like to flesh
this out soon enough to contain most of the things from the original io
test.
2019-03-10 10:45:25 +00:00
SquidDev
eaf24a3ceb Update to JUnit 5
Also display test results within the Gradle build
2019-03-10 09:40:06 +00:00
SquidDev
62760e371e Add a section on how to depend on CC:T
It's not immediatly obvious where our maven repository is.
2019-03-04 22:59:38 +00:00
SquidDev
e154e11186 Select the initial multishell tab when starting up
Before it was not actually selected until the task had yielded for the
first time. If a computer did not yield (or took a while to do so),
nothing would actually show up.
2019-03-04 16:37:08 +00:00
SquidDev
72d079ef61 Merge pull request #119 from SquidDev-CC/feature/computer-thread-schedule
- CobaltLuaMachine/ComputerExecutor can now be paused - this suspends 
   the machine via a debug hook. When doing work again, we resume the 
   machine, rather than starting a new task.
 - TimeoutState keeps track of how long the current execution of this task
   has gone on for, when its deadline is, and the cumulative execution time of
   this task.
 - ComputerThread now uses a CFS based scheduler in order to determine which
   computer to next run.
2019-03-04 15:46:28 +00:00
SquidDev
0bfb7049b0 Document everything, and several further improvements
- Only update all runtimes and the minimum runtime when queuing new
   exectors. We only need to update the current executor's runtime.
 - Fix overflows when comparing times within TimeoutState.
   System.nanotime() may (though probably won't) return negative values.
 - Hopefully explain how the scheduler works a little bit.
2019-03-04 10:22:17 +00:00
SquidDev
f7cb526793 Attempt to fix race condition in ComputerThread
- Runners would set their active executor before starting resetting the
   time, meaning it would be judged as running and terminated.
 - Similarly, the cumulative time start was reset to 0, meaning the
   computer had been judged to run for an impossibly long time.
 - If a computer hit the terminate threshold, but not the hard abort
   one, then we'd print the stack trace of the terminated thread - we
   now do it before interrupting.

There's still race conditions here when terminating a computer, but
hopefully these changes will mean they never occur under normal
operations (only when a computer has run for far too long).
2019-03-04 09:22:14 +00:00
SquidDev
e34e833d3d Small changes to ComputerThread
- Fix the timeout error message displaying utter rot.
 - Don't resize the runner array. We don't handle this correctly, so
   we shouldn't handle it at all.
 - Increment virtualRuntime after a task has executed.
2019-03-02 09:16:25 +00:00
SquidDev
a125a19728 Implement a CFS based scheduler
- The computer queue is a priority queue sorted by "virtual runtime".
 - Virtual runtime is based on the time this task has executed, divided
   by the number of pending tasks.
 - We try to execute every task within a given period. Each computer is
   allocated a fair share of that period, depending how many tasks are
   in the queue. Once a computer has used more than that period, the
   computer is paused and the next one resumed.
2019-02-28 17:23:09 +00:00
SquidDev
b3e6a53868 Allow pausing Lua machines
TimeoutState now introduces a TIMESLICE, which is the maximum period of
time a computer can run before we will look into pausing it.

When we have executed a task for more than this period, and if there are
other computers waiting to execute work, then we will suspend the
machine.

Suspending the machine sets a flag on the ComputerExecutor, and pauses
the "cumulative" time - the time spent handling this particular event.
When resuming the machine, we restart our timer and resume the machine.
2019-02-28 16:49:06 +00:00
SquidDev
218f8e53bb Further improvements to computer execution
Oh goodness, when will it end?

 - Computer errors are shown in red.

 - Lua machine operations provide whether they succeeded, and an
   optional error message (reason bios failed to load, timeout error,
   another Lua error), which is then shown to the user.

 - Clear the Cobalt "thrown soft abort" flag when resuming, rather than
   every n instructions.

 - Computers will clear their "should start" flag once the time has
   expired, irrespective of whether it turned on or not. Before
   computers would immediately restart after shutting down if the flag
   had been set much earlier.

Errors within the Lua machine are displayed in a more friendly
2019-02-28 15:44:43 +00:00
SquidDev
d02575528b Fix leaking file descriptors when closing
When closing a BufferedWriter, we close the underlying writer. As we're
using channels, this is an instance of sun.nio.cs.StreamEncoder. This
will attempt to flush the pending character.

However, if throwing an exception within .write errors, the flush will
fail and so the underlying stream is not closed. This was causing us to
leak file descriptors.

We fix this by introducing ChannelWrappers - this holds the wrapper
object (say, a BufferedWriter) and underlying channel. When closed, we
dispose of the wrapper, and then the channel. You could think of this as
doing a nested try-with-resources, rather than a single one.

Note, this is not related to JDK-6378948 - this occurs in the underlying
stream encoder instead.
2019-02-28 11:24:12 +00:00
SquidDev
c78adb2cdc Several improvements to the computer thread rework
- TimeoutState uses nanoseconds rather than milliseconds. While this is
   slightly less efficient on Windows, it's a) not the bottleneck of Lua
   execution and b) we need a monotonic counter, otherwise we could
   fail to terminate computers if the time changes.
 - Add an exception handler to all threads.
 - Document several classes a little better - I'm not sure how useful
   all of these are, but _hopefully_ it'll make the internals a little
   more accessible.
2019-02-27 20:56:45 +00:00
SquidDev
3e28f79ce9 Shutdown computers in /computercraft shutdown
Unloading them now means they'll never be turned on again, which is a
little unideal.
2019-02-27 13:49:07 +00:00
SquidDev
67af7a698b Migrate the computer tasks into a separate thread
- Move state management (turnOn, shutdown, etc...) event handling and
   the command queue into a ComputerExecutor

 - This means the computer thread now just handles running "work" on
   computer executors, rather than managing a separate command queue +
   requeuing it.
2019-02-26 13:50:09 +00:00
SquidDev
06e76f9b15 Rewrite ComputerThread and the timeout system
- Instead of setting soft/hard timeouts on the ILuaMachine, we instead
   provide it with a TimeoutState instance. This holds the current abort
   flags, which can then be polled within debug hooks.

   This means the Lua machine has to do less state management, but also
   allows a more flexible implementation of aborts.

 - Soft aborts are now handled by the TimeoutState - we track when the
   task was started, and now only need to check we're more than 7s since
   then.

   Note, these timers work with millisecond granularity, rather than
   nano, as this invokes substantially less overhead.

 - Instead of having n runners being observed with n managers, we now
   have n runners and 1 manager (or Monitor).

   The runners are now responsible for pulling work from the queue. When
   the start to execute a task, they set the time execution commenced.
   The monitor then just checks each runner every 0.1s and handles hard
   aborts (or killing the thread if need be).
2019-02-26 13:46:10 +00:00
SquidDev
6d383d005c A couple of minor tweaks
- Rename unload -> close to be a little more consistent
 - Make pollAndResetChanged be atomic, so we don't need to aquire a lock
 - Get the computer queue from the task owner, rather than a separate
   argument.
2019-02-26 12:43:45 +00:00
SquidDev
c373583723 Add a test which boots a computer and runs forever
Ideally we'd add a couple more tests in the future, but this'll do for
now.

The bootstrap class is largely yoinked from CCTweaks-Lua, so is a tad
ugly. It works though.
2019-02-26 08:44:17 +00:00
SquidDev
f1d10809d5 Make commands.collapseArgs a little more sane
We now generate a table and concatinate the elements together. This has
several benefits:
 - We no longer emit emit trailing spaces, which caused issues on 1.13's
   command system.
 - We no longer need the error level variable, nor have the weird
   recursion system - it's just easier to understand.
2019-02-26 08:40:48 +00:00
SquidDev
474f571798 Attach peripherals directly rather than deferring
Prior to this change we would schedule a new task which attached
peripherals on the ComputerThread on the empty task queue. This had a
couple of issues:
 - Slow running tasks on the computer thread could result in delays in
   peripherals being attached (technically, though rarely seen in
   practice).
 - Now that the ComputerThread runs tasks at once, there was a race
   condition in computers being turned on/off and peripherals being
   attached/detached.

Note, while the documentation said that peripherals would only be
(at|de)tached on the computer thread, wired modems would attach on the
server thread, so this was not the case in practice.

One should be aware that peripherals are still detached on the
computer thread, most notably when turning a computer on/off.

This is almost definitely going to break some less well-behaved mods,
and possible some of the well behaved ones. I've tested this on SC, so
it definitely works fine with Computronics and Plethora.
2019-02-25 19:11:35 +00:00
SquidDev
fb9c125ab8 Update Cobalt version for latest bugfixes/changes
- Fix load not unwinding stack
 - Allow transferring control between coroutines when unwinding is
   disabled

Fixes #128
2019-02-25 14:18:45 +00:00
SquidDev
162fb37421 Handle Pastebin spam protection and add a cache buster (#127) 2019-02-24 20:06:02 +00:00
Drew Lemmy
d953f031f0 Remove debugging line 😬 2019-02-24 20:00:26 +00:00
Drew Lemmy
7fde89ad95 Use stderr for pastebin errors, and a prettier cache buster 2019-02-24 19:59:10 +00:00
Drew Lemmy
bd04a93ffb Handle pastebin spam protection and add a cache buster 2019-02-24 13:47:09 +00:00
SquidDev
e2bfaafe28 Bump version for colour fix 2019-02-24 08:20:22 +00:00
SquidDev
1fb3d16b89 Fix colours.*RGB methods working with 8 bit values
They should have been using 0-1s instead. I'm a moron for not noting
this earlier, and not testing this.
2019-02-23 23:20:46 +00:00
SquidDev
35645b3d93 Add back a couple of methods for CCEmuX compat 2019-02-23 12:46:09 +00:00
SquidDev
a4cd1fe77d Stop releasing betas by default
Things just got serious I guess??
2019-02-23 10:35:15 +00:00
Wilma456 (Jakob0815)
4145914024 Make Multishell Scrollable (#123)
You can now Scroll through the program list, if the list bigger than your
screen.
2019-02-21 16:00:13 +00:00
SquidDev
6bd11a5e4a Fix the other instance of the neighbour deprecation warning 2019-02-20 18:37:22 +00:00
SquidDev
46fa798797 Several minor improvements
- Restrict what items can be inserted into printers. They're now closer
   to brewing stands or furnaces: nothing can go in the output slot,
   only ink in the ink slot, and only paper in the paper slot.
 - Fix build.gradle using the wrong version
 - Trim the width of tables to fit when displaying on the client. Closes
   #45. Note, our solution isn't perfect, as it will wordwrap too, but
   it's adaquate for now.
2019-02-20 09:48:16 +00:00
SquidDev
70a226207e Update README and versioning (#121)
- Reword elements of the README, mostly changing the elements about
   vanilla ComputerCraft.
 - Change versioning scheme: we'll now do 1.x.y, with 1.81.0 being the
   next version.
 - Include MC version in the file name
 - Stop bundling javadoc with the jar. We'll look into hosting this on
   squiddev.cc if really needed.
 - Remove the LuaJ license from the root - we no longer bundle the
   sources, so it's not needed here.

I realise this change looks a little dodgey on its own, so see #113 for
the full rationale.
2019-02-19 14:49:13 +00:00
SquidDev
257a35f3ed Merge pull request #120 from SquidDev-CC/feature/palette-improvements
Minor palette improvements
2019-02-19 10:59:35 +00:00
Lignum
af01b9514b Split colours.rgb8 into colours.packRGB and colours.unpackRGB 2019-02-19 09:51:01 +00:00
Lignum
070fd1f2ff Add term.nativePaletteColo(u)r 2019-02-19 09:50:57 +00:00
SquidDev
fb59da2b06 Update GitHub templates, removing CC repo links
See #113
2019-02-18 23:35:50 +00:00
SquidDev
11e4d0de82 Fix turtle peripherals becoming desynced
When a turtle was unloaded but not actually disposed of, the
m_peripheral map hangs around. As a result, when creating a new
ServerComputer, the peripherals aren't considered changed and so they're
never attached.

Fixes #50.

Also fix that blumin' deprecated method which has been around for a wee
while now.
2019-02-18 23:28:51 +00:00
SquidDev
e46ab1e267 Revert some image optimisations 2019-02-18 22:58:39 +00:00
SquidDev
d6e0f368df Handle managing computer inputs/outputs separatly
The Computer class currently has several resposiblities such as storing
id/label, managing redstone/peirpherals, handling management of the
computer (on/off/events) and updating the output.

In order to simplify this a little bit, we move our IAPIEnvironment
implementation into a separate file, and store all "world state"
(redstone + peripherals) in there. While we still need to have some
level of updating them within the main Computer instance, it's
substantially simpler.
2019-02-17 19:48:52 +00:00
SquidDev
9f2884bc0f Several minor improvments to websockets
- Fire close events instead of failure when open websockets error.
 - Handle ping events. I thought I was doing this already, but this
   requires a WebsocketProtocolHandler. Fixes #118
2019-02-17 19:36:18 +00:00
SquidDev
18d468e887 Fix building from a fresh setup
We were attempting to resolve the Forge jars before they had been
generated, which meant the build failed.
2019-02-16 16:01:47 +00:00
SquidDev
63f6735bb8 Attempt to reduce jar size a little
- Run optipng on all our images. This has very little effect on most of
   them (as they're all so small anyway), but has resulted in a 50%
   reduction in some cases.
 - Run Proguard on our shadowed dependencies (Cobalt).
 - Minify our JSON files, stripping all whitespace. This is mostly
   useful for FML's annotation cache, as that's a massive file, but
   still a semi-useful optimisation to make.

This has helped reduce the jar by about 110kb, which isn't much but
still feels somewhat worth it.
2019-02-14 10:53:18 +00:00
SquidDev
ab6f0ccd16 Fix advanced modems not actually being advanced
We were constructing the peripheral before the advanced property had
been set, thus it was always false. Yay for Java.

Closes #111
2019-02-12 18:11:04 +00:00
SquidDev
ae0f093e73 Strip \r from .readLine on binary handles
Note, this is technically inconsistent with the spec. However, we'll use
this method for now in order to remain backwards compatible.

Fixes #109.
2019-02-11 16:58:43 +00:00
SquidDev
e5f988e3fe Fix missing advanced turtle model when rendering
I'm not even sure how I missed this when testing.
2019-02-11 16:38:33 +00:00
SquidDev
12e82afad2 Bump Cobalt version to enable single-threading
The latest version of Cobalt has several major changes, which I'm
looking forward to taking advantage of in the coming months:

 - The Lua interpreter has been split up from the actual LuaClosure
   instance. It now runs multiple functions within one loop, handling
   pushing/popping and resuming method calls correctly.

   This means we have a theoretically infinite call depth, as we're no
   longer bounded by Java's stack size. In reality, this is limited to
   32767 (Short.MAX_VALUE), as that's a mostly equivalent to the limits
   PUC Lua exposes.

 - The stack is no longer unwound in the event of errors. This both
   simplifies error handling (not that CC:T needs to care about that)
   but also means one can call debug.traceback on a now-dead coroutine
   (which is more useful for debugging than using xpcall).

 - Most significantly, coroutines are no longer each run on a dedicated
   thread. Instead, yielding or resuming throws an exception to unwind
   the Java stack and switches to a different coroutine.

   In order to preserve compatability with CC's assumption about LuaJ's
   threading model (namely that yielding blocks the thread), we also
   provide a yieldBlock method (which CC:T consumes). This suspends the
   current thread and switches execution to a new thread (see
   SquidDev/Cobalt@b5ddf164f1 for more
   details). While this does mean we need to use more than 1 thread,
   it's still /substantially/ less than would otherwise be needed.

We've been running these changes on SwitchCraft for a few days now and
haven't seen any issues. One nice thing to observe is that the number of
CC thread has gone down from ~1.9k to ~100 (of those, ~70 are dedicated
to running coroutines). Similarly, the server has gone from generating
~15k threads over its lifetime, to ~3k. While this is still a lot, it's
a substantial improvement.
2019-02-10 22:02:30 +00:00
SquidDev
6c2db93cbd Register item colour handlers on the event instead
Another step on my misguided quest to get rid of proxies
2019-02-10 09:55:06 +00:00
SquidDev
d5edbe700b Load turtle item models using a model loader
This is far more elegant than our weird method of baking things and
manually inserting them into the model map. Also means we no longer need
the whole turtle_dynamic thing.
2019-02-10 09:45:15 +00:00
SquidDev
86ad43c3ab Fix peripheral direction not being set
We moved the direction call within the if block, but never actally
updated the condition! I'm on a roll of stupid bug fixes today, which
really isn't a good sign.
2019-02-07 23:07:49 +00:00
SquidDev
f450c0156b Recomment out a global
It's actually rather worrying this was exposed, you could cause some
serious issues with it.
2019-02-07 20:22:00 +00:00
SquidDev
8abcfcb4ac Track turtle commands as server tasks
They're basically an alternative version of issueMainThreadTask anyway.
2019-01-30 20:43:08 +00:00
SquidDev
f3cace1d03 Allow building without a git repository
Closes #102
2019-01-28 14:05:53 +00:00
SquidDev
e1e5e898ab Make monitors use a concurrent map instead of a synchronized
We didn't lock when iterating on the main-thread, so it wasn't actually
thread-safe anyway!
2019-01-25 22:59:01 +00:00
SquidDev
3aa3852ff6 Some further improvements to BlockGeneric
- Only have computers implement custom block drop logic: everything
   else only drops in creative mode.
 - Fix redstone inputs not being received correctly. Introduced in
   8b86a954ee, yes I'm a silly billy.
 - Only update the neighbour which changed.
2019-01-25 22:03:44 +00:00
SquidDev
709a6329c7 Fix all wireless modem blocks being advanced 2019-01-25 00:12:49 +00:00
SquidDev
c9f05a2939 Make require a little more consistent with Lua 5.1
- Error messages are indented correctly
 - The module's name is passed as the first argument to modules
 - Make error messages match Lua's
2019-01-23 18:50:17 +00:00
Devilholk
e41377f862 Handle connection errors on websockets 2019-01-22 11:11:25 +00:00
SquidDev
d173787a94 Another backwards compat change
Plethora only implements getPos on older versions, so we need to stub
out both.
2019-01-21 17:36:25 +00:00
SquidDev
d5aea26f3a Bump version
It's pretty soon after the previous release (10 days!) but there's a
couple of important bug fixes and some nice improvements.
2019-01-21 11:02:29 +00:00
SquidDev
2681e578c4 Merge pull request #101 from SquidDev-CC/feature/no-ticking
Make several tile entities non-ticking, hopefully reducing
server load.
2019-01-21 08:29:42 +00:00
SquidDev
1f498dcc73 Backwards compat patch for Plethora
Ughghgghghr.
2019-01-20 16:16:02 +00:00
SquidDev
83b01d35eb Make monitors non-ticking
- Convert terminals from a polling-based system to a more event-driven
   one: they now accept an onChanged callback, which marks the parent as
   dirty.
 - Schedule ticks when monitors are marked as dirty.
 - Add several missing @Overrides. This has nothing to do with the rest
   of the changes, but I'm bad at good git practice.
2019-01-20 15:39:11 +00:00
SquidDev
8a7e651c99 Several miscellaneous changes
- Merge BlockPeripheralBase and BlockPeripheral, as no other classes
   extended the former.
 - Make BlockPeripheral use ITilePeripheral instead of
   TilePeripheralBase. This allows us to use other, non-ticking tiles
   instead.
 - Convert advanced and normal modems to extend from a generic
   TileWirelessModemBase class, and thus neither now tick.
2019-01-20 14:06:41 +00:00
SquidDev
80a5759bae Make advanced modems non-ticking
- Move getPeripheralType and getLabel from IPeripheralTile to
   TilePeripheralBase. These were mostly constant on all other tiles, so
   were rather redundant.
 - Make TileAdvancedModem extend TileGeneric, and be non-ticking (using
   similar logic to all other blocks).
2019-01-20 09:34:15 +00:00
SquidDev
e8a4fbb4e3 Make TileCable non-ticking
- Move updateTick onto BlockGeneric/TileGeneric instead of the full
   wired modem, as it is used by several tiles now.
 - Make *Cable extend from *Generic, and schedule ticks instead of
   running every tick.
2019-01-19 22:25:38 +00:00
SquidDev
0ce67afcc1 Be less strict in comparing upgrade crafting items
We currently generate the crafting item once when the upgrade is first
created, and cache it for the duration of the game. As the item never
changes throughout the game, and constructing a stack is a little
expensive (we need to fire an event, etc...), the caching is worth
having.

However, some mods may register capabilities after we've constructed our
ItemStack. This means the capability will be present on other items but
not ours, meaning they are not considered equivalent, and thus the item
cannot be equipped.

In order to avoid this, we use compare items using their share-tag, like
Forge's IngredientNBT. This means the items must still be "mostly" the
same (same enchantements, etc...), but allow differing capabilities.

See NillerMedDild/Enigmatica2Expert#655 for the original bug report -
in this case, Astral Sourcery was registering the capability in init,
but we construct upgrades just before then.
2019-01-19 21:57:21 +00:00
SquidDev
a8dad23fa3 Begin investigations into reducing ticking of TEs
- Move IDirectionalTile constraint from IPeripheralTile to
   TilePeripheralBase.
 - Make *WiredModemFull no longer inherit from *PeripheralBase. While
   there is still some shared logic (namely in the syncing of "anim"),
   it's largely fine as we don't store label or direction in NBT.
 - Add a TickScheduler. This is a thread-safe version of
   World.scheduleUpdate. We simply build a set of all TEs, and schedule
   them to be updated the next tick.
 - Make ModemState receive an "onChanged" listener, which is fired
   whenever the modem changes.
 - Make WiredModemFull no longer tick, instead scheduling updates when
   it is first loaded and whenever the modem changes.
2019-01-19 10:16:41 +00:00
SquidDev
443e0f8f76 Remove FileSystemMount and rewrite JarMount
FileSystemMount was originally added to allow using ReadableByteChannels
instead of InputStreams. However, as zip files do not allow seeking,
there is no benefit of using them over the original JarMount (which we
need to preserve for backwards compatibility).

Instead of maintaining two near-identical mounts, we remove the
FileSystemMount and rewrite the JarMount implementation with several
improvements:

 - Rewrite the jar scanning algorithm to be closer to 1.13+'s data pack
   mount. This means we no longer require the jar file to have
   directories before the file (though this was not a problem in
   practice).
 - Add all JarMounts to a ReferenceQueue, closing up the ZipFile when
   they have been garbage collected (fixes #100).
 - Cache the contents of all files for 60 seconds (with some constraints
   on size). This allows us to seek on ROM files too (assuming they are
   small), by reading the whole thing into memory.
   The cache is shared across all mounts, and has a 64MiB limit, and
   thus should not have an adverse impact on memory.
2019-01-16 17:25:46 +00:00
SquidDev
a838595e1e Derive upgrade adjectives from its ID
This is done in 1.13+ for items and blocks, so we might as well do it
for upgrades now. Note we can't do it for ender pocket modems, as the
upgrade ID is spelled incorrectly there.
2019-01-14 10:42:13 +00:00
SquidDev
61daab910e Simplify placement logic of various blocks
- For those where placement is stored in the metadata (computers),
   don't also set it in onBlockPlacedBy.
 - Remove .getDefaultState(int, EnumFacing) override, as this means we
   have more control over what is passed to us (namely, placer's
   direction too).
2019-01-14 10:27:19 +00:00
SquidDev
7fd19c43e9 Try to hide CommandCopy from most completions.
"/computercraf" auto-completes to "/computercraft_copy" instead of
"/computercraft", which is rather annoying, as the former is not meant
to be used normally.
2019-01-14 10:10:52 +00:00
SquidDev
ce0685c31f Move our message model to be closer to Forge's
It's rather embarassing that it's been restructured _again_, but I think
this is a nice middle-ground. The previous implementation was written
mostly for Fabric, which doesn't always map perfectly to Forge.

 - Move the message identifier into the registration phrase. It's not
   really a property of the message itself, rather a property of the
   registry, so better suited there.

 - Move message handling into the message itself. Honestly, it was just
   ending up being rather messy mixing the logic in two places.

   This also means we can drop some proxy methods, as it's easier to
   have conditionally loaded methods.

 - Move network registry into a dedicated class, as that's what we're
   doing for everything else.
2019-01-14 10:09:22 +00:00
SquidDev
e33f852baa Store references to the registered items
This means we can avoid several rather ugly instances of getItemBlock
and a cast. We also derive the ItemBlock's registered name from the
block's name, which makes the register a little less ugly.
2019-01-12 19:01:32 +00:00
SquidDev
227d5e9e69 Fix cables not rendering the breaking steps
The fact that it's taken this long for anyone to notice this didn't work
is rather embarassing.
2019-01-12 18:35:43 +00:00
SquidDev
1c648850ab Even more proxy pruning
- Move the "world directory" getter out of the proxy - we can just use
   Forge's code here.
 - Remove the server proxies, as both were empty. We don't tend to
   register any dedicated-server specific code, so I think we can leave
   them out.
2019-01-12 18:23:22 +00:00
SquidDev
63691707fc Move registration methods into a separate class
- All "named" entries (blocks, items, recipes, TEs and pocket/turtle
   upgrades) are registeredin one place.
 - Most client side models/textures are registered in ClientRegistry -
   we can't do item colours or TEs for now, as these aren't event based.
 - A little cleanup to how we handle ItemPocketComputer models.
2019-01-12 17:51:26 +00:00
SquidDev
5d97b9c8f3 Utilise @Mod.EventBusSubscriber a little more
This offers several advantages

 - Less registration code: the subscribers are reigstered automatically,
   and we don't need to worry about sided-proxies.
 - We no longer have so many .instance() calls.
2019-01-12 16:27:40 +00:00
SquidDev
77666d7399 Some more minor cleanups
- Move SpeakerPeripheral's TileSpeaker functionality to a sub-class.
 - Use Vec3d instead of BlockPos for speaker's positions.
 - Use WorldUtil.dropItemStack to spawn in items.
 - Remove redundant lock on ModemPeripheral.
2019-01-12 15:43:18 +00:00
SquidDev
ed69495b03 Bump version 2019-01-11 21:13:51 +00:00
SquidDev
66b61d4e9e Add a config option for HTTP timeout too 2019-01-11 21:11:22 +00:00
SquidDev
8dd084ac5c A couple of minor changes to HTTP limiting
- We now error if there are too many websockets, instead of queuing
   them up. As these have a more explicit "lifetime", it could be
   confusing if http.websocket just blocks indefinitely.
 - Fix a CCME when cleaning up resources.
2019-01-11 12:07:56 +00:00
SquidDev
932f8a44fc WIP: Http rework (#98)
- Move all HTTP tasks to a unified "MonitoredResource" model. This
   provides a uniform way of tracking object's lifetimes and disposing
   of them when complete.

 - Rewrite HTTP requests to use Netty instead of standard Java. This
   offers several advantages:
    - We have access to more HTTP verbs (mostly PATCH).
    - We can now do http -> https redirects.
    - We no longer need to spawn in a new thread for each HTTP request.
      While we do need to run some tasks off-thread in order to resolve
      IPs, it's generally a much shorter task, and so is less likely to
      inflate the thread pool.

 - Introduce several limits for the http API:
    - There's a limit on how many HTTP requests and websockets may exist
      at the same time. If the limit is reached, additional ones will be
      queued up until pending requests have finished.
    - HTTP requests may upload a maximum of 4Mib and download a maximum
      of 16Mib (configurable).

 - .getResponseCode now returns the status text, as well as the status
   code.
2019-01-11 11:33:05 +00:00
SquidDev
101b3500cc Add back several more methods for Plethora
While Plethora has been updated to no longer require these, it's
probably worth keeping them around a little longer, as people may not
upgrade them in sync.
2019-01-05 20:57:32 +00:00
SquidDev
a777801e15 Enable the debug library by default
We've had this on SC for most of a year now (and SC 1 for most of its
lifetime) and not seen any issues. I'm fairly confident that it does not
allow breaking the sandbox.
2019-01-05 20:18:30 +00:00
SquidDev
0d6787641a Clean up our handling of configuration files
- Move configuration loading into a separate file, just so it doesn't
   clutter up ComputerCraft.java.
 - Normalise property names, so they're all snake_case.
 - Split properties into separate categories (http, turtle, peripheral),
   so the main one is less cluttered.
 - Define an explicit ordering of each category.
2019-01-05 20:12:02 +00:00
SquidDev
744bba300e A couple of enhancements to websockets
- Provide whether a message was binary or text in websocket_message
   and handle.receive(). (Fixes #96)
 - Provide an optional reason and status code within the websocket_close
   event.

Off topic, but also cleanup the file handles a little.
2019-01-05 18:58:23 +00:00
SquidDev
34d43d8273 Make entity in bounds selectors more restrictive
This means we can remove some additional predicates we have in place,
and hopefully make things faster as less entities are added to the list.
2019-01-03 22:20:50 +00:00
SquidDev
7bc9745c7a Remove redundant line in copyright header
Really should have noticed this when committing it.
2019-01-03 11:02:21 +00:00
SquidDev
b414cba681 Add a method stub for OpenComputers
Fixes #94
2019-01-02 17:37:16 +00:00
SquidDev
1c9110b927 Happy new year! 2019-01-01 01:10:18 +00:00
SquidDev
325459e336 Fix binary handles reading in multiples of 8192 2018-12-31 09:41:58 +00:00
SquidDev
ee3347afbd A whole bunch of refomatting
- Remove redundant constructors and super calls
 - Standardise naming of texture fields
 - Always use postfix notations for loops
 - Cleanup several peripheral classes
2018-12-30 16:42:41 +00:00
SquidDev
27aaec9a82 Move GUI constructors into the main GUI handler
We use @SideOnly to ensure classes aren't loaded on dedicated servers.

Also a tiny bit of cleanup to change several GUIs just to accept
containers.
2018-12-29 17:13:10 +00:00
SquidDev
929f23fd2d Share some map-like-item rendering code
Just refactors the hand rendering methods into a shared superclass
2018-12-29 16:42:02 +00:00
SquidDev
8422a40c69 Revert a couple of changes to be backwards compatible
- Restore ComputerState to the previous location
 - Add a stub constructor for GuiComputer
2018-12-29 14:36:03 +00:00
SquidDev
ca334e7e5c A couple of minor reformats
- nbttagcompount -> nbt. It's shorter, and hopefully will avoid
   ambiguities with 'tag' in 1.13+.
 - Remove several redundant != null checks.
2018-12-29 14:01:00 +00:00
SquidDev
54acf1d087 Sync computer state through TE data
Previously we would send computer state (labels, id, on/off) through the
ClientComputer rather than as part of the TE description. While this
mostly worked fine, it did end up making things more complex than they
needed to be.

We sync most data to the tile each tick, so there's little risk of
things getting out of date.
2018-12-29 12:44:43 +00:00
SquidDev
42d3901ee3 Move from FMLEventChannel to SimpleNetworkWrapper
- Split each network packet into it's own individual IMessage class.
 - Move the TextTable into separate classes for server and client based
   rendering.
2018-12-29 12:44:18 +00:00
SquidDev
f8b328a048 Move drop consumer code into a separate class
This has always been separate from turtles, so there is no reason to
keep it there.
2018-12-28 12:47:44 +00:00
SquidDev
41a320e9a4 Move API registration into separate classes
There's several reasons for this change:
 - Try to make ComputerCraft.java less monolithic by moving
   functionality into separate module-specific classes.
 - Hopefully make the core class less Minecraft dependent, meaning
   emulators are a little less dependent on anything outside of /core.

Note we still need /some/ methods in the main ComputerCraft class in
order to maintain backwards compatibility with Plethora and
Computronics.
2018-12-28 12:40:33 +00:00
SquidDev
57fb77d7fe Refactor common inventory code into a shared interface
Many bits of IInventory (open/close, fields, etc...) are not actually
needed most implementations, so we can clean things up a little with a
common interface.
2018-12-28 11:39:59 +00:00
SquidDev
b59dcbfc0e Remove "client" turtle brains.
These were only used for the vision camera, and so are rather pointless
now.
2018-12-27 13:10:13 +00:00
SquidDev
618c534d81 Move most recipe registration to JSON
We need this for 1.13+, so might as well get it over with.
2018-12-27 12:16:11 +00:00
SquidDev
26ba61097b Move several methods out of the proxy
Some methods act the same on both sides, and so can be in utility
classes. Others are only needed on one side, and so do not really need
to be part of the proxy.

 - Remove TurtleVisionCamera. It would be possible to add this back in
   the future, but for now it is unused and so should be removed.
 - Move frame info (cursor blink, current render frame) into a
   FrameInfo class.
 - Move record methods (name, playing a record) into a RecordUtil class.
2018-12-27 11:58:08 +00:00
SquidDev
2c87e66db8 Move several methods from TileGeneric to blocks
- getPickBlock is now implemented directly on computers and turtles,
   rather than on the tile.
 - Bounding boxes are handled on the block rather than tile. This ends
   up being a little ugly in the case of BlockPeripheral, but it's not
   the end of the world.
 - Explosion resistance is only implemented for turtles now.
2018-12-27 11:32:29 +00:00
SquidDev
f61f7df2d8 Replace "cable variant" with a block model
- Replace BlockCableCableVariant with a boolean, removing any custom
   logic around it.
 - Replace our previous cable Forge-blockstate with a vanilla one, which
   handles cable connections in the model logic.
2018-12-27 10:21:57 +00:00
SquidDev
364d31465e Move modem code into separate packages
Things were shared between common and modem, which just ended up making
things very complicated.
2018-12-27 10:14:22 +00:00
SquidDev
4c7ac50dd8 Fix a rather silly typo
I wonder if it'd be possible to extend LuaCheck to detect such cases?
2018-12-27 09:10:06 +00:00
SquidDev
37e25136ed Replace our ItemOverrideList overrides with property getters
This ends up being slightly cleaner as we can rely on Minecraft's own
model dependency system. Also reduces reliance on Forge's APIs, which
_potentially_ makes porting a little easier.
2018-12-26 18:36:41 +00:00
SquidDev
d9f03f3ec7 Make the test-file directory when running tests 2018-12-26 10:53:56 +00:00
SquidDev
4d5c52bc63 Replace WorldUtil methods with builtin alternatives
- Replace most 0 <= y < world.getHeight() checks with
  world.isBlockValid.
 - Remove several "in bounds" checks, as they'll be handled by later
   calls.
2018-12-26 10:28:32 +00:00
SquidDev
a1c4a9fb58 Replace DirectionUtil methods with builtin equivalents 2018-12-26 09:31:15 +00:00
SquidDev
031f17c98e Remove a couple of redundant commands
- Remove the two redstone commands. These are not used (maybe only by
   CCEdu), and so are somewhat redundant.
 - Inline the select command, converting it to a lambda.
 - Inline the attack/dig commands, as they did little more than wrap the
   tool command.
2018-12-26 09:21:33 +00:00
SquidDev
4ead319092 Remove direct support for beginner's turtles
As CCEdu has not been updated, and is unlikely to be updated as Dan does
not have the rights to open source it, we're removing explicit support
for now.

If an alternative arises in the future, it would be good to support, but
in a way which requires less workarounds in CC's core.
2018-12-26 09:13:15 +00:00
SquidDev
dd6bab5413 Move some shared upgrade code into a base class
Most upgrades provides a couple of constant getters (upgrade ID,
adjective, crafting item). We move the getters into a parent class and
pass the values in via the constructor instead.

Also do a tiny bit of cleanup to the upgrades. Mostly just reducing
nesting, renaming fields, etc...
2018-12-26 09:01:03 +00:00
SquidDev
5b48a0fa5f Fix a couple of issues with FileSystemMounts
- Only generate resource pack mounts if the desired directory exists.
 - Allow mounting files, as well as directories (fixes #90).

As always, also a wee bit of cleanup to some of the surrounding code.
2018-12-24 15:22:19 +00:00
SquidDev
2032e7a83a Reformat everything
It's been a long time comin'
But tonight is the end of the war, my friend
Tomorrow only one style will remain.
2018-12-23 17:46:58 +00:00
theoriginalbit
72b9d3d802 Add custom code style settings
This formats the Java and JSON code to be as close to the existing style
as possible.
2018-12-23 17:45:04 +00:00
SquidDev
70cb8ae16c Add back the previous widget methods for back compat
Previously introduced in f765b6a487.

Fixes #87
2018-12-23 16:55:25 +00:00
SquidDev
05a97a4f12 Bump version 2018-12-20 18:19:43 +00:00
SquidDev
8b86a954ee Replace RedstoneUtil.getRedstoneOutput with World's implementation
This has just become increasingly out-of-date and inaccurate, meaning
there's no obvious reason to continue to use this over World's version.

Fixes #80
2018-12-20 18:13:42 +00:00
SquidDev
741ee447ca A wee bit of a cleanup of the API
- Move some method over to defaulted methods
 - Use Objects rather than Preconditions
2018-12-17 21:33:49 +00:00
SquidDev
3537f49ced Add a .luacheckrc file
We'll look into running this on Travis in the future, but for now this
is a nice way to prevent any regressions.
2018-12-17 18:09:32 +00:00
SquidDev
c3e4a4de5e Remove LuaJ
I feel I should write a long winded commit message about the rationale
behind it, but honestly, it was just another folder in the directory
root we didn't need.
2018-12-17 18:09:31 +00:00
SquidDev
86569533e9 The big massive reformat
- Normalise all line endings to be LF rather than CLRF
 - Trim all trailing whitespace
 - Remove any tabs
2018-12-17 18:09:31 +00:00
Drew Lemmy
e6850ab644 Update README.md (fixes #84) (#85) 2018-12-16 22:13:52 +00:00
SquidDev
97c2421a22 Add a couple more modem methods for back compat 2018-12-10 08:26:46 +00:00
SquidDev
f765b6a487 Set keyHandled on the terminal GUI
This allows us to block JEI processing key events such as "o", meaning
the GUI is not constantly toggled when interacting with a turtle.

Also clean up the widget code, as there's a lot of functionality here
which only is needed in CCEdu.
2018-12-08 23:19:56 +00:00
SquidDev
3e6f6467af Allow copying peripheral names from wired modems when attaching/detaching
This is implemented in a rather ugly way: we register a client command
(/computercraft_copy) which updates the clipboard, and run that via a
click handler on the chat message.

This hopefully makes wired modems a little easier to use. We'll see.
2018-11-29 12:21:14 +00:00
SquidDev
7e6eb62504 Move the /computer command into the main computercraft command
I don't think anyone has actually ended up using this, so it's unlikely
to break anything (though do tell me if this is the case). On the flip
side, this allows us to queue events on multiple computers, and means
we can provide a little more documentation.
2018-11-29 11:57:52 +00:00
SquidDev
949b71d40c Use longs instead of ints within .seek
Some crazy person decided they wanted a 20GB file. I'm not judging.
2018-11-28 18:02:52 +00:00
SquidDev
afdfcb21b7 Merge pull request #582 from SquidDev-CC/ComputerCraft/hotfix/extract-overflow
Fix InventoryUtil ignoring the stack limit when extracting items
2018-11-27 17:43:42 +00:00
SquidDev
776a786e1b Fix InventoryUtil ignoring the stack limit when extracting items
Using turtle.suck on an inventory filled with tools would fill the
entire chest with said item, rather than extracting a single item. In
order to avoid that, we clamp the extract limit to the max stack size
when first extracting an item.

This also inlines the makeSlotList logic, which means we can avoid
creating an array for each inventory operation. This probably won't
have any meaninful performance impact (even on large inventories), but
is a nice optimisation to make.
2018-11-27 17:17:39 +00:00
SquidDev
8ae65d1bdd A couple of minor cleanups on the last commit
- Remove a redundant logger
 - Provide a getter for the ComputerCraft thread group. This allows us
   to monitor child threads within prometheus.
 - Replace a deprecated call with a fastutils alternative.
2018-11-22 12:48:06 +00:00
SquidDev
0829506176 Remove last usage of Trove
Minecraft uses it internally, so we can rely on this always being
around. I do not belive Trove exists within 1.13.
2018-11-22 12:15:55 +00:00
SquidDev
71ee692da0 Some more improvements to threading
- Put all ComputerCraft threads into a thread group
 - Be a little more aggressive in when we cleanup/abandon threads.
2018-11-22 12:09:24 +00:00
SquidDev
acd0092ed5 Add back JarMount for backwards compatibility
Some mods (*cough* Computronics *cough*) directly access this class,
rather than using the API. We add this back to ensure they still behave
as expected.

Truth be told, I can't really complain, as Plethora also does dodgy
thing with CC internals.
2018-11-22 10:06:43 +00:00
SquidDev
1160ffbf9e Bump version and require a minimum version of Forge 2018-11-21 18:11:14 +00:00
SquidDev
93cb6547bd Improvements for coroutine creation
- Keep track of the number of created and destroyed coroutines for each
   computer.
 - Run coroutines with a thread pool executor, which will keep stale
   threads around for 60 seconds. This substantially reduces the
   pressure from short-lived coroutines.
 - Update to the latest Cobalt version.
2018-11-21 16:47:06 +00:00
SquidDev
f9c91f288f Try to remove some locking
Ideally we would be able to avoid locking at all on the main thread, but
needs must.
2018-11-19 20:56:44 +00:00
SquidDev
62cf921cc6 Allow modems to handle being attached to multiple computers
- Introduce a ModemState, which shares the open channels across all
   modem instances of a wired modem.
 - Keep a set of computers for all modem peripherals.
 - Keep a map of computers -> (string, peripheral) for wired modem
   peripherals. We shouldn't need this one, as you cannot attach one
   modem to another, but it's good to be consistent.

One major change here is that modems will continue to be "on", even if
no computers are attached. This would substantially increase
implementation complexity, so I think this is an acceptable compromise
for now.

Should fix #74
2018-11-17 11:52:12 +00:00
SquidDev
4bd7381827 Add support for Forge's ISelectiveResourceReloadListener
This means we don't reload turtles every time someone just reloads
shaders or the language pack.
2018-11-17 10:54:42 +00:00
SquidDev
43459ec825 Fix read methods failing on malformed unicode.
Java configured the charset decoders/encoders for streams to REPLACE
malformed characters rather than the default REPORT. It does not do the
same for channels, and so we were catching an IO exception and returning
null.
2018-11-16 20:58:49 +00:00
SquidDev
5fa01f8b96 Truncate files when writing them
This is performed by default, but as we don't pass any options, this
flag is removed.

Closes #75
2018-11-16 13:09:12 +00:00
SquidDev
67d5693d2a Fix tile entities being registered with incorrect names
We'd somehow added spaces, which means they weren't registered under the
computercraft domain (rather, the "computercraft " one). We also create
a datafixer to ensure old worlds are handled correctly.
2018-11-16 12:29:29 +00:00
SquidDev
c2a782afa4 Remove some old scripts
These were part of the original CC repo, but aren't really needed now
that everything important (LuaJ, bundling API docs+source), has been
moved to Gradle.

We also remove the LuaJ lib. It's sad to see it go, but it was rather
redundant. We're keeping the LuaJ sources for now, as I don't really
want a really large diff.
2018-11-16 11:43:42 +00:00
SquidDev
14c9558ee6 Bump version 2018-11-03 15:44:36 +00:00
SquidDev
d53a73e7e7 Fix resource handle loading
See #70
2018-10-29 15:59:43 +00:00
SquidDev
7e334bd4a5 Fix a couple of other bugs with the fs rewrite
- Fix stdin not being considered a "readable" input
 - Return an unsigned byte rather than a signed one for no-args .read()
2018-10-28 08:39:44 +00:00
SquidDev
51e787f631 Bump version and update feature list 2018-10-24 12:49:35 +01:00
SquidDev
8080699030 Couple of minor improvements to the alternative mount implementation
- Rename openStreamFor* methods to more accurate openChannelFor*
 - Fix ArrayByteChannel having an incorrect .position() implementation

Cherry-picked from the PR against dan200/ComputerCraft
2018-10-24 12:39:22 +01:00
SquidDev
e555f9f7f0 Merge pull request #575 from SquidDev-CC/ComputerCraft/feature/file-seeking
Rewrite file systems to use ByteChannels
2018-10-24 12:20:53 +01:00
SquidDev
822db6e9b5 Add support for binary websockets
- Add an argument to send which controls whether it's a binary message
   or not. This is a little ugly, but it's probably more effective than
   anything else.
 - Fix binary frames not correctly queueing the correct data in the
   message event.

Closes #69
2018-10-23 12:15:40 +01:00
SquidDev
ac1f30ef43 Clamp the volume for all sounds, rather than just notes
This restores the previous behaviour.
2018-10-12 12:05:31 +01:00
SquidDev
0fc1b8c46b Merge pull request #578 from SquidDev-CC/ComputerCraft/feature/speaker-sound
Change speakers to use the SPacketCustomSound packet instead
2018-10-10 16:57:34 +01:00
SquidDev
e7c19bcf55 Change speakers to use the SPacketCustomSound packet instead
The method to register new SoundEvents is private, which means that few
(if any) mods actually register them. Consequently, one could not use
the speaker to play any modded sound, as they weren't registered on the
server side.

Using SPacketCustomSound does mean we can no longer determine if a sound
exists or not, but I think a price I'm willing to pay in order to allow
playing modded sounds.
2018-10-10 08:46:30 +01:00
SquidDev
63ca8aca4c Merge pull request #68 from Vexatos/patch-1
Create de_de.lang
2018-10-02 16:47:42 +01:00
Vexatos
2caa9c57fc Create de_de.lang 2018-10-02 15:43:43 +02:00
SquidDev
33fad2da15 Merge pull request #577 from SquidDev-CC/ComputerCraft/feature/get-blink
Add .getCursorBlink to monitors and terminals
2018-09-28 16:23:00 +01:00
SquidDev
518eefbe10 Rewrite file systems to use ByteChannels
This replaces the existing IMount openFor* method with openChannelFor*
ones, which return an appropriate byte channel instead.

As channels are not correctly closed when GCed, we introduce a
FileSystemWrapper. We store a weak reference to this, and when it is
GCed or the file closed, we will remove it from our "open file" set and
ensure any underlying buffers are closed.

While this change may seem a little odd, it does introduce some
benefits:

 - We can replace JarMount with a more general FileSystemMount. This
   does assume a read-only file system, but could technically be used
   for other sources.

 - Add support for seekable (binary) handles. We can now look for
   instances of SeekableByteChannel and dynamically add it. This works
   for all binary filesystem and HTTP streams.

 - Rewrite the io library to more accurately emulate PUC Lua's
   implementation. We do not correctly implement some elements (most
   noticably "*n", but it's a definite improvement.
2018-09-26 10:00:17 +01:00
SquidDev
1ba73454c1 Add .getCursorBlink to monitors and terminals
Closes #576
2018-09-23 09:34:28 +01:00
SquidDev
ee4735c17c Merge pull request #573 from osmarks/ComputerCraft/patch-1
Fix a crash in rednet `repeat`
2018-09-09 17:49:24 +01:00
Oliver Marks
b008edae90 Fix a crash in rednet repeat
This crash can be triggered remotely by specially constructed rednet messages, making this a bit of a problem, as any repeaters can be remotely crashed.
2018-09-08 21:55:36 +01:00
SquidDev
c6bd88f3ad Attempt to cut out a lot of synchronized calls
A lot of these don't actually have any effect as they'll only be called
on the main thread or they are getters where the state is guaranteed to
be consistent whenever it is accessed.

Hopefully this'll reduce the chance of world updates being blocked by
waiting for peripheral locks to be released.
2018-08-25 21:17:48 +01:00
SquidDev
efa57521c7 Bump version to 1.8pr1.8
While there haven't been a lot of changes, there's been a couple of bug
fixes and nice improvements.
2018-08-25 10:58:54 +01:00
SquidDev
4700f8831b Add a pull request template
Again, not entirely a fan of these, but there's been several PRs
which would have been better off targeting the original repo.
2018-08-24 17:37:20 +01:00
SquidDev
9428bee316 Merge pull request #65 from apemanzilla/fix/drop-consumer-overflow
Prevent stack overflows when using turtle.place() with a full inventory
2018-08-23 08:04:07 +01:00
apemanzilla
89c7183a1d Prevent stack overflows when using turtle.place() with a full inventory 2018-08-23 07:56:50 +01:00
SquidDev
d2a9e7e458 Reset a few more flags when rendering printouts
Closes #63
2018-08-13 22:25:58 +01:00
SquidDev
1774f1a079 Merge pull request #566 from SquidDev-CC/ComputerCraft/feature/tiny-lua-wins
A couple of small improvements to CraftOS
2018-08-12 15:49:19 +01:00
SquidDev
de1307913b A couple of small improvements to CraftOS
- Make window.reposition's argument validation a little more strict.
   Previously it would accept `window.reposition(x, y, width)` (no
   height argument), just not act upon it.
 - Use select instead of table.unpack within `pastebin run`.
 - Use `parallel.waitForAny` instead of `waitForAll` within the dance
   program.
 - Pipe the entire help file into `textutils.pagedPrint`, rather than
   doing it line by line.
 - Remove bytecode loading disabling from bios.lua. This never worked
   correctly, and serves little purpose as LuaJ is not vulnerable to
   such exploits.
2018-08-12 08:23:17 +01:00
SquidDev
093132533d Add charset bundled cable integration
- Bump MinecraftForge version so we don't crash on load. Oh boy, all
   the deprecation warnings.
 - Inject IBundledEmitter and IBundledReceiver capabilities onto all
   TileGenerics.
 - Register a IBundledRedstoneProvider instance for IBundledEmitter.
2018-08-11 10:49:21 +01:00
SquidDev
0685be6bfa Add issue templates
I'm not entirely a fan of massive templates, but there's 
been a couple of lacklustre issues recently, so it's probably
good to formalise my guidelines.
2018-08-04 10:52:26 +01:00
SquidDev
f40733e9a6 Error when missing computers after executing the command
This allows you to automate running various commands and still have them
"work" if some computers are not loaded.

Closes #47
2018-08-04 10:39:44 +01:00
SquidDev
a3d1cff298 Bump Cobalt version
This should allow us to do SquidDev-CC/mbs#18 due to the debug
improvements.
2018-08-03 20:58:20 +01:00
SquidDev
b8957cab5c Update to the latest mappings
This is a preliminary for updating to 1.13, as many of the name changes
apply to both. This will make it harder to remain consistent with
actual CC, though that will be less of a consideration when 1.13 hits.
2018-07-24 09:27:05 +01:00
SquidDev
3ac8dde779 Bump version 2018-07-09 21:02:20 +01:00
SquidDev
17dace979a Merge pull request #562 from SquidDev-CC/ComputerCraft/hotfix/turtle-sign-place
Be a little smarter about our detection of the placed sign
2018-07-09 20:57:42 +01:00
SquidDev
d405316a4b Be a little smarter about our detection of the placed sign
When placing a sign against a tile entity (such as a turtle or chest),
we would consider that block the "placed" one instead, meaning the text
was never set. This solution isn't entirely ideal either, but short of
capturing block snapshots I'm not sure of a better solution.

Fixes #552
2018-07-09 20:53:49 +01:00
SquidDev
7e18f2cead Clear the turtle's inventory on load 2018-07-09 18:22:42 +01:00
SquidDev
000786a1a7 Merge pull request #560 from SquidDev-CC/ComputerCraft/hotfix/turtle-destroy
Rewrite turtle block destroying
2018-07-08 23:01:13 +01:00
SquidDev
0bf13562b9 Provide a more direct way to get the related computer
Effectively shift extracting the computer away from Plethora into CC:T.
Ideally we wouldn't need this at all, but Plethora does some funky
things with tick timings.

See SquidDev-CC/plethora#125
2018-07-08 22:48:50 +01:00
SquidDev
45a189e834 Cache a turtle's fake player
Player construction can get a little expensive, and this is exacerbated
by Sponge. We now cache a turtle's fake player (updating the position
every time it is requested) in order to reduce this overhead.
2018-07-08 15:21:42 +01:00
SquidDev
0ce6f34a09 Rewrite printout rendering
- The current page is always centred when rendering in a GUI, with
   the turned pages moving from the sides.
 - Pages are no longer evenly distributed from the centre - they follow
   an exponential decay curve, so ones further out are closer together
   (a bit like an open book).
 - Render pages and books in item frames/in-hand (rather than just
   single pages).

This currently does some very dirty things with z values in order to
prevent z-fighting. It would be nice to avoid that, though turning off
writing to the z buffer causes issues with the bounding box.
2018-07-07 19:59:20 +01:00
SquidDev
4d984dc5ee Rewrite turtle block destroying
- Try to make drop capturing a little more generic. This now allows for
   capturing a block's drop at a given position, as well as any drop
   within a bounding box (for things which don't play nicely).

 - Use as much of Minecraft's block breaking logic as possible,
   hopefully simplifying things and making it more consistent with other
   mods.
2018-07-06 18:49:15 +01:00
SquidDev
984d358930 Provide .getNameLocal on modems
This provides the local modem's name on the remote network. Let's be
honest, I'll probably end up renaming this soon.
2018-06-29 20:29:04 +01:00
SquidDev
a95893b823 Send the terminal state to the pocket computer's player
As we only send the terminal to players using the GUI, the map interface
was never updated. We now will also send the terminal state to whoever
has the computer in their inventory.

This also marks the terminal as dirty when a new player picks the pocket
computer up, hopefully preventing any desync issues which might occur
then.

Fixes #42.
2018-06-24 19:18:30 +01:00
SquidDev
81aaead032 Improve using /computercraft as a non-player
- Fix text table only showing the first row (fixes #40)
 - Do not emit alignment characters in monospace environments
 - Reduce padding in monospace environments

Also make the output of dump consistent with that of the profiler: we
provide tp and view shortcuts for each computer.
2018-06-22 08:28:36 +01:00
SquidDev
a2083bcff1 Merge pull request #554 from SquidDev-CC/ComputerCraft/hotfix/gui-blemishes
Fix a couple of minor blemishes in the GUI textures
2018-06-19 22:24:32 +01:00
SquidDev
052f2a16dc Fix a couple of minor blemishes in the GUI textures
- Slight airbrush effect for normal turtles. While this is only really
   visible when upping the contrast, it's probably nice to fix.
 - A few off-colour pixels for advanced turtles
2018-06-19 22:18:48 +01:00
SquidDev
fd10ed6f62 Merge pull request #553 from SquidDev-CC/ComputerCraft/feature/fancy-printout
Fancy rendering of printouts
2018-06-19 19:44:51 +01:00
SquidDev
c0bdd4ff1d Add basic support for fancy rendering of printouts
- When held in first-person, single pages are displayed like a map.
 - When placed in an item frame, the page is drawn instead of the actual
   item.
2018-06-18 22:09:24 +01:00
SquidDev
5f0addbc3e Fix variable being declared too late 2018-06-18 19:01:36 +01:00
SquidDev
c9589ad0e7 Allow using any kind of skull for crafting heads
It's possible to acquire any mob head in vanilla, so it's probably best
if we allow any head to be used.
2018-06-02 11:12:29 +01:00
SquidDev
b21c495815 Update the README to be a bit more detailed
- Include a list of features, pretty similar to that on the forum
   thread or CurseForge page.
 - Replace CC: Tweaked with CC:T. After all, who wants to type all of
   that?
2018-05-15 12:27:04 +01:00
SquidDev
18429c50f9 Bump version 2018-05-15 11:59:21 +01:00
SquidDev
7ec8ddcf7d Delete previous chat messages of the same type
This uses a custom ComputerCraft packet to send chat messages to the
client. When received, we delete all messages of the same category
before sending the new ones.

This avoids cluttering the chat with near-identical messages, and helps
make working with the "individual dump" command easier, as the previous
computer's dump output is deleted.

Also change the max height of the TextTable to 18, so it fits within
Minecraft's default chat limit.
2018-05-15 11:44:23 +01:00
SquidDev
5bf9f9e3c5 Allow multiple HTTP request methods
This implements an argument format similar to LuaReqeust, as described
in dan200/ComputerCraft#515. The Lua argument checking code is a little
verbose and repetitive, but I'm not sure how to avoid that - we should
look into improving it in the future.

Closes #21
2018-05-15 10:11:08 +01:00
hugeblank
e4164ee9a1 amend additional typo in keys.lua
- fixed circumflex typo: you can now cîrcûmflêx on all your friends
- added comment making it clearer that the following lines are intended for backwards compatibility.
2018-05-14 15:54:06 +01:00
SquidDev
b522af3075 Add some basic tracking for HTTP requests and websockets
This should allow for easier identification of misbehaving computers,
which are consuming a large amount of bandwidth.
2018-05-14 15:52:16 +01:00
SquidDev
8775052dee Merge pull request #543 from hugeblank/ComputerCraft/patch-1
amend typo in keys.lua
2018-05-08 09:46:14 +01:00
hugeblank
c0c5d57e10 amend typo in keys.lua
The most important commit that CC has ever seen.
2018-05-08 01:10:45 -07:00
SquidDev
4c2e97b1af Enable compression extension for websockets 2018-05-05 08:34:35 +01:00
SquidDev
f17df15117 Always create extended disks
Whilst the legacy ones are important for backwards compatibility, they
cannot have an ID of 0, which introduces issues when they are the first
disk created in the world.
2018-04-27 09:51:28 +01:00
SquidDev
bfbb18bdfc Add support for tracking server-thread tasks too
This allows us to track how much work various peripherals are doing.
This will not work with all systems, such as Plethora, as that has its
own execution system.
2018-04-24 12:26:26 +01:00
SquidDev
cac65ef755 Print a useful debug log if we cannot safely terminate a task 2018-04-24 11:07:33 +01:00
SquidDev
a42793024b Merge pull request #541 from SquidDev-CC/ComputerCraft/feature/unlimited-reads
Remove upper bound on how many bytes/characters can be read
2018-04-23 16:42:28 +01:00
SquidDev
7dbc4e6455 Remove upper bound on how many bytes/characters can be read
The limit was added to prevent people creating arbitrarily large buffers
(for instance, handle.read(2^31) would create a 2GB char array). For
"large" counts, we now read in blocks of size 8192, adding to an
extendable buffer.
2018-04-23 16:41:00 +01:00
SquidDev
a0d71cb3ad A couple of fixes for maven and CCEmuX
- Add additional maven metadata and strip dependencies
 - Shift ICommand registration into the proxy, to avoid class loading
   issues. This is probably rather temperamental, but classloading
   always is.
2018-04-20 19:39:53 +01:00
SquidDev
83546d0acb Add support for Maven uploading 2018-04-19 22:36:00 +01:00
SquidDev
e2f9ddd534 Add support for arbitrary trackers
This is used by cc-prometheus to monitor statistics. It isn't currently
exposed as an API, as I'm making no guarantees on the stability of this.
2018-04-19 21:59:35 +01:00
SquidDev
911e404bfa Add support for tracking fs, turtle and peripheral operations
See #25
2018-04-17 09:22:26 +01:00
SquidDev
bfeafe163f Various improvements to the tracking system
- Trackers are created per-user, meaning multiple people can run
   /computercraft track at once.
 - Allow sorting the tracking information by arbitrary fields.
 - Add support for tracking arbitrary fields (though none are currently
   implemented).
2018-04-16 21:06:16 +01:00
SquidDev
6cf32f1f74 Various improvements to peripheral invalidation
- Abstract peripheral ID and type checking into separate class
 - Update peripherals directly rather than marking as invalid then
   fetching from the network.
 - Update peripherals when adjacent tiles change

This does result in a slightly more ugly interface, but reduces the
amount of work needed to perform partial updates of peripherals, such as
those done by neighbouring tile updates.
2018-04-16 18:22:28 +01:00
SquidDev
04f162ef25 Rename node → m_node
It's a bit of an ugly naming convention, but it's consistent.
2018-04-16 17:10:08 +01:00
SquidDev
b2aa390ae1 Split up modem and connection invalidation 2018-04-16 17:02:20 +01:00
SquidDev
6ca61f000f Minor performance improvements to WiredNetworkChange
This should improve the performance of the common case, where one
peripheral set is empty.
2018-04-16 15:31:37 +01:00
SquidDev
20a47a7f88 Merge pull request #540 from SquidDev-CC/ComputerCraft/hotfix/fakeplayer-stubs
Add additional method stubs to the TurtlePlayer
2018-04-16 09:39:15 +01:00
SquidDev
e2e6946c92 Add additional method stubs to the TurtlePlayer
Forge's default fake player implementation doesn't override all methods
which use the connection. As it is not set, we get an NPE and thus crash
the server. We simply stub those methods out ourselves to prevent such
an issue.
2018-04-16 09:34:44 +01:00
SquidDev
abe917cd54 Fix peripherals showing up when they shouldn't on world load
When initially attaching a modem, the adjacent computer would not show
up on its own peripheral list (like in vanilla CC). However, it would
show up when the chunk was reloaded as peripherals were added through a
different method.

This prevents such behaviour, always hiding the remote peripheral from
the object which provides it.

Closes #20
2018-04-07 10:23:11 +01:00
SquidDev
a1d77ab8e7 Merge pull request #536 from Luca0208/ComputerCraft/master
Make wget automatically determine the file name.
2018-04-06 21:08:54 +01:00
SquidDev
c8db671409 Override monitors' lightmap coordinates
Shaders appear to ignore all the other subtle (and not-so-subtle) hints
we drop that monitors shouldn't be rendered with shadows. This solution
isn't optimal, as monitors may still be tinted due to sunlight, but
there is nothing we can do about that.

Many thanks to ferreusveritas for their help in diagnosing, fixing and
testing this issue.
2018-03-30 12:57:27 +01:00
SquidDev
52641b7bea Allow rendering a monitor tile multiple times in a tick
Shader mods may perform multiple passes when rendering a tile, so
monitors will be drawn transparently on later passes. In order to
prevent this we allow drawing the a single tile multiple times in a
tick.
2018-03-29 12:31:20 +01:00
SquidDev
3e751ee94a Use Unicode escape code instead of literal
It doesn't compile under Gradle on my system. Goodness knows why not.
2018-03-29 11:47:45 +01:00
SquidDev
2b28cc3558 Merge remote-tracking branch 'SquidDev-CC-ComputerCraft/hotfix/disk-drive-stop' 2018-03-29 11:41:00 +01:00
SquidDev
f9761388b1 Fix .isDiskPresent() always reporting true
We were still determining if the stack was null, but post-1.11 this will
never be the case.
2018-03-29 11:36:59 +01:00
SquidDev
d28694eb57 Rewrite the command system's text padder
This uses narrow near-invisible unicode characters instead of attempting
to toggle between bold and non-bold spaces.
2018-03-25 21:31:31 +01:00
SquidDev
d758895578 Bump to Forge 1.12.2
Nobody is still using 1.12, so we might as well update to the latest -
it makes it easier to test mod compatibility at least.
2018-03-24 12:20:51 +00:00
SquidDev
043d5f00ca Convert wired elements to capabilities
See #18
2018-03-24 11:57:36 +00:00
SquidDev
36878e75b7 Merge remote-tracking branch 'origin/master' 2018-03-15 17:53:21 +00:00
SquidDev
ebb50cba48 Bump version 2018-03-15 17:43:23 +00:00
SquidDev
7c218361d9 Merge pull request #528 from SquidDev-CC/ComputerCraft/feature/computer-upgrade
Add recipes to upgrade computers
2018-03-15 17:39:17 +00:00
SquidDev
bb2eab0bed Use the ore dictionary for upgrade recipes
See #517 for motivation
2018-03-15 17:34:58 +00:00
SquidDev
e8c0cf3857 Convert TurtleRecipe to use ComputerConvertRecipe
The two recipes are pretty similar, so this allows us to substantially
simplify the code. This now introduces the additional requirement that
computers must be used to create turtles, rather than pocket computers
or another turtle.
2018-03-13 14:21:39 +00:00
SquidDev
db825a7aab Add recipes to convert computer items into their upgraded counterparts
This adds IComputerItem.withFamily(ItemStack, ComputerFamily) as well as
a ComputerFamilyRecipe class. Each type of computer (normal, turtle,
pocket) defines a recipe using this class, as they require a different
number of gold ingots to upgrade.
2018-03-13 14:14:36 +00:00
SquidDev
dbcae810f0 Fix monitor.getTextScale() being doubled
Closes #16. The original method divided by 2 in the getter, but that
was removed in our monitor rewrite.
2018-03-10 22:16:15 +00:00
Daniel Ratcliffe
914df8b0c7 Merge pull request #521 from SquidDev-CC/hotfix/modem-full-block
Fix wireless modems suffocating entities
2018-03-05 14:07:57 +00:00
SquidDev
f753513289 Wrap ComputerCraft fake player with brackets
Hopefully this'll make GriefPrevention play a little nicer
2018-03-01 15:58:09 +00:00
SquidDev
7bb8efed1d Dispose of monitor display lists when unloading worlds
This means all display lists are correctly deleted when changing
dimensions/exiting to main menu.
2018-02-24 20:37:14 +00:00
SquidDev
0cec4aee8c Merge pull request #15 from Lignum/maybe-fix-monitors
Maybe fix monitors
2018-02-24 16:59:21 +00:00
Lignum
e0c9dc24e7 Generate individual display lists instead of relying on their names being contiguous 2018-02-24 17:21:12 +01:00
SquidDev
244907a39a Various cherry picks from world thread safety
- Ensure monitor draw lists are not reused after deleting them.
 - Make terminal methods synchronized, avoding NPEs and IOOBEs when
   resizing.
2018-02-22 21:20:08 +00:00
SquidDev
9be61abd6b Merge pull request #5 from SquidDev-CC/feature/network-api
Well, how badly can this go?
2018-02-21 15:47:15 +00:00
SquidDev
922f424a78 Add full block wired modems
These act similarly to conventional wired modems, but with the advantage
that they are a full block. This means they can be attached to
peripherals which are not solid (such as chests). Further more, as they
do not have a direction, they allow wrapping peripherals on all 6 sides.

It's worth noting that wired modems do not require a cable - they will
automatically form connections to adjacent network elements when placed.
2018-02-21 15:40:08 +00:00
SquidDev
5c7828dd79 Convert TileCable to use the wired network API
There are several important things to note here:

 - The network element is associated with the cable, whilst the
   peripheral (and so packet sender/receiver) is associated with the
   modem. This allows us to have the main element be in the centre of
   the cable block, whilst the modem is in the centre of the adjacent
   computer.

 - Cables will connect to any adjacent network element, not just
   other cables.

 - Rednet messages are now sent on the computer thread, rather than the
   cable tick.
2018-02-21 15:35:38 +00:00
SquidDev
74f5093d2a Add the default implementation of wired networks 2018-02-21 15:29:34 +00:00
SquidDev
4651e362c9 Add an API for wired networks
The API is composed of three primary classes:

- IWiredElement: Represents some physical entity in the network. This
   will generally be a block (such as a cable or modem), but it is not
   required to be.

   Each element can provide a series of peripherals, which will be
   exposed to other elements on the network.

- IWiredNode: Every wired element has a unique wired node. This acts
   as a thread-safe proxy for communicating with the rest of the
   network (such as sending packets). Each node is also its own packet
   network.

- IWiredNetwork: This is responsible for keeping track of nodes and
   peripherals in the network. It provides methods for forming and
   breaking connections, correctly joining and splitting networks where
   needed.

Tiles which wish to be part of a wired network should implement
IWiredElementTile or register a custom IWiredProvider. When loaded into
the world, it should connect to adjacent nodes. Similarly, when removed
(either due to being broken or chunk unloads), it should break those
connections.

There is no method to query the layout of the network, as that offers
greater flexibility in changing or extending the implementation later
on.
2018-02-21 15:26:13 +00:00
SquidDev
a2e2a5cb37 Add the concept of "available peripherals" to IComputerAccess
This provides a mechanism for peripherals to see what else a computer is
connected to - and then interact with those peripherals.

We also add the ability to query what block or tile a peripheral
targets. This allows one to interact with the original block of adjacent
peripherals instead.
2018-02-21 15:25:20 +00:00
SquidDev
15a3882016 Fix monitor clear state being cleared without a redraw 2018-02-21 14:32:53 +00:00
SquidDev
d3ecd5214b Merge remote-tracking branch 'SquidDev-CC-ComputerCraft/feature/turtle-event' 2018-02-16 10:48:43 +00:00
SquidDev
0a8a8a742e Add config options to disable various turtle actions
Mostly intended for those people who don't like .inspect() or
.getItemDetail(), but could allow modpacks to block equipping upgrades,
placing blocks, etc...
2018-02-16 10:37:47 +00:00
SquidDev
ecff23d027 Add turtle events
The main aim of this is to allow for greater extensibility for other
mods. For instance, you can now prevent turtles placing dirt blocks, or
turning when on gravel.
2018-02-16 10:33:32 +00:00
SquidDev
20dcb32bae Add command to reload config from disk
Also bump version number, as we're relatively close to a release and
it's frustrating having to bump it when putting out previews.
2018-02-16 09:33:40 +00:00
SquidDev
678462d2db Minor fixes to the monitor rewrite 2018-02-15 20:49:34 +00:00
SquidDev
61fdfec09b Further overrides for wireless modem blockiness 2018-02-15 18:17:38 +00:00
SquidDev
5eadf5533d Fix wireless modems suffocating entities
As of #458, BlockPeripheral will act as a full/opaque block for some
peripherals and a transparent one for others. However, some Block
methods use the default state rather than the current one. This means
modems report being a full block when they are not, leading to
suffocating entities and lighting glitches.
2018-02-15 18:17:02 +00:00
SquidDev
2d3cd5dc80 Merge pull request #521 from SquidDev-CC/ComputerCraft/hotfix/modem-full-block
Fix wireless modems suffocating entities
2018-02-15 18:00:58 +00:00
SquidDev
5208ad0b98 Fix wireless modems suffocating entities
As of #458, BlockPeripheral will act as a full/opaque block for some
peripherals and a transparent one for others. However, some Block
methods use the default state rather than the current one. This means
modems report being a full block when they are not, leading to
suffocating entities and lighting glitches.
2018-02-15 17:56:08 +00:00
SquidDev
662fb96beb Overhaul monitor's terminal code
This restructures monitor in order to make it thread-safe: namely
removing any world interaction from the computer thread.

Instead of each monitor having their own terminal, resize flag, etc...
we use a monitor "multiblock" object. This is constructed on the origin
monitor and propagated to other monitors when required.

We attempt to construct the multiblock object (and so the corresponding
terminal) as lazily as posible. Consequently, we only create the
terminal when fetching the peripheral (not when attaching, as that is
done on the computer thread).

If a monitor is resized (say due to placing/breaking a monitor) then we
will invalidate all references to the multiblock object, construct a new
one if required, and propagate it to all component monitors.

This commit also fixes several instances of glLists not being deleted
after use. It is not a comprehensive fix, but that is outside the scope
of this commit.
2018-02-14 21:30:07 +00:00
SquidDev
4c14431a3d Various improvements to command system
- Ensure usage is consistent
 - Allow computer selectors to return multiple values
 - Fix commands being marked as usable when it isn't
 - Add /computercraft turn-on, a counter to /computercraft shutdown
2018-02-13 11:45:13 +00:00
SquidDev
5ae38a3f18 Merge pull request #520 from SquidDev-CC/ComputerCraft/hotfix/turtle-world-border
Prevent turtles moving beyond the world border
2018-02-13 11:21:55 +00:00
SquidDev
94e10d1f67 Prevent turtles moving beyond the world border
As tiles outside the world border are not ticked, turtles are rendered
entirely useless. Furthermore, the turtle animation will never progress
resulting in visual glitches.

In order to avoid this, we ensure the target position is within the
world border when moving to it.
2018-02-12 17:50:46 +00:00
SquidDev
0a50676884 Fix turtle owner not being persisted 2018-02-10 16:10:16 +00:00
SquidDev
41cce78fcb Merge pull request #518 from SquidDev-CC/ComputerCraft/feature/owner-tracking
Track which player "owns" a turtle
2018-02-05 11:07:06 +00:00
SquidDev
4c0fa1fabe Track which player "owns" a turtle
When a player places a turtle, they are marked as its owner. Any actions
they perform (such as breaking blocks, moving, etc...) are performed
using this player's game profile.

This allows turtles to work correctly with various permissions mods.
Previously you would have to whitelist all turtles in order for them to
function within a claim.
2018-02-04 21:35:21 +00:00
SquidDev
54e1dafa3f Merge pull request #517 from SquidDev-CC/ComputerCraft/feature/ore-dict
Add ore dictionary support to all recipes
2018-02-04 20:06:34 +00:00
SquidDev
3ac76bc05b Add ore dictionary support to all recipes 2018-02-04 20:02:12 +00:00
SquidDev
83030df3ee Add computer performance monitor 2018-02-02 13:34:27 +00:00
SquidDev
07d15caf6f Bump Cobalt version 2018-02-02 12:26:21 +00:00
SquidDev
3298efe652 Prevent computer dump command sending too much information 2018-01-20 11:07:09 +00:00
SquidDev
01d9919a3e Merge pull request #508 from SquidDev-CC/ComputerCraft/hotfix/turtle-speaker-model
Fix turtle speaker upgrade's missing texture
2018-01-19 13:10:20 +00:00
SquidDev
80b1170b63 Extract required textures from models instead
This ensures we will not get missing texture errors in the future, and
allows resource pack artists to use additional textures.
2018-01-19 13:04:50 +00:00
SquidDev
2e7302e654 Fix turtle speaker upgrade's missing texture
The sprite was not registered into the atlas, meaning it rendered the
missing texture instead.
2018-01-19 12:42:32 +00:00
SquidDev
ca7fb8a0b4 Cache turtle family within the tile
This means one can call .getFamily() in a thread-safe manner, ensuring
turtle.getFuelLimit() does not cause issues. As we use a specialist
TE class for each family this does not require any specialist caching.
2018-01-18 13:06:34 +00:00
SquidDev
c9b0894f26 Cache direction of modems within the tile
This ensures the world is not accessed from another thread.

Closes #410
2018-01-18 13:06:11 +00:00
SquidDev
c3454a195d Merge branch 'master' of https://github.com/dan200/ComputerCraft 2018-01-15 17:18:48 +00:00
Daniel Ratcliffe
3b3dd8071b Merge pull request #506 from Wojbie/Advanced-Monitor-Count-Fix
Fix advanced monitor recipe.
2018-01-15 12:59:35 +00:00
Wojbie
0d28c67534 Fix advanced monitor recipe.
Fix recipe to create 4 monitors.
2018-01-14 23:03:14 +01:00
SquidDev
d0af85754a Merge branch 'master' of https://github.com/dan200/ComputerCraft 2018-01-13 10:49:07 +00:00
Daniel Ratcliffe
3e265c27ff Merge pull request #455 from Wilma456/fileread
Add read() to Filehandle
2018-01-13 00:58:19 +00:00
Daniel Ratcliffe
8d356f50c4 Merge pull request #440 from Wilma456/iomulti
Make io.write() accept multiple args
2018-01-13 00:48:07 +00:00
Daniel Ratcliffe
f30c4f16c0 Merge pull request #411 from Wilma456/copyfixup
Fix Bug in copy.lua, mkdir.lua and rename.lua (updated)
2018-01-13 00:32:55 +00:00
Daniel Ratcliffe
8bb8caa315 Merge pull request #448 from Wilma456/writecheck
Fix check of write()
2018-01-13 00:28:08 +00:00
SquidDev
0f17a3d72e Merge branch 'master' of https://github.com/dan200/ComputerCraft 2018-01-12 14:15:22 +00:00
Daniel Ratcliffe
7647369e2d Merge pull request #446 from Wilma456/moduledir
Add folder /rom/modules
2018-01-12 14:10:50 +00:00
Daniel Ratcliffe
4b4208e724 Merge pull request #476 from SquidDev-CC/hotfix/printer-clear
Fix the printer overwriting the current page
2018-01-12 13:59:51 +00:00
Daniel Ratcliffe
2a16a1df85 Merge pull request #486 from Wilma456/extensionfix
Fix Bug in Paint and Edit
2018-01-12 13:59:15 +00:00
Daniel Ratcliffe
25f7c58400 Merge pull request #494 from SquidDev-CC/hotfix/collision-aabb
Fix getCollisionBoundingBox not using all AABBs
2018-01-12 13:57:50 +00:00
Daniel Ratcliffe
c3db91f11f Merge pull request #485 from Luca0208/patch-1
Removed the "the" that was too much(In /rom/help/cd.txt)
2018-01-12 13:56:48 +00:00
Daniel Ratcliffe
8c66ce03d4 Merge pull request #475 from Wilma456/ioline
Fix io.lines()
2018-01-12 13:56:21 +00:00
Daniel Ratcliffe
2be2a0625e Merge pull request #502 from SquidDev-CC/hotfix/missing-overlay
Fix turtle overlay not being rendered in items
2018-01-12 13:54:59 +00:00
Daniel Ratcliffe
c904d5041b Merge pull request #499 from SquidDev-CC/hotfix/null-network
Fix ComputerCraftAPI.getWirelessNetwork() failing
2018-01-12 13:54:33 +00:00
SquidDev
632762768e Add workaround for incorrect overload of getDrops being overridden
Closes #2
2017-12-30 19:03:32 +00:00
SquidDev
c69ba205f8 Merge pull request #502 from SquidDev-CC/ComputerCraft/hotfix/missing-overlay
Fix turtle overlay not being rendered in items
2017-12-24 21:49:01 +00:00
SquidDev
019f4dbea9 Fix turtle overlay not being rendered in items 2017-12-24 21:44:55 +00:00
SquidDev
259ea41ce3 Merge pull request #499 from SquidDev-CC/ComputerCraft/hotfix/null-network
Fix ComputerCraftAPI.getWirelessNetwork() failing
2017-12-10 15:39:59 +00:00
SquidDev
11290f7204 Fix ComputerCraftAPI.getWirelessNetwork() failing
I've got to admit, it is super embarrassing that a) I didn't notice this
when testing and b) no one else has noticed until now.
2017-12-10 15:37:40 +00:00
SquidDev
abd06133fb More binary compatibility stubs for ILuaAPI 2017-12-07 09:24:44 +00:00
SquidDev
29a3a0c48f Bump version 2017-12-07 09:08:15 +00:00
SquidDev
2728c63512 Add back ILuaAPI
This ensures binary compatibility with all those evil mods (Plethora)
which CC internals.
2017-12-07 09:06:47 +00:00
SquidDev
f3b11bc1c2 Copy over CCTweaks's command system
This adds several commands which may be useful for server owners. It'd
be nice to integrate this into ComputerCraft itself, but the associated
command framework is quite large so we'd have to think about it.
2017-12-06 15:51:51 +00:00
SquidDev
04590befb3 Add support for viewing arbitrary computers in a GUI
Important terminal (such as terminal size) is packed into the the
coordinate fields.
2017-12-06 15:43:25 +00:00
SquidDev
4e9034f910 Make http.websocket call synchronous in bios.lua
I thought I'd done this already, but it's possible it got lost during a
rebase.
2017-12-06 09:28:38 +00:00
SquidDev
ba9cfa3764 Bump version
Also add CurseGradle support
2017-12-01 20:05:26 +00:00
Wilma456
4fb0240a36 Changes suggested by SquidDev and update help file 2017-09-24 17:36:20 +02:00
Wilma456 (Jakob0815)
f20a7afa7f Better Code 2017-09-18 15:22:44 +02:00
Wilma456
5be2202b2e Add read() to Filehandle 2017-09-16 16:06:27 +02:00
Wilma456 (Jakob0815)
b8630f739a Add Check requested by dan200 2017-09-13 19:21:17 +02:00
SquidDev
1ef7c8e8db Only send the packet to people within 64 blocks
This is equivalent to what vanilla Minecraft does
2017-09-12 22:44:49 +01:00
Wilma456
1415dd0dae Changes requested by dan200 2017-09-12 20:43:07 +02:00
Wilma456
5989d021c7 Add folder /rom/modules 2017-09-12 16:44:22 +02:00
Wilma456
90c4ebd208 Fix Bug in copy.lua, mkdir.lua and rename.lua 2017-08-09 19:32:29 +02:00
1517 changed files with 48129 additions and 67092 deletions

View File

@@ -5,9 +5,7 @@ indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
# Sadly too many files have whitespace errors, so we leave this as is for
# now and just make sure we don't introduce any more.
# trim_trailing_whitespace = true
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]

15
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,15 @@
---
name: Bug report
about: Report some misbehaviour in the mod
labels: bug
---
<!--
## Before reporting
- Search for the bug on the issue tracker. Make sure to look at closed issues too!
-->
## Useful information to include:
- Minecraft version
- CC: Tweaked version
- Detailed reproduction steps: sometimes I can spot a bug pretty easily, but often it's much more obscure. The more information I have to help reproduce it, the quicker it'll get fixed.

View File

@@ -0,0 +1,14 @@
---
name: Feature request
about: Suggest an idea or improvement
labels: enhancement
---
<!--
## Before reporting
- Search for the suggestion here. It's possible someone's suggested it before!
-->
## Useful information to include:
- Explanation of how the feature/change should work.
- Some rationale/use case for a feature. My general approach to designing new features is to ask yourself "what issue are we trying to solve" and _then_ "is this the best way to solve this issue?".

3
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,3 @@
## A quick checklist
- If there's a existing issue, please link to it. If not, provide fill out the same information you would in a normal issue - reproduction steps for bugs, rationale for use-case.
- If you're working on CraftOS, try to write a few test cases so we can ensure everything continues to work in the future. Tests live in `src/test/resources/test-rom/spec` and can be run with `./gradlew check`.

23
.gitignore vendored
View File

@@ -1,12 +1,23 @@
build
out
run
deploy
# Build directories
/classes
/logs
/build
/out
# Runtime directories
/run
/run-*
/test-files
*.ipr
*.iws
*.iml
.idea
.gradle
luaj-2.0.3/lib
luaj-2.0.3/*.jar
*.DS_Store
.classpath
.project
.settings/
bin/
*.launch

35
.luacheckrc Normal file
View File

@@ -0,0 +1,35 @@
std = "max"
ignore = {
-- Allow access to undefined globals or their fields. In the future we'll
-- define all of CC's globals within this file
'113', '143',
-- FIXME: Ignore unused arguments and loop variables
'212', '213',
-- Disable line is too long for now. It would be possible to clean
-- this up in the future.
'631',
}
-- Only run the linter on ROM and bios for now, as the treasure disks
-- are largely unsupported.
include_files = {
'src/main/resources/assets/computercraft/lua/rom',
'src/main/resources/assets/computercraft/lua/bios.lua',
'src/test/resources/test-rom',
}
files['src/main/resources/assets/computercraft/lua/bios.lua'] = {
-- Allow declaring and mutating globals
allow_defined_top = true,
ignore = { '112', '121', '122', '131', '142' },
}
files['src/main/resources/assets/computercraft/lua/rom/apis'] = {
-- APIs may define globals on the top level. We'll ignore unused globals,
-- as obviously they may be used outside that API.
allow_defined_top = true,
ignore = { '131' },
}

View File

@@ -11,4 +11,4 @@ cache:
- $HOME/.gradle/wrapper/s
jdk:
- oraclejdk8
- openjdk8

View File

@@ -1,19 +0,0 @@
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

@@ -1,31 +1,75 @@
# ![CC: Tweaked](logo.png)
[![Build Status](https://travis-ci.org/SquidDev-CC/CC-Tweaked.svg?branch=master)](https://travis-ci.org/SquidDev-CC/CC-Tweaked)
[![Current build status](https://travis-ci.org/SquidDev-CC/CC-Tweaked.svg?branch=master)](https://travis-ci.org/SquidDev-CC/CC-Tweaked "Current build status") [![Download CC: Tweaked on CurseForge](http://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge")
CC: Tweaked is a fork of ComputerCraft which aims to provide earlier access to the more experimental and in-development
features of the mod. For a more stable experience, I recommend checking out the
[original mod](https://github.com/dan200/ComputerCraft).
CC: Tweaked is a fork of [ComputerCraft](https://github.com/dan200/ComputerCraft), adding programmable computers,
turtles and more to Minecraft.
## What?
CC: Tweaked does not aim to create a competing fork of ComputerCraft, nor am I planning to take it in in a vastly
different direction to the original mod. In fact, CC: Tweaked aims to be a nurturing ground for various features, with
a pull request against the original mod being the end goal.
ComputerCraft has always held a fond place in my heart: it's the mod which really got me into Minecraft, and it's the
mod which has kept me playing it for many years. However, development of the original mod has slowed, as the original
developers have had less time to work on the mod, and moved onto other projects and commitments.
CC: Tweaked also includes many pull requests from the community which have not yet been merged, offering a large number
of additional bug fixes and features over the original mod.
CC: Tweaked (or CC:T for short) is an attempt to continue ComputerCraft's legacy. It's not intended to be a competitor
to CC, nor do I want to take it in a vastly different direction to the original mod. Instead, CC:T focuses on making the
ComputerCraft experience as _solid_ as possible, ironing out any wrinkles that may have developed over time.
## Features
CC: Tweaked contains all the features of the latest version of ComputerCraft, as well as numerous fixes, performance
improvements and several nifty additions. I'd recommend checking out [the releases page](https://github.com/SquidDev-CC/CC-Tweaked/releases)
to see the full set of changes, but here's a couple of the more interesting additions:
- Improvements to the `http` library, including websockets, support for other HTTP methods (`PUT`, `DELETE`, etc...)
and configurable limits on HTTP usage.
- Full-block wired modems, allowing one to wrap non-solid peripherals (such as turtles, or chests if Plethora is
installed).
- Pocket computers can be held like maps, allowing you to view the screen without entering a GUI.
- Printed pages and books can be placed in item frames and held like maps.
- Several profiling and administration tools for server owners, via the `/computercraft` command. This allows operators
to track which computers are hogging resources, turn on and shutdown multiple computers at once and interact with
computers remotely.
- Closer emulation of standard Lua, adding the `debug` and `io` libraries. This also enables seeking within binary
files, meaning you don't need to read large files into memory.
- Allow running multiple computers on multiple threads, reducing latency on worlds with many computers.
## Relation to CCTweaks?
This mod has nothing to do with CCTweaks, though there is no denying the name is a throwback to it. However, I do plan
to migrate some features of CCTweaks into CC: Tweaked.
This mod has nothing to do with CCTweaks, though there is no denying the name is a throwback to it. That being said,
several features have been included, such as full block modems, the Cobalt runtime and map-like rendering for pocket
computers.
## Contributing
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you do wish to contribute
code, do consider submitting it to the ComputerCraft repository instead.
That being said, in order to start helping develop CC: Tweaked, you'll need to follow these steps:
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. In order to start helping
develop CC:T, you'll need to follow these steps:
- **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked`
- **Setup Forge:** `./gradlew setupDecompWorkspace`
- **Setup Forge:** `./gradlew build`
- **Test your changes:** `./gradlew runClient` (or run the `GradleStart` class from your IDE).
If you want to run CC: Tweaked in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from
`build/libs`.
If you want to run CC:T in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from `build/libs`.
## Community
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
ComputerCraft we have a [forum](https://forums.computercraft.cc/) and [Discord guild](https://discord.gg/H2UyJXe)!
There's also a fairly populated, albeit quiet [IRC channel](http://webchat.esper.net/?channels=#computercraft), if
that's more your cup of tea.
I'd generally recommend you don't contact me directly (email, DM, etc...) unless absolutely necessary (i.e. in order to
report exploits). You'll get a far quicker response if you ask the whole community!
## Using
If you want to depend on CC: Tweaked, we have a maven repo. However, you should be wary that some functionality is only
exposed by CC:T's API and not vanilla ComputerCraft. If you wish to support all variations of ComputerCraft, I recommend
using [cc.crzd.me's maven](https://cc.crzd.me/maven/) instead.
```groovy
dependencies {
maven { url 'https://squiddev.cc/maven/' }
}
dependencies {
implementation "org.squiddev:cc-tweaked-${mc_version}:${cct_version}"
}
```
You should also be careful to only use classes within the `dan200.computercraft.api` package. Non-API classes are
subject to change at any point. If you depend on functionality outside the API, file an issue, and we can look into
exposing more features.

View File

@@ -1,68 +1,124 @@
// For those who want the bleeding edge
buildscript {
repositories {
jcenter()
mavenCentral()
maven {
name = "forge"
url = "http://files.minecraftforge.net/maven"
url = "https://files.minecraftforge.net/maven"
}
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
classpath 'org.ajoberstar:gradle-git:1.6.0'
classpath 'com.google.code.gson:gson:2.8.1'
classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.130'
classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2'
classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0'
}
}
apply plugin: 'net.minecraftforge.gradle.forge'
apply plugin: 'org.ajoberstar.grgit'
/*
// for people who want stable - not yet functional for MC 1.8.8 - we require the forgegradle 2.1 snapshot
plugins {
id "net.minecraftforge.gradle.forge" version "2.0.2"
id "checkstyle"
id "com.github.hierynomus.license" version "0.15.0"
id "com.matthewprenger.cursegradle" version "1.3.0"
id "com.github.breadmoirai.github-release" version "2.2.4"
}
*/
version = "1.80pr1.1"
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'org.ajoberstar.grgit'
apply plugin: 'maven-publish'
apply plugin: 'maven'
version = mod_version
group = "org.squiddev"
archivesBaseName = "cc-tweaked"
archivesBaseName = "cc-tweaked-${mc_version}"
minecraft {
version = "1.12-14.21.1.2387"
runDir = "run"
replace '${version}', project.version
runs {
client {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
// the mappings can be changed at any time, and must be in the following format.
// snapshot_YYYYMMDD snapshot are built nightly.
// stable_# stables are built at the discretion of the MCP team.
// Use non-default mappings at your own risk. they may not allways work.
// simply re-run your setup task after changing the mappings to update your workspace.
mappings = "snapshot_20170629"
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
mods {
computercraft {
source sourceSets.main
}
}
}
server {
workingDirectory project.file('run')
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
mods {
computercraft {
source sourceSets.main
}
}
}
}
mappings channel: 'snapshot', version: "${mappings_version}".toString()
accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg')
}
repositories {
maven {
name = "JEI"
url = "http://dvs1.progwml6.com/files/maven"
name "JEI"
url "https://dvs1.progwml6.com/files/maven"
}
maven {
name = "squiddev"
url = "https://dl.bintray.com/squiddev/maven"
name "SquidDev"
url "https://squiddev.cc/maven"
}
ivy {
name "Charset"
artifactPattern "https://asie.pl/files/mods/Charset/LibOnly/[module]-[revision](-[classifier]).[ext]"
}
maven {
name "Amadornes"
url "https://maven.amadornes.com/"
}
}
configurations {
shade
compile.extendsFrom shade
deployerJars
}
dependencies {
deobfProvided "mezz.jei:jei_1.12:4.7.5.86:api"
runtime "mezz.jei:jei_1.12:4.7.5.86"
shade 'org.squiddev:Cobalt:0.3.0'
checkstyle "com.puppycrawl.tools:checkstyle:8.21"
minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}"
compileOnly fg.deobf("mezz.jei:jei-1.14.3:6.0.0.7:api")
// deobfProvided "pl.asie:Charset-Lib:0.5.4.6"
// deobfProvided "MCMultiPart2:MCMultiPart:2.5.3"
runtimeOnly fg.deobf("mezz.jei:jei-1.14.3:6.0.0.7")
shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.2'
deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0"
}
sourceSets {
main {
java {
exclude 'dan200/computercraft/shared/integration/mcmp'
exclude 'dan200/computercraft/shared/integration/charset'
}
}
}
// Compile tasks
javadoc {
include "dan200/computercraft/api/**/*.java"
}
@@ -71,55 +127,341 @@ jar {
dependsOn javadoc
manifest {
attributes('FMLAT': 'computercraft_at.cfg')
attributes(["Specification-Title": "computercraft",
"Specification-Vendor": "SquidDev",
"Specification-Version": "1",
"Implementation-Title": "CC: Tweaked",
"Implementation-Version": "${mod_version}",
"Implementation-Vendor" :"SquidDev",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")])
}
into("docs", { from (javadoc.destinationDir) })
into("api", { from (sourceSets.main.allSource) {
from (sourceSets.main.allSource) {
include "dan200/computercraft/api/**/*.java"
}})
}
from configurations.shade.collect { it.isDirectory() ? it : zipTree(it) }
}
[compileJava, compileTestJava].forEach {
it.configure {
options.compilerArgs << "-Xlint" << "-Xlint:-processing" << "-Werror"
}
}
import java.nio.charset.StandardCharsets
import java.nio.file.*
import java.util.zip.*
import com.google.gson.GsonBuilder
import com.google.gson.JsonElement
import com.hierynomus.gradle.license.tasks.LicenseCheck
import com.hierynomus.gradle.license.tasks.LicenseFormat
import org.ajoberstar.grgit.Grgit
import proguard.gradle.ProGuardTask
task proguard(type: ProGuardTask, dependsOn: jar) {
description "Removes unused shadowed classes from the jar"
group "compact"
injars jar.archivePath
outjars "${jar.archivePath.absolutePath.replace(".jar", "")}-min.jar"
// Add the main runtime jar and all non-shadowed dependencies
libraryjars "${System.getProperty('java.home')}/lib/rt.jar"
doFirst {
sourceSets.main.compileClasspath
.filter { !it.name.contains("Cobalt") }
.each { libraryjars it }
}
// We want to avoid as much obfuscation as possible. We're only doing this to shrink code size.
dontobfuscate; dontoptimize; keepattributes; keepparameternames
// Proguard will remove directories by default, but that breaks JarMount.
keepdirectories 'data/computercraft/lua**'
// Preserve ComputerCraft classes - we only want to strip shadowed files.
keep 'class dan200.computercraft.** { *; }'
// Preserve the constructors in Cobalt library class, as we init them via reflection
keepclassmembers 'class org.squiddev.cobalt.lib.** { <init>(...); }'
// LWJGL and Apache bundle Java 9 versions, which is great, but rather breaks Proguard
dontwarn 'module-info'
dontwarn 'org.apache.**,org.lwjgl.**'
}
task proguardMove(dependsOn: proguard) {
description "Replace the original jar with the minified version"
group "compact"
doLast {
Files.move(
file("${jar.archivePath.absolutePath.replace(".jar", "")}-min.jar").toPath(),
file(jar.archivePath).toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
}
processResources {
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
inputs.property "version", mod_version
inputs.property "mcversion", mc_version
def grgit = Grgit.open(dir: '.')
inputs.property "commithash", grgit.head().id
def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe']
def hash = 'none'
Set<String> contributors = []
try {
def grgit = Grgit.open(dir: '.')
hash = grgit.head().id
grgit.log().each {
if (!blacklist.contains(it.author.name)) contributors.add(it.author.name)
if (!blacklist.contains(it.committer.name)) contributors.add(it.committer.name)
def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe']
grgit.log().each {
if (!blacklist.contains(it.author.name)) contributors.add(it.author.name)
if (!blacklist.contains(it.committer.name)) contributors.add(it.committer.name)
}
} catch(Exception ignored) { }
inputs.property "commithash", hash
from(sourceSets.main.resources.srcDirs) {
include 'META-INF/mods.toml'
include 'data/computercraft/lua/rom/help/credits.txt'
expand 'version': mod_version,
'mcversion': mc_version,
'gitcontributors': contributors.sort(false, String.CASE_INSENSITIVE_ORDER).join('\n')
}
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
include 'assets/computercraft/lua/rom/help/credits.txt'
expand 'version':project.version,
'mcversion':project.minecraft.version,
'gitcontributors':contributors.sort(false, String.CASE_INSENSITIVE_ORDER).join('\n')
exclude 'META-INF/mods.toml'
exclude 'data/computercraft/lua/rom/help/credits.txt'
}
}
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
exclude 'assets/computercraft/lua/rom/help/credits.txt'
task compressJson(dependsOn: jar) {
group "compact"
description "Minifies all JSON files, stripping whitespace"
def jarPath = file(jar.archivePath)
def tempPath = File.createTempFile("input", ".jar", temporaryDir)
tempPath.deleteOnExit()
def gson = new GsonBuilder().create()
doLast {
// Copy over all files in the current jar to the new one, running json files from GSON. As pretty printing
// is turned off, they should be minified.
new ZipFile(jarPath).withCloseable { inJar ->
tempPath.getParentFile().mkdirs()
new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tempPath))).withCloseable { outJar ->
inJar.entries().each { entry ->
if(entry.directory) {
outJar.putNextEntry(entry)
} else if(!entry.name.endsWith(".json")) {
outJar.putNextEntry(entry)
inJar.getInputStream(entry).withCloseable { outJar << it }
} else {
ZipEntry newEntry = new ZipEntry(entry.name)
newEntry.setTime(entry.time)
outJar.putNextEntry(newEntry)
def element = inJar.getInputStream(entry).withCloseable { gson.fromJson(it.newReader("UTF8"), JsonElement.class) }
outJar.write(gson.toJson(element).getBytes(StandardCharsets.UTF_8))
}
}
}
}
// And replace the original jar again
Files.move(tempPath.toPath(), jarPath.toPath(), StandardCopyOption.REPLACE_EXISTING)
}
}
assemble.dependsOn compressJson
// Check tasks
test {
useJUnitPlatform()
testLogging {
events "skipped", "failed"
}
}
license {
mapping("java", "SLASHSTAR_STYLE")
strictCheck true
ext.year = Calendar.getInstance().get(Calendar.YEAR)
}
[licenseMain, licenseFormatMain].forEach {
it.configure {
include("**/*.java")
exclude("dan200/computercraft/api/**")
header rootProject.file('config/license/main.txt')
}
}
[licenseTest, licenseFormatTest].forEach {
it.configure {
include("**/*.java")
header rootProject.file('config/license/main.txt')
}
}
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint"
tasks.withType(LicenseFormat) {
outputs.upToDateWhen { false }
}
}
runClient.outputs.upToDateWhen { false }
runServer.outputs.upToDateWhen { false }
task licenseAPI(type: LicenseCheck);
task licenseFormatAPI(type: LicenseFormat);
[licenseAPI, licenseFormatAPI].forEach {
it.configure {
source = sourceSets.main.java
include("dan200/computercraft/api/**")
header rootProject.file('config/license/api.txt')
}
}
// Upload tasks
task checkRelease {
group "upload"
description "Verifies that everything is ready for a release"
inputs.property "version", mod_version
inputs.file("src/main/resources/data/computercraft/lua/rom/help/changelog.txt")
inputs.file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt")
doLast {
def ok = true
// Check we're targetting the current version
def whatsnew = new File("src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt").readLines()
if (whatsnew[0] != "New features in CC: Tweaked $mod_version") {
ok = false
project.logger.error("Expected `whatsnew.txt' to target $mod_version.")
}
// Check "read more" exists and trim it
def idx = whatsnew.findIndexOf { it == 'Type "help changelog" to see the full version history.' }
if (idx == -1) {
ok = false
project.logger.error("Must mention the changelog in whatsnew.txt")
} else {
whatsnew = whatsnew.getAt(0 ..< idx)
}
// Check whatsnew and changelog match.
def versionChangelog = "# " + whatsnew.join("\n")
def changelog = new File("src/main/resources/data/computercraft/lua/rom/help/changelog.txt").getText()
if (!changelog.startsWith(versionChangelog)) {
ok = false
project.logger.error("whatsnew and changelog are not in sync")
}
if (!ok) throw new IllegalStateException("Could not check release")
}
}
curseforge {
apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : ''
project {
id = '282001'
releaseType = 'beta'
changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})."
relations {
incompatible "computercraft"
}
}
}
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
// artifact sourceJar
}
}
}
uploadArchives {
repositories {
if(project.hasProperty('mavenUploadUrl')) {
mavenDeployer {
configuration = configurations.deployerJars
repository(url: project.property('mavenUploadUrl')) {
authentication(
userName: project.property('mavenUploadUser'),
privateKey: project.property('mavenUploadKey'))
}
pom.project {
name 'CC: Tweaked'
packaging 'jar'
description 'CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.'
url 'https://github.com/SquidDev-CC/CC-Tweaked'
scm {
url 'https://github.com/SquidDev-CC/CC-Tweaked.git'
}
issueManagement {
system 'github'
url 'https://github.com/SquidDev-CC/CC-Tweaked/issues'
}
licenses {
license {
name 'ComputerCraft Public License, Version 1.0'
url 'https://github.com/SquidDev-CC/CC-Tweaked/blob/master/LICENSE'
distribution 'repo'
}
}
}
pom.whenConfigured { pom ->
pom.dependencies.clear()
}
}
}
}
}
githubRelease {
token project.hasProperty('githubApiKey') ? project.githubApiKey : ''
owner 'SquidDev-CC'
repo 'CC-Tweaked'
targetCommitish { Grgit.open(dir: '.').branch.current().name }
tagName "v${mc_version}-${mod_version}"
releaseName "[${mc_version}] ${mod_version}"
body {
"## " + new File("src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt")
.readLines()
.takeWhile { it != 'Type "help changelog" to see the full version history.' }
.join("\n").trim()
}
prerelease true
}
def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"]
uploadTasks.forEach { tasks.getByName(it).dependsOn checkRelease }
task uploadAll(dependsOn: uploadTasks) {
group "upload"
description "Uploads to all repositories (Maven, Curse, GitHub release)"
}

View File

@@ -1,12 +0,0 @@
#!/bin/sh
cd luaj-2.0.3
echo "Building LuaJ..."
ant clean
ant
echo "Copying output to libs..."
rm ../libs/luaj-jse-2.0.3.jar
cp luaj-jse-2.0.3.jar ../libs
echo "Done."
cd ..

View File

@@ -1,10 +0,0 @@
#!/bin/sh
echo "Java code:"
cat `find src | grep \\.java$` | wc
echo "Lua code:"
cat `find src/main/resources/assets/computercraft/lua | grep \\.lua$` | wc
echo "JSON:"
cat `find src/main/resources/assets/computercraft | grep \\.json$` | wc

View File

@@ -0,0 +1,159 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<property name="tabWidth" value="4"/>
<property name="charset" value="UTF-8" />
<module name="SuppressionFilter">
<property name="file" value="config/checkstyle/suppressions.xml" />
</module>
<module name="TreeWalker">
<!-- Annotations -->
<module name="AnnotationLocation" />
<module name="AnnotationUseStyle" />
<module name="MissingDeprecated">
<property name="skipNoJavadoc" value="true" />
</module>
<module name="MissingOverride" />
<!-- Blocks -->
<module name="EmptyBlock" />
<module name="EmptyCatchBlock">
<property name="exceptionVariableName" value="ignored" />
</module>
<module name="LeftCurly">
<property name="option" value="nl" />
<!-- The defaults, minus lambdas. -->
<property name="tokens" value="ANNOTATION_DEF,CLASS_DEF,CTOR_DEF,ENUM_CONSTANT_DEF,ENUM_DEF,INTERFACE_DEF,LITERAL_CASE,LITERAL_CATCH,LITERAL_DEFAULT,LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_FOR,LITERAL_IF,LITERAL_SWITCH,LITERAL_SYNCHRONIZED,LITERAL_TRY,LITERAL_WHILE,METHOD_DEF,OBJBLOCK,STATIC_INIT" />
</module>
<module name="NeedBraces">
<property name="allowSingleLineStatement" value="true"/>
</module>
<module name="RightCurly">
<property name="option" value="alone" />
</module>
<!-- Class design. As if we've ever followed good practice here. -->
<module name="FinalClass" />
<module name="InterfaceIsType" />
<module name="MutableException" />
<module name="OneTopLevelClass" />
<!-- Coding -->
<module name="ArrayTrailingComma" />
<module name="EqualsHashCode" />
<!-- FallThrough does not handle unreachable code well -->
<module name="IllegalInstantiation" />
<module name="IllegalThrows" />
<module name="ModifiedControlVariable" />
<module name="NoClone" />
<module name="NoFinalizer" />
<module name="OneStatementPerLine" />
<module name="PackageDeclaration" />
<module name="SimplifyBooleanExpression" />
<module name="SimplifyBooleanReturn" />
<module name="StringLiteralEquality" />
<module name="UnnecessaryParentheses" />
<!-- Imports -->
<module name="CustomImportOrder" />
<module name="IllegalImport" />
<module name="RedundantImport" />
<module name="UnusedImports" />
<!-- Javadoc -->
<module name="AtclauseOrder" />
<!-- TODO: Cleanup our documentation before enabling JavadocMethod, JavadocStyle, JavadocType and SummaryJavadoc. -->
<module name="NonEmptyAtclauseDescription" />
<module name="SingleLineJavadoc" />
<!-- Misc -->
<module name="ArrayTypeStyle" />
<module name="CommentsIndentation" />
<module name="Indentation" />
<module name="OuterTypeFilename" />
<!-- Modifiers -->
<module name="ModifierOrder" />
<module name="RedundantModifier" />
<!-- Naming -->
<module name="ClassTypeParameterName" />
<module name="InterfaceTypeParameterName" />
<module name="LambdaParameterName" />
<module name="LocalFinalVariableName" />
<module name="LocalVariableName" />
<!-- Allow an optional m_ on private members -->
<module name="MemberName">
<property name="applyToPrivate" value="false" />
<property name="applyToPackage" value="false" />
</module>
<module name="MemberName">
<property name="format" value="^(m_)?[a-z][a-zA-Z0-9]*$" />
<property name="applyToPrivate" value="true" />
<property name="applyToPackage" value="true" />
</module>
<module name="MethodName" />
<module name="MethodTypeParameterName" />
<module name="PackageName">
<property name="format" value="^dan200\.computercraf(\.[a-z][a-z0-9]*)*" />
</module>
<module name="ParameterName" />
<module name="StaticVariableName">
<property name="format" value="^[a-z][a-zA-Z0-9]*|CAPABILITY(_[A-Z]+)?$" />
<property name="applyToPrivate" value="false" />
</module>
<module name="StaticVariableName">
<property name="format" value="^(s_)?[a-z][a-zA-Z0-9]*|CAPABILITY(_[A-Z]+)?$" />
<property name="applyToPrivate" value="true" />
</module>
<module name="TypeName" />
<!-- Whitespace -->
<module name="EmptyForInitializerPad"/>
<module name="EmptyForIteratorPad">
<property name="option" value="space"/>
</module>
<module name="GenericWhitespace" />
<module name="MethodParamPad" />
<module name="NoLineWrap" />
<module name="NoWhitespaceAfter">
<property name="tokens" value="AT,INC,DEC,UNARY_MINUS,UNARY_PLUS,BNOT,LNOT,DOT,ARRAY_DECLARATOR,INDEX_OP" />
</module>
<module name="NoWhitespaceBefore" />
<!-- TODO: Decide on an OperatorWrap style. -->
<module name="ParenPad">
<property name="option" value="space" />
<property name="tokens" value="ANNOTATION,ANNOTATION_FIELD_DEF,CTOR_CALL,CTOR_DEF,ENUM_CONSTANT_DEF,LITERAL_CATCH,LITERAL_DO,LITERAL_FOR,LITERAL_IF,LITERAL_NEW,LITERAL_SWITCH,LITERAL_SYNCHRONIZED,LITERAL_WHILE,METHOD_CALL,METHOD_DEF,RESOURCE_SPECIFICATION,SUPER_CTOR_CALL,LAMBDA" />
</module>
<module name="ParenPad">
<property name="option" value="nospace" />
<property name="tokens" value="DOT,EXPR,QUESTION" />
</module>
<module name="SeparatorWrap">
<property name="option" value="eol" />
<property name="tokens" value="COMMA,SEMI,ELLIPSIS,ARRAY_DECLARATOR,RBRACK,METHOD_REF" />
</module>
<module name="SeparatorWrap">
<property name="option" value="nl" />
<property name="tokens" value="DOT,AT" />
</module>
<module name="SingleSpaceSeparator" />
<module name="TypecastParenPad" />
<module name="WhitespaceAfter">
<property name="tokens" value="COMMA" />
</module>
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true" />
<property name="ignoreEnhancedForColon" value="false" />
<property name="tokens" value="ASSIGN,BAND,BAND_ASSIGN,BOR,BOR_ASSIGN,BSR,BSR_ASSIGN,BXOR,BXOR_ASSIGN,COLON,DIV,DIV_ASSIGN,EQUAL,GE,GT,LAMBDA,LAND,LCURLY,LE,LITERAL_RETURN,LOR,LT,MINUS,MINUS_ASSIGN,MOD,MOD_ASSIGN,NOT_EQUAL,PLUS,PLUS_ASSIGN,QUESTION,RCURLY,SL,SLIST,SL_ASSIGN,SR,SR_ASSIGN,STAR,STAR_ASSIGN,LITERAL_ASSERT,TYPE_EXTENSION_AND" />
</module>
</module>
<module name="FileTabCharacter" />
<module name="NewlineAtEndOfFile" />
</module>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions>
<!-- All the config options and method fields. -->
<suppress checks="StaticVariableName" files=".*[\\/]ComputerCraft.java" />
<suppress checks="StaticVariableName" files=".*[\\/]ComputerCraftAPI.java" />
</suppressions>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,61 @@
<code_scheme name="Project" version="173">
<JSON>
<option name="OBJECT_WRAPPING" value="1" />
<option name="ARRAY_WRAPPING" value="1" />
</JSON>
<JavaCodeStyleSettings>
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="JD_P_AT_EMPTY_LINES" value="false" />
<option name="JD_PRESERVE_LINE_FEEDS" value="true" />
</JavaCodeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
<option name="BRACE_STYLE" value="2" />
<option name="CLASS_BRACE_STYLE" value="2" />
<option name="METHOD_BRACE_STYLE" value="2" />
<option name="LAMBDA_BRACE_STYLE" value="5" />
<option name="ELSE_ON_NEW_LINE" value="true" />
<option name="CATCH_ON_NEW_LINE" value="true" />
<option name="FINALLY_ON_NEW_LINE" value="true" />
<option name="SPACE_WITHIN_METHOD_CALL_PARENTHESES" value="true" />
<option name="SPACE_WITHIN_METHOD_PARENTHESES" value="true" />
<option name="SPACE_WITHIN_IF_PARENTHESES" value="true" />
<option name="SPACE_WITHIN_WHILE_PARENTHESES" value="true" />
<option name="SPACE_WITHIN_FOR_PARENTHESES" value="true" />
<option name="SPACE_WITHIN_TRY_PARENTHESES" value="true" />
<option name="SPACE_WITHIN_CATCH_PARENTHESES" value="true" />
<option name="SPACE_WITHIN_SWITCH_PARENTHESES" value="true" />
<option name="SPACE_WITHIN_SYNCHRONIZED_PARENTHESES" value="true" />
<option name="SPACE_WITHIN_ARRAY_INITIALIZER_BRACES" value="true" />
<option name="SPACE_BEFORE_IF_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_WHILE_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_TRY_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_CATCH_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_SWITCH_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_SYNCHRONIZED_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
<option name="KEEP_SIMPLE_LAMBDAS_IN_ONE_LINE" value="true" />
<option name="KEEP_SIMPLE_CLASSES_IN_ONE_LINE" value="true" />
<option name="IF_BRACE_FORCE" value="1" />
<option name="DOWHILE_BRACE_FORCE" value="1" />
<option name="WHILE_BRACE_FORCE" value="1" />
<option name="FOR_BRACE_FORCE" value="1" />
<option name="SPACE_WITHIN_ANNOTATION_PARENTHESES" value="true" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JSON">
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="SPACE_WITHIN_BRACKETS" value="true" />
<option name="SPACE_WITHIN_BRACES" value="true" />
<indentOptions>
<option name="INDENT_SIZE" value="4" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
</code_scheme>

3
config/license/api.txt Normal file
View File

@@ -0,0 +1,3 @@
This file is part of the public ComputerCraft API - http://www.computercraft.info
Copyright Daniel Ratcliffe, 2011-${year}. This API may be redistributed unmodified and in full only.
For help using the API, and posting your mods, visit the forums at computercraft.info.

3
config/license/main.txt Normal file
View File

@@ -0,0 +1,3 @@
This file is part of ComputerCraft - http://www.computercraft.info
Copyright Daniel Ratcliffe, 2011-${year}. Do not distribute without permission.
Send enquiries to dratcliffe@gmail.com

View File

@@ -1,21 +0,0 @@
#!/bin/sh
echo "Building with gradle..."
rm -rf build/libs
rm -rf build/resources
rm -rf build/classes
chmod -R +rw src/main/resources
chmod +x gradlew
./gradlew build
echo "Deleting old deployment..."
rm -rf deploy
mkdir deploy
echo "Making new deployment..."
INPUTJAR=`ls -1 build/libs | grep -v sources`
OUTPUTJAR=`ls -1 build/libs | grep -v sources | sed s/\-//g`
FRIENDLYNAME=`ls -1 build/libs | grep -v sources | sed s/\-/\ /g | sed s/\.jar//g`
cp build/libs/$INPUTJAR deploy/$OUTPUTJAR
echo "Done."

7
gradle.properties Normal file
View File

@@ -0,0 +1,7 @@
# Mod properties
mod_version=1.84.0
# Minecraft properties
mc_version=1.14.4
forge_version=28.0.11
mappings_version=20190721-1.14.3

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-bin.zip

Binary file not shown.

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>

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>

View File

@@ -1,19 +0,0 @@
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

@@ -1,780 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Getting Started with LuaJ</title>
<link rel="stylesheet" type="text/css" href="http://www.lua.org/lua.css">
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1">
</head>
<body>
<hr>
<h1>
<a href="README.html"><img src="http://sourceforge.net/dbimage.php?id=196139" alt="" border="0"></a>
Getting Started with LuaJ
</h1>
James Roseborough, Ian Farmer, Version 2.0.3
<p>
<small>
Copyright &copy; 2009-2012 Luaj.org.
Freely available under the terms of the
<a href="http://sourceforge.net/dbimage.php?id=196142">Luaj license</a>.
</small>
<hr>
<p>
<a href="#1">introduction</a>
&middot;
<a href="#2">examples</a>
&middot;
<a href="#3">concepts</a>
&middot;
<a href="#4">libraries</a>
&middot;
<a href="#5">luaj api</a>
&middot;
<a href="#6">parser</a>
&middot;
<a href="#7">building</a>
&middot;
<a href="#8">downloads</a>
&middot;
<a href="#9">release notes</a>
<!-- ====================================================================== -->
<p>
<h1>1 - <a name="1">Introduction</a></h1>
<h2>Goals of Luaj</h2>
Luaj is a lua interpreter based on the 5.1.x version of lua with the following goals in mind:
<ul>
<li>Java-centric implementation of lua vm built to leverage standard Java features.
<li>Lightweight, high performance execution of lua.
<li>Multi-platform to be able to run on JME, JSE, or JEE environments.
<li>Complete set of libraries and tools for integration into real-world projects.
<li>Dependable due to sufficient unit testing of vm and library features.
</ul>
<h2>Differences with 1.0</h2>
In addition to the basic goals of luaj, version 2.0 is aimed
at improving on the 1.0 vm in the following aspects.
<ul>
<li>Support for compiling lua source code into Java source code.
<li>Support for compiling lua bytecode directly into Java bytecode.
<li>Improved performance of of lua bytecode processing.
<li>Stackless vm design centered around dynamically typed objects.
<li>More alignment with C API (see <a href="names.csv">names.csv</a> for details)
<li>Improved class and package naming conventions.
<li>Improved unit tests of core classes.
<li>Improved quality due to major redesign and rewrite of core elements.
<li>More complete implementation including weak keys and values, and all metatags.
</ul>
<h2>Performance</h2>
Good performance is a major goal of luaj.
The following table provides measured execution times on a subset of benchmarks from
<a href="http://shootout.alioth.debian.org/">the computer language benchmarks game</a>
in comparison with the standard C distribution.
<table cellspacing="10"><tr><td><table>
<tr valign="top">
<td><u>Project</td>
<td><u>Version</td>
<td><u>Mode</td>
<td rowspan="9">&nbsp;&nbsp;</td>
<td colspan="4" align="center"><u>Benchmark&nbsp;execution&nbsp;time&nbsp;(sec)</td>
<td rowspan="9">&nbsp;&nbsp;</td>
<td><u>Language</td>
<td><u>Sample&nbsp;command</td>
</tr>
<tr valign="top">
<td colspan="2"></td>
<td></td>
<td><em>binarytrees 15</em></td>
<td><em>fannkuch 10</em></td>
<td><em>nbody 1e6</em></td>
<td><em>nsieve 9</em></td>
</tr>
<tr valign="top">
<td>luaj</td>
<td>2.0</td>
<td>-b (luajc)</td>
<td>2.980</td>
<td>5.073</td>
<td>16.794</td>
<td>11.274</td>
<td>Java</td>
<td>java -cp luaj-jse-2.0.3.jar;bcel-5.2.jar lua <b>-b</b> fannkuch.lua 10</td></tr>
<tr valign="top">
<td></td>
<td></td>
<td>-j (lua2java)</td>
<td>4.463</td>
<td>5.884</td>
<td>16.701</td>
<td>13.789</td>
<td></td>
<td>java -cp luaj-jse-2.0.3.jar lua <b>-j</b> fannkuch.lua 10</td></tr>
<tr valign="top">
<td></td>
<td></td>
<td>-n (interpreted)</td>
<td>12.838</td>
<td>23.290</td>
<td>36.894</td>
<td>15.163</td>
<td></td>
<td>java -cp luaj-jse-2.0.3.jar lua -n fannkuch.lua 10</td></tr>
<tr valign="top">
<td>lua</td>
<td>5.1.4</td>
<td></td>
<td>17.637</td>
<td>16.044</td>
<td>15.201</td>
<td>5.477</td>
<td>C</td>
<td>lua fannkuch.lua 10</td></tr>
<tr valign="top">
<td>jill</td>
<td>1.0.1</td>
<td></td>
<td>44.512</td>
<td>54.630</td>
<td>72.172</td>
<td>20.779</td>
<td>Java</td>
<td></td></tr>
<tr valign="top">
<td>kahlua</td>
<td>1.0</td>
<td>jse</td>
<td>22.963</td>
<td>63.277</td>
<td>68.223</td>
<td>21.529</td>
<td>Java</td>
<td></td></tr>
<tr valign="top">
<td>mochalua</td>
<td>1.0</td>
<td></td>
<td>50.457</td>
<td>70.368</td>
<td>82.868</td>
<td>41.262</td>
<td>Java</td>
<td></td></tr>
</table></td></tr></table>
Luaj in interpreted mode performs well for the benchmarks, and even better when source-to-source (lua2java)
or bytecode-to-bytecode (luajc) compilers are used,
and actually executes <em>faster</em> than C-based lua in some cases.
It is also faster than Java-lua implementations Jill, Kahlua, and Mochalua for all benchmarks tested.
<h1>2 - <a name="2">Simple Examples</a></h1>
<h2>Run a lua script in Java SE</h2>
<p>
From the main distribution directory line type:
<pre>
java -cp lib/luaj-jse-2.0.3.jar lua examples/lua/hello.lua
</pre>
<p>
You should see the following output:
<pre>
hello, world
</pre>
To see how luaj can be used to acccess most Java API's including swing, try:
<pre>
java -cp lib/luaj-jse-2.0.3.jar lua examples/lua/swingapp.lua
</pre>
<h2>Compile lua source to lua bytecode</h2>
<p>
From the main distribution directory line type:
<pre>
java -cp lib/luaj-jse-2.0.3.jar luac examples/lua/hello.lua
java -cp lib/luaj-jse-2.0.3.jar lua luac.out
</pre>
<p>
The compiled output "luac.out" is lua bytecode and should run and produce the same result.
<h2>Compile lua source to java source</h2>
<p>
Luaj can compile to lua source code to Java source code:
<pre>
java -cp lib/luaj-jse-2.0.3.jar lua2java -s examples/lua -d . hello.lua
javac -cp lib/luaj-jse-2.0.3.jar hello.java
java -cp &quot;lib/luaj-jse-2.0.3.jar;.&quot; lua -l hello
</pre>
<p>
The output <em>hello.java</em> is Java source, that implements the logic in hello.lua directly.
Once <em>hello.java</em> is compiled into <em>hello.class</em> it can be required and used in place of the original lua script, but with better performance.
There are no additional dependencies for compiling or running source-to-source compiled lua.
<p>
Lua scripts can also be run directly in this mode without precompiling using the <em>lua</em> command with the <b><em>-j</em></b> option when run in JDK 1.5 or higher:
<pre>
java -cp lib/luaj-jse-2.0.3.jar lua -j examples/lua/hello.lua
</pre>
<h2>Compile lua bytecode to java bytecode</h2>
<p>
Luaj can compile lua sources or binaries directly to java bytecode if the bcel library is on the class path. From the main distribution directory line type:
<pre>
ant bcel-lib
java -cp &quot;lib/luaj-jse-2.0.3.jar;lib/bcel-5.2.jar&quot; luajc -s examples/lua -d . hello.lua
java -cp &quot;lib/luaj-jse-2.0.3.jar;.&quot; lua -l hello
</pre>
<p>
The output <em>hello.class</em> is Java bytecode, should run and produce the same result.
There is no runtime dependency on the bcel library,
but the compiled classes must be in the class path at runtime, unless runtime jit-compiling via luajc and bcel are desired (see later sections).
<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-2.0.3.jar;lib/bcel-5.2.jar&quot; lua -b examples/lua/hello.lua
</pre>
<h2>Run a script in a Java Application</h2>
<p>
The following pattern is used within Java SE
<pre>
import org.luaj.vm2.*;
import org.luaj.vm2.lib.jse.*;
String script = "examples/lua/hello.lua";
LuaValue _G = JsePlatform.standardGlobals();
_G.get("dofile").call( LuaValue.valueOf(script) );
</pre>
<p>
A simple example may be found in
<pre>
examples/jse/SampleJseMain.java
</pre>
<p>
You must include the library <b>lib/luaj-jse-2.0.3.jar</b> in your class path.
<h2>Run a script in a MIDlet</h2>
<p>
The for MIDlets the <em>JmePlatform</em> is used instead:
<pre>
import org.luaj.vm2.*;
import org.luaj.vm2.lib.jme.*;
String script = "examples/lua/hello.lua";
LuaValue _G = JmePlatform.standardGlobals();
_G.get("dofile").call( LuaValue.valueOf(script) );
</pre>
<p>
The file must be a resource within within the midlet jar for <em>dofile()</em> to find it.
Any files included via <em>require()</em> must also be part of the midlet resources.
<p>
A simple example may be found in
<pre>
examples/jme/SampleMIDlet.java
</pre>
<p>
You must include the library <b>lib/luaj-jme-2.0.3.jar</b> in your midlet jar.
<p>
An ant script to build and run the midlet is in
<pre>
build-midlet.xml
</pre>
<p>
You must install the wireless toolkit and define <em>WTK_HOME</em> for this script to work.
<h2>Run a script using JSR-223 Dynamic Scripting</h2>
<p>
The standard use of JSR-223 scripting engines may be used:
<pre>
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine e = mgr.getEngineByExtension(".lua");
e.put("x", 25);
e.eval("y = math.sqrt(x)");
System.out.println( "y="+e.get("y") );
</pre>
<p>
All standard aspects of script engines including compiled statements should be supported.
<p>
You must include the library <b>lib/luaj-jse-2.0.3.jar</b> in your class path.
<p>
A working example may be found in
<pre>
examples/jse/ScriptEngineSample.java
</pre>
To compile and run it using Java 1.6 or higher:
<pre>
javac examples/jse/ScriptEngineSample.java
java -cp &quot;lib/luaj-jse-2.0.3.jar;examples/jse&quot; ScriptEngineSample
</pre>
<h2>Excluding the lua bytecode compiler</h2>
By default, the compiler is included whenever <em>standardGlobals()</em> or <em>debugGlobals()</em> are called.
Without a compiler, files can still be executed, but they must be compiled elsewhere beforehand.
The "luac" utility is provided in the jse jar for this purpose, or a standard lua compiler can be used.
<p>
To exclude the lua-to-lua-bytecode compiler, do not call
<em>standardGlobals()</em> or <em>debugGlobals()</em>
but instead initialize globals with including only those libraries
that are needed and omitting the line:
<pre>
org.luaj.vm2.compiler.LuaC.install();
</pre>
<h2>Including the Lua2Java lua-source-to-Java-source compiler</h2>
<p>
To compile from lua sources to Java sources for all lua loaded at runtime,
install the Lua2Java compiler <em>after</em> globals have been created using:
<pre>
org.luaj.vm2.jse.lua2java.Lua2Java.install();
</pre>
This uses the system Java compiler to compile from Java source to Java bytecode,
and cannot compile lua binary files containing lua bytecode at runtime.
<h2>Including the LuaJC lua-bytecode-to-Java-bytecode compiler</h2>
<p>
To compile from lua to Java bytecode for all lua loaded at runtime,
install the LuaJC compiler <em>after</em> globals have been created using:
<pre>
org.luaj.vm2.jse.luajc.LuaJC.install();
</pre>
<p>
This will compile all lua bytecode into Java bytecode, regardless of if they are loaded as
lua source or lua binary files.
<p>
The requires <em>bcel</em> to be on the class path, and the ClassLoader of JSE or CDC.
<h1>3 - <a name="3">Concepts</a></h1>
<h2>Globals</h2>
The old notion of platform has been replaced with creation of globals.
Two classes are provided to encapsulate common combinations of libraries.
<h3>JsePlatform</h3>
This class can be used as a factory for globals in a typical Java SE application.
All standard libraries are included, as well as the luajava library.
The default search path is the current directory,
and the math operations include all those supported by Java SE.
<h3>JmePlatform</h3>
This class can be used to set up the basic environment for a Java ME application.
The default search path is limited to the jar resources,
and the math operations are limited to those supported by Java ME.
All libraries are included except luajava, and the os, io, and math libraries are
limited to those functions that can be supported on that platform.
<h1>4 - <a name="4">Libraries</a></h1>
<h2>Standard Libraries</h2>
Libraries are coded to closely match the behavior specified in
See <a href="http://www.lua.org/manual/5.1/">standard lua documentation</a> for details on the library API's
<p>
The following libraries are loaded by both <em>JsePlatform.standardGlobals()</em> and <em>JmePlatform.standardGlobals()</em>:
<pre> base
coroutine
io
math
os
package
string
table
</pre>
<p>
The <em>JsePlatform.standardGlobals()</em> globals also include:
<pre> luajava
</pre>
<p>
The <em>JsePlatform.debugGlobals()</em> and <em>JsePlatform.debugGlobals()</em> functions produce globals that include:
<pre> debug
</pre>
<h3>I/O Library</h3>
The implementation of the <em>io</em> library differs by platform owing to platform limitations.
<p>
The <em>JmePlatform.standardGlobals()</em> instantiated the io library <em>io</em> in
<pre>
src/jme/org/luaj/vm2/lib/jme/JmeIoLib.java
</pre>
The <em>JsePlatform.standardGlobals()</em> includes support for random access and is in
<pre>
src/jse/org/luaj/vm2/lib/jse/JseIoLib.java
</pre>
<h3>OS Library</h3>
The implementation of the <em>os</em> library also differs per platform.
<p>
The basic <em>os</em> library implementation us used by <em>JmePlatform</em> and is in:
<pre>
src/core/org/luaj/lib/OsLib.java
</pre>
A richer version for use by <em>JsePlatform</em> is :
<pre>
src/jse/org/luaj/vm2/lib/jse/JseOsLib.java
</pre>
Time is a represented as number of milliseconds since the epoch,
and most time and date formatting, locales, and other features
are not implemented.
<h3>Coroutine Library</h3>
The <em>coroutine</em> library is implemented using one JavaThread per coroutine.
This allows <em>coroutine.yield()</em> can be called from anywhere,
as with the yield-from-anywhere patch in C-based lua.
<p>
Luaj uses WeakReferences and the OrphanedThread error to ensure that coroutines that are no longer referenced
are properly garbage collected. For thread safety, OrphanedThread should not be caught by Java code.
See <a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/LuaThread.html">LuaThread</a>
and <a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/OrphanedThread.html">OrphanedThread</a>
javadoc for details.
<h3>Debug Library</h3>
The <em>debug</em> library is not included by default by
<em>JmePlatform.standardGlobals()</em> or <em>JsePlatform.standardGlobsls()</em> .
The functions <em>JmePlatform.debugGlobals()</em> and <em>JsePlatform.debugGlobsls()</em>
create globals that contain the debug library in addition to the other standard libraries.
To install dynamically from lua use java-class-based require:</em>:
<pre>
require 'org.luaj.vm2.lib.DebugLib'
</pre>
The <em>lua</em> command line utility includes the <em>debug</em> library by default.
<h3>The Luajava Library</h3>
The <em>JsePlatform.standardGlobals()</em> includes the <em>luajava</em> library, which simplifies binding to Java classes and methods.
It is patterned after the original <a href="http://www.keplerproject.org/luajava/">luajava project</a>.
<p>
The following lua script will open a swing frame on Java SE:
<pre>
jframe = luajava.bindClass( "javax.swing.JFrame" )
frame = luajava.newInstance( "javax.swing.JFrame", "Texts" );
frame:setDefaultCloseOperation(jframe.EXIT_ON_CLOSE)
frame:setSize(300,400)
frame:setVisible(true)
</pre>
<p>
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-2.0.3.jar lua examples/lua/swingapp.lua
</pre>
<p>
The Java ME platform does not include this library, and it cannot be made to work because of the lack of a reflection API in Java ME.
<p>
The <em>lua</em> connand line tool includes <em>luajava</em>.
<h1>5 - <a name="5">LuaJ API</a></h1>
<h2>API Javadoc</h2>
The javadoc for the main classes in the LuaJ API are on line at
<pre>
<a href="http://luaj.sourceforge.net/api/2.0/index.html">http://luaj.sourceforge.net/api/2.0</a>
</pre>
You can also build a local version from sources using
<pre>
ant doc
</pre>
<h2>LuaValue and Varargs</h2>
All lua value manipulation is now organized around
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/LuaValue.html">LuaValue</a>
which exposes the majority of interfaces used for lua computation.
<pre>
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/LuaValue.html">org.luaj.vm2.LuaValue</a>
</pre>
<h3>Common Functions</h3>
<em>LuaValue</em> exposes functions for each of the operations in LuaJ.
Some commonly used functions and constants include:
<pre>
call(); // invoke the function with no arguments
call(LuaValue arg1); // call the function with 1 argument
invoke(Varargs arg); // call the function with variable arguments, variable return values
get(int index); // get a table entry using an integer key
get(LuaValue key); // get a table entry using an arbitrary key, may be a LuaInteger
rawget(int index); // raw get without metatable calls
valueOf(int i); // return LuaValue corresponding to an integer
valueOf(String s); // return LuaValue corresponding to a String
toint(); // return value as a Java int
tojstring(); // return value as a Java String
isnil(); // is the value nil
NIL; // the value nil
NONE; // a Varargs instance with no values
</pre>
<h2>Varargs</h2>
The interface <a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/Varargs.html">Varargs</a> provides an abstraction for
both a variable argument list and multiple return values.
For convenience, <em>LuaValue</em> implements <em>Varargs</em> so a single value can be supplied anywhere
variable arguments are expected.
<pre>
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/Varargs.html">org.luaj.vm2.Varargs</a>
</pre>
<h3>Common Functions</h3>
<em>Varargs</em> exposes functions for accessing elements, and coercing them to specific types:
<pre>
narg(); // return number of arguments
arg1(); // return the first argument
arg(int n); // return the nth argument
isnil(int n); // true if the nth argument is nil
checktable(int n); // return table or throw error
optlong(int n,long d); // return n if a long, d if no argument, or error if not a long
</pre>
See the <a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/Varargs.html">Varargs</a> API for a complete list.
<h2>LibFunction</h2>
The simplest way to implement a function is to choose a base class based on the number of arguments to the function.
LuaJ provides 5 base classes for this purpose, depending if the function has 0, 1, 2, 3 or variable arguments,
and if it provide multiple return values.
<pre>
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/lib/ZeroArgFunction.html">org.luaj.vm2.lib.ZeroArgFunction</a>
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/lib/OneArgFunction.html">org.luaj.vm2.lib.OneArgFunction</a>
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/lib/TwoArgFunction.html">org.luaj.vm2.lib.TwoArgFunction</a>
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/lib/ThreeArgFunction.html">org.luaj.vm2.lib.ThreeArgFunction</a>
<a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/lib/VarArgFunction.html">org.luaj.vm2.lib.VarArgFunction</a>
</pre>
Each of these functions has an abstract method that must be implemented,
and argument fixup is done automatically by the classes as each Java function is invoked.
<p>
For example, to implement a &quot;hello, world&quot; function, we could supply:
<pre>
pubic class hello extends ZeroArgFunction {
public LuaValue call() {
env.get("print").call(valueOf("hello, world"));
}
}
</pre>
The value <em>env</em> is the environment of the function, and is normally supplied
by the instantiating object whenever default loading is used.
<p>
Calling this function from lua could be done by:
<pre>
require( 'hello' )()
</pre>
while calling this function from Java would look like:
<pre>
new hello().call();
</pre>
Note that in both the lua and Java case, extra arguments will be ignored, and the function will be called.
Also, no virtual machine instance is necessary to call the function.
To allow for arguments, or return multiple values, extend one of the other base classes.
<h2>Closures</h2>
Closures still exist in this framework, but are optional, and are only used to implement lua bytecode execution.
<h1>6 - <a name="6">Parser</a></h1>
<h2>Javacc Grammar</h2>
A Javacc grammarwas developed to simplify the creation of Java-based parsers for the lua language.
The grammar is specified for <a href="https://javacc.dev.java.net/">javacc version 5.0</a> because that tool generates standalone
parsers that do not require a separate runtime.
<p>
A plain undecorated grammer that can be used for validation is available in <a href="grammar/Lua51.jj">grammar/Lua51.jj</a>
while a grammar that generates a typed parse tree is in <a href="grammar/LuaParser.jj">grammar/LuaParser.jj</a>
<h2>Creating a Parse Tree from Lua Source</h2>
The default lu compiler does a single-pass compile of lua source to lua bytecode, so no explicit parse tree is produced.
<p>
To simplify the creation of abstract syntax trees from lua sources, the LuaParser class is generated as part of the JME build.
To use it, provide an input stream, and invoke the root generator, which will return a Chunk if the file is valid,
or throw a ParseException if there is a syntax error.
<p>
For example, to parse a file and print all variable names, use code like:
<pre>
try {
String file = "main.lua";
LuaParser parser = new LuaParser(new FileInputStream(file));
Chunk chunk = parser.Chunk();
chunk.accept( new Visitor() {
public void visit(Exp.NameExp exp) {
System.out.println("Name in use: "+exp.name.name);
}
} );
} catch ( ParseException e ) {
System.out.println("parse failed: " + e.getMessage() + "\n"
+ "Token Image: '" + e.currentToken.image + "'\n"
+ "Location: " + e.currentToken.beginLine + ":" + e.currentToken.beginColumn
+ "-" + e.currentToken.endLine + "," + e.currentToken.endColumn);
}
</pre>
In luaj 2.0.3 error reporting was turned on in the parser so line numbers are avaiable for most parse exceptions.
This example may be found in
<pre>
examples/jse/SampleParser.java
</pre>
<p>
See the <a href="http://luaj.sourceforge.net/api/2.0/org/luaj/vm2/ast/package-summary.html">org.luaj.vm2.ast package</a> javadoc for the API relating to the syntax tree that is produced.
<h1>7 - <a name="7">Building and Testing</a></h1>
<h2>Building the jars</h2>
An ant file is included in the root directory which builds the libraries by default.
<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>
<p>
Unit test scripts can be found in these locations
<pre>
test/lua/*.lua
test/junit/org/luaj/vm2/compiler/lua5.1-tests.zip
test/junit/org/luaj/vm2/compiler/regressions.zip
test/junit/org/luaj/vm2/vm1/luajvm1-tests.zip
</pre>
<h2>Code coverage</h2>
<p>
A build script for running unit tests and producing code coverage statistics is in
<pre>
build-coverage.xml
</pre>
It relies on the cobertura code coverage library.
<h1>8 - <a name="8">Downloads</a></h1>
<h2>Downloads and Project Pages</h2>
Downloads for all version available on SourceForge or LuaForge.
Sources are hosted on SourceForge and available via sourceforge.net
<br/>
<pre>
<a href="http://luaj.sourceforge.net/">SourceForge Luaj Project Page</a>
<a href="http://sourceforge.net/project/platformdownload.php?group_id=197627">SourceForge Luaj Download Area</a>
</pre>
<p/>
and LuaForge:
<pre>
<a href="http://luaforge.net/projects/luaj/">LuaForge Luaj Project Page</a>
<a href="http://luaforge.net/frs/?group_id=457">LuaForge Luaj Project Area</a>
</pre>
<h1>9 - <a name="9">Release Notes</a></h1>
<h2>Main Changes by Version</h2>
<table cellspacing="10"><tr><td><table cellspacing="4">
<tr valign="top"><td>&nbsp;&nbsp;<b>2.0</b></td><td><ul>
<li>Initial release of 2.0 version </li>
</ul></td></tr>
<tr valign="top"><td>&nbsp;&nbsp;<b>2.0.1</b></td><td><ul>
<li>Improve correctness of singleton construction related to static initialization </li>
<li>Fix nan-related error in constant folding logic that was failing on some JVMs </li>
<li>JSR-223 fixes: add META-INF/services entry in jse jar, improve bindings implementation </li>
</ul></td></tr>
<tr valign="top"><td>&nbsp;&nbsp;<b>2.0.2</b></td><td><ul>
<li>JSR-223 bindings change: non Java-primitives will now be passed as LuaValue </li>
<li>JSR-223 enhancement: allow both ".lua" and "lua" as extensions in getScriptEngine() </li>
<li>JSR-223 fix: use system class loader to support using luaj as JRE extension </li>
<li>Improve selection logic when binding to overloaded functions using luajava</li>
<li>Enhance javadoc, put it <a href="docs/api/index.html">in distribution</a> and <a href="http://luaj.sourceforge.net/api/2.0/index.html">on line</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>
<tr valign="top"><td>&nbsp;&nbsp;<b>2.0.3</b></td><td><ul>
<li>Improve coroutine state logic including let unreferenced coroutines be garbage collected </li>
<li>Fix lua command vararg values passed into main script to match what is in global arg table </li>
<li>Add arithmetic metatag processing when left hand side is a number and right hand side has metatable </li>
<li>Fix load(func) when mutiple string fragments are supplied by calls to func </li>
<li>Allow access to public members of private inner classes where possible </li>
<li>Turn on error reporting in LuaParser so line numbers ar available in ParseException </li>
<li>Improve compatibility of table.remove() </li>
<li>Disallow base library setfenv() calls on Java functions </li>
</ul></td></tr>
</table></td></tr></table>
<h2>Known Issues</h2>
<ul>
<li>debug code may not be completely removed by some obfuscators
<li>tail calls are not tracked in debug information
<li>using both version 1 and 2 libraries together in the same java vm has not been tested
<li>module() and setfenv() only partially supported for lau2java or luajc compiled lua
<li>values associated with weak keys may linger longer than expected
<li>behavior of luaj when a SecurityManager is used has not been fully characterized
</ul>

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,172 +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">
<delete dir="build"/>
<delete>
<fileset dir="." includes="luaj-*.jar"/>
</delete>
</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="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;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*,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*"/>
<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"/>
<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-2008 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"/>
</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="all" depends="clean,jar-jme,jar-jse,jar-jse-sources"/>
</project>

View File

@@ -1,89 +0,0 @@
LuaValue Consructors,,Return type,,,,,,,,,,
,valueOf(boolean),LuaBoolean,,,,,,,,,,
,valueOf(null),LuaNil,,,,,,,,,,
,valueOf(int) ,LuaInteger,,,,,,,,,,
,valueOf(double),LuaNumber,,,,,,,,,,
,valueOf(long),LuaNumber,,,,,,,,,,
,valueOf(String),LuaString,,,,,,,,,,
,tableOf(...),LuaTable,,,,,,,,,,
,listOf(LuaValue[]),LuaTable,,,,,,,,,,
,userdataOf(Object),LuaUserdata,,,,,,,,,,
,"uerdataOf(Object,Value)",LuaUserdata,,,,,,,,,,
,,,,,,,Arugment type,,,,,
,,,LuaBoolean,LuaClosure,LuaFunction,LuaDouble,LuaInteger,LuaNil,LuaString,LuaTable,LuaThread,LuaUserdata
Type Check Functions,,,,,,,,,,,,
,isboolean,boolean,TRUE,f,f,f,f,f,f,f,f,f
,isclosure,boolean,f,TRUE,f,f,f,f,f,f,f,f
,isfunction,boolean,f,TRUE,TRUE,f,f,f,f,f,f,f
,isint,boolean,f,f,f,f,TRUE,f,true | f,f,f,f
,isinttype,boolean,f,f,f,f,TRUE,f,f,f,f,f
,isnumber,boolean,f,f,f,TRUE,TRUE,f,true | f,f,f,f
,islong,boolean,f,f,f,true | f,TRUE,f,true | f,f,f,f
,isnil,boolean,f,f,f,f,f,TRUE,f,f,f,f
,isstring,boolean,f,f,f,true | f,TRUE,f,TRUE,f,f,f
,istable,boolean,f,f,f,f,f,f,f,TRUE,f,f
,isthread,boolean,f,f,f,f,f,f,f,f,TRUE,f
,isuserdata,boolean,f,f,f,f,f,f,f,f,f,TRUE
,isuserdata(Class c),boolean,f,f,f,f,f,f,f,f,f,true | f
Java Type Coercion Functions,,,,,,,,,,,,
,toboolean,boolean,this.v,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE
,tobyte,byte,0,0,0,0,this.v | 0,0,this.v | 0,0,0,0
,tochar,char,0,0,0,0,this.v | 0,0,this.v | 0,0,0,0
,todouble,double,0,0,0,this.v,this.v,0,this.v | 0,0,0,0
,tofloat,float,0,0,0,this.v | 0,this.v,0,this.v | 0,0,0,0
,toint,int,0,0,0,0,this.v,0,this.v | 0,0,0,0
,tolong,long,0,0,0,0,this.v,0,this.v | 0,0,0,0
,toshort,short,0,0,0,0,this.v | 0,0,this.v | 0,0,0,0
,tojstring,String,"""true""|""false""","""closure: x""","""name""",(str) this.v,(str) this.v,"""nil""",this.v,"""table: x""","""thread: x""","""userdata: x"""
,touserdata,Object,null,null,null,null,null,null,null,null,this,this.instance
,,,LuaBoolean,LuaClosure,LuaFunction,LuaDouble,LuaInteger,LuaNil,LuaString,LuaTable,LuaThread,LuaUserdata
Optional Argument Conversion Functions,,,,,,,,,,,,
,optboolean,boolean,this,e,e,e,e,defval,e,e,e,e
,optclosure,LuaClosure,n,this,e,e,e,defval,e,e,e,e
,optdouble,double,e,e,e,this,this,defval,this | e,e,e,e
,optfunction,LuaFunction,n,this,this,e,e,defval,e,e,e,e
,optint,int,e,e,e,(int) this,this,defval,this | e,e,e,e
,optinteger,LuaInteger,e,e,e,(int) this,this,defval,this | e,e,e,e
,optlong,long,e,e,e,(long) this,this,defval,this | e,e,e,e
,optnumber,LuaNumber,e,e,e,this,this,defval,this | e,e,e,e
,optjstring,String,e,e,e,(str) this.v,(str) this.v,defval,this,e,e,e
,optstring,LuaString,e,e,e,(str) this.v,(str) this.v,defval,this,e,e,e
,opttable,LuaTable,e,e,e,e,e,defval,e,this,e,e
,optthread,LuaThread,e,e,e,e,e,defval,e,e,this,n
,optuserdata,Object,e,e,e,e,e,defval,e,e,e,instance
,optuserdata(Class c),Object,e,e,e,e,e,defval,e,e,e,instance | e
Required Argument Conversion Functions,,,,,,,,,,,,
,checkboolean,boolean,this,e,e,e,e,e,e,e,e,e
,checkclosure,LuaClosure,e,this,e,e,e,e,e,e,e,e
,checkdouble,double,e,e,e,this,this,e,e,e,e,e
,checkfunction,LuaFunction,e,this,this,e,e,e,e,e,e,e
,checkint,int,e,e,e,this | e,this,e,e,e,e,e
,checkinteger,LuaInteger,e,e,e,e,this,e,e,e,e,e
,checklong,LuaNumber,e,e,e,this | e,this,e,e,e,e,e
,checknumber,LuaNumber,e,e,e,this,this,e,e,e,e,e
,checkjstring,String,e,e,e,(str) this.v,(str) this.v,e,(str) this.v,e,e,e
,checkstring,LuaString,e,e,e,(str) this.v,(str) this.v,e,this,e,e,e
,checktable,LuaTable,e,e,e,e,e,e,e,this,e,e
,checkthread,LuaThread,e,e,e,e,e,e,e,e,this,e
,checkuserdata,Object,e,e,e,e,e,e,e,e,e,instance
,checkuserdata(Class c),Object,e,e,e,e,e,e,e,e,e,instance | e
,checkvalue,LuaValue,this,this,this,this,this,e,this,this,this,this
,,,LuaBoolean,LuaClosure,LuaFunction,LuaDouble,LuaInteger,LuaNil,LuaString,LuaTable,LuaThread,LuaUserdata
Lua Language Operations,,,,,,,,,,,,
,type,int,TBOOLEAN,TFUNCTION,TFUNCTION,TNUMBER,TNUMBER,TNIL,TSTRING,TTABLE,TTHREAD,TUSERDATA
,typename,string,"""boolean""","""function""","""function""","""number""","""number""","""nil""","""string""","""table""","""thread""","""userdata"""
,len,LuaInteger,e,e,e,e,e,e,#v,#v,e,e
,length,int,e,e,e,e,e,e,#v,#v,e,e
,getmetatable,LuaValue,static,static,static,static,static,static,static,instance,static ,instance
,setmetatable,LuaValue,e,e,e,e,e,e,e,instance,e,instance
,getfenv,LuaTable,e,instance,instance,e,e,e,e,e,instance,e
,setfenv,LuaFunction,e,instance,instance,e,e,e,e,e,instance,e
,call,LuaValue,__call,call,call,__call,__call,__call,__call,__call,__call,__call
,invoke,Varargs,__call,call,call,__call,__call,__call,__call,__call,__call,__call
,get,LuaValue,__index,__index,__index,__index,__index,__index,__index,get,__index,__index
,set,LuaValue,__newindex,__newindex,__newindex,__newindex,__newindex,__newindex,__newindex,set,__newindex,__newindex
1 LuaValue Consructors Return type
2 valueOf(boolean) LuaBoolean
3 valueOf(null) LuaNil
4 valueOf(int) LuaInteger
5 valueOf(double) LuaNumber
6 valueOf(long) LuaNumber
7 valueOf(String) LuaString
8 tableOf(...) LuaTable
9 listOf(LuaValue[]) LuaTable
10 userdataOf(Object) LuaUserdata
11 uerdataOf(Object,Value) LuaUserdata
12 Arugment type
13 LuaBoolean LuaClosure LuaFunction LuaDouble LuaInteger LuaNil LuaString LuaTable LuaThread LuaUserdata
14 Type Check Functions
15 isboolean boolean TRUE f f f f f f f f f
16 isclosure boolean f TRUE f f f f f f f f
17 isfunction boolean f TRUE TRUE f f f f f f f
18 isint boolean f f f f TRUE f true | f f f f
19 isinttype boolean f f f f TRUE f f f f f
20 isnumber boolean f f f TRUE TRUE f true | f f f f
21 islong boolean f f f true | f TRUE f true | f f f f
22 isnil boolean f f f f f TRUE f f f f
23 isstring boolean f f f true | f TRUE f TRUE f f f
24 istable boolean f f f f f f f TRUE f f
25 isthread boolean f f f f f f f f TRUE f
26 isuserdata boolean f f f f f f f f f TRUE
27 isuserdata(Class c) boolean f f f f f f f f f true | f
28 Java Type Coercion Functions
29 toboolean boolean this.v TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
30 tobyte byte 0 0 0 0 this.v | 0 0 this.v | 0 0 0 0
31 tochar char 0 0 0 0 this.v | 0 0 this.v | 0 0 0 0
32 todouble double 0 0 0 this.v this.v 0 this.v | 0 0 0 0
33 tofloat float 0 0 0 this.v | 0 this.v 0 this.v | 0 0 0 0
34 toint int 0 0 0 0 this.v 0 this.v | 0 0 0 0
35 tolong long 0 0 0 0 this.v 0 this.v | 0 0 0 0
36 toshort short 0 0 0 0 this.v | 0 0 this.v | 0 0 0 0
37 tojstring String "true"|"false" "closure: x" "name" (str) this.v (str) this.v "nil" this.v "table: x" "thread: x" "userdata: x"
38 touserdata Object null null null null null null null null this this.instance
39 LuaBoolean LuaClosure LuaFunction LuaDouble LuaInteger LuaNil LuaString LuaTable LuaThread LuaUserdata
40 Optional Argument Conversion Functions
41 optboolean boolean this e e e e defval e e e e
42 optclosure LuaClosure n this e e e defval e e e e
43 optdouble double e e e this this defval this | e e e e
44 optfunction LuaFunction n this this e e defval e e e e
45 optint int e e e (int) this this defval this | e e e e
46 optinteger LuaInteger e e e (int) this this defval this | e e e e
47 optlong long e e e (long) this this defval this | e e e e
48 optnumber LuaNumber e e e this this defval this | e e e e
49 optjstring String e e e (str) this.v (str) this.v defval this e e e
50 optstring LuaString e e e (str) this.v (str) this.v defval this e e e
51 opttable LuaTable e e e e e defval e this e e
52 optthread LuaThread e e e e e defval e e this n
53 optuserdata Object e e e e e defval e e e instance
54 optuserdata(Class c) Object e e e e e defval e e e instance | e
55 Required Argument Conversion Functions
56 checkboolean boolean this e e e e e e e e e
57 checkclosure LuaClosure e this e e e e e e e e
58 checkdouble double e e e this this e e e e e
59 checkfunction LuaFunction e this this e e e e e e e
60 checkint int e e e this | e this e e e e e
61 checkinteger LuaInteger e e e e this e e e e e
62 checklong LuaNumber e e e this | e this e e e e e
63 checknumber LuaNumber e e e this this e e e e e
64 checkjstring String e e e (str) this.v (str) this.v e (str) this.v e e e
65 checkstring LuaString e e e (str) this.v (str) this.v e this e e e
66 checktable LuaTable e e e e e e e this e e
67 checkthread LuaThread e e e e e e e e this e
68 checkuserdata Object e e e e e e e e e instance
69 checkuserdata(Class c) Object e e e e e e e e e instance | e
70 checkvalue LuaValue this this this this this e this this this this
71 LuaBoolean LuaClosure LuaFunction LuaDouble LuaInteger LuaNil LuaString LuaTable LuaThread LuaUserdata
72 Lua Language Operations
73 type int TBOOLEAN TFUNCTION TFUNCTION TNUMBER TNUMBER TNIL TSTRING TTABLE TTHREAD TUSERDATA
74 typename string "boolean" "function" "function" "number" "number" "nil" "string" "table" "thread" "userdata"
75 len LuaInteger e e e e e e #v #v e e
76 length int e e e e e e #v #v e e
77 getmetatable LuaValue static static static static static static static instance static instance
78 setmetatable LuaValue e e e e e e e instance e instance
79 getfenv LuaTable e instance instance e e e e e instance e
80 setfenv LuaFunction e instance instance e e e e e instance e
81 call LuaValue __call call call __call __call __call __call __call __call __call
82 invoke Varargs __call call call __call __call __call __call __call __call __call
83 get LuaValue __index __index __index __index __index __index __index get __index __index
84 set LuaValue __newindex __newindex __newindex __newindex __newindex __newindex __newindex set __newindex __newindex

View File

@@ -1,260 +0,0 @@
/*******************************************************************************
* 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;
/**
* 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.
* <p>
* To convert back to a {@link LuaValue} again,
* the function {@link Buffer#value()} is used.
* @see LuaValue
* @see LuaValue#buffer()
* @see LuaString
*/
public final class Buffer {
/** Default capacity for a buffer: 64 */
private static final int DEFAULT_CAPACITY = 64;
/** Shared static array with no bytes */
private static final byte[] NOBYTES = {};
/** Bytes in this buffer */
private byte[] bytes;
/** Length of this buffer */
private int length;
/** Offset into the byte array */
private int offset;
/** Value of this buffer, when not represented in bytes */
private LuaValue value;
/**
* Create buffer with default capacity
* @see #DEFAULT_CAPACITY
*/
public Buffer() {
this(DEFAULT_CAPACITY);
}
/**
* Create buffer with specified initial capacity
* @param initialCapacity the initial capacity
*/
public Buffer( int initialCapacity ) {
bytes = new byte[ initialCapacity ];
length = 0;
offset = 0;
value = null;
}
/**
* Create buffer with specified initial value
* @param value the initial value
*/
public Buffer(LuaValue value) {
bytes = NOBYTES;
length = offset = 0;
this.value = value;
}
/**
* Get buffer contents as a {@link LuaValue}
* @return value as a {@link LuaValue}, converting as necessary
*/
public LuaValue value() {
return value != null? value: this.tostring();
}
/**
* Set buffer contents as a {@link LuaValue}
* @param value value to set
*/
public Buffer setvalue(LuaValue value) {
bytes = NOBYTES;
offset = length = 0;
this.value = value;
return this;
}
/**
* Convert the buffer to a {@link LuaString}
* @return the value as a {@link LuaString}
*/
public final 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() {
return value().tojstring();
}
/**
* Convert the buffer to a Java String
* @return the value as a Java String
*/
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 ) {
makeroom( 0, 1 );
bytes[ offset + length++ ] = b;
return this;
}
/**
* Append a {@link LuaValue} to the buffer.
* @return {@code this} to allow call chaining
*/
public final 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 ) {
final int n = str.m_length;
makeroom( 0, n );
str.copyInto( 0, bytes, offset + length, n );
length += n;
return this;
}
/**
* 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[], byte[], int)
*/
public final Buffer append( String str ) {
char[] chars = str.toCharArray();
/* DAN200 START */
/*
final int n = LuaString.lengthAsUtf8( chars );
makeroom( 0, n );
LuaString.encodeToUtf8( chars, bytes, offset + length );
length += n;
*/
makeroom( 0, chars.length );
for( int i=0; i<chars.length; ++i )
{
char ch = chars[i];
bytes[ offset + length + i ] = (ch < 256) ? (byte)ch : (byte)'?';
}
length += chars.length;
/* DAN200 END */
return 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}
* @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}
* <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}
* @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}
* @return {@link Buffer} for use in call chaining.
*/
public Buffer prepend(LuaString s) {
int n = s.m_length;
makeroom( n, 0 );
System.arraycopy( s.m_bytes, s.m_offset, bytes, offset-n, n );
offset -= n;
length += n;
value = null;
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
*/
public final void makeroom( int nbefore, int nafter ) {
if ( value != null ) {
LuaString s = value.strvalue();
value = null;
length = s.m_length;
offset = nbefore;
bytes = new byte[nbefore+length+nafter];
System.arraycopy(s.m_bytes, s.m_offset, bytes, offset, length);
} else if ( offset+length+nafter > bytes.length || offset<nbefore ) {
int n = nbefore+length+nafter;
int m = n<32? 32: n<length*2? length*2: n;
realloc( m, nbefore==0? 0: m-length-nafter );
}
}
/** 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 ) {
if ( newSize != bytes.length ) {
byte[] newBytes = new byte[ newSize ];
System.arraycopy( bytes, offset, newBytes, newOffset, length );
bytes = newBytes;
offset = newOffset;
}
}
}

View File

@@ -1,428 +0,0 @@
/*******************************************************************************
* 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 manage loading of {@link Prototype} instances.
* <p>
* The {@link LoadState} class exposes one main function,
* namely {@link #load(InputStream, String, LuaValue)},
* to be used to load code from a particular input stream.
* <p>
* A simple pattern for loading and executing code is
* <pre> {@code
* LuaValue _G = JsePlatform.standardGlobals();
* LoadState.load( new FileInputStream("main.lua"), "main.lua", _G ).call();
* } </pre>
* This should work regardless of which {@link LuaCompiler}
* has been installed.
* <p>
*
* Prior to loading code, a compiler should be installed.
* <p>
* By default, when using {@link JsePlatform} or {@JmePlatform}
* to construct globals, the {@link LuaC} compiler is installed.
* <p>
* To override the default compiler with, say, the {@link LuaJC}
* lua-to-java bytecode compiler, install it before loading,
* for example:
* <pre> {@code
* LuaValue _G = JsePlatform.standardGlobals();
* LuaJC.install();
* LoadState.load( new FileInputStream("main.lua"), "main.lua", _G ).call();
* } </pre>
*
* @see LuaCompiler
* @see LuaClosure
* @see LuaFunction
* @see LoadState#compiler
* @see LoadState#load(InputStream, String, LuaValue)
* @see LuaC
* @see LuaJC
*/
public class LoadState {
/** 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;
/** Interface for the compiler, if it is installed.
* <p>
* See the {@link LuaClosure} documentation for examples of how to use the compiler.
* @see LuaClosure
* @see #load(InputStream, String, LuaValue)
* */
public interface LuaCompiler {
/** Load into a Closure or LuaFunction from a Stream and initializes the environment
* @throws IOException */
public LuaFunction load(InputStream stream, String filename, LuaValue env) throws IOException;
}
/** Compiler instance, if installed */
public static LuaCompiler compiler = null;
/** Signature byte indicating the file is a compiled binary chunk */
private static final byte[] LUA_SIGNATURE = { '\033', 'L', 'u', 'a' };
/** Name for compiled chunks */
public static final String SOURCE_BINARY_STRING = "binary string";
/** for header of binary files -- this is Lua 5.1 */
public static final int LUAC_VERSION = 0x51;
/** 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 LuaString[] NOSTRVALUES = {};
private static final int[] NOINTS = {};
/** Read buffer */
private byte[] buf = new byte[512];
/** 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) | (((long)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.valueOf( 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;
}
/**
* Load the debug infor 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.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();
f.upvalues = n>0? new LuaString[n]: NOSTRVALUES;
for ( int i=0; i<n; i++ ) {
f.upvalues[i] = 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.nups = is.readUnsignedByte();
f.numparams = is.readUnsignedByte();
f.is_vararg = is.readUnsignedByte();
f.maxstacksize = is.readUnsignedByte();
f.code = loadIntArray();
loadConstants(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();
}
/**
* Load lua in either binary or text form from an input stream.
* @param firstByte the first byte of the input stream
* @param stream InputStream to read, after having read the first byte already
* @param name Name to apply to the loaded chunk
* @return {@link Prototype} that was loaded
* @throws IllegalArgumentException if the signature is bac
* @throws IOException if an IOException occurs
*/
public static LuaFunction load( InputStream stream, String name, LuaValue env ) throws IOException {
if ( compiler != null )
return compiler.load(stream, name, env);
else {
int firstByte = stream.read();
if ( firstByte != LUA_SIGNATURE[0] )
throw new LuaError("no compiler");
Prototype p = loadBinaryChunk( firstByte, stream, name );
return new LuaClosure( p, env );
}
}
/**
* Load lua thought to be a binary chunk from its first byte from an input stream.
* @param firstByte the first byte of the input stream
* @param stream InputStream to read, after having read the first byte already
* @param name Name to apply to the loaded chunk
* @return {@link Prototype} that was loaded
* @throws IllegalArgumentException if the signature is bac
* @throws IOException if an IOException occurs
*/
public static Prototype loadBinaryChunk( int firstByte, InputStream stream, String name ) throws IOException {
// check rest of signature
if ( firstByte != LUA_SIGNATURE[0]
|| stream.read() != LUA_SIGNATURE[1]
|| stream.read() != LUA_SIGNATURE[2]
|| stream.read() != LUA_SIGNATURE[3] )
throw new IllegalArgumentException("bad signature");
// load file as a compiled chunk
String sname = getSourceName(name);
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 );
}
}

View File

@@ -1,52 +0,0 @@
/*******************************************************************************
* 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;
/**
* Data class to hold debug information relatign to local variables for a {@link Prototype}
*/
public class LocVars {
/** The local variable name */
public LuaString varname;
/** The instruction offset when the variable comes into scope */
public int startpc;
/** The instruction offset when the variable goes out of scope */
public int endpc;
/**
* 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
*/
public LocVars(LuaString varname, int startpc, int endpc) {
this.varname = varname;
this.startpc = startpc;
this.endpc = endpc;
}
public String tojstring() {
return varname+" "+startpc+"-"+endpc;
}
}

View File

@@ -1,337 +0,0 @@
/*******************************************************************************
* 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;
/** masks for new-style vararg */
public static final int VARARG_HASARG = 1;
public static final int VARARG_ISVARARG = 2;
public static final int VARARG_NEEDSARG = 4;
// 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;
/*
** 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_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 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 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_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_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 ((int)(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_LOADBOOL = 2;/* A B C R(A) := (Bool)B; if (C) pc++ */
public static final int OP_LOADNIL = 3; /* A B R(A) := ... := R(B) := nil */
public static final int OP_GETUPVAL = 4; /* A B R(A) := UpValue[B] */
public static final int OP_GETGLOBAL = 5; /* A Bx R(A) := Gbl[Kst(Bx)] */
public static final int OP_GETTABLE = 6; /* A B C R(A) := R(B)[RK(C)] */
public static final int OP_SETGLOBAL = 7; /* A Bx Gbl[Kst(Bx)] := R(A) */
public static final int OP_SETUPVAL = 8; /* A B UpValue[B] := R(A) */
public static final int OP_SETTABLE = 9; /* A B C R(A)[RK(B)] := RK(C) */
public static final int OP_NEWTABLE = 10; /* A B C R(A) := {} (size = B,C) */
public static final int OP_SELF = 11; /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
public static final int OP_ADD = 12; /* A B C R(A) := RK(B) + RK(C) */
public static final int OP_SUB = 13; /* A B C R(A) := RK(B) - RK(C) */
public static final int OP_MUL = 14; /* A B C R(A) := RK(B) * RK(C) */
public static final int OP_DIV = 15; /* A B C R(A) := RK(B) / RK(C) */
public static final int OP_MOD = 16; /* A B C R(A) := RK(B) % RK(C) */
public static final int OP_POW = 17; /* A B C R(A) := RK(B) ^ RK(C) */
public static final int OP_UNM = 18; /* A B R(A) := -R(B) */
public static final int OP_NOT = 19; /* A B R(A) := not R(B) */
public static final int OP_LEN = 20; /* A B R(A) := length of R(B) */
public static final int OP_CONCAT = 21; /* A B C R(A) := R(B).. ... ..R(C) */
public static final int OP_JMP = 22; /* sBx pc+=sBx */
public static final int OP_EQ = 23; /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
public static final int OP_LT = 24; /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
public static final int OP_LE = 25; /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
public static final int OP_TEST = 26; /* A C if not (R(A) <=> C) then pc++ */
public static final int OP_TESTSET = 27; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
public static final int OP_CALL = 28; /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
public static final int OP_TAILCALL = 29; /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
public static final int OP_RETURN = 30; /* A B return R(A), ... ,R(A+B-2) (see note) */
public static final int OP_FORLOOP = 31; /* 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 = 32; /* A sBx R(A)-=R(A+2); pc+=sBx */
public static final int OP_TFORLOOP = 33; /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++ */
public static final int OP_SETLIST = 34; /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
public static final int OP_CLOSE = 35; /* A close all variables in the stack up to (>=) R(A)*/
public static final int OP_CLOSURE = 36; /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
public static final int OP_VARARG = 37; /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
public static final int NUM_OPCODES = OP_VARARG + 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) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_LOADBOOL */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_LOADNIL */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_GETUPVAL */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgN<<2) | (iABx), /* OP_GETGLOBAL */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgK<<2) | (iABC), /* OP_GETTABLE */
(0<<7) | (0<<6) | (OpArgK<<4) | (OpArgN<<2) | (iABx), /* OP_SETGLOBAL */
(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) | (1<<6) | (OpArgR<<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 */
(1<<7) | (0<<6) | (OpArgN<<4) | (OpArgU<<2) | (iABC), /* OP_TFORLOOP */
(0<<7) | (0<<6) | (OpArgU<<4) | (OpArgU<<2) | (iABC), /* OP_SETLIST */
(0<<7) | (0<<6) | (OpArgN<<4) | (OpArgN<<2) | (iABC), /* OP_CLOSE */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABx), /* OP_CLOSURE */
(0<<7) | (1<<6) | (OpArgU<<4) | (OpArgN<<2) | (iABC), /* OP_VARARG */
};
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;
}

View File

@@ -1,103 +0,0 @@
/*******************************************************************************
* 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;
/**
* 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 {@link 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()}
* <p>
* @see LuaValue
* @see LuaValue#valueOf(boolean)
* @see LuaValue#TRUE
* @see LuaValue#FALSE
*/
public final class LuaBoolean extends LuaValue {
/** The singleton instance representing lua {@code true} */
static final LuaBoolean _TRUE = new LuaBoolean(true);
/** The singleton instance representing lua {@code false} */
static final LuaBoolean _FALSE = new LuaBoolean(false);
/** Shared static metatable for boolean values represented in lua. */
public static LuaValue s_metatable;
/** The value of the boolean */
public final boolean v;
LuaBoolean(boolean b) {
this.v = b;
}
public int type() {
return LuaValue.TBOOLEAN;
}
public String typename() {
return "boolean";
}
public boolean isboolean() {
return true;
}
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;
}
public boolean toboolean() {
return v;
}
public String tojstring() {
return v ? "true" : "false";
}
public boolean optboolean(boolean defval) {
return this.v;
}
public boolean checkboolean() {
return v;
}
public LuaValue getmetatable() {
return s_metatable;
}
}

View File

@@ -1,521 +0,0 @@
/*******************************************************************************
* 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.ByteArrayInputStream;
import java.io.InputStream;
import org.luaj.vm2.LoadState.LuaCompiler;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.lib.DebugLib;
/**
* 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.
* <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 LuaCompiler#load(java.io.InputStream, String, LuaValue)}
* <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 LuaC}:
* <pre> {@code
* InputStream is = new ByteArrayInputStream("print('hello,world').getBytes());
* Prototype p = LuaC.instance.compile(is, "script");
* LuaValue _G = JsePlatform.standardGlobals()
* LuaClosure f = new LuaClosure(p, _G);
* }</pre>
* <p>
* To construct it indirectly, the {@link LuaC} compiler may be used,
* which implements the {@link LuaCompiler} interface:
* <pre> {@code
* LuaFunction f = LuaC.instance.load(is, "script", _G);
* }</pre>
* <p>
* Typically, a closure that has just been loaded needs to be initialized by executing it,
* and its return value can be saved if needed:
* <pre> {@code
* LuaValue r = f.call();
* _G.set( "mypkg", r )
* }</pre>
* <p>
* In the preceding, the loaded value is typed as {@link LuaFunction}
* to allow for the possibility of other compilers such as {@link LuaJC}
* producing {@link LuaFunction} directly without
* creating a {@link Prototype} or {@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#setfenv(LuaValue)}</li>
* <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 LoadState#compiler
*/
public class LuaClosure extends LuaFunction {
private static final UpValue[] NOUPVALUES = new UpValue[0];
public final Prototype p;
public final UpValue[] upValues;
LuaClosure() {
p = null;
upValues = null;
}
/** Supply the initial environment */
public LuaClosure(Prototype p, LuaValue env) {
super( env );
this.p = p;
this.upValues = p.nups>0? new UpValue[p.nups]: NOUPVALUES;
}
protected LuaClosure(int nupvalues, LuaValue env) {
super( env );
this.p = null;
this.upValues = nupvalues>0? new UpValue[nupvalues]: NOUPVALUES;
}
public boolean isclosure() {
return true;
}
public LuaClosure optclosure(LuaClosure defval) {
return this;
}
public LuaClosure checkclosure() {
return this;
}
public LuaValue getmetatable() {
return s_metatable;
}
public final LuaValue call() {
LuaValue[] stack = new LuaValue[p.maxstacksize];
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
return execute(stack,NONE).arg1();
}
public final LuaValue call(LuaValue arg) {
LuaValue[] stack = new LuaValue[p.maxstacksize];
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
switch ( p.numparams ) {
default: stack[0]=arg; return execute(stack,NONE).arg1();
case 0: return execute(stack,arg).arg1();
}
}
public final LuaValue call(LuaValue arg1, LuaValue arg2) {
LuaValue[] stack = new LuaValue[p.maxstacksize];
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
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();
}
}
public final LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
LuaValue[] stack = new LuaValue[p.maxstacksize];
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
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();
}
}
public final Varargs invoke(Varargs varargs) {
return onInvoke( varargs ).eval();
}
public Varargs onInvoke(Varargs varargs) {
LuaValue[] stack = new LuaValue[p.maxstacksize];
System.arraycopy(NILS, 0, stack, 0, p.maxstacksize);
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
UpValue[] openups = p.p.length>0? new UpValue[stack.length]: null;
// create varargs "arg" table
if ( p.is_vararg >= Lua.VARARG_NEEDSARG )
stack[p.numparams] = new LuaTable(varargs);
// debug wants args to this function
if (DebugLib.DEBUG_ENABLED)
DebugLib.debugSetupCall(varargs, stack);
// process instructions
LuaThread.CallStack cs = LuaThread.onCall( this );
try {
while ( true ) {
if (DebugLib.DEBUG_ENABLED)
DebugLib.debugBytecode(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_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(B):= nil */
for ( b=i>>>23; a<=b; )
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_GETGLOBAL: /* A Bx R(A):= Gbl[Kst(Bx)] */
stack[a] = env.get(k[i>>>14]);
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_SETGLOBAL: /* A Bx Gbl[Kst(Bx)]:= R(A) */
env.set(k[i>>>14], stack[a]);
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 = stack[c].concat(sb);
stack[a] = sb.value();
} else {
stack[a] = stack[c-1].concat(stack[c]);
}
}
continue;
case Lua.OP_JMP: /* sBx pc+=sBx */
pc += (i>>>14)-0x1ffff;
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 = b>0?
varargsOf(stack,a+1,b-1): // exact arg count
varargsOf(stack, a+1, top-v.narg()-(a+1), v); // from prev top
v = stack[a].invoke(v);
if ( c > 0 ) {
while ( --c > 0 )
stack[a+c-1] = v.arg(c);
v = NONE; // TODO: necessary?
} else {
top = a + v.narg();
}
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 = step.add(stack[a]);
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_TFORLOOP: /*
* A C R(A+3), ... ,R(A+2+C):= R(A)(R(A+1),
* R(A+2)): if R(A+3) ~= nil then R(A+2)=R(A+3)
* else pc++
*/
// TODO: stack call on for loop body, such as: stack[a].call(ci);
v = stack[a].invoke(varargsOf(stack[a+1],stack[a+2]));
if ( (o=v.arg1()).isnil() )
++pc;
else {
stack[a+2] = stack[a+3] = o;
for ( c=(i>>14)&0x1ff; c>1; --c )
stack[a+2+c] = v.arg(c);
v = NONE; // todo: necessary?
}
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_CLOSE: /* A close all variables in the stack up to (>=) R(A)*/
for ( b=openups.length; --b>=a; )
if ( openups[b]!=null ) {
openups[b].close();
openups[b] = null;
}
continue;
case Lua.OP_CLOSURE: /* A Bx R(A):= closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
{
Prototype newp = p.p[i>>>14];
LuaClosure newcl = new LuaClosure(newp, env);
for ( int j=0, nup=newp.nups; j<nup; ++j ) {
i = code[pc++];
//b = B(i);
b = i>>>23;
newcl.upValues[j] = (i&4) != 0?
upValues[b]:
openups[b]!=null? openups[b]: (openups[b]=new UpValue(stack,b));
}
stack[a] = newcl;
}
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;
}
}
} catch ( LuaError le ) {
throw le;
} catch ( Exception e ) {
throw new LuaError(e);
} finally {
cs.onReturn();
if ( openups != null )
for ( int u=openups.length; --u>=0; )
if ( openups[u] != null )
openups[u].close();
}
}
protected LuaValue getUpvalue(int i) {
return upValues[i].getValue();
}
protected void setUpvalue(int i, LuaValue v) {
upValues[i].setValue(v);
}
}

View File

@@ -1,288 +0,0 @@
/*******************************************************************************
* 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;
import org.luaj.vm2.lib.MathLib;
/**
* Extension of {@link LuaNumber} which can hold a Java double 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 values which can be represented as int
* are wrapped in {@link LuaInteger} instead of {@link LuaDouble}.
* <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
* when dealing with Nan or Infinite values.
* <p>
* LuaDouble also defines functions for handling the unique math rules of lua devision and modulo in
* <ul>
* <li>{@link #ddiv(double, double)}</li>
* <li>{@link #ddiv_d(double, double)}</li>
* <li>{@link #dmod(double, double)}</li>
* <li>{@link #dmod_d(double, double)}</li>
* </ul>
* <p>
* @see LuaValue
* @see LuaNumber
* @see LuaInteger
* @see LuaValue#valueOf(int)
* @see LuaValue#valueOf(double)
*/
public class LuaDouble extends LuaNumber {
/** Constant LuaDouble representing NaN (not a number) */
public static final LuaDouble NAN = new LuaDouble( Double.NaN );
/** Constant LuaDouble representing positive infinity */
public static final LuaDouble POSINF = new LuaDouble( Double.POSITIVE_INFINITY );
/** Constant LuaDouble representing negative infinity */
public static final LuaDouble NEGINF = new LuaDouble( Double.NEGATIVE_INFINITY );
/** Constant String representation for NaN (not a number), "nan" */
public static final String JSTR_NAN = "nan";
/** Constant String representation for positive infinity, "inf" */
public static final String JSTR_POSINF = "inf";
/** Constant String representation for negative infinity, "-inf" */
public static final String JSTR_NEGINF = "-inf";
/** The value being held by this instance. */
final double v;
public static LuaNumber valueOf(double d) {
int id = (int) d;
return d==id? (LuaNumber) LuaInteger.valueOf(id): (LuaNumber) new LuaDouble(d);
}
/** Don't allow ints to be boxed by DoubleValues */
private LuaDouble(double d) {
this.v = d;
}
public int hashCode() {
long l = Double.doubleToLongBits(v);
return ((int)(l>>32)) | (int) l;
}
public boolean islong() {
return v == (long) v;
}
public byte tobyte() { return (byte) (long) v; }
public char tochar() { return (char) (long) v; }
public double todouble() { return v; }
public float tofloat() { return (float) v; }
public int toint() { return (int) (long) v; }
public long tolong() { return (long) v; }
public short toshort() { return (short) (long) v; }
public double optdouble(double defval) { return v; }
public int optint(int defval) { return (int) (long) v; }
public LuaInteger optinteger(LuaInteger defval) { return LuaInteger.valueOf((int) (long)v); }
public long optlong(long defval) { return (long) v; }
public LuaInteger checkinteger() { return LuaInteger.valueOf( (int) (long) v ); }
// unary operators
public LuaValue neg() { return valueOf(-v); }
// object equality, used for key comparison
public boolean equals(Object o) { return o instanceof LuaDouble? ((LuaDouble)o).v == v: false; }
// equality w/ metatable processing
public LuaValue eq( LuaValue val ) { return val.raweq(v)? TRUE: FALSE; }
public boolean eq_b( LuaValue val ) { return val.raweq(v); }
// equality w/o metatable processing
public boolean raweq( LuaValue val ) { return val.raweq(v); }
public boolean raweq( double val ) { return v == val; }
public boolean raweq( int val ) { return v == val; }
// basic binary arithmetic
public LuaValue add( LuaValue rhs ) { return rhs.add(v); }
public LuaValue add( double lhs ) { return LuaDouble.valueOf(lhs + v); }
public LuaValue sub( LuaValue rhs ) { return rhs.subFrom(v); }
public LuaValue sub( double rhs ) { return LuaDouble.valueOf(v - rhs); }
public LuaValue sub( int rhs ) { return LuaDouble.valueOf(v - rhs); }
public LuaValue subFrom( double lhs ) { return LuaDouble.valueOf(lhs - v); }
public LuaValue mul( LuaValue rhs ) { return rhs.mul(v); }
public LuaValue mul( double lhs ) { return LuaDouble.valueOf(lhs * v); }
public LuaValue mul( int lhs ) { return LuaDouble.valueOf(lhs * v); }
public LuaValue pow( LuaValue rhs ) { return rhs.powWith(v); }
public LuaValue pow( double rhs ) { return MathLib.dpow(v,rhs); }
public LuaValue pow( int rhs ) { return MathLib.dpow(v,rhs); }
public LuaValue powWith( double lhs ) { return MathLib.dpow(lhs,v); }
public LuaValue powWith( int lhs ) { return MathLib.dpow(lhs,v); }
public LuaValue div( LuaValue rhs ) { return rhs.divInto(v); }
public LuaValue div( double rhs ) { return LuaDouble.ddiv(v,rhs); }
public LuaValue div( int rhs ) { return LuaDouble.ddiv(v,rhs); }
public LuaValue divInto( double lhs ) { return LuaDouble.ddiv(lhs,v); }
public LuaValue mod( LuaValue rhs ) { return rhs.modFrom(v); }
public LuaValue mod( double rhs ) { return LuaDouble.dmod(v,rhs); }
public LuaValue mod( int rhs ) { return LuaDouble.dmod(v,rhs); }
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
/** Divide two double numbers according to lua math, and return a {@link LuaValue} result.
* @param lhs Left-hand-side of the division.
* @param rhs Right-hand-side of the division.
* @return {@link LuaValue} for the result of the division,
* taking into account positive and negiative infinity, and Nan
* @see #ddiv_d(double, double)
*/
public static LuaValue ddiv(double lhs, double rhs) {
return rhs!=0? valueOf( lhs / rhs ): lhs>0? POSINF: lhs==0? NAN: NEGINF;
}
/** Divide two double numbers according to lua math, and return a double result.
* @param lhs Left-hand-side of the division.
* @param rhs Right-hand-side of the division.
* @return Value of the division, taking into account positive and negative infinity, and Nan
* @see #ddiv(double, double)
*/
public static double ddiv_d(double lhs, double rhs) {
return rhs!=0? lhs / rhs: lhs>0? Double.POSITIVE_INFINITY: lhs==0? Double.NaN: Double.NEGATIVE_INFINITY;
}
/** Take modulo double numbers according to lua math, and return a {@link LuaValue} result.
* @param lhs Left-hand-side of the modulo.
* @param rhs Right-hand-side of the modulo.
* @return {@link LuaValue} for the result of the modulo,
* using lua's rules for modulo
* @see #dmod_d(double, double)
*/
public static LuaValue dmod(double lhs, double rhs) {
return rhs!=0? valueOf( lhs-rhs*Math.floor(lhs/rhs) ): NAN;
}
/** Take modulo for double numbers according to lua math, and return a double result.
* @param lhs Left-hand-side of the modulo.
* @param rhs Right-hand-side of the modulo.
* @return double value for the result of the modulo,
* using lua's rules for modulo
* @see #dmod(double, double)
*/
public static double dmod_d(double lhs, double rhs) {
return rhs!=0? lhs-rhs*Math.floor(lhs/rhs): Double.NaN;
}
// relational operators
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? LuaValue.TRUE: FALSE; }
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( 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( 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( 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( 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( 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( 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( int rhs ) { return v >= rhs; }
public boolean gteq_b( double rhs ) { return v >= rhs; }
// string comparison
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";
}
*/
long l = (long) v;
if ( l == v )
return Long.toString(l);
if ( Double.isNaN(v) )
return JSTR_NAN;
if ( Double.isInfinite(v) )
return (v<0? JSTR_NEGINF: JSTR_POSINF);
return Float.toString((float)v);
}
public LuaString strvalue() {
return LuaString.valueOf(tojstring());
}
public LuaString optstring(LuaString defval) {
return LuaString.valueOf(tojstring());
}
public LuaValue tostring() {
return LuaString.valueOf(tojstring());
}
public String optjstring(String defval) {
return tojstring();
}
public LuaNumber optnumber(LuaNumber defval) {
return this;
}
public boolean isnumber() {
return true;
}
public boolean isstring() {
return true;
}
public LuaValue tonumber() {
return this;
}
public int checkint() { return (int) (long) v; }
public long checklong() { return (long) v; }
public LuaNumber checknumber() { return this; }
public double checkdouble() { return v; }
public String checkjstring() {
return tojstring();
}
public LuaString checkstring() {
return LuaString.valueOf(tojstring());
}
public LuaValue checkvalidkey() {
if ( Double.isNaN(v) )
throw new LuaError("table index expected, got nan");
return this;
}
}

View File

@@ -1,132 +0,0 @@
/*******************************************************************************
* 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;
import org.luaj.vm2.lib.DebugLib;
/**
* 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.
* <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.
* <p>
*/
public class LuaError extends RuntimeException {
private static final long serialVersionUID = 1L;
private String traceback;
/**
* Run the error hook if there is one
* @param msg the message to use in error hook processing.
* */
private static String errorHook(String msg) {
LuaThread thread = LuaThread.getRunning();
if ( thread.err != null ) {
LuaValue errfunc = thread.err;
thread.err = null;
try {
return errfunc.call( LuaValue.valueOf(msg) ).tojstring();
} catch ( Throwable t ) {
return "error in error handling";
} finally {
thread.err = errfunc;
}
}
return msg;
}
private Throwable cause;
/** 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) {
super( errorHook( addFileLine( "vm error: "+cause ) ) );
this.cause = cause;
this.traceback = DebugLib.traceback(1);
}
/**
* Construct a LuaError with a specific message.
*
* @param message message to supply
*/
public LuaError(String message) {
super( errorHook( addFileLine( message ) ) );
this.traceback = DebugLib.traceback(1);
}
/**
* 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
*/
public LuaError(String message, int level) {
super( errorHook( addFileLine( message, level ) ) );
this.traceback = DebugLib.traceback(1);
}
/**
* Add file and line info to a message at a particular level
* @param message the String message to use
* @param level where to supply line info from in call stack
* */
private static String addFileLine( String message, int level ) {
if ( message == null ) return null;
if ( level == 0 ) return message;
String fileline = DebugLib.fileline(level-1);
return fileline!=null? fileline+": "+message: message;
}
/** Add file and line info for the nearest enclosing closure
* @param message the String message to use
* */
private static String addFileLine( String message ) {
if ( message == null ) return null;
String fileline = DebugLib.fileline();
return fileline!=null? fileline+": "+message: message;
}
/** Print the message and stack trace */
public void printStackTrace() {
System.out.println( toString() );
if ( traceback != null )
System.out.println( traceback );
}
/**
* Get the cause, if any.
*/
public Throwable getCause() {
return cause;
}
}

View File

@@ -1,82 +0,0 @@
/*******************************************************************************
* 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;
/**
* Base class for functions implemented in Java.
* <p>
* Direct subclass include {@link 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 LibFunction
* @see LuaClosure
*/
abstract
public class LuaFunction extends LuaValue {
/** Shared static metatable for all functions and closures. */
public static LuaValue s_metatable;
protected LuaValue env;
public LuaFunction() {
this.env = NIL;
}
public LuaFunction(LuaValue env) {
this.env = env;
}
public int type() {
return TFUNCTION;
}
public String typename() {
return "function";
}
public boolean isfunction() {
return true;
}
public LuaValue checkfunction() {
return this;
}
public LuaFunction optfunction(LuaFunction defval) {
return this;
}
public LuaValue getmetatable() {
return s_metatable;
}
public LuaValue getfenv() {
return env;
}
public void setfenv(LuaValue env) {
this.env = env!=null? env: NIL;
}
}

View File

@@ -1,215 +0,0 @@
/*******************************************************************************
* 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;
}
public boolean isint() { return true; }
public boolean isinttype() { return true; }
public boolean islong() { return true; }
public byte tobyte() { return (byte) v; }
public char tochar() { return (char) v; }
public double todouble() { return v; }
public float tofloat() { return v; }
public int toint() { return v; }
public long tolong() { return v; }
public short toshort() { return (short) v; }
public double optdouble(double defval) { return v; }
public int optint(int defval) { return v; }
public LuaInteger optinteger(LuaInteger defval) { return this; }
public long optlong(long defval) { return v; }
public String tojstring() {
return Integer.toString(v);
}
public LuaString strvalue() {
return LuaString.valueOf(Integer.toString(v));
}
public LuaString optstring(LuaString defval) {
return LuaString.valueOf(Integer.toString(v));
}
public LuaValue tostring() {
return LuaString.valueOf(Integer.toString(v));
}
public String optjstring(String defval) {
return Integer.toString(v);
}
public LuaInteger checkinteger() {
return this;
}
public boolean isstring() {
return true;
}
public int hashCode() {
return v;
}
// unary operators
public LuaValue neg() { return valueOf(-(long)v); }
// object equality, used for key comparison
public boolean equals(Object o) { return o instanceof LuaInteger? ((LuaInteger)o).v == v: false; }
// equality w/ metatable processing
public LuaValue eq( LuaValue val ) { return val.raweq(v)? TRUE: FALSE; }
public boolean eq_b( LuaValue val ) { return val.raweq(v); }
// equality w/o metatable processing
public boolean raweq( LuaValue val ) { return val.raweq(v); }
public boolean raweq( double val ) { return v == val; }
public boolean raweq( int val ) { return v == val; }
// arithmetic operators
public LuaValue add( LuaValue rhs ) { return rhs.add(v); }
public LuaValue add( double lhs ) { return LuaDouble.valueOf(lhs + v); }
public LuaValue add( int lhs ) { return LuaInteger.valueOf(lhs + (long)v); }
public LuaValue sub( LuaValue rhs ) { return rhs.subFrom(v); }
public LuaValue sub( double rhs ) { return LuaDouble.valueOf(v - rhs); }
public LuaValue sub( int rhs ) { return LuaDouble.valueOf(v - rhs); }
public LuaValue subFrom( double lhs ) { return LuaDouble.valueOf(lhs - v); }
public LuaValue subFrom( int lhs ) { return LuaInteger.valueOf(lhs - (long)v); }
public LuaValue mul( LuaValue rhs ) { return rhs.mul(v); }
public LuaValue mul( double lhs ) { return LuaDouble.valueOf(lhs * v); }
public LuaValue mul( int lhs ) { return LuaInteger.valueOf(lhs * (long)v); }
public LuaValue pow( LuaValue rhs ) { return rhs.powWith(v); }
public LuaValue pow( double rhs ) { return MathLib.dpow(v,rhs); }
public LuaValue pow( int rhs ) { return MathLib.dpow(v,rhs); }
public LuaValue powWith( double lhs ) { return MathLib.dpow(lhs,v); }
public LuaValue powWith( int lhs ) { return MathLib.dpow(lhs,v); }
public LuaValue div( LuaValue rhs ) { return rhs.divInto(v); }
public LuaValue div( double rhs ) { return LuaDouble.ddiv(v,rhs); }
public LuaValue div( int rhs ) { return LuaDouble.ddiv(v,rhs); }
public LuaValue divInto( double lhs ) { return LuaDouble.ddiv(lhs,v); }
public LuaValue mod( LuaValue rhs ) { return rhs.modFrom(v); }
public LuaValue mod( double rhs ) { return LuaDouble.dmod(v,rhs); }
public LuaValue mod( int rhs ) { return LuaDouble.dmod(v,rhs); }
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
// relational operators
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? TRUE: FALSE; }
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( int rhs ) { return v < rhs; }
public boolean lt_b( double rhs ) { return v < rhs; }
public LuaValue lteq( LuaValue rhs ) { return rhs.gteq_b(v)? TRUE: FALSE; }
public LuaValue lteq( 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( int rhs ) { return v <= rhs; }
public boolean lteq_b( double rhs ) { return v <= rhs; }
public LuaValue gt( LuaValue rhs ) { return rhs.lt_b(v)? TRUE: FALSE; }
public LuaValue gt( 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( int rhs ) { return v > rhs; }
public boolean gt_b( double rhs ) { return v > rhs; }
public LuaValue gteq( LuaValue rhs ) { return rhs.lteq_b(v)? TRUE: FALSE; }
public LuaValue gteq( 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( int rhs ) { return v >= rhs; }
public boolean gteq_b( double rhs ) { return v >= rhs; }
// string comparison
public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; }
public int checkint() {
return v;
}
public long checklong() {
return v;
}
public double checkdouble() {
return v;
}
public String checkjstring() {
return String.valueOf(v);
}
public LuaString checkstring() {
return valueOf( String.valueOf(v) );
}
}

View File

@@ -1,104 +0,0 @@
/*******************************************************************************
* 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;
/**
* 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.
* <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.
* @see LuaValue
* @see LuaValue#NIL
*/
public class LuaNil extends LuaValue {
static final LuaNil _NIL = new LuaNil();
public static LuaValue s_metatable;
LuaNil() {}
public int type() {
return LuaValue.TNIL;
}
public String typename() {
return "nil";
}
public String tojstring() {
return "nil";
}
public LuaValue not() {
return LuaValue.TRUE;
}
public boolean toboolean() {
return false;
}
public boolean isnil() {
return true;
}
public LuaValue getmetatable() {
return s_metatable;
}
public boolean equals(Object o) {
return o instanceof LuaNil;
}
public LuaValue checknotnil() {
return argerror("value");
}
public LuaValue checkvalidkey() {
return typerror("table index");
}
// optional argument conversions - nil alwas falls badk to default value
public boolean optboolean(boolean defval) { return defval; }
public LuaClosure optclosure(LuaClosure defval) { return defval; }
public double optdouble(double defval) { return defval; }
public LuaFunction optfunction(LuaFunction defval) { return defval; }
public int optint(int defval) { return defval; }
public LuaInteger optinteger(LuaInteger defval) { return defval; }
public long optlong(long defval) { return defval; }
public LuaNumber optnumber(LuaNumber defval) { return defval; }
public LuaTable opttable(LuaTable defval) { return defval; }
public LuaThread optthread(LuaThread defval) { return defval; }
public String optjstring(String defval) { return defval; }
public LuaString optstring(LuaString defval) { return defval; }
public Object optuserdata(Object defval) { return defval; }
public Object optuserdata(Class c, Object defval) { return defval; }
public LuaValue optvalue(LuaValue defval) { return defval; }
}

View File

@@ -1,81 +0,0 @@
/*******************************************************************************
* 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;
/**
* 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.
* @see LuaInteger
* @see LuaDouble
* @see LuaValue
*
*/
abstract
public class LuaNumber extends LuaValue {
/** Shared static metatable for all number values represented in lua. */
public static LuaValue s_metatable;
public int type() {
return TNUMBER;
}
public String typename() {
return "number";
}
public LuaNumber checknumber() {
return this;
}
public LuaNumber checknumber(String errmsg) {
return this;
}
public LuaNumber optnumber(LuaNumber defval) {
return this;
}
public LuaValue tonumber() {
return this;
}
public boolean isnumber() {
return true;
}
public boolean isstring() {
return true;
}
public LuaValue getmetatable() {
return s_metatable;
}
public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
public LuaValue concatTo(LuaNumber lhs) { return strvalue().concatTo(lhs.strvalue()); }
public LuaValue concatTo(LuaString lhs) { return strvalue().concatTo(lhs); }
}

View File

@@ -1,749 +0,0 @@
/*******************************************************************************
* 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;
import java.io.ByteArrayInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.String;
import java.lang.ref.WeakReference;
import java.util.Hashtable;
import org.luaj.vm2.lib.MathLib;
import org.luaj.vm2.lib.StringLib;
/**
* Subclass of {@link LuaValue} for representing lua strings.
* <p>
* Because lua string values are more nearly sequences of bytes than
* sequences of characters or unicode code points, the {@link LuaString}
* implementation holds the string value in an internal byte array.
* <p>
* {@link LuaString} values are generally not mutable once constructed,
* so multiple {@link LuaString} values can chare a single byte array.
* <p>
* Currently {@link LuaString}s are pooled via a centrally managed weak table.
* To ensure that as many string values as possible take advantage of this,
* Constructors are not exposed directly. As with number, booleans, and nil,
* instance construction should be via {@link LuaValue#valueOf(byte[])} or similar API.
* <p>
* When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed.
* The functions
* {@link LuaString#lengthAsUtf8(char[]),
* {@link LuaString#encodeToUtf8(char[], byte[], int)}, and
* {@link LuaString#decodeAsUtf8(byte[], int, int)
* are used to convert back and forth between UTF8 byte arrays and character arrays.
*
* @see LuaValue
* @see LuaValue#valueOf(String)
* @see LuaValue#valueOf(byte[])
*/
public class LuaString extends LuaValue {
/** The singleton instance representing lua {@code true} */
public static LuaValue s_metatable;
/** The bytes for the string */
public final byte[] m_bytes;
/** The offset into the byte array, 0 means start at the first byte */
public final int m_offset;
/** The number of bytes that comprise this string */
public final int m_length;
private static final Hashtable index_java = new Hashtable();
private final static LuaString index_get(Hashtable indextable, Object key) {
WeakReference w = (WeakReference) indextable.get(key);
return w!=null? (LuaString) w.get(): null;
}
private final static void index_set(Hashtable indextable, Object key, LuaString value) {
indextable.put(key, new WeakReference(value));
}
/**
* Get a {@link LuaString} instance whose bytes match
* the supplied Java String using the UTF8 encoding.
* @param string Java String containing characters to encode as UTF8
* @return {@link LuaString} with UTF8 bytes corresponding to the supplied String
*/
public static LuaString valueOf(String string) {
LuaString s = index_get( index_java, string );
if ( s != null ) return s;
char[] c = string.toCharArray();
/* DAN200 START */
/*
byte[] b = new byte[lengthAsUtf8(c)];
encodeToUtf8(c, b, 0);
*/
byte[] b = new byte[c.length];
for( int i=0; i<b.length; ++i )
{
char ch = c[i];
b[i] = (ch < 256) ? (byte)ch : (byte)'?';
}
/* DAN200 END */
s = valueOf(b, 0, b.length);
index_set( index_java, string, s );
return s;
}
// TODO: should this be deprecated or made private?
/** Construct a {@link LuaString} around a byte array without copying the contents.
* <p>
* The array is used directly after this is called, so clients must not change contents.
* <p>
* @param bytes byte buffer
* @param off offset into the byte buffer
* @param len length of the byte buffer
* @return {@link LuaString} wrapping the byte buffer
*/
public static LuaString valueOf(byte[] bytes, int off, int len) {
return new LuaString(bytes, off, len);
}
/** Construct a {@link LuaString} using the supplied characters as byte values.
* <p>
* Only th elow-order 8-bits of each character are used, the remainder is ignored.
* <p>
* This is most useful for constructing byte sequences that do not conform to UTF8.
* @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array.
* @return {@link LuaString} wrapping a copy of the byte buffer
*/
public static LuaString valueOf(char[] bytes) {
int n = bytes.length;
byte[] b = new byte[n];
for ( int i=0; i<n; i++ )
b[i] = (byte) bytes[i];
return valueOf(b, 0, n);
}
/** Construct a {@link LuaString} around a byte array without copying the contents.
* <p>
* The array is used directly after this is called, so clients must not change contents.
* <p>
* @param bytes byte buffer
* @return {@link LuaString} wrapping the byte buffer
*/
public static LuaString valueOf(byte[] bytes) {
return valueOf(bytes, 0, bytes.length);
}
/** Construct a {@link LuaString} around a byte array without copying the contents.
* <p>
* The array is used directly after this is called, so clients must not change contents.
* <p>
* @param bytes byte buffer
* @param offset offset into the byte buffer
* @param length length of the byte buffer
* @return {@link LuaString} wrapping the byte buffer
*/
private LuaString(byte[] bytes, int offset, int length) {
this.m_bytes = bytes;
this.m_offset = offset;
this.m_length = length;
}
public boolean isstring() {
return true;
}
public LuaValue getmetatable() {
return s_metatable;
}
public int type() {
return LuaValue.TSTRING;
}
public String typename() {
return "string";
}
public String tojstring() {
/* DAN200 START */
/*
return decodeAsUtf8(m_bytes, m_offset, m_length);
*/
char[] chars = new char[ m_length ];
for( int i=0; i<chars.length; ++i )
{
chars[i] = (char)(m_bytes[ m_offset + i ] & 255);
}
return new String( chars );
/* DAN200 END */
}
// get is delegated to the string library
public LuaValue get(LuaValue key) {
return s_metatable!=null? gettable(this,key): StringLib.instance.get(key);
}
// unary operators
public LuaValue neg() { double d = scannumber(10); return Double.isNaN(d)? super.neg(): valueOf(-d); }
// basic binary arithmetic
public LuaValue add( LuaValue rhs ) { double d = scannumber(10); return Double.isNaN(d)? arithmt(ADD,rhs): rhs.add(d); }
public LuaValue add( double rhs ) { return valueOf( checkarith() + rhs ); }
public LuaValue add( int rhs ) { return valueOf( checkarith() + rhs ); }
public LuaValue sub( LuaValue rhs ) { double d = scannumber(10); return Double.isNaN(d)? arithmt(SUB,rhs): rhs.subFrom(d); }
public LuaValue sub( double rhs ) { return valueOf( checkarith() - rhs ); }
public LuaValue sub( int rhs ) { return valueOf( checkarith() - rhs ); }
public LuaValue subFrom( double lhs ) { return valueOf( lhs - checkarith() ); }
public LuaValue mul( LuaValue rhs ) { double d = scannumber(10); return Double.isNaN(d)? arithmt(MUL,rhs): rhs.mul(d); }
public LuaValue mul( double rhs ) { return valueOf( checkarith() * rhs ); }
public LuaValue mul( int rhs ) { return valueOf( checkarith() * rhs ); }
public LuaValue pow( LuaValue rhs ) { double d = scannumber(10); return Double.isNaN(d)? arithmt(POW,rhs): rhs.powWith(d); }
public LuaValue pow( double rhs ) { return MathLib.dpow(checkarith(),rhs); }
public LuaValue pow( int rhs ) { return MathLib.dpow(checkarith(),rhs); }
public LuaValue powWith( double lhs ) { return MathLib.dpow(lhs, checkarith()); }
public LuaValue powWith( int lhs ) { return MathLib.dpow(lhs, checkarith()); }
public LuaValue div( LuaValue rhs ) { double d = scannumber(10); return Double.isNaN(d)? arithmt(DIV,rhs): rhs.divInto(d); }
public LuaValue div( double rhs ) { return LuaDouble.ddiv(checkarith(),rhs); }
public LuaValue div( int rhs ) { return LuaDouble.ddiv(checkarith(),rhs); }
public LuaValue divInto( double lhs ) { return LuaDouble.ddiv(lhs, checkarith()); }
public LuaValue mod( LuaValue rhs ) { double d = scannumber(10); return Double.isNaN(d)? arithmt(MOD,rhs): rhs.modFrom(d); }
public LuaValue mod( double rhs ) { return LuaDouble.dmod(checkarith(), rhs); }
public LuaValue mod( int rhs ) { return LuaDouble.dmod(checkarith(), rhs); }
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 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 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 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 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; }
// concatenation
public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
public LuaValue concatTo(LuaNumber lhs) { return concatTo(lhs.strvalue()); }
public LuaValue concatTo(LuaString lhs) {
byte[] b = new byte[lhs.m_length+this.m_length];
System.arraycopy(lhs.m_bytes, lhs.m_offset, b, 0, lhs.m_length);
System.arraycopy(this.m_bytes, this.m_offset, b, lhs.m_length, this.m_length);
return new LuaString(b, 0, b.length);
}
// string comparison
public int strcmp(LuaValue lhs) { return -lhs.strcmp(this); }
public int strcmp(LuaString rhs) {
for ( int i=0, j=0; i<m_length && j<rhs.m_length; ++i, ++j ) {
if ( m_bytes[m_offset+i] != rhs.m_bytes[rhs.m_offset+j] ) {
return ((int)m_bytes[m_offset+i]) - ((int) rhs.m_bytes[rhs.m_offset+j]);
}
}
return m_length - rhs.m_length;
}
/** Check for number in arithmetic, or throw aritherror */
private double checkarith() {
double d = scannumber(10);
if ( Double.isNaN(d) )
aritherror();
return d;
}
public int checkint() {
return (int) (long) checkdouble();
}
public LuaInteger checkinteger() {
return valueOf(checkint());
}
public long checklong() {
return (long) checkdouble();
}
public double checkdouble() {
double d = scannumber(10);
if ( Double.isNaN(d) )
argerror("number");
return d;
}
public LuaNumber checknumber() {
return valueOf(checkdouble());
}
public LuaNumber checknumber(String msg) {
double d = scannumber(10);
if ( Double.isNaN(d) )
error(msg);
return valueOf(d);
}
public LuaValue tonumber() {
return tonumber(10);
}
public boolean isnumber() {
double d = scannumber(10);
return ! Double.isNaN(d);
}
public boolean isint() {
double d = scannumber(10);
if ( Double.isNaN(d) )
return false;
int i = (int) d;
return i == d;
}
public boolean islong() {
double d = scannumber(10);
if ( Double.isNaN(d) )
return false;
long l = (long) d;
return l == d;
}
public byte tobyte() { return (byte) toint(); }
public char tochar() { return (char) toint(); }
public double todouble() { double d=scannumber(10); return Double.isNaN(d)? 0: d; }
public float tofloat() { return (float) todouble(); }
public int toint() { return (int) tolong(); }
public long tolong() { return (long) todouble(); }
public short toshort() { return (short) toint(); }
public double optdouble(double defval) {
return checknumber().checkdouble();
}
public int optint(int defval) {
return checknumber().checkint();
}
public LuaInteger optinteger(LuaInteger defval) {
return checknumber().checkinteger();
}
public long optlong(long defval) {
return checknumber().checklong();
}
public LuaNumber optnumber(LuaNumber defval) {
return checknumber().checknumber();
}
public LuaString optstring(LuaString defval) {
return this;
}
public LuaValue tostring() {
return this;
}
public String optjstring(String defval) {
return tojstring();
}
public LuaString strvalue() {
return this;
}
public LuaString substring( int beginIndex, int endIndex ) {
return new LuaString( m_bytes, m_offset + beginIndex, endIndex - beginIndex );
}
public int hashCode() {
int h = m_length; /* seed */
int step = (m_length>>5)+1; /* if string is too long, don't hash all its chars */
for (int l1=m_length; l1>=step; l1-=step) /* compute hash */
h = h ^ ((h<<5)+(h>>2)+(((int) m_bytes[m_offset+l1-1] ) & 0x0FF ));
return h;
}
// object comparison, used in key comparison
public boolean equals( Object o ) {
if ( o instanceof LuaString ) {
return raweq( (LuaString) o );
}
return false;
}
// equality w/ metatable processing
public LuaValue eq( LuaValue val ) { return val.raweq(this)? TRUE: FALSE; }
public boolean eq_b( LuaValue val ) { return val.raweq(this); }
// equality w/o metatable processing
public boolean raweq( LuaValue val ) {
return val.raweq(this);
}
public boolean raweq( LuaString s ) {
if ( this == s )
return true;
if ( s.m_length != m_length )
return false;
if ( s.m_bytes == m_bytes && s.m_offset == m_offset )
return true;
if ( s.hashCode() != hashCode() )
return false;
for ( int i=0; i<m_length; i++ )
if ( s.m_bytes[s.m_offset+i] != m_bytes[m_offset+i] )
return false;
return true;
}
public static boolean equals( LuaString a, int i, LuaString b, int j, int n ) {
return equals( a.m_bytes, a.m_offset + i, b.m_bytes, b.m_offset + j, n );
}
public static boolean equals( byte[] a, int i, byte[] b, int j, int n ) {
if ( a.length < i + n || b.length < j + n )
return false;
while ( --n>=0 )
if ( a[i++]!=b[j++] )
return false;
return true;
}
public void write(DataOutputStream writer, int i, int len) throws IOException {
writer.write(m_bytes,m_offset+i,len);
}
public LuaValue len() {
return LuaInteger.valueOf(m_length);
}
public int length() {
return m_length;
}
public int luaByte(int index) {
return m_bytes[m_offset + index] & 0x0FF;
}
public int charAt( int index ) {
if ( index < 0 || index >= m_length )
throw new IndexOutOfBoundsException();
return luaByte( index );
}
public String checkjstring() {
return tojstring();
}
public LuaString checkstring() {
return this;
}
/** Convert value to an input stream.
*
* @return {@link InputStream} whose data matches the bytes in this {@link LuaString}
*/
public InputStream toInputStream() {
return new ByteArrayInputStream(m_bytes, m_offset, m_length);
}
/**
* Copy the bytes of the string into the given byte array.
* @param strOffset offset from which to copy
* @param bytes destination byte array
* @param arrayOffset offset in destination
* @param len number of bytes to copy
*/
public void copyInto( int strOffset, byte[] bytes, int arrayOffset, int len ) {
System.arraycopy( m_bytes, m_offset+strOffset, bytes, arrayOffset, len );
}
/** Java version of strpbrk - find index of any byte that in an accept string.
* @param accept {@link LuaString} containing characters to look for.
* @return index of first match in the {@code accept} string, or -1 if not found.
*/
public int indexOfAny( LuaString accept ) {
final int ilimit = m_offset + m_length;
final int jlimit = accept.m_offset + accept.m_length;
for ( int i = m_offset; i < ilimit; ++i ) {
for ( int j = accept.m_offset; j < jlimit; ++j ) {
if ( m_bytes[i] == accept.m_bytes[j] ) {
return i - m_offset;
}
}
}
return -1;
}
/**
* Find the index of a byte starting at a point in this string
* @param b the byte to look for
* @param start the first index in the string
* @return index of first match found, or -1 if not found.
*/
public int indexOf( byte b, int start ) {
for ( int i=0, j=m_offset+start; i < m_length; ++i ) {
if ( m_bytes[j++] == b )
return i;
}
return -1;
}
/**
* Find the index of a string starting at a point in this string
* @param s the string to search for
* @param start the first index in the string
* @return index of first match found, or -1 if not found.
*/
public int indexOf( LuaString s, int start ) {
final int slen = s.length();
final int limit = m_offset + m_length - slen;
for ( int i = m_offset + start; i <= limit; ++i ) {
if ( equals( m_bytes, i, s.m_bytes, s.m_offset, slen ) ) {
/* DAN200 START */
//return i;
return i - m_offset;
/* DAN200 END */
}
}
return -1;
}
/**
* Find the last index of a string in this string
* @param s the string to search for
* @return index of last match found, or -1 if not found.
*/
public int lastIndexOf( LuaString s ) {
final int slen = s.length();
final int limit = m_offset + m_length - slen;
for ( int i = limit; i >= m_offset; --i ) {
if ( equals( m_bytes, i, s.m_bytes, s.m_offset, slen ) ) {
/* DAN200 START */
//return i;
return i - m_offset;
/* DAN200 END */
}
}
return -1;
}
/**
* Convert to Java String interpreting as utf8 characters.
*
* @param bytes byte array in UTF8 encoding to convert
* @param offset starting index in byte array
* @param length number of bytes to convert
* @return Java String corresponding to the value of bytes interpreted using UTF8
* @see #lengthAsUtf8(char[])
* @see #encodeToUtf8(char[], byte[], int)
* @see #isValidUtf8()
*/
/* DAN200 START */
//public static String decodeAsUtf8(byte[] bytes, int offset, int length) {
private static String decodeAsUtf8(byte[] bytes, int offset, int length) {
/* DAN200 END */
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;
}
}
char[] chars=new char[n];
for ( i=offset,j=offset+length,n=0; i<j; ) {
chars[n++] = (char) (
((b=bytes[i++])>=0||i>=j)? b:
(b<-32||i+1>=j)? (((b&0x3f) << 6) | (bytes[i++]&0x3f)):
(((b&0xf) << 12) | ((bytes[i++]&0x3f)<<6) | (bytes[i++]&0x3f)));
}
return new String(chars);
}
/**
* Count the number of bytes required to encode the string as UTF-8.
* @param chars Array of unicode characters to be encoded as UTF-8
* @return count of bytes needed to encode using UTF-8
* @see #encodeToUtf8(char[], byte[], int)
* @see #decodeAsUtf8(byte[], int, int)
* @see #isValidUtf8()
*/
/* DAN200 START */
//public static int lengthAsUtf8(char[] chars) {
private static int lengthAsUtf8(char[] chars) {
/* DAN200 END */
int i,b;
char c;
for ( i=b=chars.length; --i>=0; )
if ( (c=chars[i]) >=0x80 )
b += (c>=0x800)? 2: 1;
return b;
}
/**
* Encode the given Java string as UTF-8 bytes, writing the result to bytes
* starting at offset.
* <p>
* The string should be measured first with lengthAsUtf8
* to make sure the given byte array is large enough.
* @param chars Array of unicode characters to be encoded as UTF-8
* @param bytes byte array to hold the result
* @param off offset into the byte array to start writing
* @see #lengthAsUtf8(char[])
* @see #decodeAsUtf8(byte[], int, int)
* @see #isValidUtf8()
*/
/* DAN200 START */
//public static void encodeToUtf8(char[] chars, byte[] bytes, int off) {
private static void encodeToUtf8(char[] chars, byte[] bytes, int off) {
/* DAN200 END */
final int n = chars.length;
char c;
for ( int i=0, j=off; i<n; i++ ) {
if ( (c = chars[i]) < 0x80 ) {
bytes[j++] = (byte) c;
} else if ( c < 0x800 ) {
bytes[j++] = (byte) (0xC0 | ((c>>6) & 0x1f));
bytes[j++] = (byte) (0x80 | ( c & 0x3f));
} else {
bytes[j++] = (byte) (0xE0 | ((c>>12) & 0x0f));
bytes[j++] = (byte) (0x80 | ((c>>6) & 0x3f));
bytes[j++] = (byte) (0x80 | ( c & 0x3f));
}
}
}
/** Check that a byte sequence is valid UTF-8
* @return true if it is valid UTF-8, otherwise false
* @see #lengthAsUtf8(char[])
* @see #encodeToUtf8(char[], byte[], int)
* @see #decodeAsUtf8(byte[], int, int)
*/
public boolean isValidUtf8() {
int i,j,n,b,e=0;
for ( i=m_offset,j=m_offset+m_length,n=0; i<j; ++n ) {
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;
return false;
}
return true;
}
// --------------------- number conversion -----------------------
/**
* convert to a number using a supplied base, or NIL if it can't be converted
* @param base the base to use, such as 10
* @return IntValue, DoubleValue, or NIL depending on the content of the string.
* @see LuaValue#tonumber()
*/
public LuaValue tonumber( int base ) {
double d = scannumber( base );
return Double.isNaN(d)? NIL: valueOf(d);
}
/**
* Convert to a number in a base, or return Double.NaN if not a number.
* @param base the base to use, such as 10
* @return double value if conversion is valid, or Double.NaN if not
*/
public double scannumber( int base ) {
if ( base >= 2 && base <= 36 ) {
int i=m_offset,j=m_offset+m_length;
while ( i<j && m_bytes[i]==' ' ) ++i;
while ( i<j && m_bytes[j-1]==' ' ) --j;
if ( i>=j )
return Double.NaN;
if ( ( base == 10 || base == 16 ) && ( m_bytes[i]=='0' && i+1<j && (m_bytes[i+1]=='x'||m_bytes[i+1]=='X') ) ) {
base = 16;
i+=2;
}
double l = scanlong( base, i, j );
return Double.isNaN(l) && base==10? scandouble(i,j): l;
}
return Double.NaN;
}
/**
* Scan and convert a long value, or return Double.NaN if not found.
* @param base the base to use, such as 10
* @param start the index to start searching from
* @param end the first index beyond the search range
* @return double value if conversion is valid,
* or Double.NaN if not
*/
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++ ) {
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 )
return Double.NaN;
x = x * base + digit;
}
return neg? -x: x;
}
/**
* Scan and convert a double value, or return Double.NaN if not a double.
* @param start the index to start searching from
* @param end the first index beyond the search range
* @return double value if conversion is valid,
* or Double.NaN if not
*/
private double scandouble(int start, int end) {
if ( end>start+64 ) end=start+64;
for ( int i=start; i<end; i++ ) {
switch ( m_bytes[i] ) {
case '-':
case '+':
case '.':
case 'e': case 'E':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
break;
default:
return Double.NaN;
}
}
char [] c = new char[end-start];
for ( int i=start; i<end; i++ )
c[i-start] = (char) m_bytes[i];
try {
return Double.parseDouble(new String(c));
} catch ( Exception e ) {
return Double.NaN;
}
}
}

View File

@@ -1,718 +0,0 @@
/*******************************************************************************
* 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.util.Vector;
/**
* Subclass of {@link LuaValue} for representing lua tables.
* <p>
* Almost all API's implemented in {@link LuaTable} are defined and documented in {@link LuaValue}.
* <p>
* If a table is needed, the one of the type-checking functions can be used such as
* {@link #istable()},
* {@link #checktable()}, or
* {@link #opttable(LuaTable)}
* <p>
* The main table operations are defined on {@link LuaValue}
* for getting and setting values with and without metatag processing:
* <ul>
* <li>{@link #get(LuaValue)}</li>
* <li>{@link #set(LuaValue,LuaValue)}</li>
* <li>{@link #rawget(LuaValue)}</li>
* <li>{@link #rawset(LuaValue,LuaValue)}</li>
* <li>plus overloads such as {@link #get(String)}, {@link #get(int)}, and so on</li>
* </ul>
* <p>
* To iterate over key-value pairs from Java, use
* <pre> {@code
* LuaValue k = LuaValue.NIL;
* while ( true ) {
* Varargs n = table.next(k);
* if ( (k = n.arg1()).isnil() )
* break;
* LuaValue v = n.arg(2)
* process( k, v )
* }}</pre>
*
* <p>
* As with other types, {@link LuaTable} instances should be constructed via one of the table constructor
* methods on {@link LuaValue}:
* <ul>
* <li>{@link LuaValue#tableOf()} empty table</li>
* <li>{@link LuaValue#tableOf(int, int)} table with capacity</li>
* <li>{@link LuaValue#listOf(LuaValue[])} initialize array part</li>
* <li>{@link LuaValue#listOf(LuaValue[], Varargs)} initialize array part</li>
* <li>{@link LuaValue#tableOf(LuaValue[])} initialize named hash part</li>
* <li>{@link LuaValue#tableOf(Varargs, int)} initialize named hash part</li>
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[])} initialize array and named parts</li>
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[], Varargs)} initialize array and named parts</li>
* </ul>
* @see LuaValue
*/
public class LuaTable extends LuaValue {
private static final int MIN_HASH_CAPACITY = 2;
private static final LuaString N = valueOf("n");
/** the array values */
protected LuaValue[] array;
/** the hash keys */
protected LuaValue[] hashKeys;
/** the hash values */
protected LuaValue[] hashValues;
/** the number of hash entries */
protected int hashEntries;
/** metatable for this table, or null */
protected LuaValue m_metatable;
/** Construct empty table */
public LuaTable() {
array = NOVALS;
hashKeys = NOVALS;
hashValues = NOVALS;
}
/**
* Construct table with preset capacity.
* @param narray capacity of array part
* @param nhash capacity of hash part
*/
public LuaTable(int narray, int nhash) {
presize(narray, nhash);
}
/**
* Construct table with named and unnamed parts.
* @param named Named elements in order {@code key-a, value-a, key-b, value-b, ... }
* @param unnamed Unnamed elements in order {@code value-1, value-2, ... }
* @param lastarg Additional unnamed values beyond {@code unnamed.length}
*/
public LuaTable(LuaValue[] named, LuaValue[] unnamed, Varargs lastarg) {
int nn = (named!=null? named.length: 0);
int nu = (unnamed!=null? unnamed.length: 0);
int nl = (lastarg!=null? lastarg.narg(): 0);
presize(nu+nl, nn-(nn>>1));
for ( int i=0; i<nu; i++ )
rawset(i+1,unnamed[i]);
if ( lastarg != null )
for ( int i=1,n=lastarg.narg(); i<=n; ++i )
rawset(nu+i,lastarg.arg(i));
for ( int i=0; i<nn; i+=2 )
if (!named[i+1].isnil())
rawset(named[i], named[i+1]);
}
/**
* Construct table of unnamed elements.
* @param varargs Unnamed elements in order {@code value-1, value-2, ... }
*/
public LuaTable(Varargs varargs) {
this(varargs,1);
}
/**
* Construct table of unnamed elements.
* @param varargs Unnamed elements in order {@code value-1, value-2, ... }
* @param firstarg the index in varargs of the first argument to include in the table
*/
public LuaTable(Varargs varargs, int firstarg) {
int nskip = firstarg-1;
int n = Math.max(varargs.narg()-nskip,0);
presize( n, 1 );
set(N, valueOf(n));
for ( int i=1; i<=n; i++ )
set(i, varargs.arg(i+nskip));
}
public int type() {
return LuaValue.TTABLE;
}
public String typename() {
return "table";
}
public boolean istable() {
return true;
}
public LuaTable checktable() {
return this;
}
public LuaTable opttable(LuaTable defval) {
return this;
}
public void presize( int narray ) {
if ( narray > array.length )
array = resize( array, narray );
}
public void presize(int narray, int nhash) {
if ( nhash > 0 && nhash < MIN_HASH_CAPACITY )
nhash = MIN_HASH_CAPACITY;
array = (narray>0? new LuaValue[narray]: NOVALS);
hashKeys = (nhash>0? new LuaValue[nhash]: NOVALS);
hashValues = (nhash>0? new LuaValue[nhash]: NOVALS);
hashEntries = 0;
}
/** Resize the table */
private static LuaValue[] resize( LuaValue[] old, int n ) {
LuaValue[] v = new LuaValue[n];
System.arraycopy(old, 0, v, 0, old.length);
return v;
}
/**
* Get the length of the array part of the table.
* @return length of the array part, does not relate to count of objects in the table.
*/
protected int getArrayLength() {
return array.length;
}
/**
* Get the length of the hash part of the table.
* @return length of the hash part, does not relate to count of objects in the table.
*/
protected int getHashLength() {
return hashValues.length;
}
public LuaValue getmetatable() {
return m_metatable;
}
public LuaValue setmetatable(LuaValue metatable) {
m_metatable = metatable;
LuaValue mode;
if ( m_metatable!=null && (mode=m_metatable.rawget(MODE)).isstring() ) {
String m = mode.tojstring();
boolean k = m.indexOf('k')>=0;
boolean v = m.indexOf('v')>=0;
return changemode(k,v);
}
return this;
}
/**
* Change the mode of a table
* @param weakkeys true to make the table have weak keys going forward
* @param weakvalues true to make the table have weak values going forward
* @return {@code this} or a new {@link WeakTable} if the mode change requires copying.
*/
protected LuaTable changemode(boolean weakkeys, boolean weakvalues) {
if ( weakkeys || weakvalues )
return new WeakTable(weakkeys, weakvalues, this);
return this;
}
public LuaValue get( int key ) {
LuaValue v = rawget(key);
return v.isnil() && m_metatable!=null? gettable(this,valueOf(key)): v;
}
public LuaValue get( LuaValue key ) {
LuaValue v = rawget(key);
return v.isnil() && m_metatable!=null? gettable(this,key): v;
}
public LuaValue rawget( int key ) {
if ( key>0 && key<=array.length )
return array[key-1]!=null? array[key-1]: NIL;
return hashget( LuaInteger.valueOf(key) );
}
public LuaValue rawget( LuaValue key ) {
if ( key.isinttype() ) {
int ikey = key.toint();
if ( ikey>0 && ikey<=array.length )
return array[ikey-1]!=null? array[ikey-1]: NIL;
}
return hashget( key );
}
protected LuaValue hashget(LuaValue key) {
if ( hashEntries > 0 ) {
LuaValue v = hashValues[hashFindSlot(key)];
return v!=null? v: NIL;
}
return NIL;
}
public void set( int key, LuaValue value ) {
if ( m_metatable==null || ! rawget(key).isnil() || ! settable(this,LuaInteger.valueOf(key),value) )
rawset(key, value);
}
/** caller must ensure key is not nil */
public void set( LuaValue key, LuaValue value ) {
key.checkvalidkey();
if ( m_metatable==null || ! rawget(key).isnil() || ! settable(this,key,value) )
rawset(key, value);
}
public void rawset( int key, LuaValue value ) {
if ( ! arrayset(key, value) )
hashset( LuaInteger.valueOf(key), value );
}
/** caller must ensure key is not nil */
public void rawset( LuaValue key, LuaValue value ) {
if ( !key.isinttype() || !arrayset(key.toint(), value) )
hashset( key, value );
}
/** Set an array element */
private boolean arrayset( int key, LuaValue value ) {
if ( key>0 && key<=array.length ) {
array[key-1] = (value.isnil()? null: value);
return true;
} else if ( key==array.length+1 && !value.isnil() ) {
expandarray();
array[key-1] = value;
return true;
}
return false;
}
/** Expand the array part */
private void expandarray() {
int n = array.length;
int m = Math.max(2,n*2);
array = resize(array, m);
for ( int i=n; i<m; i++ ) {
LuaValue k = LuaInteger.valueOf(i+1);
LuaValue v = hashget(k);
if ( !v.isnil() ) {
hashset(k, NIL);
array[i] = v;
}
}
}
/** Remove the element at a position in a list-table
*
* @param pos the position to remove
* @return The removed item, or {@link #NONE} if not removed
*/
public LuaValue remove(int pos) {
int n = length();
if ( pos == 0 )
pos = n;
else if (pos > n)
return NONE;
LuaValue v = rawget(pos);
for ( LuaValue r=v; !r.isnil(); ) {
r = rawget(pos+1);
rawset(pos++, r);
}
return v.isnil()? NONE: v;
}
/** Insert an element at a position in a list-table
*
* @param pos the position to remove
* @param value The value to insert
*/
public void insert(int pos, LuaValue value) {
if ( pos == 0 )
pos = length()+1;
while ( ! value.isnil() ) {
LuaValue v = rawget( pos );
rawset(pos++, value);
value = v;
}
}
/** Concatenate the contents of a table efficiently, using {@link Buffer}
*
* @param sep {@link LuaString} separater to apply between elements
* @param i the first element index
* @param j the last element index, inclusive
* @return {@link LuaString} value of the concatenation
*/
public LuaValue concat(LuaString sep, int i, int j) {
Buffer sb = new Buffer ();
if ( i<=j ) {
sb.append( get(i).checkstring() );
while ( ++i<=j ) {
sb.append( sep );
sb.append( get(i).checkstring() );
}
}
return sb.tostring();
}
public LuaValue getn() {
for ( int n=getArrayLength(); n>0; --n )
if ( !rawget(n).isnil() )
return LuaInteger.valueOf(n);
return ZERO;
}
public int length() {
int a = getArrayLength();
int n = a+1,m=0;
while ( !rawget(n).isnil() ) {
m = n;
n += a+getHashLength()+1;
}
while ( n > m+1 ) {
int k = (n+m) / 2;
if ( !rawget(k).isnil() )
m = k;
else
n = k;
}
return m;
}
public LuaValue len() {
return LuaInteger.valueOf(length());
}
/** Return table.maxn() as defined by lua 5.0.
* <p>
* Provided for compatibility, not a scalable operation.
* @return value for maxn
*/
public int maxn() {
int n = 0;
for ( int i=0; i<array.length; i++ )
if ( array[i] != null )
n = i+1;
for ( int i=0; i<hashKeys.length; i++ ) {
LuaValue v = hashKeys[i];
if ( v!=null && v.isinttype() ) {
int key = v.toint();
if ( key > n )
n = key;
}
}
return n;
}
/**
* Get the next element after a particular key in the table
* @return key,value or nil
*/
public Varargs next( LuaValue key ) {
int i = 0;
do {
// find current key index
if ( ! key.isnil() ) {
if ( key.isinttype() ) {
i = key.toint();
if ( i>0 && i<=array.length ) {
if ( array[i-1] == null )
error( "invalid key to 'next'" );
break;
}
}
if ( hashKeys.length == 0 )
error( "invalid key to 'next'" );
i = hashFindSlot(key);
if ( hashKeys[i] == null )
error( "invalid key to 'next'" );
i += 1+array.length;
}
} while ( false );
// check array part
for ( ; i<array.length; ++i )
if ( array[i] != null )
return varargsOf(LuaInteger.valueOf(i+1),array[i]);
// check hash part
for ( i-=array.length; i<hashKeys.length; ++i )
if ( hashKeys[i] != null )
return varargsOf(hashKeys[i],hashValues[i]);
// nothing found, push nil, return nil.
return NIL;
}
/**
* Get the next element after a particular key in the
* contiguous array part of a table
* @return key,value or none
*/
public Varargs inext(LuaValue key) {
int k = key.checkint() + 1;
LuaValue v = rawget(k);
return v.isnil()? NONE: varargsOf(LuaInteger.valueOf(k),v);
}
/**
* Call the supplied function once for each key-value pair
*
* @param func function to call
*/
public LuaValue foreach(LuaValue func) {
Varargs n;
LuaValue k = NIL;
LuaValue v;
while ( !(k = ((n = next(k)).arg1())).isnil() )
if ( ! (v = func.call(k, n.arg(2))).isnil() )
return v;
return NIL;
}
/**
* Call the supplied function once for each key-value pair
* in the contiguous array part
*
* @param func
*/
public LuaValue foreachi(LuaValue func) {
LuaValue v,r;
for ( int k=0; !(v = rawget(++k)).isnil(); )
if ( ! (r = func.call(valueOf(k), v)).isnil() )
return r;
return NIL;
}
/**
* Set a hashtable value
* @param key key to set
* @param value value to set
*/
public void hashset(LuaValue key, LuaValue value) {
if ( value.isnil() )
hashRemove(key);
else {
if ( hashKeys.length == 0 ) {
hashKeys = new LuaValue[ MIN_HASH_CAPACITY ];
hashValues = new LuaValue[ MIN_HASH_CAPACITY ];
}
int slot = hashFindSlot( key );
if ( hashFillSlot( slot, value ) )
return;
hashKeys[slot] = key;
hashValues[slot] = value;
if ( checkLoadFactor() )
rehash();
}
}
/**
* Find the hashtable slot to use
* @param key key to look for
* @return slot to use
*/
public int hashFindSlot(LuaValue key) {
int i = ( key.hashCode() & 0x7FFFFFFF ) % hashKeys.length;
// This loop is guaranteed to terminate as long as we never allow the
// table to get 100% full.
LuaValue k;
while ( ( k = hashKeys[i] ) != null && !k.raweq(key) ) {
i = ( i + 1 ) % hashKeys.length;
}
return i;
}
private boolean hashFillSlot( int slot, LuaValue value ) {
hashValues[ slot ] = value;
if ( hashKeys[ slot ] != null ) {
return true;
} else {
++hashEntries;
return false;
}
}
private void hashRemove( LuaValue key ) {
if ( hashKeys.length > 0 ) {
int slot = hashFindSlot( key );
hashClearSlot( slot );
}
}
/**
* Clear a particular slot in the table
* @param i slot to clear.
*/
protected void hashClearSlot( int i ) {
if ( hashKeys[ i ] != null ) {
int j = i;
int n = hashKeys.length;
while ( hashKeys[ j = ( ( j + 1 ) % n ) ] != null ) {
final int k = ( ( hashKeys[ j ].hashCode() )& 0x7FFFFFFF ) % n;
if ( ( j > i && ( k <= i || k > j ) ) ||
( j < i && ( k <= i && k > j ) ) ) {
hashKeys[ i ] = hashKeys[ j ];
hashValues[ i ] = hashValues[ j ];
i = j;
}
}
--hashEntries;
hashKeys[ i ] = null;
hashValues[ i ] = null;
if ( hashEntries == 0 ) {
hashKeys = NOVALS;
hashValues = NOVALS;
}
}
}
private boolean checkLoadFactor() {
// Using a load factor of (n+1) >= 7/8 because that is easy to compute without
// overflow or division.
final int hashCapacity = hashKeys.length;
return hashEntries >= (hashCapacity - (hashCapacity>>3));
}
private void rehash() {
final int oldCapacity = hashKeys.length;
final int newCapacity = oldCapacity+(oldCapacity>>2)+MIN_HASH_CAPACITY;
final LuaValue[] oldKeys = hashKeys;
final LuaValue[] oldValues = hashValues;
hashKeys = new LuaValue[ newCapacity ];
hashValues = new LuaValue[ newCapacity ];
for ( int i = 0; i < oldCapacity; ++i ) {
final LuaValue k = oldKeys[i];
if ( k != null ) {
final LuaValue v = oldValues[i];
final int slot = hashFindSlot( k );
hashKeys[slot] = k;
hashValues[slot] = v;
}
}
}
// ----------------- sort support -----------------------------
//
// implemented heap sort from wikipedia
//
// Only sorts the contiguous array part.
//
/** Sort the table using a comparator.
* @param comparator {@link LuaValue} to be called to compare elements.
*/
public void sort(LuaValue comparator) {
int n = array.length;
while ( n > 0 && array[n-1] == null )
--n;
if ( n > 1 )
heapSort(n, comparator);
}
private void heapSort(int count, LuaValue cmpfunc) {
heapify(count, cmpfunc);
for ( int end=count-1; end>0; ) {
swap(end, 0);
siftDown(0, --end, cmpfunc);
}
}
private void heapify(int count, LuaValue cmpfunc) {
for ( int start=count/2-1; start>=0; --start )
siftDown(start, count - 1, cmpfunc);
}
private void siftDown(int start, int end, LuaValue cmpfunc) {
for ( int root=start; root*2+1 <= end; ) {
int child = root*2+1;
if (child < end && compare(child, child + 1, cmpfunc))
++child;
if (compare(root, child, cmpfunc)) {
swap(root, child);
root = child;
} else
return;
}
}
private boolean compare(int i, int j, LuaValue cmpfunc) {
LuaValue a = array[i];
LuaValue b = array[j];
if ( a == null || b == null )
return false;
if ( ! cmpfunc.isnil() ) {
return cmpfunc.call(a,b).toboolean();
} else {
return a.lt_b(b);
}
}
private void swap(int i, int j) {
LuaValue a = array[i];
array[i] = array[j];
array[j] = a;
}
/** This may be deprecated in a future release.
* It is recommended to count via iteration over next() instead
* @return count of keys in the table
* */
public int keyCount() {
LuaValue k = LuaValue.NIL;
for ( int i=0; true; i++ ) {
Varargs n = next(k);
if ( (k = n.arg1()).isnil() )
return i;
}
}
/** This may be deprecated in a future release.
* It is recommended to use next() instead
* @return array of keys in the table
* */
public LuaValue[] keys() {
Vector l = new Vector();
LuaValue k = LuaValue.NIL;
while ( true ) {
Varargs n = next(k);
if ( (k = n.arg1()).isnil() )
break;
l.addElement( k );
}
LuaValue[] a = new LuaValue[l.size()];
l.copyInto(a);
return a;
}
// equality w/ metatable processing
public LuaValue eq( LuaValue val ) { return eq_b(val)? TRUE: FALSE; }
public boolean eq_b( LuaValue val ) {
if ( this == val ) return true;
if ( m_metatable == null || !val.istable() ) return false;
LuaValue valmt = val.getmetatable();
return valmt!=null && LuaValue.eqmtcall(this, m_metatable, val, valmt);
}
}

View File

@@ -1,433 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007-2012 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.
******************************************************************************/
package org.luaj.vm2;
/* DAN200 START */
import java.lang.ref.WeakReference;
import java.util.Enumeration;
import java.util.Vector;
/* DAN200 END */
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.DebugLib;
/**
* 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 a call to {@link #setGlobals(LuaValue)}
* at some point during globals initialization.
* See {@link BaseLib} for additional documentation and example code.
* <p>
* The utility classes {@link JsePlatform} and {@link JmePlatform}
* see to it that this initialization is done properly.
* For this reason it is highly recommended to use one of these classes
* when initializing globals.
* <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.
* <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.
*
* @see LuaValue
* @see JsePlatform
* @see JmePlatform
* @see CoroutineLib
*/
public class LuaThread extends LuaValue {
public static LuaValue s_metatable;
public static int coroutine_count = 0;
/** Interval at which to check for lua threads that are no longer referenced.
* This can be changed by Java startup code if desired.
*/
static long thread_orphan_check_interval = 30000;
private static final int STATUS_INITIAL = 0;
private static final int STATUS_SUSPENDED = 1;
private static final int STATUS_RUNNING = 2;
private static final int STATUS_NORMAL = 3;
private static final int STATUS_DEAD = 4;
private static final String[] STATUS_NAMES = {
"suspended",
"suspended",
"running",
"normal",
"dead",};
private LuaValue env;
private final State state;
/** Field to hold state of error condition during debug hook function calls. */
public LuaValue err;
final CallStack callstack = new CallStack();
public static final int MAX_CALLSTACK = 256;
private static final LuaThread main_thread = new LuaThread();
// state of running thread including call stack
private static LuaThread running_thread = main_thread;
/** Interval to check for LuaThread dereferencing. */
public static int GC_INTERVAL = 30000;
/** Thread-local used by DebugLib to store debugging state. */
public Object debugState;
/* DAN200 START */
private Vector children = new Vector();
/* DAN200 END */
/** Private constructor for main thread only */
private LuaThread() {
state = new State(this, null);
state.status = STATUS_RUNNING;
}
/**
* Create a LuaThread around a function and environment
* @param func The function to execute
* @param env The environment to apply to the thread
*/
public LuaThread(LuaValue func, LuaValue env) {
LuaValue.assert_(func != null, "function cannot be null");
this.env = env;
state = new State(this, func);
}
public int type() {
return LuaValue.TTHREAD;
}
public String typename() {
return "thread";
}
public boolean isthread() {
return true;
}
public LuaThread optthread(LuaThread defval) {
return this;
}
public LuaThread checkthread() {
return this;
}
public LuaValue getmetatable() {
return s_metatable;
}
public LuaValue getfenv() {
return env;
}
public void setfenv(LuaValue env) {
this.env = env;
}
public String getStatus() {
return STATUS_NAMES[state.status];
}
/**
* Get the currently running thread.
* @return {@link LuaThread} that is currenly running
*/
public static LuaThread getRunning() {
return running_thread;
}
/**
* Test if this is the main thread
* @return true if this is the main thread
*/
public static boolean isMainThread(LuaThread r) {
return r == main_thread;
}
/**
* Set the globals of the current thread.
* <p>
* This must be done once before any other code executes.
* @param globals The global variables for the main ghread.
*/
public static void setGlobals(LuaValue globals) {
running_thread.env = globals;
}
/** Get the current thread's environment
* @return {@link LuaValue} containing the global variables of the current thread.
*/
public static LuaValue getGlobals() {
LuaValue e = running_thread.env;
return e!=null? e: LuaValue.error("LuaThread.setGlobals() not initialized");
}
/**
* Callback used at the beginning of a call to prepare for possible getfenv/setfenv calls
* @param function Function being called
* @return CallStack which is used to signal the return or a tail-call recursion
* @see DebugLib
*/
public static final CallStack onCall(LuaFunction function) {
CallStack cs = running_thread.callstack;
cs.onCall(function);
return cs;
}
/**
* Get the function called as a specific location on the stack.
* @param level 1 for the function calling this one, 2 for the next one.
* @return LuaFunction on the call stack, or null if outside of range of active stack
*/
public static final LuaFunction getCallstackFunction(int level) {
return running_thread.callstack.getFunction(level);
}
/**
* Replace the error function of the currently running thread.
* @param errfunc the new error function to use.
* @return the previous error function.
*/
public static LuaValue setErrorFunc(LuaValue errfunc) {
LuaValue prev = running_thread.err;
running_thread.err = errfunc;
return prev;
}
/** Yield the current thread with arguments
*
* @param args The arguments to send as return values to {@link #resume(Varargs)}
* @return {@link Varargs} provided as arguments to {@link #resume(Varargs)}
*/
public static Varargs yield(Varargs args) {
State s = running_thread.state;
if (s.function == null)
throw new LuaError("cannot yield main thread");
return s.lua_yield(args);
}
/** Start or resume this thread
*
* @param args The arguments to send as return values to {@link #yield(Varargs)}
* @return {@link Varargs} provided as arguments to {@link #yield(Varargs)}
*/
public Varargs resume(Varargs args) {
if (this.state.status > STATUS_SUSPENDED)
return LuaValue.varargsOf(LuaValue.FALSE,
LuaValue.valueOf("cannot resume "+LuaThread.STATUS_NAMES[this.state.status]+" coroutine"));
return state.lua_resume(this, args);
}
/* DAN200 START */
public void addChild( LuaThread thread ) {
this.children.addElement( new WeakReference( thread ) );
}
public Varargs abandon() {
if( this.state.status > STATUS_SUSPENDED ) {
return LuaValue.varargsOf( LuaValue.FALSE, LuaValue.valueOf( "cannot abandon " + STATUS_NAMES[this.state.status] + " coroutine" ) );
} else {
this.state.lua_abandon( this );
Enumeration it = this.children.elements();
while( it.hasMoreElements() ) {
WeakReference ref = (WeakReference)it.nextElement();
LuaThread thread = (LuaThread)ref.get();
if(thread != null && !thread.getStatus().equals("dead")) {
thread.abandon();
}
}
this.children.removeAllElements();
return LuaValue.varargsOf( new LuaValue[] { LuaValue.TRUE } );
}
}
/* DAN200 END */
static class State implements Runnable {
final WeakReference lua_thread;
final LuaValue function;
Varargs args = LuaValue.NONE;
Varargs result = LuaValue.NONE;
String error = null;
int status = LuaThread.STATUS_INITIAL;
/* DAN200 START */
boolean abandoned = false;
/* DAN200 END */
State(LuaThread lua_thread, LuaValue function) {
this.lua_thread = new WeakReference(lua_thread);
this.function = function;
}
public synchronized void run() {
try {
Varargs a = this.args;
this.args = LuaValue.NONE;
this.result = function.invoke(a);
} catch (Throwable t) {
this.error = t.getMessage();
} finally {
this.status = LuaThread.STATUS_DEAD;
this.notify();
}
}
synchronized Varargs lua_resume(LuaThread new_thread, Varargs args) {
LuaThread previous_thread = LuaThread.running_thread;
try {
LuaThread.running_thread = new_thread;
this.args = args;
if (this.status == STATUS_INITIAL) {
this.status = STATUS_RUNNING;
new Thread(this, "Coroutine-"+(++coroutine_count)).start();
} else {
this.notify();
}
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));
} catch (InterruptedException ie) {
throw new OrphanedThread();
} finally {
running_thread = previous_thread;
running_thread.state.status =STATUS_RUNNING;
this.args = LuaValue.NONE;
this.result = LuaValue.NONE;
this.error = null;
}
}
synchronized Varargs lua_yield(Varargs args) {
try {
this.result = args;
this.status = STATUS_SUSPENDED;
this.notify();
do {
this.wait(thread_orphan_check_interval);
/* DAN200 START */
//if (this.lua_thread.get() == null) {
if( this.abandoned || this.lua_thread.get() == null ) {
/* DAN200 END */
this.status = STATUS_DEAD;
throw new OrphanedThread();
}
} while (this.status == STATUS_SUSPENDED);
return this.args;
} catch (InterruptedException ie) {
this.status = STATUS_DEAD;
throw new OrphanedThread();
} finally {
this.args = LuaValue.NONE;
this.result = LuaValue.NONE;
}
}
/* DAN200 START */
synchronized void lua_abandon(LuaThread thread) {
LuaThread current = LuaThread.running_thread;
try {
current.state.status = STATUS_NORMAL;
this.abandoned = true;
if(this.status == STATUS_INITIAL) {
this.status = STATUS_DEAD;
} else {
this.notify();
this.wait();
}
} catch (InterruptedException var7) {
this.status = STATUS_DEAD;
} finally {
current.state.status = STATUS_RUNNING;
this.args = LuaValue.NONE;
this.result = LuaValue.NONE;
this.error = null;
}
}
/* DAN200 END */
}
public static class CallStack {
final LuaFunction[] functions = new LuaFunction[MAX_CALLSTACK];
int calls = 0;
/**
* Method to indicate the start of a call
* @see DebugLib
*/
final void onCall(LuaFunction function) {
functions[calls++] = function;
if (DebugLib.DEBUG_ENABLED)
DebugLib.debugOnCall(running_thread, calls, function);
}
/**
* Method to signal the end of a call
* @see DebugLib
*/
public final void onReturn() {
functions[--calls] = null;
if (DebugLib.DEBUG_ENABLED)
DebugLib.debugOnReturn(running_thread, calls);
}
/**
* Get number of calls in stack
* @return number of calls in current call stack
* @see DebugLib
*/
public final int getCallstackDepth() {
return calls;
}
/**
* Get the function at a particular level of the stack.
* @param level # of levels back from the top of the stack.
* @return LuaFunction, or null if beyond the stack limits.
*/
LuaFunction getFunction(int level) {
return level>0 && level<=calls? functions[calls-level]: null;
}
}
}

View File

@@ -1,126 +0,0 @@
/*******************************************************************************
* 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;
public class LuaUserdata extends LuaValue {
public final Object m_instance;
public LuaValue m_metatable;
public LuaUserdata(Object obj) {
m_instance = obj;
}
public LuaUserdata(Object obj, LuaValue metatable) {
m_instance = obj;
m_metatable = metatable;
}
public String tojstring() {
return String.valueOf(m_instance);
}
public int type() {
return LuaValue.TUSERDATA;
}
public String typename() {
return "userdata";
}
public int hashCode() {
return m_instance.hashCode();
}
public Object userdata() {
return m_instance;
}
public boolean isuserdata() { return true; }
public boolean isuserdata(Class c) { return c.isAssignableFrom(m_instance.getClass()); }
public Object touserdata() { return m_instance; }
public Object touserdata(Class c) { return c.isAssignableFrom(m_instance.getClass())? m_instance: null; }
public Object optuserdata(Object defval) { return m_instance; }
public Object optuserdata(Class c, Object defval) {
if (!c.isAssignableFrom(m_instance.getClass()))
typerror(c.getName());
return m_instance;
}
public LuaValue getmetatable() {
return m_metatable;
}
public LuaValue setmetatable(LuaValue metatable) {
this.m_metatable = metatable;
return this;
}
public Object checkuserdata() {
return m_instance;
}
public Object checkuserdata(Class c) {
if ( c.isAssignableFrom(m_instance.getClass()) )
return m_instance;
return typerror(c.getName());
}
public LuaValue get( LuaValue key ) {
return m_metatable!=null? gettable(this,key): NIL;
}
public void set( LuaValue key, LuaValue value ) {
if ( m_metatable==null || ! settable(this,key,value) )
error( "cannot set "+key+" for userdata" );
}
public boolean equals( Object val ) {
if ( this == val )
return true;
if ( ! (val instanceof LuaUserdata) )
return false;
LuaUserdata u = (LuaUserdata) val;
return m_instance.equals(u.m_instance);
}
// equality w/ metatable processing
public LuaValue eq( LuaValue val ) { return eq_b(val)? TRUE: FALSE; }
public boolean eq_b( LuaValue val ) {
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
public boolean raweq( LuaValue val ) { return val.raweq(this); }
public boolean raweq( LuaUserdata val ) {
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;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,44 +0,0 @@
/*******************************************************************************
* Copyright (c) 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.
******************************************************************************/
package org.luaj.vm2;
/**
* {@link java.lang.Error} sublcass that indicates a lua thread that is no
* longer referenced has been detected.
* <p>
* The java thread in which this is thrown should correspond to a
* {@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.
* <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
* handling could break the thread-safety of the application because other lua
* processing could be going on in a different thread.
*/
public class OrphanedThread extends Error {
public OrphanedThread() {
super("orphaned thread");
}
}

View File

@@ -1,417 +0,0 @@
/*******************************************************************************
* 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.ByteArrayOutputStream;
import java.io.PrintStream;
/**
* Debug helper class to pretty-print lua bytecodes.
* @see Prototype
* @see LuaClosure
*/
public class Print extends Lua {
/** opcode names */
private static final String STRING_FOR_NULL = "null";
public static PrintStream ps = System.out;
public static final String[] OPNAMES = {
"MOVE",
"LOADK",
"LOADBOOL",
"LOADNIL",
"GETUPVAL",
"GETGLOBAL",
"GETTABLE",
"SETGLOBAL",
"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",
"TFORLOOP",
"SETLIST",
"CLOSE",
"CLOSURE",
"VARARG",
null,
};
static void printString(PrintStream ps, final LuaString s) {
ps.print('"');
for (int i = 0, n = s.m_length; i < n; i++) {
int c = s.m_bytes[s.m_offset+i];
if ( c >= ' ' && c <= '~' && c != '\"' && c != '\\' )
ps.print((char) c);
else {
switch (c) {
case '"':
ps.print("\\\"");
break;
case '\\':
ps.print("\\\\");
break;
case 0x0007: /* bell */
ps.print("\\a");
break;
case '\b': /* backspace */
ps.print("\\b");
break;
case '\f': /* form feed */
ps.print("\\f");
break;
case '\t': /* tab */
ps.print("\\t");
break;
case '\r': /* carriage return */
ps.print("\\r");
break;
case '\n': /* newline */
ps.print("\\n");
break;
case 0x000B: /* vertical tab */
ps.print("\\v");
break;
default:
ps.print('\\');
ps.print(Integer.toString(1000 + 0xff&c).substring(1));
break;
}
}
}
ps.print('"');
}
static void printValue( PrintStream ps, LuaValue v ) {
switch ( v.type() ) {
case LuaValue.TSTRING: printString( ps, (LuaString) v ); break;
default: ps.print( v.tojstring() );
}
}
static void printConstant(PrintStream ps, Prototype f, int i) {
printValue( ps, f.k[i] );
}
/**
* Print the code in a prototype
* @param f the {@link Prototype}
*/
public static void printCode(Prototype f) {
int[] code = f.code;
int pc, n = code.length;
for (pc = 0; pc < n; pc++) {
printOpCode(f, pc);
ps.println();
}
}
/**
* Print an opcode in a prototype
* @param f the {@link Prototype}
* @param pc the program counter to look up and print
*/
public static void printOpCode(Prototype f, int pc) {
printOpCode(ps,f,pc);
}
/**
* 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
*/
public static void printOpCode(PrintStream ps, Prototype f, int pc) {
int[] code = f.code;
int i = code[pc];
int o = GET_OPCODE(i);
int a = GETARG_A(i);
int b = GETARG_B(i);
int c = GETARG_C(i);
int bx = GETARG_Bx(i);
int sbx = GETARG_sBx(i);
int line = getline(f, pc);
ps.print(" " + (pc + 1) + " ");
if (line > 0)
ps.print("[" + line + "] ");
else
ps.print("[-] ");
ps.print(OPNAMES[o] + " ");
switch (getOpMode(o)) {
case iABC:
ps.print( a );
if (getBMode(o) != OpArgN)
ps.print(" "+(ISK(b) ? (-1 - INDEXK(b)) : b));
if (getCMode(o) != OpArgN)
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));
}
break;
case iAsBx:
if (o == OP_JMP)
ps.print( sbx );
else
ps.print(a + " " + sbx);
break;
}
switch (o) {
case OP_LOADK:
ps.print(" ; ");
printConstant(ps, f, bx);
break;
case OP_GETUPVAL:
case OP_SETUPVAL:
ps.print(" ; ");
if ( f.upvalues.length > b )
printValue(ps, f.upvalues[b]);
else
ps.print( "-" );
break;
case OP_GETGLOBAL:
case OP_SETGLOBAL:
ps.print(" ; ");
printConstant( ps, f, bx );
break;
case OP_GETTABLE:
case OP_SELF:
if (ISK(c)) {
ps.print(" ; ");
printConstant(ps, f, INDEXK(c));
}
break;
case OP_SETTABLE:
case OP_ADD:
case OP_SUB:
case OP_MUL:
case OP_DIV:
case OP_POW:
case OP_EQ:
case OP_LT:
case OP_LE:
if (ISK(b) || ISK(c)) {
ps.print(" ; ");
if (ISK(b))
printConstant(ps, f, INDEXK(b));
else
ps.print("-");
ps.print(" ");
if (ISK(c))
printConstant(ps, f, INDEXK(c));
else
ps.print("-");
}
break;
case OP_JMP:
case OP_FORLOOP:
case OP_FORPREP:
ps.print(" ; to " + (sbx + pc + 2));
break;
case OP_CLOSURE:
ps.print(" ; " + f.p[bx].getClass().getName());
break;
case OP_SETLIST:
if (c == 0)
ps.print(" ; " + ((int) code[++pc]));
else
ps.print(" ; " + ((int) c));
break;
case OP_VARARG:
ps.print( " ; is_vararg="+ f.is_vararg );
break;
default:
break;
}
}
private static int getline(Prototype f, int pc) {
return pc>0 && f.lineinfo!=null && pc<f.lineinfo.length? f.lineinfo[pc]: -1;
}
static void printHeader(Prototype f) {
String s = String.valueOf(f.source);
if (s.startsWith("@") || s.startsWith("="))
s = s.substring(1);
else if ("\033Lua".equals(s))
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");
}
static void printConstants(Prototype f) {
int i, n = f.k.length;
ps.print("constants (" + n + ") for " + id(f) + ":\n");
for (i = 0; i < n; i++) {
ps.print(" " + (i + 1) + " ");
printValue( ps, f.k[i] );
ps.print( "\n");
}
}
static void printLocals(Prototype f) {
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));
}
}
static void printUpValues(Prototype f) {
int i, n = f.upvalues.length;
ps.print("upvalues (" + n + ") for " + id(f) + ":\n");
for (i = 0; i < n; i++) {
ps.print(" " + i + " " + f.upvalues[i] + "\n");
}
}
public static void print(Prototype p) {
printFunction(p, true);
}
public static void printFunction(Prototype f, boolean full) {
int i, n = f.p.length;
printHeader(f);
printCode(f);
if (full) {
printConstants(f);
printLocals(f);
printUpValues(f);
}
for (i = 0; i < n; i++)
printFunction(f.p[i], full);
}
private static void format( String s, int maxcols ) {
int n = s.length();
if ( n > maxcols )
ps.print( s.substring(0,maxcols) );
else {
ps.print( s );
for ( int i=maxcols-n; --i>=0; )
ps.print( ' ' );
}
}
private static String id(Prototype f) {
return "Proto";
}
private void _assert(boolean b) {
if ( !b )
throw new NullPointerException("_assert failed");
}
/**
* 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}
* @param top the top of the stack
* @param varargs any {@link Varargs} value that may apply
*/
public static void printState(LuaClosure cl, int pc, LuaValue[] stack, int top, Varargs varargs) {
// print opcode into buffer
PrintStream previous = ps;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ps = new PrintStream( baos );
printOpCode( cl.p, pc );
ps.flush();
ps.close();
ps = previous;
format( baos.toString(), 50 );
// print stack
ps.print('[');
for ( int i=0; i<stack.length; i++ ) {
LuaValue v = stack[i];
if ( v == null )
ps.print(STRING_FOR_NULL);
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");
break;
case LuaValue.TFUNCTION:
ps.print( ( v instanceof LuaClosure )?
((LuaClosure)v).p.toString(): v.tojstring() );
break;
case LuaValue.TUSERDATA:
Object o = v.touserdata();
if ( o != null ) {
String n = o.getClass().getName();
n = n.substring(n.lastIndexOf('.')+1);
ps.print( n+": "+Integer.toHexString(o.hashCode()) );
} else {
ps.print( v.toString() );
}
break;
default:
ps.print(v.tojstring());
}
if ( i+1 == top )
ps.print(']');
ps.print( " | " );
}
ps.print(varargs);
ps.println();
}
}

View File

@@ -1,77 +0,0 @@
/*******************************************************************************
* 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>
* See documentatation on {@link LuaClosure} for information on how to load
* and execute a {@link Prototype}.
* @see LuaClosure
*/
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 names */
public LuaString[] upvalues;
public LuaString source;
public int nups;
public int linedefined;
public int lastlinedefined;
public int numparams;
public int is_vararg;
public int maxstacksize;
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 */
}
}

View File

@@ -1,97 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010-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;
/**
* 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.
* <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.
* <p>
* 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 LuaJC
*/
public class TailcallVarargs extends Varargs {
private LuaValue func;
private Varargs args;
private Varargs result;
public TailcallVarargs(LuaValue f, Varargs args) {
this.func = f;
this.args = args;
}
public TailcallVarargs(LuaValue object, LuaValue methodname, Varargs args) {
this.func = object.get(methodname);
this.args = LuaValue.varargsOf(object, args);
}
public boolean isTailcall() {
return true;
}
public Varargs eval() {
while ( result == null ) {
Varargs r = func.onInvoke(args);
if (r.isTailcall()) {
TailcallVarargs t = (TailcallVarargs) r;
func = t.func;
args = t.args;
}
else {
result = r;
func = null;
args = null;
}
}
return result;
}
public LuaValue arg( int i ) {
if ( result == null )
eval();
return result.arg(i);
}
public LuaValue arg1() {
if (result == null)
eval();
return result.arg1();
}
public int narg() {
if (result == null)
eval();
return result.narg();
}
}

View File

@@ -1,77 +0,0 @@
/*******************************************************************************
* 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;
/** Upvalue used with Closure formulation
* <p>
* @see LuaClosure
* @see Prototype
*/
public final class UpValue {
LuaValue[] array; // initially the stack, becomes a holder
int index;
/**
* Create an upvalue relative to a stack
* @param stack the stack
* @param index the index on the stack for the upvalue
*/
public UpValue( LuaValue[] stack, int index) {
this.array = stack;
this.index = index;
}
/**
* Convert this upvalue to a Java String
* @return the Java String for this upvalue.
* @see LuaValue#tojstring()
*/
public String tojstring() {
return array[index].tojstring();
}
/**
* Get the value of the upvalue
* @return the {@link LuaValue} for this upvalue
*/
public final LuaValue getValue() {
return array[index];
}
/**
* Set the value of the upvalue
* @param the {@link LuaValue} to set it to
*/
public final void setValue( LuaValue value ) {
array[index] = value;
}
/**
* Close this upvalue so it is no longer on the stack
*/
public final void close() {
array = new LuaValue[] { array[index] };
index = 0;
}
}

View File

@@ -1,537 +0,0 @@
/*******************************************************************************
* 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;
/**
* Class to encapsulate varargs values, either as part of a variable argument list, or multiple return values.
* <p>
* To construct varargs, use one of the static methods such as
* {@code LuaValue.varargsOf(LuaValue,LuaValue)}
* <p>
* <p>
* Any LuaValue can be used as a stand-in for Varargs, for both calls and return values.
* When doing so, nargs() will return 1 and arg1() or arg(1) will return this.
* This simplifies the case when calling or implementing varargs functions with only
* 1 argument or 1 return value.
* <p>
* Varargs can also be derived from other varargs by appending to the front with a call
* such as {@code LuaValue.varargsOf(LuaValue,Varargs)}
* or by taking a portion of the args using {@code Varargs.subargs(int start)}
* <p>
* @see LuaValue#varargsOf(LuaValue[])
* @see LuaValue#varargsOf(LuaValue, Varargs)
* @see LuaValue#varargsOf(LuaValue[], Varargs)
* @see LuaValue#varargsOf(LuaValue, LuaValue, Varargs)
* @see LuaValue#varargsOf(LuaValue[], int, int)
* @see LuaValue#varargsOf(LuaValue[], int, int, Varargs)
* @see LuaValue#subargs(int)
*/
public abstract class Varargs {
/**
* Get the n-th argument value (1-based).
* @param i the index of the argument to get, 1 is the first argument
* @return Value at position i, or LuaValue.NIL if there is none.
* @see Varargs#arg1()
* @see LuaValue#NIL
*/
abstract public LuaValue arg( int i );
/**
* Get the number of arguments, or 0 if there are none.
* @return number of arguments.
*/
abstract public int narg();
/**
* Get the first argument in the list.
* @return LuaValue which is first in the list, or LuaValue.NIL if there are no values.
* @see Varargs#arg(int)
* @see LuaValue#NIL
*/
abstract public LuaValue arg1();
/**
* Evaluate any pending tail call and return result.
* @return the evaluated tail call result
*/
public Varargs eval() { return this; }
/**
* Return true if this is a TailcallVarargs
* @return true if a tail call, false otherwise
*/
public boolean isTailcall() {
return false;
}
// -----------------------------------------------------------------------
// utilities to get specific arguments and type-check them.
// -----------------------------------------------------------------------
/** Gets the type of argument {@code i}
* @param i the index of the argument to convert, 1 is the first argument
* @return int value corresponding to one of the LuaValue integer type values
* @see LuaValue.TNIL
* @see LuaValue.TBOOLEAN
* @see LuaValue.TNUMBER
* @see LuaValue.TSTRING
* @see LuaValue.TTABLE
* @see LuaValue.TFUNCTION
* @see LuaValue.TUSERDATA
* @see LuaValue.TTHREAD
* */
public int type(int i) { return arg(i).type(); }
/** Tests if argument i is nil.
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument is nil or does not exist, false otherwise
* @see LuaValue.TNIL
* */
public boolean isnil(int i) { return arg(i).isnil(); }
/** Tests if argument i is a function.
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument exists and is a function or closure, false otherwise
* @see LuaValue.TFUNCTION
* */
public boolean isfunction(int i) { return arg(i).isfunction(); }
/** Tests if argument i is a number.
* Since anywhere a number is required, a string can be used that
* is a number, this will return true for both numbers and
* strings that can be interpreted as numbers.
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument exists and is a number or
* string that can be interpreted as a number, false otherwise
* @see LuaValue.TNUMBER
* @see LuaValue.TSTRING
* */
public boolean isnumber(int i) { return arg(i).isnumber(); }
/** Tests if argument i is a string.
* Since all lua numbers can be used where strings are used,
* this will return true for both strings and numbers.
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument exists and is a string or number, false otherwise
* @see LuaValue.TNUMBER
* @see LuaValue.TSTRING
* */
public boolean isstring(int i) { return arg(i).isstring(); }
/** Tests if argument i is a table.
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument exists and is a lua table, false otherwise
* @see LuaValue.TTABLE
* */
public boolean istable(int i) { return arg(i).istable(); }
/** Tests if argument i is a thread.
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument exists and is a lua thread, false otherwise
* @see LuaValue.TTHREAD
* */
public boolean isthread(int i) { return arg(i).isthread(); }
/** Tests if argument i is a userdata.
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument exists and is a userdata, false otherwise
* @see LuaValue.TUSERDATA
* */
public boolean isuserdata(int i) { return arg(i).isuserdata(); }
/** Tests if a value exists at argument i.
* @param i the index of the argument to test, 1 is the first argument
* @return true if the argument exists, false otherwise
* */
public boolean isvalue(int i) { return i>0 && i<=narg(); }
/** Return argument i as a boolean value, {@code defval} if nil, or throw a LuaError if any other type.
* @param i the index of the argument to test, 1 is the first argument
* @return true if argument i is boolean true, false if it is false, or defval if not supplied or nil
* @exception LuaError if the argument is not a lua boolean
* */
public boolean optboolean(int i, boolean defval) { return arg(i).optboolean(defval); }
/** Return argument i as a closure, {@code defval} if nil, or throw a LuaError if any other type.
* @param i the index of the argument to test, 1 is the first argument
* @return LuaClosure if argument i is a closure, or defval if not supplied or nil
* @exception LuaError if the argument is not a lua closure
* */
public LuaClosure optclosure(int i, LuaClosure defval) { return arg(i).optclosure(defval); }
/** Return argument i as a double, {@code defval} if nil, or throw a LuaError if it cannot be converted to one.
* @param i the index of the argument to test, 1 is the first argument
* @return java double value if argument i is a number or string that converts to a number, or defval if not supplied or nil
* @exception LuaError if the argument is not a number
* */
public double optdouble(int i, double defval) { return arg(i).optdouble(defval); }
/** Return argument i as a function, {@code defval} if nil, or throw a LuaError if an incompatible type.
* @param i the index of the argument to test, 1 is the first argument
* @return LuaValue that can be called if argument i is lua function or closure, or defval if not supplied or nil
* @exception LuaError if the argument is not a lua function or closure
* */
public LuaFunction optfunction(int i, LuaFunction defval) { return arg(i).optfunction(defval); }
/** Return argument i as a java int value, discarding any fractional part, {@code defval} if nil, or throw a LuaError if not a number.
* @param i the index of the argument to test, 1 is the first argument
* @return int value with fraction discarded and truncated if necessary if argument i is number, or defval if not supplied or nil
* @exception LuaError if the argument is not a number
* */
public int optint(int i, int defval) { return arg(i).optint(defval); }
/** Return argument i as a java int value, {@code defval} if nil, or throw a LuaError if not a number or is not representable by a java int.
* @param i the index of the argument to test, 1 is the first argument
* @return LuaInteger value that fits in a java int without rounding, or defval if not supplied or nil
* @exception LuaError if the argument cannot be represented by a java int value
* */
public LuaInteger optinteger(int i, LuaInteger defval) { return arg(i).optinteger(defval); }
/** Return argument i as a java long value, discarding any fractional part, {@code defval} if nil, or throw a LuaError if not a number.
* @param i the index of the argument to test, 1 is the first argument
* @return long value with fraction discarded and truncated if necessary if argument i is number, or defval if not supplied or nil
* @exception LuaError if the argument is not a number
* */
public long optlong(int i, long defval) { return arg(i).optlong(defval); }
/** Return argument i as a LuaNumber, {@code defval} if nil, or throw a LuaError if not a number or string that can be converted to a number.
* @param i the index of the argument to test, 1 is the first argument, or defval if not supplied or nil
* @return LuaNumber if argument i is number or can be converted to a number
* @exception LuaError if the argument is not a number
* */
public LuaNumber optnumber(int i, LuaNumber defval) { return arg(i).optnumber(defval); }
/** Return argument i as a java String if a string or number, {@code defval} if nil, or throw a LuaError if any other type
* @param i the index of the argument to test, 1 is the first argument
* @return String value if argument i is a string or number, or defval if not supplied or nil
* @exception LuaError if the argument is not a string or number
* */
public String optjstring(int i, String defval) { return arg(i).optjstring(defval); }
/** Return argument i as a LuaString if a string or number, {@code defval} if nil, or throw a LuaError if any other type
* @param i the index of the argument to test, 1 is the first argument
* @return LuaString value if argument i is a string or number, or defval if not supplied or nil
* @exception LuaError if the argument is not a string or number
* */
public LuaString optstring(int i, LuaString defval) { return arg(i).optstring(defval); }
/** Return argument i as a LuaTable if a lua table, {@code defval} if nil, or throw a LuaError if any other type.
* @param i the index of the argument to test, 1 is the first argument
* @return LuaTable value if a table, or defval if not supplied or nil
* @exception LuaError if the argument is not a lua table
* */
public LuaTable opttable(int i, LuaTable defval) { return arg(i).opttable(defval); }
/** Return argument i as a LuaThread if a lua thread, {@code defval} if nil, or throw a LuaError if any other type.
* @param i the index of the argument to test, 1 is the first argument
* @return LuaThread value if a thread, or defval if not supplied or nil
* @exception LuaError if the argument is not a lua thread
* */
public LuaThread optthread(int i, LuaThread defval) { return arg(i).optthread(defval); }
/** Return argument i as a java Object if a userdata, {@code defval} if nil, or throw a LuaError if any other type.
* @param i the index of the argument to test, 1 is the first argument
* @return java Object value if argument i is a userdata, or defval if not supplied or nil
* @exception LuaError if the argument is not a userdata
* */
public Object optuserdata(int i, Object defval) { return arg(i).optuserdata(defval); }
/** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass,
* {@code defval} if nil, or throw a LuaError if any other type.
* @param i the index of the argument to test, 1 is the first argument
* @param c the class to which the userdata instance must be assignable
* @return java Object value if argument i is a userdata whose instance Class c or a subclass, or defval if not supplied or nil
* @exception LuaError if the argument is not a userdata or from whose instance c is not assignable
* */
public Object optuserdata(int i, Class c, Object defval) { return arg(i).optuserdata(c,defval); }
/** Return argument i as a LuaValue if it exists, or {@code defval}.
* @param i the index of the argument to test, 1 is the first argument
* @return LuaValue value if the argument exists, defval if not
* @exception LuaError if the argument does not exist.
* */
public LuaValue optvalue(int i, LuaValue defval) { return i>0 && i<=narg()? arg(i): defval; }
/** Return argument i as a boolean value, or throw an error if any other type.
* @param i the index of the argument to test, 1 is the first argument
* @return true if argument i is boolean true, false if it is false
* @exception LuaError if the argument is not a lua boolean
* */
public boolean checkboolean(int i) { return arg(i).checkboolean(); }
/** Return argument i as a closure, or throw an error if any other type.
* @param i the index of the argument to test, 1 is the first argument
* @return LuaClosure if argument i is a closure.
* @exception LuaError if the argument is not a lua closure
* */
public LuaClosure checkclosure(int i) { return arg(i).checkclosure(); }
/** Return argument i as a double, or throw an error if it cannot be converted to one.
* @param i the index of the argument to test, 1 is the first argument
* @return java double value if argument i is a number or string that converts to a number
* @exception LuaError if the argument is not a number
* */
public double checkdouble(int i) { return arg(i).checknumber().todouble(); }
/** Return argument i as a function, or throw an error if an incompatible type.
* @param i the index of the argument to test, 1 is the first argument
* @return LuaValue that can be called if argument i is lua function or closure
* @exception LuaError if the argument is not a lua function or closure
* */
public LuaValue checkfunction(int i) { return arg(i).checkfunction(); }
/** Return argument i as a java int value, discarding any fractional part, or throw an error if not a number.
* @param i the index of the argument to test, 1 is the first argument
* @return int value with fraction discarded and truncated if necessary if argument i is number
* @exception LuaError if the argument is not a number
* */
public int checkint(int i) { return arg(i).checknumber().toint(); }
/** Return argument i as a java int value, or throw an error if not a number or is not representable by a java int.
* @param i the index of the argument to test, 1 is the first argument
* @return LuaInteger value that fits in a java int without rounding
* @exception LuaError if the argument cannot be represented by a java int value
* */
public LuaInteger checkinteger(int i) { return arg(i).checkinteger(); }
/** Return argument i as a java long value, discarding any fractional part, or throw an error if not a number.
* @param i the index of the argument to test, 1 is the first argument
* @return long value with fraction discarded and truncated if necessary if argument i is number
* @exception LuaError if the argument is not a number
* */
public long checklong(int i) { return arg(i).checknumber().tolong(); }
/** Return argument i as a LuaNumber, or throw an error if not a number or string that can be converted to a number.
* @param i the index of the argument to test, 1 is the first argument
* @return LuaNumber if argument i is number or can be converted to a number
* @exception LuaError if the argument is not a number
* */
public LuaNumber checknumber(int i) { return arg(i).checknumber(); }
/** Return argument i as a java String if a string or number, or throw an error if any other type
* @param i the index of the argument to test, 1 is the first argument
* @return String value if argument i is a string or number
* @exception LuaError if the argument is not a string or number
* */
public String checkjstring(int i) { return arg(i).checkjstring(); }
/** Return argument i as a LuaString if a string or number, or throw an error if any other type
* @param i the index of the argument to test, 1 is the first argument
* @return LuaString value if argument i is a string or number
* @exception LuaError if the argument is not a string or number
* */
public LuaString checkstring(int i) { return arg(i).checkstring(); }
/** Return argument i as a LuaTable if a lua table, or throw an error if any other type.
* @param i the index of the argument to test, 1 is the first argument
* @return LuaTable value if a table
* @exception LuaError if the argument is not a lua table
* */
public LuaTable checktable(int i) { return arg(i).checktable(); }
/** Return argument i as a LuaThread if a lua thread, or throw an error if any other type.
* @param i the index of the argument to test, 1 is the first argument
* @return LuaThread value if a thread
* @exception LuaError if the argument is not a lua thread
* */
public LuaThread checkthread(int i) { return arg(i).checkthread(); }
/** Return argument i as a java Object if a userdata, or throw an error if any other type.
* @param i the index of the argument to test, 1 is the first argument
* @return java Object value if argument i is a userdata
* @exception LuaError if the argument is not a userdata
* */
public Object checkuserdata(int i) { return arg(i).checkuserdata(); }
/** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass,
* or throw an error if any other type.
* @param i the index of the argument to test, 1 is the first argument
* @param c the class to which the userdata instance must be assignable
* @return java Object value if argument i is a userdata whose instance Class c or a subclass
* @exception LuaError if the argument is not a userdata or from whose instance c is not assignable
* */
public Object checkuserdata(int i,Class c) { return arg(i).checkuserdata(c); }
/** Return argument i as a LuaValue if it exists, or throw an error.
* @param i the index of the argument to test, 1 is the first argument
* @return LuaValue value if the argument exists
* @exception LuaError if the argument does not exist.
* */
public LuaValue checkvalue(int i) { return i<=narg()? arg(i): LuaValue.argerror(i,"value expected"); }
/** Return argument i as a LuaValue if it is not nil, or throw an error if it is nil.
* @param i the index of the argument to test, 1 is the first argument
* @return LuaValue value if the argument is not nil
* @exception LuaError if the argument doesn't exist or evaluates to nil.
* */
public LuaValue checknotnil(int i) { return arg(i).checknotnil(); }
/** Return argument i as a LuaValue when a user-supplied assertion passes, or throw an error.
* @param test user supplied assertion to test against
* @param i the index to report in any error message
* @param msg the error message to use when the test fails
* @return LuaValue value if the value of {@code test} is {@code true}
* @exception LuaError if the the value of {@code test} is {@code false}
* */
public void argcheck(boolean test, int i, String msg) { if (!test) LuaValue.argerror(i,msg); }
/** Return true if there is no argument or nil at argument i.
* @param i the index of the argument to test, 1 is the first argument
* @return true if argument i contains either no argument or nil
* */
public boolean isnoneornil(int i) {
return i>narg() || arg(i).isnil();
}
/** Convert argument {@code i} to java boolean based on lua rules for boolean evaluation.
* @param i the index of the argument to convert, 1 is the first argument
* @return {@code false} if argument i is nil or false, otherwise {@code true}
* */
public boolean toboolean(int i) { return arg(i).toboolean(); }
/** Return argument i as a java byte value, discarding any fractional part and truncating,
* or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument
* @return byte value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
* */
public byte tobyte(int i) { return arg(i).tobyte(); }
/** Return argument i as a java char value, discarding any fractional part and truncating,
* or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument
* @return char value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
* */
public char tochar(int i) { return arg(i).tochar(); }
/** Return argument i as a java double value or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument
* @return double value if argument i is number, otherwise 0
* */
public double todouble(int i) { return arg(i).todouble(); }
/** Return argument i as a java float value, discarding excess fractional part and truncating,
* or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument
* @return float value with excess fraction discarded and truncated if necessary if argument i is number, otherwise 0
* */
public float tofloat(int i) { return arg(i).tofloat(); }
/** Return argument i as a java int value, discarding any fractional part and truncating,
* or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument
* @return int value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
* */
public int toint(int i) { return arg(i).toint(); }
/** Return argument i as a java long value, discarding any fractional part and truncating,
* or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument
* @return long value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
* */
public long tolong(int i) { return arg(i).tolong(); }
/** Return argument i as a java String based on the type of the argument.
* @param i the index of the argument to convert, 1 is the first argument
* @return String value representing the type
* */
public String tojstring(int i) { return arg(i).tojstring(); }
/** Return argument i as a java short value, discarding any fractional part and truncating,
* or 0 if not a number.
* @param i the index of the argument to convert, 1 is the first argument
* @return short value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
* */
public short toshort(int i) { return arg(i).toshort(); }
/** Return argument i as a java Object if a userdata, or null.
* @param i the index of the argument to convert, 1 is the first argument
* @return java Object value if argument i is a userdata, otherwise null
* */
public Object touserdata(int i) { return arg(i).touserdata(); }
/** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass, or null.
* @param i the index of the argument to convert, 1 is the first argument
* @param c the class to which the userdata instance must be assignable
* @return java Object value if argument i is a userdata whose instance Class c or a subclass, otherwise null
* */
public Object touserdata(int i,Class c) { return arg(i).touserdata(c); }
/** Convert the list of varargs values to a human readable java String.
* @return String value in human readable form such as {1,2}.
*/
public String tojstring() {
Buffer sb = new Buffer();
sb.append( "(" );
for ( int i=1,n=narg(); i<=n; i++ ) {
if (i>1) sb.append( "," );
sb.append( arg(i).tojstring() );
}
sb.append( ")" );
return sb.tojstring();
}
/** Convert the value or values to a java String using Varargs.tojstring()
* @return String value in human readable form.
* @see Varargs#tojstring()
*/
public String toString() { return tojstring(); }
/**
* Create a {@code Varargs} instance containing arguments starting at index {@code start}
* @param start the index from which to include arguments, where 1 is the first argument.
* @return Varargs containing argument { start, start+1, ... , narg-start-1 }
*/
public Varargs subargs(final int start) {
int end = narg();
switch ( end-start ) {
case 0: return arg(start);
case 1: return new LuaValue.PairVarargs(arg(start),arg(end));
}
return end<start? (Varargs) LuaValue.NONE: new SubVarargs(this,start,end);
}
/**
* Implementation of Varargs for use in the Varargs.subargs() function.
* @see Varargs#subargs(int)
*/
private static class SubVarargs extends Varargs {
private final Varargs v;
private final int start;
private final int end;
public SubVarargs(Varargs varargs, int start, int end) {
this.v = varargs;
this.start = start;
this.end = end;
}
public LuaValue arg(int i) {
i += start-1;
return i>=start && i<=end? v.arg(i): LuaValue.NIL;
}
public LuaValue arg1() {
return v.arg(start);
}
public int narg() {
return end+1-start;
}
}
}

View File

@@ -1,349 +0,0 @@
/*******************************************************************************
* 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;
import java.lang.ref.WeakReference;
import org.luaj.vm2.lib.TwoArgFunction;
/**
* 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.
* <p>
* However, calling the constructors directly when weak tables are required from
* Java will reduce overhead.
*/
public class WeakTable extends LuaTable {
private boolean weakkeys,weakvalues;
/**
* 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
*/
public WeakTable(boolean weakkeys, boolean weakvalues) {
this(weakkeys, weakvalues, 0, 0);
}
/**
* Construct a table with weak keys, weak values, or both, and an initial capacity
* @param weakkeys true to let the table have weak keys
* @param weakvalues true to let the table have weak values
* @param narray capacity of array part
* @param nhash capacity of hash part
*/
protected WeakTable(boolean weakkeys, boolean weakvalues, int narray, int nhash) {
super(narray, nhash);
this.weakkeys = weakkeys;
this.weakvalues = weakvalues;
}
/**
* Construct a table with weak keys, weak values, or both, and a source of initial data
* @param weakkeys true to let the table have weak keys
* @param weakvalues true to let the table have weak values
* @param source {@link LuaTable} containing the initial elements
*/
protected WeakTable(boolean weakkeys, boolean weakvalues, LuaTable source) {
this(weakkeys, weakvalues, source.getArrayLength(), source.getHashLength());
Varargs n;
LuaValue k = NIL;
while ( !(k = ((n = source.next(k)).arg1())).isnil() )
rawset(k, n.arg(2));
m_metatable = source.m_metatable;
}
public void presize( int narray ) {
super.presize(narray);
}
/**
* Presize capacity of both array and hash parts.
* @param narray capacity of array part
* @param nhash capacity of hash part
*/
public void presize(int narray, int nhash) {
super.presize(narray, nhash);
}
protected int getArrayLength() {
return super.getArrayLength();
}
protected int getHashLength() {
return super.getHashLength();
}
protected LuaTable changemode(boolean weakkeys, boolean weakvalues) {
this.weakkeys = weakkeys;
this.weakvalues = weakvalues;
return this;
}
/**
* 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}
*/
LuaValue weaken( LuaValue value ) {
switch ( value.type() ) {
case LuaValue.TFUNCTION:
case LuaValue.TTHREAD:
case LuaValue.TTABLE:
return new WeakValue(value);
case LuaValue.TUSERDATA:
return new WeakUserdata(value);
default:
return value;
}
}
public void rawset( int key, LuaValue value ) {
if ( weakvalues )
value = weaken( value );
super.rawset(key, value);
}
public void rawset( LuaValue key, LuaValue value ) {
if ( weakvalues )
value = weaken( value );
if ( weakkeys ) {
switch ( key.type() ) {
case LuaValue.TFUNCTION:
case LuaValue.TTHREAD:
case LuaValue.TTABLE:
case LuaValue.TUSERDATA:
key = value = new WeakEntry(this, key, value);
break;
default:
break;
}
}
super.rawset(key, value);
}
public LuaValue rawget( int key ) {
return super.rawget(key).strongvalue();
}
public LuaValue rawget( LuaValue key ) {
return super.rawget(key).strongvalue();
}
/** Get the hash value for a key
* key the key to look up
* */
protected LuaValue hashget(LuaValue key) {
if ( hashEntries > 0 ) {
int i = hashFindSlot(key);
if ( hashEntries == 0 )
return NIL;
LuaValue v = hashValues[i];
return v!=null? v: NIL;
}
return NIL;
}
// override to remove values for weak keys as we search
public int hashFindSlot(LuaValue key) {
int i = ( key.hashCode() & 0x7FFFFFFF ) % hashKeys.length;
LuaValue k;
while ( ( k = hashKeys[i] ) != null ) {
if ( k.isweaknil() ) {
hashClearSlot(i);
if ( hashEntries == 0 )
return 0;
}
else {
if ( k.raweq(key.strongkey()) )
return i;
i = ( i + 1 ) % hashKeys.length;
}
}
return i;
}
public int maxn() {
return super.maxn();
}
/**
* Get the next element after a particular key in the table
* @return key,value or nil
*/
public Varargs next( LuaValue key ) {
while ( true ) {
Varargs n = super.next(key);
LuaValue k = n.arg1();
if ( k.isnil() )
return NIL;
LuaValue ks = k.strongkey();
LuaValue vs = n.arg(2).strongvalue();
if ( ks.isnil() || vs.isnil() ) {
super.rawset(k, NIL);
} else {
return varargsOf(ks,vs);
}
}
}
// ----------------- sort support -----------------------------
public void sort(final LuaValue comparator) {
super.sort( new TwoArgFunction() {
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return comparator.call( arg1.strongvalue(), arg2.strongvalue() );
}
} );
}
/** Internal class to implement weak values.
* @see WeakTable
*/
static class WeakValue extends LuaValue {
final WeakReference ref;
protected WeakValue(LuaValue value) {
ref = new WeakReference(value);
}
public int type() {
illegal("type","weak value");
return 0;
}
public String typename() {
illegal("typename","weak value");
return null;
}
public String toString() {
return "weak<"+ref.get()+">";
}
public LuaValue strongvalue() {
Object o = ref.get();
return o!=null? (LuaValue)o: NIL;
}
public boolean raweq(LuaValue rhs) {
Object o = ref.get();
return o!=null && rhs.raweq((LuaValue)o);
}
public boolean isweaknil() {
return ref.get() == null;
}
}
/** Internal class to implement weak userdata values.
* @see WeakTable
*/
static final class WeakUserdata extends WeakValue {
private final WeakReference ob;
private final LuaValue mt;
private WeakUserdata(LuaValue value) {
super(value);
ob = new WeakReference(value.touserdata());
mt = value.getmetatable();
}
public LuaValue strongvalue() {
Object u = ref.get();
if ( u != null )
return (LuaValue) u;
Object o = ob.get();
return o!=null? userdataOf(o,mt): NIL;
}
public boolean raweq(LuaValue rhs) {
if ( ! rhs.isuserdata() )
return false;
LuaValue v = (LuaValue) ref.get();
if ( v != null && v.raweq(rhs) )
return true;
return rhs.touserdata() == ob.get();
}
public boolean isweaknil() {
return ob.get() == null || ref.get() == null;
}
}
/** Internal class to implement weak table entries.
* @see WeakTable
*/
static final class WeakEntry extends LuaValue {
final LuaValue weakkey;
LuaValue weakvalue;
final int keyhash;
private WeakEntry(WeakTable table, LuaValue key, LuaValue weakvalue) {
this.weakkey = table.weaken(key);
this.keyhash = key.hashCode();
this.weakvalue = weakvalue;
}
public LuaValue strongkey() {
return weakkey.strongvalue();
}
// when looking up the value, look in the keys metatable
public LuaValue strongvalue() {
LuaValue key = weakkey.strongvalue();
if ( key.isnil() )
return weakvalue = NIL;
return weakvalue.strongvalue();
}
public int type() {
return TNONE;
}
public String typename() {
illegal("typename","weak entry");
return null;
}
public String toString() {
return "weak<"+weakkey.strongvalue()+","+strongvalue()+">";
}
public int hashCode() {
return keyhash;
}
public boolean raweq(LuaValue rhs) {
//return rhs.raweq(weakkey.strongvalue());
return weakkey.raweq(rhs);
}
public boolean isweaknil() {
return weakkey.isweaknil() || weakvalue.isweaknil();
}
}
}

View File

@@ -1,267 +0,0 @@
/*******************************************************************************
* 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.compiler;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.luaj.vm2.LocVars;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue;
public class DumpState {
/** mark for precompiled code (`<esc>Lua') */
public static final String LUA_SIGNATURE = "\033Lua";
/** for header of binary files -- this is Lua 5.1 */
public static final int LUAC_VERSION = 0x51;
/** 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;
/** expected lua header bytes */
private static final byte[] LUAC_HEADER_SIGNATURE = { '\033', 'L', 'u', 'a' };
/** 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 */
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;
/** default number format */
public static final int NUMBER_FORMAT_DEFAULT = NUMBER_FORMAT_FLOATS_OR_DOUBLES;
// header fields
private boolean IS_LITTLE_ENDIAN = false;
private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT;
private int SIZEOF_LUA_NUMBER = 8;
private static final int SIZEOF_INT = 4;
private static final int SIZEOF_SIZET = 4;
private static final int SIZEOF_INSTRUCTION = 4;
DataOutputStream writer;
boolean strip;
int status;
public DumpState(OutputStream w, boolean strip) {
this.writer = new DataOutputStream( w );
this.strip = strip;
this.status = 0;
}
void dumpBlock(final byte[] b, int size) throws IOException {
writer.write(b, 0, size);
}
void dumpChar(int b) throws IOException {
writer.write( b );
}
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);
} else {
writer.writeInt(x);
}
}
void dumpString(LuaString s) throws IOException {
final int len = s.len().toint();
dumpInt( len+1 );
s.write( writer, 0, len );
writer.write( 0 );
}
void dumpDouble(double d) throws IOException {
long l = Double.doubleToLongBits(d);
if ( IS_LITTLE_ENDIAN ) {
dumpInt( (int) l );
dumpInt( (int) (l>>32) );
} else {
writer.writeLong(l);
}
}
void dumpCode( final Prototype f ) throws IOException {
final int[] code = f.code;
int n = code.length;
dumpInt( n );
for ( int i=0; i<n; i++ )
dumpInt( code[i] );
}
void dumpConstants(final Prototype f) throws IOException {
final LuaValue[] k = f.k;
int i, n = k.length;
dumpInt(n);
for (i = 0; i < n; i++) {
final LuaValue o = k[i];
switch ( o.type() ) {
case LuaValue.TNIL:
writer.write(LuaValue.TNIL);
break;
case LuaValue.TBOOLEAN:
writer.write(LuaValue.TBOOLEAN);
dumpChar(o.toboolean() ? 1 : 0);
break;
case LuaValue.TNUMBER:
switch (NUMBER_FORMAT) {
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
writer.write(LuaValue.TNUMBER);
dumpDouble(o.todouble());
break;
case NUMBER_FORMAT_INTS_ONLY:
if ( ! ALLOW_INTEGER_CASTING && ! o.isint() )
throw new java.lang.IllegalArgumentException("not an integer: "+o);
writer.write(LuaValue.TNUMBER);
dumpInt(o.toint());
break;
case NUMBER_FORMAT_NUM_PATCH_INT32:
if ( o.isint() ) {
writer.write(LuaValue.TINT);
dumpInt(o.toint());
} else {
writer.write(LuaValue.TNUMBER);
dumpDouble(o.todouble());
}
break;
default:
throw new IllegalArgumentException("number format not supported: "+NUMBER_FORMAT);
}
break;
case LuaValue.TSTRING:
writer.write(LuaValue.TSTRING);
dumpString((LuaString)o);
break;
default:
throw new IllegalArgumentException("bad type for " + o);
}
}
n = f.p.length;
dumpInt(n);
for (i = 0; i < n; i++)
dumpFunction(f.p[i], f.source);
}
void dumpDebug(final Prototype f) throws IOException {
int i, n;
n = (strip) ? 0 : f.lineinfo.length;
dumpInt(n);
for (i = 0; i < n; i++)
dumpInt(f.lineinfo[i]);
n = (strip) ? 0 : f.locvars.length;
dumpInt(n);
for (i = 0; i < n; i++) {
LocVars lvi = f.locvars[i];
dumpString(lvi.varname);
dumpInt(lvi.startpc);
dumpInt(lvi.endpc);
}
n = (strip) ? 0 : f.upvalues.length;
dumpInt(n);
for (i = 0; i < n; i++)
dumpString(f.upvalues[i]);
}
void dumpFunction(final Prototype f, final LuaString string) throws IOException {
if ( f.source == null || f.source.equals(string) || strip )
dumpInt(0);
else
dumpString(f.source);
dumpInt(f.linedefined);
dumpInt(f.lastlinedefined);
dumpChar(f.nups);
dumpChar(f.numparams);
dumpChar(f.is_vararg);
dumpChar(f.maxstacksize);
dumpCode(f);
dumpConstants(f);
dumpDebug(f);
}
void dumpHeader() throws IOException {
writer.write( LUAC_HEADER_SIGNATURE );
writer.write( LUAC_VERSION );
writer.write( LUAC_FORMAT );
writer.write( IS_LITTLE_ENDIAN? 1: 0 );
writer.write( SIZEOF_INT );
writer.write( SIZEOF_SIZET );
writer.write( SIZEOF_INSTRUCTION );
writer.write( SIZEOF_LUA_NUMBER );
writer.write( NUMBER_FORMAT );
}
/*
** dump Lua function as precompiled chunk
*/
public static int dump( Prototype f, OutputStream w, boolean strip ) throws IOException {
DumpState D = new DumpState(w,strip);
D.dumpHeader();
D.dumpFunction(f,null);
return D.status;
}
/**
*
* @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
* @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 {
switch ( numberFormat ) {
case NUMBER_FORMAT_FLOATS_OR_DOUBLES:
case NUMBER_FORMAT_INTS_ONLY:
case NUMBER_FORMAT_NUM_PATCH_INT32:
break;
default:
throw new IllegalArgumentException("number format not supported: "+numberFormat);
}
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.dumpHeader();
D.dumpFunction(f,null);
return D.status;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,37 +0,0 @@
/*******************************************************************************
* 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.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

@@ -1,31 +0,0 @@
/*******************************************************************************
* 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.compiler;
public class IntPtr {
int i;
IntPtr() {
}
IntPtr(int value) {
this.i = value;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,251 +0,0 @@
/*******************************************************************************
* 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.compiler;
import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import org.luaj.vm2.LoadState;
import org.luaj.vm2.LocVars;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaClosure;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.LoadState.LuaCompiler;
/**
* 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.
* <p>
* Implements the {@link LuaCompiler} interface for loading
* initialized chunks, which is an interface common to
* lua bytecode compiling and java bytecode compiling.
* <p>
* Teh {@link LuaC} compiler is installed by default by both the
* {@link JsePlatform} and {@link JmePlatform} classes,
* so in the following example, the default {@link LuaC} compiler
* will be used:
* <pre> {@code
* LuaValue _G = JsePlatform.standardGlobals();
* LoadState.load( new ByteArrayInputStream("print 'hello'".getBytes()), "main.lua", _G ).call();
* } </pre>
* @see LuaCompiler
* @see LuaJC
* @see JsePlatform
* @see JmePlatform
* @see BaseLib
* @see LuaValue
* @see LuaCompiler
* @see Prototype
*/
public class LuaC extends Lua implements LuaCompiler {
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.
*/
public static void install() {
org.luaj.vm2.LoadState.compiler = instance;
}
protected static void _assert(boolean b) {
if (!b)
throw new LuaError("compiler assert failed");
}
public static final int MAXSTACK = 250;
static final int LUAI_MAXUPVALUES = 60;
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;
/* OpArgMask */
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 */
static void SET_OPCODE(InstructionPtr i,int o) {
i.set( ( i.get() & (MASK_NOT_OP)) | ((o << POS_OP) & MASK_OP) );
}
static void SETARG_A(InstructionPtr i,int u) {
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) );
}
static void SETARG_C(InstructionPtr i,int u) {
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) );
}
static void SETARG_sBx(InstructionPtr i,int u) {
SETARG_Bx( i, u + MAXARG_sBx );
}
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) ;
}
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) ;
}
// vector reallocation
static LuaValue[] realloc(LuaValue[] v, int n) {
LuaValue[] a = new LuaValue[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static Prototype[] realloc(Prototype[] v, int n) {
Prototype[] a = new Prototype[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static LuaString[] realloc(LuaString[] v, int n) {
LuaString[] a = new LuaString[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static LocVars[] realloc(LocVars[] v, int n) {
LocVars[] a = new LocVars[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static int[] realloc(int[] v, int n) {
int[] a = new int[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static byte[] realloc(byte[] v, int n) {
byte[] a = new byte[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
public int nCcalls;
Hashtable strings;
protected LuaC() {}
private LuaC(Hashtable strings) {
this.strings = strings;
}
/** Load into a Closure or LuaFunction, with the supplied initial environment */
public LuaFunction load(InputStream stream, String name, LuaValue env) throws IOException {
Prototype p = compile( stream, name );
return new LuaClosure( p, env );
}
/** Compile a prototype or load as a binary chunk */
public static Prototype compile(InputStream stream, String name) throws IOException {
int firstByte = stream.read();
return ( firstByte == '\033' )?
LoadState.loadBinaryChunk(firstByte, stream, name):
(new LuaC(new Hashtable())).luaY_parser(firstByte, stream, name);
}
/** Parse the input */
private Prototype luaY_parser(int firstByte, InputStream z, String name) {
LexState lexstate = new LexState(this, z);
FuncState funcstate = new FuncState();
// lexstate.buff = buff;
lexstate.setinput( this, firstByte, z, (LuaString) LuaValue.valueOf(name) );
lexstate.open_func(funcstate);
/* main func. is always vararg */
funcstate.f.is_vararg = LuaC.VARARG_ISVARARG;
funcstate.f.source = (LuaString) LuaValue.valueOf(name);
lexstate.next(); /* read first token */
lexstate.chunk();
lexstate.check(LexState.TK_EOS);
lexstate.close_func();
LuaC._assert (funcstate.prev == null);
LuaC._assert (funcstate.f.nups == 0);
LuaC._assert (lexstate.fs == null);
return funcstate.f;
}
// look up and keep at most one copy of each string
public LuaString newTString(byte[] bytes, int offset, int len) {
LuaString tmp = LuaString.valueOf(bytes, offset, len);
LuaString v = (LuaString) strings.get(tmp);
if ( v == null ) {
// must copy bytes, since bytes could be from reusable buffer
byte[] copy = new byte[len];
System.arraycopy(bytes, offset, copy, 0, len);
v = LuaString.valueOf(copy);
strings.put(v, v);
}
return v;
}
public String pushfstring(String string) {
return string;
}
public LuaFunction load(Prototype p, String filename, LuaValue env) {
return new LuaClosure( p, env );
}
}

View File

@@ -1,430 +0,0 @@
/*******************************************************************************
* 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.io.InputStream;
import java.io.PrintStream;
import org.luaj.vm2.LoadState;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* 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 #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
* directory lookup, use {@link JseBaseLib} instead.
* <p>
* Typically, this library is included as part of a call to either
* {@link JmePlatform#standardGlobals()}
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* LuaTable _G = new LuaTable();
* LuaThread.setGlobals(_G);
* _G.load(new BaseLib());
* _G.get("print").call(LuaValue.valueOf("hello, world"));
* } </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 JseBaseLib
* @see ResourceFinder
* @see #FINDER
* @see LibFunction
* @see JsePlatform
* @see JmePlatform
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.1">http://www.lua.org/manual/5.1/manual.html#5.1</a>
*/
public class BaseLib extends OneArgFunction implements ResourceFinder {
public static BaseLib instance;
public InputStream STDIN = null;
public PrintStream STDOUT = System.out;
public PrintStream STDERR = System.err;
/**
* Singleton file opener for this Java ClassLoader realm.
*
* Unless set or changed elsewhere, will be set by the BaseLib that is created.
*/
public static ResourceFinder FINDER;
private LuaValue next;
private LuaValue inext;
private static final String[] LIB2_KEYS = {
"collectgarbage", // ( opt [,arg] ) -> value
"error", // ( message [,level] ) -> ERR
"setfenv", // (f, table) -> void
};
private static final String[] LIBV_KEYS = {
"assert", // ( v [,message] ) -> v, message | ERR
"dofile", // ( filename ) -> result1, ...
"getfenv", // ( [f] ) -> env
"getmetatable", // ( object ) -> table
"load", // ( func [,chunkname] ) -> chunk | nil, msg
"loadfile", // ( [filename] ) -> chunk | nil, msg
"loadstring", // ( string [,chunkname] ) -> chunk | nil, msg
"pcall", // (f, arg1, ...) -> status, result1, ...
"xpcall", // (f, err) -> result1, ...
"print", // (...) -> void
"select", // (f, ...) -> value1, ...
"unpack", // (list [,i [,j]]) -> result1, ...
"type", // (v) -> value
"rawequal", // (v1, v2) -> boolean
"rawget", // (table, index) -> value
"rawset", // (table, index, value) -> table
"setmetatable", // (table, metatable) -> table
"tostring", // (e) -> value
"tonumber", // (e [,base]) -> value
"pairs", // "pairs" (t) -> iter-func, t, nil
"ipairs", // "ipairs", // (t) -> iter-func, t, 0
"next", // "next" ( table, [index] ) -> next-index, next-value
"__inext", // "inext" ( table, [int-index] ) -> next-index, next-value
};
/**
* Construct a base libarary instance.
*/
public BaseLib() {
instance = this;
}
public LuaValue call(LuaValue arg) {
env.set( "_G", env );
env.set( "_VERSION", Lua._VERSION );
bind( env, BaseLib2.class, LIB2_KEYS );
bind( env, BaseLibV.class, LIBV_KEYS );
// remember next, and inext for use in pairs and ipairs
next = env.get("next");
inext = env.get("__inext");
// inject base lib int vararg instances
for ( int i=0; i<LIBV_KEYS.length; i++ )
((BaseLibV) env.get(LIBV_KEYS[i])).baselib = this;
// set the default resource finder if not set already
if ( FINDER == null )
FINDER = this;
return env;
}
/** ResourceFinder implementation
*
* Tries to open the file as a resource, which can work for .
*/
public InputStream findResource(String filename) {
Class c = getClass();
return c.getResourceAsStream(filename.startsWith("/")? filename: "/"+filename);
}
static final class BaseLib2 extends TwoArgFunction {
public LuaValue call(LuaValue arg1, LuaValue arg2) {
switch ( opcode ) {
case 0: // "collectgarbage", // ( opt [,arg] ) -> value
String s = arg1.checkjstring();
int result = 0;
if ( "collect".equals(s) ) {
System.gc();
return ZERO;
} else if ( "count".equals(s) ) {
Runtime rt = Runtime.getRuntime();
long used = rt.totalMemory() - rt.freeMemory();
return valueOf(used/1024.);
} else if ( "step".equals(s) ) {
System.gc();
return LuaValue.TRUE;
} else {
this.argerror(1, "gc op");
}
return NIL;
case 1: // "error", // ( message [,level] ) -> ERR
throw new LuaError( arg1.isnil()? null: arg1.tojstring(), arg2.optint(1) );
case 2: { // "setfenv", // (f, table) -> void
LuaTable t = arg2.checktable();
LuaValue f = getfenvobj(arg1);
if ( ! f.isthread() && ! f.isclosure() )
error("'setfenv' cannot change environment of given object");
f.setfenv(t);
return f.isthread()? NONE: f;
}
}
return NIL;
}
}
private static LuaValue getfenvobj(LuaValue arg) {
if ( arg.isfunction() )
return arg;
int level = arg.optint(1);
arg.argcheck(level>=0, 1, "level must be non-negative");
if ( level == 0 )
return LuaThread.getRunning();
LuaValue f = LuaThread.getCallstackFunction(level);
arg.argcheck(f != null, 1, "invalid level");
return f;
}
static final class BaseLibV extends VarArgFunction {
public BaseLib baselib;
public Varargs invoke(Varargs args) {
switch ( opcode ) {
case 0: // "assert", // ( v [,message] ) -> v, message | ERR
if ( !args.arg1().toboolean() )
error( args.narg()>1? args.optjstring(2,"assertion failed!"): "assertion failed!" );
return args;
case 1: // "dofile", // ( filename ) -> result1, ...
{
Varargs v = args.isnil(1)?
BaseLib.loadStream( baselib.STDIN, "=stdin" ):
BaseLib.loadFile( args.checkjstring(1) );
return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke();
}
case 2: // "getfenv", // ( [f] ) -> env
{
LuaValue f = getfenvobj(args.arg1());
LuaValue e = f.getfenv();
return e!=null? e: NIL;
}
case 3: // "getmetatable", // ( object ) -> table
{
LuaValue mt = args.checkvalue(1).getmetatable();
return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL;
}
case 4: // "load", // ( func [,chunkname] ) -> chunk | nil, msg
{
LuaValue func = args.checkfunction(1);
String chunkname = args.optjstring(2, "function");
return BaseLib.loadStream(new StringInputStream(func), chunkname);
}
case 5: // "loadfile", // ( [filename] ) -> chunk | nil, msg
{
return args.isnil(1)?
BaseLib.loadStream( baselib.STDIN, "stdin" ):
BaseLib.loadFile( args.checkjstring(1) );
}
case 6: // "loadstring", // ( string [,chunkname] ) -> chunk | nil, msg
{
LuaString script = args.checkstring(1);
String chunkname = args.optjstring(2, "string");
return BaseLib.loadStream(script.toInputStream(),chunkname);
}
case 7: // "pcall", // (f, arg1, ...) -> status, result1, ...
{
LuaValue func = args.checkvalue(1);
LuaThread.CallStack cs = LuaThread.onCall(this);
try {
return pcall(func,args.subargs(2),null);
} finally {
cs.onReturn();
}
}
case 8: // "xpcall", // (f, err) -> result1, ...
{
LuaThread.CallStack cs = LuaThread.onCall(this);
try {
return pcall(args.arg1(),NONE,args.checkvalue(2));
} finally {
cs.onReturn();
}
}
case 9: // "print", // (...) -> void
{
LuaValue tostring = LuaThread.getGlobals().get("tostring");
for ( int i=1, n=args.narg(); i<=n; i++ ) {
if ( i>1 ) baselib.STDOUT.write( '\t' );
LuaString s = tostring.call( args.arg(i) ).strvalue();
int z = s.indexOf((byte)0, 0);
baselib.STDOUT.write( s.m_bytes, s.m_offset, z>=0? z: s.m_length );
}
baselib.STDOUT.println();
return NONE;
}
case 10: // "select", // (f, ...) -> value1, ...
{
int n = args.narg()-1;
if ( args.arg1().equals(valueOf("#")) )
return valueOf(n);
int i = args.checkint(1);
if ( i == 0 || i < -n )
argerror(1,"index out of range");
return args.subargs(i<0? n+i+2: i+1);
}
case 11: // "unpack", // (list [,i [,j]]) -> result1, ...
{
int na = args.narg();
LuaTable t = args.checktable(1);
int n = t.length();
int i = na>=2? args.checkint(2): 1;
int j = na>=3? args.checkint(3): n;
n = j-i+1;
if ( n<0 ) return NONE;
if ( n==1 ) return t.get(i);
if ( n==2 ) return varargsOf(t.get(i),t.get(j));
LuaValue[] v = new LuaValue[n];
for ( int k=0; k<n; k++ )
v[k] = t.get(i+k);
return varargsOf(v);
}
case 12: // "type", // (v) -> value
return valueOf(args.checkvalue(1).typename());
case 13: // "rawequal", // (v1, v2) -> boolean
return valueOf(args.checkvalue(1) == args.checkvalue(2));
case 14: // "rawget", // (table, index) -> value
return args.checktable(1).rawget(args.checkvalue(2));
case 15: { // "rawset", // (table, index, value) -> table
LuaTable t = args.checktable(1);
t.rawset(args.checknotnil(2), args.checkvalue(3));
return t;
}
case 16: { // "setmetatable", // (table, metatable) -> table
final LuaValue t = args.arg1();
final LuaValue mt0 = t.getmetatable();
if ( mt0!=null && !mt0.rawget(METATABLE).isnil() )
error("cannot change a protected metatable");
final LuaValue mt = args.checkvalue(2);
return t.setmetatable(mt.isnil()? null: mt.checktable());
}
case 17: { // "tostring", // (e) -> value
LuaValue arg = args.checkvalue(1);
LuaValue h = arg.metatag(TOSTRING);
if ( ! h.isnil() )
return h.call(arg);
LuaValue v = arg.tostring();
if ( ! v.isnil() )
return v;
return valueOf(arg.tojstring());
}
case 18: { // "tonumber", // (e [,base]) -> value
LuaValue arg1 = args.checkvalue(1);
final int base = args.optint(2,10);
if (base == 10) { /* standard conversion */
return arg1.tonumber();
} else {
if ( base < 2 || base > 36 )
argerror(2, "base out of range");
return arg1.checkstring().tonumber(base);
}
}
case 19: // "pairs" (t) -> iter-func, t, nil
return varargsOf( baselib.next, args.checktable(1), NIL );
case 20: // "ipairs", // (t) -> iter-func, t, 0
return varargsOf( baselib.inext, args.checktable(1), ZERO );
case 21: // "next" ( table, [index] ) -> next-index, next-value
return args.checktable(1).next(args.arg(2));
case 22: // "inext" ( table, [int-index] ) -> next-index, next-value
return args.checktable(1).inext(args.arg(2));
}
return NONE;
}
}
public static Varargs pcall(LuaValue func, Varargs args, LuaValue errfunc) {
LuaValue olderr = LuaThread.setErrorFunc(errfunc);
try {
Varargs result = varargsOf(LuaValue.TRUE, func.invoke(args));
LuaThread.setErrorFunc(olderr);
return result;
} catch ( LuaError le ) {
LuaThread.setErrorFunc(olderr);
String m = le.getMessage();
return varargsOf(FALSE, m!=null? valueOf(m): NIL);
} catch ( Exception e ) {
LuaThread.setErrorFunc(olderr);
String m = e.getMessage();
return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
}
}
/**
* Load from a named file, returning the chunk or nil,error of can't load
* @return Varargs containing chunk, or NIL,error-text on error
*/
public static Varargs loadFile(String filename) {
InputStream is = FINDER.findResource(filename);
if ( is == null )
return varargsOf(NIL, valueOf("cannot open "+filename+": No such file or directory"));
try {
return loadStream(is, "@"+filename);
} finally {
try {
is.close();
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
public static Varargs loadStream(InputStream is, String chunkname) {
try {
if ( is == null )
return varargsOf(NIL, valueOf("not found: "+chunkname));
return LoadState.load(is, chunkname, LuaThread.getGlobals());
} catch (Exception e) {
return varargsOf(NIL, valueOf(e.getMessage()));
}
}
private static class StringInputStream extends InputStream {
final LuaValue func;
byte[] bytes;
int offset, remaining = 0;
StringInputStream(LuaValue func) {
this.func = func;
}
public int read() throws IOException {
if ( remaining <= 0 ) {
LuaValue s = func.call();
if ( s.isnil() )
return -1;
LuaString ls = s.strvalue();
bytes = ls.m_bytes;
offset = ls.m_offset;
remaining = ls.m_length;
if (remaining <= 0)
return -1;
}
--remaining;
return bytes[offset++];
}
}
}

View File

@@ -1,181 +0,0 @@
/*******************************************************************************
* Copyright (c) 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.
******************************************************************************/
package org.luaj.vm2.lib;
import org.luaj.vm2.LuaInteger;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of LibFunction that implements the Lua standard {@code bit32} library.
*/
public class Bit32Lib extends ZeroArgFunction
{
public LuaValue call( )
{
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"
} );
env.set( "bit32", t );
return t;
}
public static final class Bit32LibV extends VarArgFunction
{
public Varargs invoke( Varargs args )
{
switch( opcode )
{
case 0: // band
{
int result = -1;
for( int i = 1; i <= args.narg(); i++ )
{
result &= args.checkint( i );
}
return bitsToValue( result );
}
case 1: // bnot
return bitsToValue( ~args.checkint( 1 ) );
case 2: // bot
{
int result = 0;
for( int i = 1; i <= args.narg(); i++ )
{
result |= args.checkint( i );
}
return bitsToValue( result );
}
case 3: // btest
{
int bits = -1;
for( int i = 1; i <= args.narg(); i++ )
{
bits &= args.checkint( i );
}
return valueOf( bits != 0 );
}
case 4: // bxor
{
int result = 0;
for( int i = 1; i <= args.narg(); i++ )
{
result ^= args.checkint( i );
}
return bitsToValue( result );
}
case 5: // extract
{
int field = args.checkint( 2 );
int width = args.optint( 3, 1 );
if( field < 0 ) argerror( 2, "field cannot be negative" );
if( width <= 0 ) argerror( 3, "width must be postive" );
if( field + width > 32 ) error( "trying to access non-existent bits" );
return bitsToValue( (args.checkint( 1 ) >>> field) & (-1 >>> (32 - width)) );
}
case 6: // replace
{
int n = args.checkint( 1 );
int v = args.checkint( 2 );
int field = args.checkint( 3 );
int width = args.optint( 4, 1 );
if( field < 0 ) argerror( 3, "field cannot be negative" );
if( width <= 0 ) argerror( 4, "width must be postive" );
if( field + width > 32 ) error( "trying to access non-existent bits" );
int mask = (-1 >>> (32 - width)) << field;
n = (n & ~mask) | ((v << field) & mask);
return bitsToValue( n );
}
}
return NIL;
}
}
public static final class Bit32Lib2 extends TwoArgFunction
{
public LuaValue call( LuaValue arg1, LuaValue arg2 )
{
switch( opcode )
{
case 0: // arshift
{
int x = arg1.checkint();
int disp = arg2.checkint();
return disp >= 0 ? bitsToValue( x >> disp ) : bitsToValue( x << -disp );
}
case 1: // lrotate
return rotate( arg1.checkint(), arg2.checkint() );
case 2: // lshift
return shift( arg1.checkint(), arg2.checkint() );
case 3: // rrotate
return rotate( arg1.checkint(), -arg2.checkint() );
case 4: // rshift
return shift( arg1.checkint(), -arg2.checkint() );
}
return NIL;
}
}
static LuaValue rotate( int x, int disp )
{
if( disp < 0 )
{
disp = -disp & 31;
return bitsToValue( (x >>> disp) | (x << (32 - disp)) );
}
else
{
disp = disp & 31;
return bitsToValue( (x << disp) | (x >>> (32 - disp)) );
}
}
static LuaValue shift( int x, int disp )
{
if( disp >= 32 || disp <= -32 )
{
return ZERO;
}
else if( disp >= 0 )
{
return bitsToValue( x << disp );
}
else
{
return bitsToValue( x >>> -disp );
}
}
private static LuaValue bitsToValue( int x )
{
return x < 0 ? LuaValue.valueOf( (long) x & 0xFFFFFFFFL ) : LuaInteger.valueOf( x );
}
}

View File

@@ -1,134 +0,0 @@
/*******************************************************************************
* Copyright (c) 2007-2011 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.
******************************************************************************/
package org.luaj.vm2.lib;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* 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.
* <p>
* Typically, this library is included as part of a call to either
* {@link JsePlatform#standardGlobals()} or {@link JmePlatform#standardGlobals()}
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* LuaTable _G = new LuaTable();
* _G.load(new CoroutineLib());
* } </pre>
* Doing so will ensure the library is properly initialized
* and loaded into the globals table.
* <p>
* @see LibFunction
* @see JsePlatform
* @see JmePlatform
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.2">http://www.lua.org/manual/5.1/manual.html#5.2</a>
*/
public class CoroutineLib extends VarArgFunction {
private static final int INIT = 0;
private static final int CREATE = 1;
private static final int RESUME = 2;
private static final int RUNNING = 3;
private static final int STATUS = 4;
private static final int YIELD = 5;
private static final int WRAP = 6;
private static final int WRAPPED = 7;
public CoroutineLib() {
}
private LuaTable init() {
LuaTable t = new LuaTable();
bind(t, CoroutineLib.class, new String[] {
"create", "resume", "running", "status", "yield", "wrap" },
CREATE);
env.set("coroutine", t);
PackageLib.instance.LOADED.set("coroutine", t);
return t;
}
public Varargs invoke(Varargs args) {
switch ( opcode ) {
case INIT: {
return init();
}
case CREATE: {
final LuaValue func = args.checkfunction(1);
/* DAN200 START */
//return new LuaThread(func, LuaThread.getGlobals() );
final LuaThread thread = new LuaThread( func, LuaThread.getGlobals() );
LuaThread.getRunning().addChild( thread );
return thread;
/* DAN200 END */
}
case RESUME: {
final LuaThread t = args.checkthread(1);
return t.resume( args.subargs(2) );
}
case RUNNING: {
final LuaThread r = LuaThread.getRunning();
return LuaThread.isMainThread(r)? NIL: r;
}
case STATUS: {
return valueOf( args.checkthread(1).getStatus() );
}
case YIELD: {
return LuaThread.yield( args );
}
case WRAP: {
final LuaValue func = args.checkfunction(1);
final LuaThread thread = new LuaThread(func, func.getfenv());
/* DAN200 START */
LuaThread.getRunning().addChild( thread );
/* DAN200 END */
CoroutineLib cl = new CoroutineLib();
cl.setfenv(thread);
cl.name = "wrapped";
cl.opcode = WRAPPED;
return cl;
}
case WRAPPED: {
final LuaThread t = (LuaThread) env;
final Varargs result = t.resume( args );
if ( result.arg1().toboolean() ) {
return result.subargs(2);
} else {
error( result.arg(2).tojstring() );
}
}
default:
return NONE;
}
}
}

View File

@@ -1,977 +0,0 @@
/*******************************************************************************
* 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.lang.ref.WeakReference;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaBoolean;
import org.luaj.vm2.LuaClosure;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaNil;
import org.luaj.vm2.LuaNumber;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Print;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.Varargs;
/**
* 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 LuaCompiler} such as {@link LuaJC},
* this cannot be done in all cases.
* <p>
* Typically, this library is included as part of a call to either
* {@link JsePlatform#debugGlobals()} or {@link JmePlatform#debugGlobals()}
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* LuaTable _G = new LuaTable();
* _G.load(new DebugLib());
* } </pre>
* Doing so will ensure the library is properly initialized
* and loaded into the globals table.
* <p>
* @see LibFunction
* @see JsePlatform
* @see JmePlatform
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.9">http://www.lua.org/manual/5.1/manual.html#5.9</a>
*/
public class DebugLib extends VarArgFunction {
public static final boolean CALLS = (null != System.getProperty("CALLS"));
public static final boolean TRACE = (null != System.getProperty("TRACE"));
// leave this unset to allow obfuscators to
// remove it in production builds
public static boolean DEBUG_ENABLED;
static final String[] NAMES = {
"debug",
"getfenv",
"gethook",
"getinfo",
"getlocal",
"getmetatable",
"getregistry",
"getupvalue",
"setfenv",
"sethook",
"setlocal",
"setmetatable",
"setupvalue",
"traceback",
};
private static final int INIT = 0;
private static final int DEBUG = 1;
private static final int GETFENV = 2;
private static final int GETHOOK = 3;
private static final int GETINFO = 4;
private static final int GETLOCAL = 5;
private static final int GETMETATABLE = 6;
private static final int GETREGISTRY = 7;
private static final int GETUPVALUE = 8;
private static final int SETFENV = 9;
private static final int SETHOOK = 10;
private static final int SETLOCAL = 11;
private static final int SETMETATABLE = 12;
private static final int SETUPVALUE = 13;
private static final int TRACEBACK = 14;
/* maximum stack for a Lua function */
private static final int MAXSTACK = 250;
private static final LuaString LUA = valueOf("Lua");
private static final LuaString JAVA = valueOf("Java");
private static final LuaString QMARK = valueOf("?");
private static final LuaString GLOBAL = valueOf("global");
private static final LuaString LOCAL = valueOf("local");
private static final LuaString METHOD = valueOf("method");
private static final LuaString UPVALUE = valueOf("upvalue");
private static final LuaString FIELD = valueOf("field");
private static final LuaString CALL = valueOf("call");
private static final LuaString LINE = valueOf("line");
private static final LuaString COUNT = valueOf("count");
private static final LuaString RETURN = valueOf("return");
private static final LuaString TAILRETURN = valueOf("tail return");
private static final LuaString FUNC = valueOf("func");
private static final LuaString NUPS = valueOf("nups");
private static final LuaString NAME = valueOf("name");
private static final LuaString NAMEWHAT = valueOf("namewhat");
private static final LuaString WHAT = valueOf("what");
private static final LuaString SOURCE = valueOf("source");
private static final LuaString SHORT_SRC = valueOf("short_src");
private static final LuaString LINEDEFINED = valueOf("linedefined");
private static final LuaString LASTLINEDEFINED = valueOf("lastlinedefined");
private static final LuaString CURRENTLINE = valueOf("currentline");
private static final LuaString ACTIVELINES = valueOf("activelines");
public DebugLib() {
}
private LuaTable init() {
DEBUG_ENABLED = true;
LuaTable t = new LuaTable();
bind(t, DebugLib.class, NAMES, DEBUG);
env.set("debug", t);
PackageLib.instance.LOADED.set("debug", t);
return t;
}
public Varargs invoke(Varargs args) {
switch ( opcode ) {
case INIT: return init();
case DEBUG: return _debug(args);
case GETFENV: return _getfenv(args);
case GETHOOK: return _gethook(args);
case GETINFO: return _getinfo(args,this);
case GETLOCAL: return _getlocal(args);
case GETMETATABLE: return _getmetatable(args);
case GETREGISTRY: return _getregistry(args);
case GETUPVALUE: return _getupvalue(args);
case SETFENV: return _setfenv(args);
case SETHOOK: return _sethook(args);
case SETLOCAL: return _setlocal(args);
case SETMETATABLE: return _setmetatable(args);
case SETUPVALUE: return _setupvalue(args);
case TRACEBACK: return _traceback(args);
default: return NONE;
}
}
// ------------------------ Debug Info management --------------------------
//
// when DEBUG_ENABLED is set to true, these functions will be called
// by Closure instances as they process bytecodes.
//
// Each thread will get a DebugState attached to it by the debug library
// which will track function calls, hook functions, etc.
//
static class DebugInfo {
LuaValue func;
LuaClosure closure;
LuaValue[] stack;
Varargs varargs, extras;
int pc, top;
private DebugInfo() {
func = NIL;
}
private DebugInfo(LuaValue func) {
pc = -1;
setfunction( func );
}
void setargs(Varargs varargs, LuaValue[] stack) {
this.varargs = varargs;
this.stack = stack;
}
void setfunction( LuaValue func ) {
this.func = func;
this.closure = (func instanceof LuaClosure? (LuaClosure) func: null);
}
void clear() {
func = NIL;
closure = null;
stack = null;
varargs = extras = null;
pc = top = 0;
}
public void bytecode(int pc, Varargs extras, int top) {
this.pc = pc;
this.top = top;
this.extras = extras;
}
public int currentline() {
if ( closure == null ) return -1;
int[] li = closure.p.lineinfo;
return li==null || pc<0 || pc>=li.length? -1: li[pc];
}
public LuaString[] getfunckind() {
if ( closure == null || pc<0 ) return null;
int stackpos = (closure.p.code[pc] >> 6) & 0xff;
return getobjname(this, stackpos);
}
public String sourceline() {
if ( closure == null ) return func.tojstring();
String s = closure.p.source.tojstring();
int line = currentline();
return (s.startsWith("@")||s.startsWith("=")? s.substring(1): s) + ":" + line;
}
public String tracename() {
// if ( func != null )
// return func.tojstring();
LuaString[] kind = getfunckind();
if ( kind == null )
return "function ?";
return "function "+kind[0].tojstring();
}
public LuaString getlocalname(int index) {
if ( closure == null ) return null;
return closure.p.getlocalname(index, pc);
}
public String tojstring() {
return tracename()+" "+sourceline();
}
}
/** DebugState is associated with a Thread */
static class DebugState {
private final WeakReference thread_ref;
private int debugCalls = 0;
private DebugInfo[] debugInfo = new DebugInfo[LuaThread.MAX_CALLSTACK+1];
private LuaValue hookfunc;
private boolean hookcall,hookline,hookrtrn,inhook;
private int hookcount,hookcodes;
private int line;
DebugState(LuaThread thread) {
this.thread_ref = new WeakReference(thread);
}
public DebugInfo nextInfo() {
DebugInfo di = debugInfo[debugCalls];
if ( di == null )
debugInfo[debugCalls] = di = new DebugInfo();
return di;
}
public DebugInfo pushInfo( int calls ) {
while ( debugCalls < calls ) {
nextInfo();
++debugCalls;
}
return debugInfo[debugCalls-1];
}
public void popInfo(int calls) {
while ( debugCalls > calls )
debugInfo[--debugCalls].clear();
}
void callHookFunc(DebugState ds, LuaString type, LuaValue arg) {
if ( inhook || hookfunc == null )
return;
inhook = true;
try {
int n = debugCalls;
ds.nextInfo().setargs( arg, null );
ds.pushInfo(n+1).setfunction(hookfunc);
try {
hookfunc.call(type,arg);
} finally {
ds.popInfo(n);
}
} catch ( Exception e ) {
e.printStackTrace();
} finally {
inhook = false;
}
}
public void sethook(LuaValue func, boolean call, boolean line, boolean rtrn, int count) {
this.hookcount = count;
this.hookcall = call;
this.hookline = line;
this.hookrtrn = rtrn;
this.hookfunc = func;
}
DebugInfo getDebugInfo() {
try {
return debugInfo[debugCalls-1];
} catch ( Exception e ) {
if ( debugCalls <= 0 )
return debugInfo[debugCalls++] = new DebugInfo();
return null;
}
}
DebugInfo getDebugInfo(int level) {
return level < 0 || level >= debugCalls? null: debugInfo[debugCalls-level-1];
}
public DebugInfo findDebugInfo(LuaValue func) {
for ( int i=debugCalls; --i>=0; ) {
if ( debugInfo[i].func == func ) {
return debugInfo[i];
}
}
return new DebugInfo(func);
}
public String tojstring() {
LuaThread thread = (LuaThread) thread_ref.get();
return thread != null? DebugLib.traceback(thread, 0): "orphaned thread";
}
}
static DebugState getDebugState( LuaThread thread ) {
if ( thread.debugState == null )
thread.debugState = new DebugState(thread);
return (DebugState) thread.debugState;
}
static DebugState getDebugState() {
return getDebugState( LuaThread.getRunning() );
}
/** Called by Closures to set up stack and arguments to next call */
public static void debugSetupCall(Varargs args, LuaValue[] stack) {
DebugState ds = getDebugState();
if ( ds.inhook )
return;
ds.nextInfo().setargs( args, stack );
}
/** Called by Closures and recursing java functions on entry
* @param thread the thread for the call
* @param calls the number of calls in the call stack
* @param func the function called
*/
public static void debugOnCall(LuaThread thread, int calls, LuaFunction func) {
DebugState ds = getDebugState();
if ( ds.inhook )
return;
DebugInfo di = ds.pushInfo(calls);
di.setfunction( func );
if(CALLS)System.out.println("calling "+func);
if ( ds.hookcall )
ds.callHookFunc( ds, CALL, LuaValue.NIL );
}
/** Called by Closures and recursing java functions on return
* @param thread the thread for the call
* @param calls the number of calls in the call stack
*/
public static void debugOnReturn(LuaThread thread, int calls) {
DebugState ds = getDebugState(thread);
if ( ds.inhook )
return;
if(CALLS)System.out.println("returning");
try {
if ( ds.hookrtrn )
ds.callHookFunc( ds, RETURN, LuaValue.NIL );
} finally {
getDebugState().popInfo(calls);
}
}
/** Called by Closures on bytecode execution */
public static void debugBytecode( int pc, Varargs extras, int top ) {
DebugState ds = getDebugState();
if ( ds.inhook )
return;
DebugInfo di = ds.getDebugInfo();
if(TRACE)Print.printState(di.closure, pc, di.stack, top, di.varargs);
di.bytecode( pc, extras, top );
if ( ds.hookcount > 0 ) {
if ( ++ds.hookcodes >= ds.hookcount ) {
ds.hookcodes = 0;
ds.callHookFunc( ds, COUNT, LuaValue.NIL );
}
}
if ( ds.hookline ) {
int newline = di.currentline();
if ( newline != ds.line ) {
int c = di.closure.p.code[pc];
if ( (c&0x3f) != Lua.OP_JMP || ((c>>>14)-0x1ffff) >= 0 ) {
ds.line = newline;
ds.callHookFunc( ds, LINE, LuaValue.valueOf(newline) );
}
}
}
}
// ------------------- library function implementations -----------------
// j2se subclass may wish to override and provide actual console here.
// j2me platform has not System.in to provide console.
static Varargs _debug(Varargs args) {
return NONE;
}
static Varargs _gethook(Varargs args) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
DebugState ds = getDebugState(thread);
return varargsOf(
ds.hookfunc,
valueOf((ds.hookcall?"c":"")+(ds.hookline?"l":"")+(ds.hookrtrn?"r":"")),
valueOf(ds.hookcount));
}
static Varargs _sethook(Varargs args) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
LuaValue func = args.optfunction(a++, null);
String str = args.optjstring(a++,"");
int count = args.optint(a++,0);
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;
}
getDebugState(thread).sethook(func, call, line, rtrn, count);
return NONE;
}
static Varargs _getfenv(Varargs args) {
LuaValue object = args.arg1();
LuaValue env = object.getfenv();
return env!=null? env: LuaValue.NIL;
}
static Varargs _setfenv(Varargs args) {
LuaValue object = args.arg1();
LuaTable table = args.checktable(2);
object.setfenv(table);
return object;
}
protected static Varargs _getinfo(Varargs args, LuaValue level0func) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
LuaValue func = args.arg(a++);
String what = args.optjstring(a++, "nSluf");
// find the stack info
DebugState ds = getDebugState( thread );
DebugInfo di = null;
if ( func.isnumber() ) {
int level = func.checkint();
di = level>0?
ds.getDebugInfo(level-1):
new DebugInfo( level0func );
} else {
di = ds.findDebugInfo( func.checkfunction() );
}
if ( di == null )
return NIL;
// start a table
LuaTable info = new LuaTable();
LuaClosure c = di.closure;
for (int i = 0, j = what.length(); i < j; i++) {
switch (what.charAt(i)) {
case 'S': {
if ( c != null ) {
Prototype p = c.p;
info.set(WHAT, LUA);
info.set(SOURCE, p.source);
info.set(SHORT_SRC, valueOf(sourceshort(p)));
info.set(LINEDEFINED, valueOf(p.linedefined));
info.set(LASTLINEDEFINED, valueOf(p.lastlinedefined));
} else {
String shortName = di.func.tojstring();
LuaString name = LuaString.valueOf("[Java] "+shortName);
info.set(WHAT, JAVA);
info.set(SOURCE, name);
info.set(SHORT_SRC, valueOf(shortName));
info.set(LINEDEFINED, LuaValue.MINUSONE);
info.set(LASTLINEDEFINED, LuaValue.MINUSONE);
}
break;
}
case 'l': {
int line = di.currentline();
info.set( CURRENTLINE, valueOf(line) );
break;
}
case 'u': {
info.set(NUPS, valueOf(c!=null? c.p.nups: 0));
break;
}
case 'n': {
LuaString[] kind = di.getfunckind();
info.set(NAME, kind!=null? kind[0]: QMARK);
info.set(NAMEWHAT, kind!=null? kind[1]: EMPTYSTRING);
break;
}
case 'f': {
info.set( FUNC, di.func );
break;
}
case 'L': {
LuaTable lines = new LuaTable();
info.set(ACTIVELINES, lines);
// if ( di.luainfo != null ) {
// int line = di.luainfo.currentline();
// if ( line >= 0 )
// lines.set(1, IntValue.valueOf(line));
// }
break;
}
}
}
return info;
}
public static String sourceshort(Prototype p) {
String name = p.source.tojstring();
if ( name.startsWith("@") || name.startsWith("=") )
name = name.substring(1);
else if ( name.startsWith("\033") )
name = "binary string";
return name;
}
static Varargs _getlocal(Varargs args) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
int level = args.checkint(a++);
int local = args.checkint(a++);
DebugState ds = getDebugState(thread);
DebugInfo di = ds.getDebugInfo(level-1);
LuaString name = (di!=null? di.getlocalname(local): null);
if ( name != null ) {
LuaValue value = di.stack[local-1];
return varargsOf( name, value );
} else {
return NIL;
}
}
static Varargs _setlocal(Varargs args) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
int level = args.checkint(a++);
int local = args.checkint(a++);
LuaValue value = args.arg(a++);
DebugState ds = getDebugState(thread);
DebugInfo di = ds.getDebugInfo(level-1);
LuaString name = (di!=null? di.getlocalname(local): null);
if ( name != null ) {
di.stack[local-1] = value;
return name;
} else {
return NIL;
}
}
static LuaValue _getmetatable(Varargs args) {
LuaValue object = args.arg(1);
LuaValue mt = object.getmetatable();
return mt!=null? mt: NIL;
}
static Varargs _setmetatable(Varargs args) {
LuaValue object = args.arg(1);
try {
LuaValue mt = args.opttable(2, null);
switch ( object.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: object.setmetatable( mt );
}
return LuaValue.TRUE;
} catch ( LuaError e ) {
return varargsOf(FALSE, valueOf(e.toString()));
}
}
static Varargs _getregistry(Varargs args) {
return new LuaTable();
}
static LuaString findupvalue(LuaClosure c, int up) {
if ( c.upValues != null && up > 0 && up <= c.upValues.length ) {
if ( c.p.upvalues != null && up <= c.p.upvalues.length )
return c.p.upvalues[up-1];
else
return LuaString.valueOf( "."+up );
}
return null;
}
static Varargs _getupvalue(Varargs args) {
LuaValue func = args.checkfunction(1);
int up = args.checkint(2);
if ( func instanceof LuaClosure ) {
LuaClosure c = (LuaClosure) func;
LuaString name = findupvalue(c, up);
if ( name != null ) {
return varargsOf(name, c.upValues[up-1].getValue() );
}
}
return NIL;
}
static LuaValue _setupvalue(Varargs args) {
LuaValue func = args.checkfunction(1);
int up = args.checkint(2);
LuaValue value = args.arg(3);
if ( func instanceof LuaClosure ) {
LuaClosure c = (LuaClosure) func;
LuaString name = findupvalue(c, up);
if ( name != null ) {
c.upValues[up-1].setValue(value);
return name;
}
}
return NIL;
}
static LuaValue _traceback(Varargs args) {
int a=1;
LuaThread thread = args.isthread(a)? args.checkthread(a++): LuaThread.getRunning();
String message = args.optjstring(a++, null);
int level = args.optint(a++,1);
String tb = DebugLib.traceback(thread, level-1);
return valueOf(message!=null? message+"\n"+tb: tb);
}
// =================== public utilities ====================
/**
* Get a traceback as a string for the current thread
*/
public static String traceback(int level) {
return traceback(LuaThread.getRunning(), level);
}
/**
* Get a traceback for a particular thread.
* @param thread LuaThread to provide stack trace for
* @param level 0-based level to start reporting on
* @return String containing the stack trace.
*/
public static String traceback(LuaThread thread, int level) {
StringBuffer sb = new StringBuffer();
DebugState ds = getDebugState(thread);
sb.append( "stack traceback:" );
DebugInfo di = ds.getDebugInfo(level);
if ( di != null ) {
sb.append( "\n\t" );
sb.append( di.sourceline() );
sb.append( " in " );
while ( (di = ds.getDebugInfo(++level)) != null ) {
sb.append( di.tracename() );
sb.append( "\n\t" );
sb.append( di.sourceline() );
sb.append( " in " );
}
sb.append( "main chunk" );
}
return sb.toString();
}
/**
* Get file and line for the nearest calling closure.
* @return String identifying the file and line of the nearest lua closure,
* or the function name of the Java call if no closure is being called.
*/
public static String fileline() {
DebugState ds = getDebugState(LuaThread.getRunning());
DebugInfo di;
for ( int i=0, n=ds.debugCalls; i<n; i++ ) {
di = ds.getDebugInfo(i);
if ( di != null && di.func.isclosure() )
return di.sourceline();
}
return fileline(0);
}
/**
* Get file and line for a particular level, even if it is a java function.
*
* @param level 0-based index of level to get
* @return String containing file and line info if available
*/
public static String fileline(int level) {
DebugState ds = getDebugState(LuaThread.getRunning());
DebugInfo di = ds.getDebugInfo(level);
return di!=null? di.sourceline(): null;
}
// =======================================================
static void lua_assert(boolean x) {
if (!x) throw new RuntimeException("lua_assert failed");
}
// return StrValue[] { name, namewhat } if found, null if not
static LuaString[] getobjname(DebugInfo di, int stackpos) {
LuaString name;
if (di.closure != null) { /* a Lua function? */
Prototype p = di.closure.p;
int pc = di.pc; // currentpc(L, ci);
int i;// Instruction i;
name = p.getlocalname(stackpos + 1, pc);
if (name != null) /* is a local? */
return new LuaString[] { name, LOCAL };
i = symbexec(p, pc, stackpos); /* try symbolic execution */
lua_assert(pc != -1);
switch (Lua.GET_OPCODE(i)) {
case Lua.OP_GETGLOBAL: {
int g = Lua.GETARG_Bx(i); /* global index */
// lua_assert(p.k[g].isString());
return new LuaString[] { p.k[g].strvalue(), GLOBAL };
}
case Lua.OP_MOVE: {
int a = Lua.GETARG_A(i);
int b = Lua.GETARG_B(i); /* move from `b' to `a' */
if (b < a)
return getobjname(di, b); /* get name for `b' */
break;
}
case Lua.OP_GETTABLE: {
int k = Lua.GETARG_C(i); /* key index */
name = kname(p, k);
return new LuaString[] { name, FIELD };
}
case Lua.OP_GETUPVAL: {
int u = Lua.GETARG_B(i); /* upvalue index */
name = u < p.upvalues.length ? p.upvalues[u] : QMARK;
return new LuaString[] { name, UPVALUE };
}
case Lua.OP_SELF: {
int k = Lua.GETARG_C(i); /* key index */
name = kname(p, k);
return new LuaString[] { name, METHOD };
}
default:
break;
}
}
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 boolean checkreg(Prototype pt,int reg) {
return (reg < pt.maxstacksize);
}
static boolean precheck(Prototype pt) {
if (!(pt.maxstacksize <= MAXSTACK)) return false;
lua_assert(pt.numparams + (pt.is_vararg & Lua.VARARG_HASARG) <= pt.maxstacksize);
lua_assert((pt.is_vararg & Lua.VARARG_NEEDSARG) == 0
|| (pt.is_vararg & Lua.VARARG_HASARG) != 0);
if (!(pt.upvalues.length <= pt.nups)) return false;
if (!(pt.lineinfo.length == pt.code.length || pt.lineinfo.length == 0)) return false;
if (!(Lua.GET_OPCODE(pt.code[pt.code.length - 1]) == Lua.OP_RETURN)) return false;
return true;
}
static boolean checkopenop(Prototype pt,int pc) {
int i = pt.code[(pc)+1];
switch (Lua.GET_OPCODE(i)) {
case Lua.OP_CALL:
case Lua.OP_TAILCALL:
case Lua.OP_RETURN:
case Lua.OP_SETLIST: {
if (!(Lua.GETARG_B(i) == 0)) return false;
return true;
}
default:
return false; /* invalid instruction after an open call */
}
}
//static int checkArgMode (Prototype pt, int r, enum OpArgMask mode) {
static boolean checkArgMode (Prototype pt, int r, int mode) {
switch (mode) {
case Lua.OpArgN: if (!(r == 0)) return false; break;
case Lua.OpArgU: break;
case Lua.OpArgR: checkreg(pt, r); break;
case Lua.OpArgK:
if (!(Lua.ISK(r) ? Lua.INDEXK(r) < pt.k.length : r < pt.maxstacksize)) return false;
break;
}
return true;
}
// return last instruction, or 0 if error
static int symbexec(Prototype pt, int lastpc, int reg) {
int pc;
int last; /* stores position of last instruction that changed `reg' */
last = pt.code.length - 1; /*
* points to final return (a `neutral'
* instruction)
*/
if (!(precheck(pt))) return 0;
for (pc = 0; pc < lastpc; pc++) {
int i = pt.code[pc];
int op = Lua.GET_OPCODE(i);
int a = Lua.GETARG_A(i);
int b = 0;
int c = 0;
if (!(op < Lua.NUM_OPCODES)) return 0;
if (!checkreg(pt, a)) return 0;
switch (Lua.getOpMode(op)) {
case Lua.iABC: {
b = Lua.GETARG_B(i);
c = Lua.GETARG_C(i);
if (!(checkArgMode(pt, b, Lua.getBMode(op)))) return 0;
if (!(checkArgMode(pt, c, Lua.getCMode(op)))) return 0;
break;
}
case Lua.iABx: {
b = Lua.GETARG_Bx(i);
if (Lua.getBMode(op) == Lua.OpArgK)
if (!(b < pt.k.length)) return 0;
break;
}
case Lua.iAsBx: {
b = Lua.GETARG_sBx(i);
if (Lua.getBMode(op) == Lua.OpArgR) {
int dest = pc + 1 + b;
if (!(0 <= dest && dest < pt.code.length)) return 0;
if (dest > 0) {
/* cannot jump to a setlist count */
int d = pt.code[dest - 1];
if ((Lua.GET_OPCODE(d) == Lua.OP_SETLIST && Lua.GETARG_C(d) == 0)) return 0;
}
}
break;
}
}
if (Lua.testAMode(op)) {
if (a == reg)
last = pc; /* change register `a' */
}
if (Lua.testTMode(op)) {
if (!(pc + 2 < pt.code.length)) return 0; /* check skip */
if (!(Lua.GET_OPCODE(pt.code[pc + 1]) == Lua.OP_JMP)) return 0;
}
switch (op) {
case Lua.OP_LOADBOOL: {
if (!(c == 0 || pc + 2 < pt.code.length)) return 0; /* check its jump */
break;
}
case Lua.OP_LOADNIL: {
if (a <= reg && reg <= b)
last = pc; /* set registers from `a' to `b' */
break;
}
case Lua.OP_GETUPVAL:
case Lua.OP_SETUPVAL: {
if (!(b < pt.nups)) return 0;
break;
}
case Lua.OP_GETGLOBAL:
case Lua.OP_SETGLOBAL: {
if (!(pt.k[b].isstring())) return 0;
break;
}
case Lua.OP_SELF: {
if (!checkreg(pt, a + 1)) return 0;
if (reg == a + 1)
last = pc;
break;
}
case Lua.OP_CONCAT: {
if (!(b < c)) return 0; /* at least two operands */
break;
}
case Lua.OP_TFORLOOP: {
if (!(c >= 1)) return 0; /* at least one result (control variable) */
if (!checkreg(pt, a + 2 + c)) return 0; /* space for results */
if (reg >= a + 2)
last = pc; /* affect all regs above its base */
break;
}
case Lua.OP_FORLOOP:
case Lua.OP_FORPREP:
if (!checkreg(pt, a + 3)) return 0;
/* go through */
case Lua.OP_JMP: {
int dest = pc + 1 + b;
/* not full check and jump is forward and do not skip `lastpc'? */
if (reg != Lua.NO_REG && pc < dest && dest <= lastpc)
pc += b; /* do the jump */
break;
}
case Lua.OP_CALL:
case Lua.OP_TAILCALL: {
if (b != 0) {
if (!checkreg(pt, a + b - 1)) return 0;
}
c--; /* c = num. returns */
if (c == Lua.LUA_MULTRET) {
if (!(checkopenop(pt, pc))) return 0;
} else if (c != 0)
if (!checkreg(pt, a + c - 1)) return 0;
if (reg >= a)
last = pc; /* affect all registers above base */
break;
}
case Lua.OP_RETURN: {
b--; /* b = num. returns */
if (b > 0)
if (!checkreg(pt, a + b - 1)) return 0;
break;
}
case Lua.OP_SETLIST: {
if (b > 0)
if (!checkreg(pt, a + b)) return 0;
if (c == 0)
pc++;
break;
}
case Lua.OP_CLOSURE: {
int nup, j;
if (!(b < pt.p.length)) return 0;
nup = pt.p[b].nups;
if (!(pc + nup < pt.code.length)) return 0;
for (j = 1; j <= nup; j++) {
int op1 = Lua.GET_OPCODE(pt.code[pc + j]);
if (!(op1 == Lua.OP_GETUPVAL || op1 == Lua.OP_MOVE)) return 0;
}
if (reg != Lua.NO_REG) /* tracing? */
pc += nup; /* do not 'execute' these pseudo-instructions */
break;
}
case Lua.OP_VARARG: {
if (!((pt.is_vararg & Lua.VARARG_ISVARARG) != 0
&& (pt.is_vararg & Lua.VARARG_NEEDSARG) == 0)) return 0;
b--;
if (b == Lua.LUA_MULTRET)
if (!(checkopenop(pt, pc))) return 0;
if (!checkreg(pt, a + b - 1)) return 0;
break;
}
default:
break;
}
}
return pt.code[last];
}
}

View File

@@ -1,607 +0,0 @@
/*******************************************************************************
* 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.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 JsePlatform#standardGlobals()} or {@link JmePlatform#standardGlobals()}
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* LuaTable _G = new LuaTable();
* _G.load(new JseIoLib());
* LuaThread.setGlobals(_G);
* _G.load(new JseBaseLib());
* _G.load(new PackageLib());
* _G.load(new JseIoLib());
* _G.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </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.
* @see LibFunction
* @see JsePlatform
* @see JmePlatform
* @see JseIoLib
* @see 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>
*/
abstract
public class IoLib extends OneArgFunction {
abstract
protected class File extends LuaValue{
abstract public void write( LuaString string ) throws IOException;
abstract public void flush() throws IOException;
abstract public boolean isstdfile();
abstract public void close() throws IOException;
abstract public boolean isclosed();
// returns new position
abstract public int seek(String option, int bytecount) throws IOException;
abstract public void setvbuf(String mode, int size);
// get length remaining to read
abstract public int remaining() throws IOException;
// peek ahead one character
abstract public int peek() throws IOException, EOFException;
// return char if read, -1 if eof, throw IOException on other exception
abstract public int read() throws IOException, EOFException;
// return number of bytes read if positive, false if eof, throw IOException on other exception
abstract public int read(byte[] bytes, int offset, int length) throws IOException;
// delegate method access to file methods table
public LuaValue get( LuaValue key ) {
return filemethods.get(key);
}
// essentially a userdata instance
public int type() {
return LuaValue.TUSERDATA;
}
public String typename() {
return "userdata";
}
// displays as "file" type
public String tojstring() {
return "file: " + Integer.toHexString(hashCode());
}
}
/**
* 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;
/**
* 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;
public IoLib() {
}
public LuaValue call(LuaValue arg) {
// 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);
PackageLib.instance.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 {
public IoLib iolib;
public IoLibV() {
}
public IoLibV(LuaValue env, String name, int opcode, IoLib iolib) {
super();
this.env = env;
this.name = name;
this.opcode = opcode;
this.iolib = iolib;
}
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.isvalue(1)? args.checkjstring(1): null);
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,1024));
case FILE_LINES: return iolib._file_lines(args.arg1());
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(env);
}
} catch ( IOException ioe ) {
return errorresult(ioe);
}
return NONE;
}
}
private File input() {
return infile!=null? infile: (infile=ioopenfile("-","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(file.checkjstring(),"r"):
checkfile(file);
return infile;
}
// io.output(filename) -> file
public Varargs _io_output(LuaValue filename) {
outfile = filename.isnil()? output():
filename.isstring()? ioopenfile(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 {
return openProgram(prog, mode);
}
// io.open(filename, [mode]) -> file | nil,err
public Varargs _io_open(String filename, String mode) throws IOException {
return rawopenfile(filename, mode);
}
// io.lines(filename) -> iterator
public Varargs _io_lines(String filename) {
infile = filename==null? input(): ioopenfile(filename,"r");
checkopen(infile);
return lines(infile);
}
// 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) {
checkfile(file).setvbuf(mode,size);
return LuaValue.TRUE;
}
// file:lines() -> iterator
public Varargs _file_lines(LuaValue file) {
return lines(checkfile(file));
}
// 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 {
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) throws IOException {
return freadline(checkfile(file));
}
private File output() {
return outfile!=null? outfile: (outfile=ioopenfile("-","w"));
}
private File errput() {
return errfile!=null? errfile: (errfile=ioopenfile("-","w"));
}
private File ioopenfile(String filename, String mode) {
try {
return rawopenfile(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;
}
private 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) {
try {
return new IoLibV(f,"lnext",LINES_ITER,this);
} 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 LuaValue.TRUE;
}
private Varargs ioread(File f, Varargs args) throws IOException {
int i,n=args.narg();
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); 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(String filename, String mode) throws IOException {
boolean isstdfile = "-".equals(filename);
boolean isreadmode = mode.startsWith("r");
if ( isstdfile ) {
return isreadmode?
wrapStdin():
wrapStdout();
}
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 {
byte[] b = new byte[count];
int r;
if ( ( r = f.read(b,0,b.length) ) < 0 )
return NIL;
return LuaString.valueOf(b, 0, r);
}
public static LuaValue freaduntil(File f,boolean lineonly) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c;
try {
if ( lineonly ) {
loop: while ( (c = f.read()) > 0 ) {
switch ( c ) {
case '\r': break;
case '\n': 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.valueOf(baos.toByteArray());
}
public static LuaValue freadline(File f) throws IOException {
return freaduntil(f,true);
}
public static LuaValue freadall(File f) throws IOException {
int n = f.remaining();
if ( n >= 0 ) {
return freadbytes(f, n);
} else {
return freaduntil(f,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

@@ -1,200 +0,0 @@
/*******************************************************************************
* 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 org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaValue;
/**
* 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.
* <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.
* <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.
* <ul>
* <li>{@link ZeroArgFunction}</li>
* <li>{@link OneArgFunction}</li>
* <li>{@link TwoArgFunction}</li>
* <li>{@link ThreeArgFunction}</li>
* <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,
* initializes the library.
* <p>
* For example, the following code will implement a library called "hyperbolic"
* with two functions, "sinh", and "cosh":
<pre> {@code
* import org.luaj.vm2.LuaValue;
* import org.luaj.vm2.lib.OneArgFunction;
*
* public class hyperbolic extends OneArgFunction {
*
* public hyperbolic() {}
*
* public LuaValue call(LuaValue libname) {
* LuaValue library = tableOf();
* library.set( "sinh", new sinh() );
* library.set( "cosh", new cosh() );
* env.set( "hyperbolic", library );
* return library;
* }
*
* static class sinh extends OneArgFunction {
* public LuaValue call(LuaValue x) {
* return LuaValue.valueOf(Math.sinh(x.checkdouble()));
* }
* }
*
* static class cosh extends OneArgFunction {
* public LuaValue call(LuaValue x) {
* return LuaValue.valueOf(Math.cosh(x.checkdouble()));
* }
* }
*}
*}</pre>
* The default constructor is used to instantiate the library
* in response to {@code require 'hyperbolic'} statement,
* provided it is on Javas class path.
* This instance is then invoked with the name supplied to require()
* as the only argument, and library should initialized whatever global
* data it needs to and place it into the environment if needed.
* In this case, it creates two function, 'sinh', and 'cosh', and puts
* them into a global table called 'hyperbolic.'
* It placed the library table into the globals via the {@link #env}
* local variable which corresponds to the globals that apply when the
* library is loaded.
* <p>
* To test it, a script such as this can be used:
* <pre> {@code
* local t = require('hyperbolic')
* print( 't', t )
* print( 'hyperbolic', hyperbolic )
* for k,v in pairs(t) do
* print( 'k,v', k,v )
* end
* print( 'sinh(.5)', hyperbolic.sinh(.5) )
* print( 'cosh(.5)', hyperbolic.cosh(.5) )
* }</pre>
* <p>
* It should produce something like:
* <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>
* <p>
* 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.
* <p>
* 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.
* <p>
* Binding functions initialize this to the name to which it is bound.
*/
protected String name;
/** Default constructor for use by subclasses */
protected LibFunction() {
}
public String tojstring() {
return name != null? name: super.tojstring();
}
/**
* 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.
* @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.
* @see #bind(LuaValue, Class, String[], int)
*/
protected void bind(LuaValue env, Class factory, String[] names ) {
bind( env, factory, names, 0 );
}
/**
* 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.
* @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.
* @param firstopcode the first opcode to use
* @see #bind(LuaValue, Class, String[])
*/
protected void bind(LuaValue env, Class factory, String[] names, int firstopcode ) {
try {
for ( int i=0, n=names.length; i<n; i++ ) {
LibFunction f = (LibFunction) factory.newInstance();
f.opcode = firstopcode + i;
f.name = names[i];
f.env = env;
env.set(f.name, f);
}
} catch ( Exception e ) {
throw new LuaError( "bind failed: "+e );
}
}
/** 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 */
protected static LuaValue[] newupn() {
return new LuaValue[] { NIL };
}
/** Java code generation utility to allocate storage for upvalue, initialize with value */
protected static LuaValue[] newupl(LuaValue v) {
return new LuaValue[] { v };
}
}

View File

@@ -1,251 +0,0 @@
/*******************************************************************************
* 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.util.Random;
import org.luaj.vm2.LuaDouble;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* 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:
* <ul>
* <li>acos</li>
* <li>asin</li>
* <li>atan</li>
* <li>cosh</li>
* <li>log</li>
* <li>log10</li>
* <li>sinh</li>
* <li>tanh</li>
* <li>atan2</li>
* </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.
* <p>
* Typically, this library is included as part of a call to either
* {@link JmePlatform#standardGlobals()}
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* LuaTable _G = new LuaTable();
* LuaThread.setGlobals(_G);
* _G.load(new BaseLib());
* _G.load(new PackageLib());
* _G.load(new MathLib());
* System.out.println( _G.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
* } </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.
* @see LibFunction
* @see JsePlatform
* @see JmePlatform
* @see JseMathLib
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.6">http://www.lua.org/manual/5.1/manual.html#5.6</a>
*/
public class MathLib extends OneArgFunction {
public static MathLib MATHLIB = null;
private Random random;
public MathLib() {
MATHLIB = this;
}
public LuaValue call(LuaValue arg) {
LuaTable t = new LuaTable(0,30);
t.set( "pi", Math.PI );
t.set( "huge", LuaDouble.POSINF );
bind( t, MathLib1.class, new String[] {
"abs", "ceil", "cos", "deg",
"exp", "floor", "rad", "sin",
"sqrt", "tan" } );
bind( t, MathLib2.class, new String[] {
"fmod", "ldexp", "pow", } );
bind( t, MathLibV.class, new String[] {
"frexp", "max", "min", "modf",
"randomseed", "random", } );
((MathLibV) t.get("randomseed")).mathlib = this;
((MathLibV) t.get("random" )).mathlib = this;
env.set("math", t);
PackageLib.instance.LOADED.set("math", t);
return t;
}
static final class MathLib1 extends OneArgFunction {
public LuaValue call(LuaValue arg) {
switch ( opcode ) {
case 0: return valueOf(Math.abs(arg.checkdouble()));
case 1: return valueOf(Math.ceil(arg.checkdouble()));
case 2: return valueOf(Math.cos(arg.checkdouble()));
case 3: return valueOf(Math.toDegrees(arg.checkdouble()));
case 4: return dpow(Math.E,arg.checkdouble());
case 5: return valueOf(Math.floor(arg.checkdouble()));
case 6: return valueOf(Math.toRadians(arg.checkdouble()));
case 7: return valueOf(Math.sin(arg.checkdouble()));
case 8: return valueOf(Math.sqrt(arg.checkdouble()));
case 9: return valueOf(Math.tan(arg.checkdouble()));
}
return NIL;
}
}
static final class MathLib2 extends TwoArgFunction {
protected MathLib mathlib;
public LuaValue call(LuaValue arg1, LuaValue arg2) {
switch ( opcode ) {
case 0: { // fmod
double x = arg1.checkdouble();
double y = arg2.checkdouble();
double q = x/y;
double f = x - y * (q>=0? Math.floor(q): Math.ceil(q));
return valueOf( f );
}
case 1: { // ldexp
double x = arg1.checkdouble();
double y = arg2.checkdouble()+1023.5;
long e = (long) ((0!=(1&((int)y)))? Math.floor(y): Math.ceil(y-1));
return valueOf(x * Double.longBitsToDouble(e << 52));
}
case 2: { // pow
return dpow(arg1.checkdouble(), arg2.checkdouble());
}
}
return NIL;
}
}
/** 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) );
}
public static double dpow_d(double a, double b) {
return MATHLIB!=null?
MATHLIB.dpow_lib(a,b):
dpow_default(a,b);
}
/**
* Hook to override default dpow behavior with faster implementation.
*/
public double dpow_lib(double a, double b) {
return dpow_default(a,b);
}
/**
* Default JME version computes using longhand heuristics.
*/
protected static double dpow_default(double a, double b) {
if ( b < 0 )
return 1 / dpow_default( a, -b );
double p = 1;
int whole = (int) b;
for ( double v=a; whole > 0; whole>>=1, v*=v )
if ( (whole & 1) != 0 )
p *= v;
if ( (b -= whole) > 0 ) {
int frac = (int) (0x10000 * b);
for ( ; (frac&0xffff)!=0; frac<<=1 ) {
a = Math.sqrt(a);
if ( (frac & 0x8000) != 0 )
p *= a;
}
}
return p;
}
static final class MathLibV extends VarArgFunction {
protected MathLib mathlib;
public Varargs invoke(Varargs args) {
switch ( opcode ) {
case 0: { // frexp
double x = args.checkdouble(1);
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;
return varargsOf( valueOf(m), valueOf(e) );
}
case 1: { // max
double m = args.checkdouble(1);
for ( int i=2,n=args.narg(); i<=n; ++i )
m = Math.max(m,args.checkdouble(i));
return valueOf(m);
}
case 2: { // min
double m = args.checkdouble(1);
for ( int i=2,n=args.narg(); i<=n; ++i )
m = Math.min(m,args.checkdouble(i));
return valueOf(m);
}
case 3: { // modf
double x = args.checkdouble(1);
double intPart = ( x > 0 ) ? Math.floor( x ) : Math.ceil( x );
double fracPart = x - intPart;
return varargsOf( valueOf(intPart), valueOf(fracPart) );
}
case 4: { // randomseed
long seed = args.checklong(1);
mathlib.random = new Random(seed);
return NONE;
}
case 5: { // random
if ( mathlib.random == null )
mathlib.random = new Random();
switch ( args.narg() ) {
case 0:
return valueOf( mathlib.random.nextDouble() );
case 1: {
int m = args.checkint(1);
if (m<1) argerror(1, "interval is empty");
return valueOf( 1 + mathlib.random.nextInt(m) );
}
default: {
int m = args.checkint(1);
int n = args.checkint(2);
if (n<m) argerror(2, "interval is empty");
return valueOf( m + mathlib.random.nextInt(n+1-m) );
}
}
}
}
return NONE;
}
}
}

View File

@@ -1,79 +0,0 @@
/*******************************************************************************
* 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 org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/** 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,
* 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}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* @see #call(LuaValue)
* @see LibFunction
* @see ZeroArgFunction
* @see TwoArgFunction
* @see ThreeArgFunction
* @see VarArgFunction
*/
abstract public class OneArgFunction extends LibFunction {
abstract public LuaValue call(LuaValue arg);
/** Default constructor */
public OneArgFunction() {
}
/** Constructor with specific environment
* @param env The environment to apply during constructon.
*/
public OneArgFunction( LuaValue env ) {
this.env = env;
}
public final LuaValue call() {
return call(NIL);
}
public final LuaValue call(LuaValue arg1, LuaValue arg2) {
return call(arg1);
}
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return call(arg1);
}
public Varargs invoke(Varargs varargs) {
return call(varargs.arg1());
}
}

View File

@@ -1,323 +0,0 @@
/*******************************************************************************
* 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 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 JmePlatform#standardGlobals()}
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* LuaTable _G = new LuaTable();
* LuaThread.setGlobals(_G);
* _G.load(new BaseLib());
* _G.load(new PackageLib());
* _G.load(new OsLib());
* System.out.println( _G.get("os").get("time").call() );
* } </pre>
* Doing so will ensure the library is properly initialized
* and loaded into the globals table.
* <p>
* @see LibFunction
* @see JseOsLib
* @see JsePlatform
* @see 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 VarArgFunction {
public static String TMP_PREFIX = ".luaj";
public static String TMP_SUFFIX = "tmp";
private static final int INIT = 0;
private static final int CLOCK = 1;
private static final int DATE = 2;
private static final int DIFFTIME = 3;
private static final int EXECUTE = 4;
private static final int EXIT = 5;
private static final int GETENV = 6;
private static final int REMOVE = 7;
private static final int RENAME = 8;
private static final int SETLOCALE = 9;
private static final int TIME = 10;
private static final int TMPNAME = 11;
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;
/**
* Create and OsLib instance.
*/
public OsLib() {
}
public LuaValue init() {
LuaTable t = new LuaTable();
bind(t, this.getClass(), NAMES, CLOCK);
env.set("os", t);
PackageLib.instance.LOADED.set("os", t);
return t;
}
public Varargs invoke(Varargs args) {
try {
switch ( opcode ) {
case INIT:
return init();
case CLOCK:
return valueOf(clock());
case DATE: {
String s = args.optjstring(1, null);
double t = args.optdouble(2,-1);
return valueOf( date(s, t==-1? System.currentTimeMillis()/1000.: t) );
}
case DIFFTIME:
return valueOf(difftime(args.checkdouble(1),args.checkdouble(2)));
case EXECUTE:
return valueOf(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.arg1().isnil()? null: args.checktable(1)));
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.
*/
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.
*
* If format starts with '!', then the date is formatted in Coordinated
* Universal Time. After this optional character, if format is the string
* "*t", then date returns a table with the following fields: year
* (four digits), month (1--12), day (1--31), hour (0--23), min (0--59),
* sec (0--61), wday (weekday, Sunday is 1), yday (day of the year),
* and isdst (daylight saving flag, a boolean).
*
* If format is not "*t", then date returns the date as a string,
* formatted according to the same rules as the C function strftime.
*
* 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 time 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.
*/
protected String date(String format, double time) {
return new java.util.Date((long)(time*1000)).toString();
}
/**
* 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 int execute(String command) {
return 0;
}
/**
* Calls the C function exit, with an optional code, to terminate the host program.
* @param code
*/
protected void exit(int code) {
/* DAN200 START */
//System.exit(code);
/* DAN200 END */
}
/**
* Returns the value of the process environment variable varname,
* or null if the variable is not defined.
* @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) {
return System.currentTimeMillis();
}
/**
* 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

@@ -1,466 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010-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.InputStream;
import java.io.PrintStream;
import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* Subclass of {@link LibFunction} which implements the lua standard package and module
* library functions.
*
* <p>
* Typically, this library is included as part of a call to either
* {@link JsePlatform#standardGlobals()} or {@link JmePlatform#standardGlobals()}
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* LuaTable _G = new LuaTable();
* LuaThread.setGlobals(_G);
* _G.load(new BaseLib());
* _G.load(new PackageLib());
* System.out.println( _G.get("require").call(LuaValue.valueOf("hyperbolic")) );
* } </pre>
* In practice, the first 4 lines of the above are minimal requirements to get
* and initialize a globals table capable of basic reqire, print, and other functions,
* so it is much more convenient to use the {@link JsePlatform} and {@link JmePlatform}
* utility classes instead.
* <p>
* This 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 JseBaseLib} documetnation.
* @see LibFunction
* @see BaseLib
* @see JseBaseLib
* @see JsePlatform
* @see JmePlatform
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.3">http://www.lua.org/manual/5.1/manual.html#5.3</a>
*/
public class PackageLib extends OneArgFunction {
public static String DEFAULT_LUA_PATH = "?.lua";
public InputStream STDIN = null;
public PrintStream STDOUT = System.out;
public LuaTable LOADED;
public LuaTable PACKAGE;
/** Most recent instance of PackageLib */
public static PackageLib instance;
/** Loader that loads from preload table if found there */
public LuaValue preload_loader;
/** Loader that loads as a lua script using the LUA_PATH */
public LuaValue lua_loader;
/** Loader that loads as a Java class. Class must have public constructor and be a LuaValue */
public LuaValue java_loader;
private static final LuaString _M = valueOf("_M");
private static final LuaString _NAME = valueOf("_NAME");
private static final LuaString _PACKAGE = valueOf("_PACKAGE");
private static final LuaString _DOT = valueOf(".");
private static final LuaString _LOADERS = valueOf("loaders");
private static final LuaString _LOADED = valueOf("loaded");
private static final LuaString _LOADLIB = valueOf("loadlib");
private static final LuaString _PRELOAD = valueOf("preload");
private static final LuaString _PATH = valueOf("path");
private static final LuaString _SEEALL = valueOf("seeall");
private static final LuaString _SENTINEL = valueOf("\u0001");
private static final int OP_MODULE = 0;
private static final int OP_REQUIRE = 1;
private static final int OP_LOADLIB = 2;
private static final int OP_SEEALL = 3;
private static final int OP_PRELOAD_LOADER = 4;
private static final int OP_LUA_LOADER = 5;
private static final int OP_JAVA_LOADER = 6;
public PackageLib() {
instance = this;
}
public LuaValue call(LuaValue arg) {
env.set("require", new PkgLib1(env,"require",OP_REQUIRE,this));
env.set("module", new PkgLibV(env,"module",OP_MODULE,this));
env.set( "package", PACKAGE=tableOf( new LuaValue[] {
_LOADED, LOADED=tableOf(),
_PRELOAD, tableOf(),
_PATH, valueOf(DEFAULT_LUA_PATH),
_LOADLIB, new PkgLibV(env,"loadlib",OP_LOADLIB,this),
_SEEALL, new PkgLib1(env,"seeall",OP_SEEALL,this),
_LOADERS, listOf(new LuaValue[] {
preload_loader = new PkgLibV(env,"preload_loader", OP_PRELOAD_LOADER,this),
lua_loader = new PkgLibV(env,"lua_loader", OP_LUA_LOADER,this),
java_loader = new PkgLibV(env,"java_loader", OP_JAVA_LOADER,this),
}) }) );
LOADED.set("package", PACKAGE);
return env;
}
static final class PkgLib1 extends OneArgFunction {
PackageLib lib;
public PkgLib1(LuaValue env,String name, int opcode, PackageLib lib) {
this.env = env;
this.name = name;
this.opcode = opcode;
this.lib = lib;
}
public LuaValue call(LuaValue arg) {
switch ( opcode ) {
case OP_REQUIRE:
return lib.require(arg);
case OP_SEEALL: {
LuaTable t = arg.checktable();
LuaValue m = t.getmetatable();
if ( m == null )
t.setmetatable(m=tableOf());
m.set( INDEX, LuaThread.getGlobals() );
return NONE;
}
}
return NIL;
}
}
static final class PkgLibV extends VarArgFunction {
PackageLib lib;
public PkgLibV(LuaValue env,String name, int opcode, PackageLib lib) {
this.env = env;
this.name = name;
this.opcode = opcode;
this.lib = lib;
}
public Varargs invoke(Varargs args) {
switch ( opcode ) {
case OP_MODULE:
return lib.module(args);
case OP_LOADLIB:
return loadlib(args);
case OP_PRELOAD_LOADER: {
return lib.loader_preload(args);
}
case OP_LUA_LOADER: {
return lib.loader_Lua(args);
}
case OP_JAVA_LOADER: {
return lib.loader_Java(args);
}
}
return NONE;
}
}
/** Allow packages to mark themselves as loaded */
public void setIsLoaded(String name, LuaTable value) {
LOADED.set(name, value);
}
public void setLuaPath( String newLuaPath ) {
PACKAGE.set( _PATH, valueOf(newLuaPath) );
}
public String tojstring() {
return "package";
}
// ======================== Module, Package loading =============================
/**
* module (name [, ...])
*
* Creates a module. If there is a table in package.loaded[name], this table
* is the module. Otherwise, if there is a global table t with the given
* name, this table is the module. Otherwise creates a new table t and sets
* it as the value of the global name and the value of package.loaded[name].
* This function also initializes t._NAME with the given name, t._M with the
* module (t itself), and t._PACKAGE with the package name (the full module
* name minus last component; see below). Finally, module sets t as the new
* environment of the current function and the new value of
* package.loaded[name], so that require returns t.
*
* If name is a compound name (that is, one with components separated by
* dots), module creates (or reuses, if they already exist) tables for each
* component. For instance, if name is a.b.c, then module stores the module
* table in field c of field b of global a.
*
* This function may receive optional options after the module name, where
* each option is a function to be applied over the module.
*/
public Varargs module(Varargs args) {
LuaString modname = args.checkstring(1);
int n = args.narg();
LuaValue value = LOADED.get(modname);
LuaValue module;
if ( ! value.istable() ) { /* not found? */
/* try global variable (and create one if it does not exist) */
LuaValue globals = LuaThread.getGlobals();
module = findtable( globals, modname );
if ( module == null )
error( "name conflict for module '"+modname+"'" );
LOADED.set(modname, module);
} else {
module = (LuaTable) value;
}
/* check whether table already has a _NAME field */
LuaValue name = module.get(_NAME);
if ( name.isnil() ) {
modinit( module, modname );
}
// set the environment of the current function
LuaFunction f = LuaThread.getCallstackFunction(1);
if ( f == null )
error("no calling function");
if ( ! f.isclosure() )
error("'module' not called from a Lua function");
f.setfenv(module);
// apply the functions
for ( int i=2; i<=n; i++ )
args.arg(i).call( module );
// returns no results
return NONE;
}
/**
*
* @param table the table at which to start the search
* @param fname the name to look up or create, such as "abc.def.ghi"
* @return the table for that name, possible a new one, or null if a non-table has that name already.
*/
private static final LuaValue findtable(LuaValue table, LuaString fname) {
int b, e=(-1);
do {
e = fname.indexOf(_DOT, b=e+1 );
if ( e < 0 )
e = fname.m_length;
LuaString key = fname.substring(b, e);
LuaValue val = table.rawget(key);
if ( val.isnil() ) { /* no such field? */
LuaTable field = new LuaTable(); /* new table for field */
table.set(key, field);
table = field;
} else if ( ! val.istable() ) { /* field has a non-table value? */
return null;
} else {
table = val;
}
} while ( e < fname.m_length );
return table;
}
private static final void modinit(LuaValue module, LuaString modname) {
/* module._M = module */
module.set(_M, module);
int e = modname.lastIndexOf(_DOT);
module.set(_NAME, modname );
module.set(_PACKAGE, (e<0? EMPTYSTRING: modname.substring(0,e+1)) );
}
/**
* 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.
*
* To find a loader, require is guided by the package.loaders array. By changing this array,
* we can change how require looks for a module. The following explanation is based on the
* default configuration for package.loaders.
*
* 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 C loader
* using the path stored in package.cpath. If that also fails, it tries an all-in-one loader
* (see package.loaders).
*
* Once a loader is found, require calls the loader with a single argument, modname.
* If the loader returns any value, require assigns the returned value to package.loaded[modname].
* If the loader returns no 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 signals an error.
*/
public LuaValue require( LuaValue arg ) {
LuaString name = arg.checkstring();
LuaValue loaded = LOADED.get(name);
if ( loaded.toboolean() ) {
if ( loaded == _SENTINEL )
error("loop or previous error loading module '"+name+"'");
return loaded;
}
/* else must load it; iterate over available loaders */
LuaTable tbl = PACKAGE.get(_LOADERS).checktable();
StringBuffer sb = new StringBuffer();
LuaValue chunk = null;
for ( int i=1; true; i++ ) {
LuaValue loader = tbl.get(i);
if ( loader.isnil() ) {
error( "module '"+name+"' not found: "+name+sb );
}
/* call loader with module name as argument */
chunk = loader.call(name);
if ( chunk.isfunction() )
break;
if ( chunk.isstring() )
sb.append( chunk.tojstring() );
}
// load the module using the loader
LOADED.set(name, _SENTINEL);
LuaValue result = chunk.call(name);
if ( ! result.isnil() )
LOADED.set( name, result );
else if ( (result = LOADED.get(name)) == _SENTINEL )
LOADED.set( name, result = LuaValue.TRUE );
return result;
}
public static Varargs loadlib( Varargs args ) {
args.checkstring(1);
return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent"));
}
LuaValue loader_preload( Varargs args ) {
LuaString name = args.checkstring(1);
LuaValue preload = PACKAGE.get(_PRELOAD).checktable();
LuaValue val = preload.get(name);
return val.isnil()?
valueOf("\n\tno field package.preload['"+name+"']"):
val;
}
LuaValue loader_Lua( Varargs args ) {
String name = args.checkjstring(1);
InputStream is = null;
// get package path
LuaValue pp = PACKAGE.get(_PATH);
if ( ! pp.isstring() )
return valueOf("package.path is not a string");
String path = pp.tojstring();
// check the path elements
int e = -1;
int n = path.length();
StringBuffer sb = null;
name = name.replace('.','/');
while ( e < n ) {
// find next template
int b = e+1;
e = path.indexOf(';',b);
if ( e < 0 )
e = path.length();
String template = path.substring(b,e);
// create filename
int q = template.indexOf('?');
String filename = template;
if ( q >= 0 ) {
filename = template.substring(0,q) + name + template.substring(q+1);
}
// try loading the file
Varargs v = BaseLib.loadFile(filename);
if ( v.arg1().isfunction() )
return v.arg1();
// report error
if ( sb == null )
sb = new StringBuffer();
sb.append( "\n\t'"+filename+"': "+v.arg(2) );
}
return valueOf(sb.toString());
}
LuaValue loader_Java( Varargs args ) {
String name = args.checkjstring(1);
String classname = toClassname( name );
Class c = null;
LuaValue v = null;
try {
c = Class.forName(classname);
v = (LuaValue) c.newInstance();
v.setfenv(env);
return v;
} catch ( ClassNotFoundException cnfe ) {
return valueOf("\n\tno class '"+classname+"'" );
} catch ( Exception e ) {
return valueOf("\n\tjava load failed on '"+classname+"', "+e );
}
}
/** Convert lua filename to valid class name */
public static final String toClassname( String filename ) {
int n=filename.length();
int j=n;
if ( filename.endsWith(".lua") )
j -= 4;
for ( int k=0; k<j; k++ ) {
char c = filename.charAt(k);
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=='\\'))? '.': '_' );
}
return sb.toString();
}
}
return n==j? filename: filename.substring(0,j);
}
private static final boolean isClassnamePart(char c) {
if ( (c>='a'&&c<='z') || (c>='A'&&c<='Z') || (c>='0'&&c<='9') )
return true;
switch ( c ) {
case '.':
case '$':
case '_':
return true;
default:
return false;
}
}
}

View File

@@ -1,57 +0,0 @@
/*******************************************************************************
* 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.InputStream;
/**
* 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.
* <p>
* The Jme version of base lib {@link BaseLib}
* implements {@link BaseLib#FINDER} via {@link Class#getResourceAsStream(String)},
* while the Jse version {@link 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 BaseLib#FINDER
* @see JseBaseLib
* @see JmePlatform
* @see JsePlatform
*/
public interface ResourceFinder {
/**
* Try to open a file, or return null if not found.
*
* @see org.luaj.vm2.lib.BaseLib
* @see org.luaj.vm2.lib.jse.JseBaseLib
*
* @param filename
* @return InputStream, or null if not found.
*/
public InputStream findResource( String filename );
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,124 +0,0 @@
/*******************************************************************************
* 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 org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/**
* 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 JsePlatform#standardGlobals()} or {@link JmePlatform#standardGlobals()}
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* LuaTable _G = new LuaTable();
* LuaThread.setGlobals(_G);
* _G.load(new BaseLib());
* _G.load(new PackageLib());
* _G.load(new TableLib());
* LuaValue tbl = LuaValue.listOf( new LuaValue[] {
* LuaValue.valueOf( "abc" ),
* LuaValue.valueOf( "def" ) } );
* LuaValue sep = LuaValue.valueOf( "-" );
* System.out.println( _G.get("table").get("concat").call( tbl, sep ) );
* } </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.
* @see LibFunction
* @see JsePlatform
* @see JmePlatform
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.5">http://www.lua.org/manual/5.1/manual.html#5.5</a>
*/
public class TableLib extends OneArgFunction {
public TableLib() {
}
private LuaTable init() {
LuaTable t = new LuaTable();
bind(t, TableLib.class, new String[] { "getn", "maxn", }, 1 );
bind(t, TableLibV.class, new String[] {
"remove", "concat", "insert", "sort", "foreach", "foreachi", } );
env.set("table", t);
PackageLib.instance.LOADED.set("table", t);
return t;
}
public LuaValue call(LuaValue arg) {
switch ( opcode ) {
case 0: // init library
return init();
case 1: // "getn" (table) -> number
return arg.checktable().getn();
case 2: // "maxn" (table) -> number
return valueOf( arg.checktable().maxn());
}
return NIL;
}
static final class TableLibV extends VarArgFunction {
public Varargs invoke(Varargs args) {
switch ( opcode ) {
case 0: { // "remove" (table [, pos]) -> removed-ele
LuaTable table = args.checktable(1);
int pos = args.narg()>1? args.checkint(2): 0;
return table.remove(pos);
}
case 1: { // "concat" (table [, sep [, i [, j]]]) -> string
LuaTable table = args.checktable(1);
return table.concat(
args.optstring(2,LuaValue.EMPTYSTRING),
args.optint(3,1),
args.isvalue(4)? args.checkint(4): table.length() );
}
case 2: { // "insert" (table, [pos,] value) -> prev-ele
final LuaTable table = args.checktable(1);
final int pos = args.narg()>2? args.checkint(2): 0;
final LuaValue value = args.arg( args.narg()>2? 3: 2 );
table.insert( pos, value );
return NONE;
}
case 3: { // "sort" (table [, comp]) -> void
LuaTable table = args.checktable(1);
LuaValue compare = (args.isnoneornil(2)? NIL: args.checkfunction(2));
table.sort( compare );
return NONE;
}
case 4: { // (table, func) -> void
return args.checktable(1).foreach( args.checkfunction(2) );
}
case 5: { // "foreachi" (table, func) -> void
return args.checktable(1).foreachi( args.checkfunction(2) );
}
}
return NONE;
}
}
}

View File

@@ -1,80 +0,0 @@
/*******************************************************************************
* 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 org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/** 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,
* 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}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* @see #call(LuaValue,LuaValue,LuaValue)
* @see LibFunction
* @see ZeroArgFunction
* @see OneArgFunction
* @see TwoArgFunction
* @see VarArgFunction
*/
abstract public class ThreeArgFunction extends LibFunction {
abstract public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3);
/** Default constructor */
public ThreeArgFunction() {
}
/** Constructor with specific environment
* @param env The environment to apply during constructon.
*/
public ThreeArgFunction( LuaValue env ) {
this.env = env;
}
public final LuaValue call() {
return call(NIL, NIL, NIL);
}
public final LuaValue call(LuaValue arg) {
return call(arg, NIL, NIL);
}
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return call(arg1, arg2, NIL);
}
public Varargs invoke(Varargs varargs) {
return call(varargs.arg1(),varargs.arg(2),varargs.arg(3));
}
}

View File

@@ -1,80 +0,0 @@
/*******************************************************************************
* 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 org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/** 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.
* <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}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* @see #call(LuaValue,LuaValue)
* @see LibFunction
* @see ZeroArgFunction
* @see OneArgFunction
* @see ThreeArgFunction
* @see VarArgFunction
*/
abstract public class TwoArgFunction extends LibFunction {
abstract public LuaValue call(LuaValue arg1, LuaValue arg2);
/** Default constructor */
public TwoArgFunction() {
}
/** Constructor with specific environment
* @param env The environment to apply during constructon.
*/
public TwoArgFunction( LuaValue env ) {
this.env = env;
}
public final LuaValue call() {
return call(NIL, NIL);
}
public final LuaValue call(LuaValue arg) {
return call(arg, NIL);
}
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return call(arg1, arg2);
}
public Varargs invoke(Varargs varargs) {
return call(varargs.arg1(),varargs.arg(2));
}
}

View File

@@ -1,100 +0,0 @@
/*******************************************************************************
* 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 org.luaj.vm2.LuaThread;
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.
* <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 {@linnk 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}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* @see #invoke(Varargs)
* @see LibFunction
* @see ZeroArgFunction
* @see OneArgFunction
* @see TwoArgFunction
* @see ThreeArgFunction
*/
abstract public class VarArgFunction extends LibFunction {
public VarArgFunction() {
}
public VarArgFunction( LuaValue env ) {
this.env = env;
}
public LuaValue call() {
return invoke(NONE).arg1();
}
public LuaValue call(LuaValue arg) {
return invoke(arg).arg1();
}
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return invoke(varargsOf(arg1,arg2)).arg1();
}
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return invoke(varargsOf(arg1,arg2,arg3)).arg1();
}
/**
* Override and implement for the best performance.
* May not have expected behavior for tail calls.
* Should not be used if either:
* - function needs to be used as a module
* - function has a possibility of returning a TailcallVarargs
* @param args the arguments to the function call.
*/
public Varargs invoke(Varargs args) {
LuaThread.CallStack cs = LuaThread.onCall(this);
try {
return this.onInvoke(args).eval();
} finally {
cs.onReturn();
}
}
/**
* Override to provide a call implementation that runs in an environment
* that can participate in setfenv, and behaves as expected
* when returning TailcallVarargs.
* @param args the arguments to the function call.
*/
public Varargs onInvoke(Varargs args) {
return invoke(args);
}
}

View File

@@ -1,77 +0,0 @@
/*******************************************************************************
* 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 org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
/** 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.
* <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}.
* <p>
* See {@link LibFunction} for more information on implementation libraries and library functions.
* @see #call()
* @see LibFunction
* @see OneArgFunction
* @see TwoArgFunction
* @see ThreeArgFunction
* @see VarArgFunction
*/
abstract public class ZeroArgFunction extends LibFunction {
abstract public LuaValue call();
/** Default constructor */
public ZeroArgFunction() {
}
/** Constructor with specific environment
* @param env The environment to apply during constructon.
*/
public ZeroArgFunction( LuaValue env ) {
this.env = env;
}
public LuaValue call(LuaValue arg) {
return call();
}
public LuaValue call(LuaValue arg1, LuaValue arg2) {
return call();
}
public LuaValue call(LuaValue arg1, LuaValue arg2, LuaValue arg3) {
return call();
}
public Varargs invoke(Varargs varargs) {
return call();
}
}

View File

@@ -1,227 +0,0 @@
/*******************************************************************************
* 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.jme;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.BaseLib;
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.
* <p>
* 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 JmePlatform#standardGlobals()}
* <p>
* To instantiate and use it directly,
* link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as:
* <pre> {@code
* LuaTable _G = new LuaTable();
* LuaThread.setGlobals(_G);
* _G.load(new BaseLib());
* _G.load(new PackageLib());
* _G.load(new JmeIoLib());
* _G.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
* } </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.
* @see LibFunction
* @see JsePlatform
* @see JmePlatform
* @see IoLib
* @see JseIoLib
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.6">http://www.lua.org/manual/5.1/manual.html#5.6</a>
*/
public class JmeIoLib extends IoLib {
public JmeIoLib() {
super();
}
protected File wrapStdin() throws IOException {
return new FileImpl(BaseLib.instance.STDIN);
}
protected File wrapStdout() throws IOException {
return new FileImpl(BaseLib.instance.STDOUT);
}
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);
} else {
if ( ! readMode )
conn.truncate(0);
}
*/
return f;
}
private static void notimplemented() throws IOException {
throw new IOException("not implemented");
}
protected File openProgram(String prog, String mode) throws IOException {
notimplemented();
return null;
}
protected File tmpFile() throws IOException {
notimplemented();
return null;
}
private final class FileImpl extends File {
private final StreamConnection conn;
private final InputStream is;
private final OutputStream os;
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 );
}
public String tojstring() {
return "file ("+this.hashCode()+")";
}
public boolean isstdfile() {
return conn == null;
}
public void close() throws IOException {
closed = true;
if ( conn != null ) {
conn.close();
}
}
public void flush() throws IOException {
if ( os != null )
os.flush();
}
public void write(LuaString s) throws IOException {
if ( os != null )
os.write( s.m_bytes, s.m_offset, s.m_length );
else
notimplemented();
if ( nobuffer )
flush();
}
public boolean isclosed() {
return closed;
}
public int seek(String option, int pos) throws IOException {
/*
if ( conn != null ) {
if ( "set".equals(option) ) {
conn.seek(pos);
return (int) conn.getFilePointer();
} else if ( "end".equals(option) ) {
conn.seek(conn.length()+1+pos);
return (int) conn.length()+1;
} else {
conn.seek(conn.getFilePointer()+pos);
return (int) conn.getFilePointer();
}
}
*/
notimplemented();
return 0;
}
public void setvbuf(String mode, int size) {
nobuffer = "no".equals(mode);
}
// get length remaining to read
public int remaining() throws IOException {
return -1;
}
// peek ahead one character
public int peek() throws IOException {
if ( lookahead < 0 )
lookahead = is.read();
return lookahead;
}
// return char if read, -1 if eof, throw IOException on other exception
public int read() throws IOException {
if ( lookahead >= 0 ) {
int c = lookahead;
lookahead = -1;
return c;
}
if ( is != null )
return is.read();
notimplemented();
return 0;
}
// return number of bytes read if positive, -1 if eof, throws IOException
public int read(byte[] bytes, int offset, int length) throws IOException {
int n,i=0;
if (is!=null) {
if ( length > 0 && lookahead >= 0 ) {
bytes[offset] = (byte) lookahead;
lookahead = -1;
i += 1;
}
for ( ; i<length; ) {
n = is.read(bytes, offset+i, length-i);
if ( n < 0 )
return ( i > 0 ? i : -1 );
i += n;
}
} else {
notimplemented();
}
return length;
}
}
}

View File

@@ -1,130 +0,0 @@
/*******************************************************************************
* 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.jme;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.LoadState;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.BaseLib;
import org.luaj.vm2.lib.CoroutineLib;
import org.luaj.vm2.lib.DebugLib;
import org.luaj.vm2.lib.MathLib;
import org.luaj.vm2.lib.OsLib;
import org.luaj.vm2.lib.PackageLib;
import org.luaj.vm2.lib.StringLib;
import org.luaj.vm2.lib.TableLib;
/** The {@link 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
* <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 JmeIoLib} for details</li>
* <li>luajava is not available, see {@link 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
* LuaValue _G = JmePlatform.standardGlobals();
* _G.get("print").call(LuaValue.valueOf("hello, world"));
* } </pre>
* <p>
* Once globals are created, a simple way to load and run a script is:
* <pre> {@code
* LoadState.load( getClass().getResourceAsStream("main.lua"), "main.lua", _G ).call();
* } </pre>
* <p>
* although {@code require} could also be used:
* <pre> {@code
* _G.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}.
* <p>
* The standard globals will contain all standard libraries in their JME flavors:
* <ul>
* <li>{@link BaseLib}</li>
* <li>{@link PackageLib}</li>
* <li>{@link TableLib}</li>
* <li>{@link StringLib}</li>
* <li>{@link CoroutineLib}</li>
* <li>{@link MathLib}</li>
* <li>{@link 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.
* <p>
* 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,
* and that linkage is made to {@link LuaThread#setGlobals(LuaValue)}.
* @see JsePlatform
* @see LoadState
*/
public class JmePlatform {
/**
* Create a standard set of globals for JME including all the libraries.
*
* @return Table of globals initialized with the standard JME libraries
* @see #debugGlobals()
* @see JsePlatform
* @see JmePlatform
*/
public static LuaTable standardGlobals() {
LuaTable _G = new LuaTable();
_G.load(new BaseLib());
_G.load(new PackageLib());
_G.load(new OsLib());
_G.load(new MathLib());
_G.load(new TableLib());
_G.load(new StringLib());
_G.load(new CoroutineLib());
_G.load(new JmeIoLib());
LuaThread.setGlobals(_G);
LuaC.install();
return _G;
}
/** Create standard globals including the {@link debug} library.
*
* @return Table of globals initialized with the standard JSE and debug libraries
* @see #standarsGlobals()
* @see JsePlatform
* @see JmePlatform
* @see DebugLib
*/
public static LuaTable debugGlobals() {
LuaTable _G = standardGlobals();
_G.load(new DebugLib());
return _G;
}
}

View File

@@ -1 +0,0 @@
org.luaj.vm2.script.LuaScriptEngineFactory

View File

@@ -1,223 +0,0 @@
/*******************************************************************************
* 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.
******************************************************************************/
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Vector;
import org.luaj.vm2.LoadState;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.lua2java.Lua2Java;
import org.luaj.vm2.luajc.LuaJC;
/**
* lua command for use in java se environments.
*/
public class lua {
private static final String version = Lua._VERSION + "Copyright (c) 2009 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" +
" -j use lua2java source-to-source compiler\n" +
" -b use luajc bytecode-to-bytecode compiler (requires bcel on class path)\n" +
" -n nodebug - do not load debug library by default\n" +
" -- stop handling options\n" +
" - execute stdin and stop handling options";
private static void usageExit() {
System.out.println(usage);
System.exit(-1);
}
private static LuaValue _G;
public static void main( String[] args ) throws IOException {
// process args
boolean interactive = (args.length == 0);
boolean versioninfo = false;
boolean processing = true;
boolean nodebug = false;
boolean luajc = false;
boolean lua2java = false;
Vector libs = null;
try {
// stateful argument processing
for ( int i=0; i<args.length; i++ ) {
if ( ! processing || ! args[i].startsWith("-") ) {
// input file - defer to last stage
break;
} else if ( args[i].length() <= 1 ) {
// input file - defer to last stage
break;
} else {
switch ( args[i].charAt(1) ) {
case 'e':
if ( ++i >= args.length )
usageExit();
// input script - defer to last stage
break;
case 'b':
luajc = true;
break;
case 'j':
lua2java = true;
break;
case 'l':
if ( ++i >= args.length )
usageExit();
libs = libs!=null? libs: new Vector();
libs.addElement( args[i] );
break;
case 'i':
interactive = true;
break;
case 'v':
versioninfo = true;
break;
case 'n':
nodebug = true;
break;
case '-':
if ( args[i].length() > 2 )
usageExit();
processing = false;
break;
default:
usageExit();
break;
}
}
}
// echo version
if ( versioninfo )
System.out.println(version);
// new lua state
_G = nodebug? JsePlatform.standardGlobals(): JsePlatform.debugGlobals();
if ( luajc ) LuaJC.install();
if ( lua2java) Lua2Java.install();
for ( int i=0, n=libs!=null? libs.size(): 0; i<n; i++ )
loadLibrary( (String) libs.elementAt(i) );
// input script processing
processing = true;
for ( int i=0; i<args.length; i++ ) {
if ( ! processing || ! args[i].startsWith("-") ) {
processScript( new FileInputStream(args[i]), args[i], args, i );
break;
} else if ( "-".equals( args[i] ) ) {
processScript( System.in, "=stdin", args, i );
break;
} else {
switch ( args[i].charAt(1) ) {
case 'l':
++i;
break;
case 'e':
++i;
processScript( new ByteArrayInputStream(args[i].getBytes()), "string", args, i );
break;
case '-':
processing = false;
break;
}
}
}
if ( interactive )
interactiveMode();
} catch ( IOException ioe ) {
System.err.println( ioe.toString() );
System.exit(-2);
}
}
private static void loadLibrary( String libname ) throws IOException {
LuaValue slibname =LuaValue.valueOf(libname);
try {
// load via plain require
_G.get("require").call(slibname);
} catch ( Exception e ) {
try {
// load as java class
LuaValue v = (LuaValue) Class.forName(libname).newInstance();
v.setfenv(_G);
v.call(slibname, _G);
} catch ( Exception f ) {
throw new IOException("loadLibrary("+libname+") failed: "+e+","+f );
}
}
}
private static void processScript( InputStream script, String chunkname, String[] args, int firstarg ) throws IOException {
try {
LuaFunction c;
try {
c = LoadState.load(script, chunkname, _G);
} finally {
script.close();
}
Varargs scriptargs = (args!=null? setGlobalArg(args, firstarg): LuaValue.NONE);
c.invoke( scriptargs );
} catch ( Exception e ) {
e.printStackTrace( System.err );
}
}
private static Varargs setGlobalArg(String[] args, int i) {
LuaTable arg = LuaValue.tableOf();
for ( int j=0; j<args.length; j++ )
arg.set( j-i, LuaValue.valueOf(args[j]) );
_G.set( "arg", arg );
return _G.get("unpack").invoke(arg);
}
private static void interactiveMode( ) throws IOException {
BufferedReader reader = new BufferedReader( new InputStreamReader( System.in ) );
while ( true ) {
System.out.print("> ");
System.out.flush();
String line = reader.readLine();
if ( line == null )
return;
processScript( new ByteArrayInputStream(line.getBytes()), "=stdin", null, 0 );
}
}
}

View File

@@ -1,213 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import org.luaj.vm2.Lua;
import org.luaj.vm2.ast.Chunk;
import org.luaj.vm2.lib.jse.JsePlatform;
import org.luaj.vm2.lua2java.JavaCodeGen;
import org.luaj.vm2.parser.LuaParser;
/**
* Compile lua sources into java sources.
*/
public class lua2java {
private static final String version = Lua._VERSION + "Copyright (C) 2010 luaj.org";
private static final String usage =
"usage: java -cp luaj-jse.jar lua2java [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" +
" -e enc override default character encoding\n" +
" -r recursively compile all\n" +
" -v verbose\n";
private static void usageExit() {
System.out.println(usage);
System.exit(-1);
}
private String srcdir = null;
private String destdir = null;
private String pkgprefix = null;
private String encoding = "ISO8859-1";
private boolean recurse = false;
private boolean verbose = false;
private List files = new ArrayList();
public static void main( String[] args ) throws IOException {
new lua2java( args );
}
private lua2java( String[] args ) throws IOException {
// process args
try {
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 'p':
if ( ++i >= args.length )
usageExit();
pkgprefix = args[i];
break;
case 'e':
if ( ++i >= args.length )
usageExit();
encoding = args[i];
break;
case 'r':
recurse = true;
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("encoding: "+encoding);
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 ( int i=0; i<seeds.size(); i++ )
collectFiles( srcdir+"/"+seeds.get(i) );
// check for at least one file
if ( files.size() <= 0 ) {
System.err.println("no files found in "+seeds);
System.exit(-1);
}
// process input files
JsePlatform.standardGlobals();
for ( int i=0,n=files.size(); i<n; i++ )
processFile( (InputFile) files.get(i) );
} catch ( Exception ioe ) {
System.err.println( ioe.toString() );
System.exit(-2);
}
}
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 ( int i=0; i<f.length; i++ )
scanfile( dir, f[i], 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) );
}
}
class InputFile {
public File infile;
public File outdir;
public File outfile;
public String javapackage;
public String javaclassname;
public InputFile(File dir, File f, String javapackage) {
String outdirpath = javapackage!=null? destdir+"/"+javapackage.replace('.', '/'): destdir;
this.javaclassname = f.getName().substring(0,f.getName().lastIndexOf('.'));
this.javapackage = javapackage;
this.infile = f;
this.outdir = new File(outdirpath);
this.outfile = new File(outdirpath+"/"+this.javaclassname+".java");
}
}
private void processFile( InputFile inf ) {
inf.outdir.mkdirs();
try {
if ( verbose )
System.out.println(
"pkg="+inf.javapackage+" file="+inf.javaclassname+".java dest="+inf.outfile+" src="+inf.infile);
FileInputStream in = new FileInputStream(inf.infile);
FileOutputStream out = new FileOutputStream(inf.outfile);
PrintWriter pw = new PrintWriter(out);
LuaParser parser = new LuaParser(in,encoding);
Chunk chunk = parser.Chunk();
new JavaCodeGen(chunk,pw,inf.javapackage,inf.javaclassname);
pw.close();
out.close();
in.close();
} catch ( Exception e ) {
e.printStackTrace( System.err );
}
}
}

View File

@@ -1,181 +0,0 @@
/*******************************************************************************
* 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.
******************************************************************************/
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.luaj.vm2.Lua;
import org.luaj.vm2.Print;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.compiler.DumpState;
import org.luaj.vm2.compiler.LuaC;
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" +
" -- stop handling options\n";
private static void usageExit() {
System.out.println(usage);
System.exit(-1);
}
private boolean list = false;
private String output = "luac.out";
private boolean parseonly = false;
private boolean stripdebug = false;
private boolean littleendian = false;
private int numberformat = DumpState.NUMBER_FORMAT_DEFAULT;
private boolean versioninfo = false;
private boolean processing = true;
public static void main( String[] args ) throws IOException {
new luac( args );
}
private luac( String[] args ) throws IOException {
// process args
try {
// get stateful args
for ( int i=0; i<args.length; i++ ) {
if ( ! processing || ! args[i].startsWith("-") ) {
// input file - defer to next stage
} else if ( args[i].length() <= 1 ) {
// input file - defer to next stage
} else {
switch ( args[i].charAt(1) ) {
case 'l':
list = true;
break;
case 'o':
if ( ++i >= args.length )
usageExit();
output = args[i];
break;
case 'p':
parseonly = true;
break;
case 's':
stripdebug = true;
break;
case 'e':
littleendian = true;
break;
case 'i':
if ( args[i].length() <= 2 )
usageExit();
numberformat = Integer.parseInt(args[i].substring(2));
break;
case 'v':
versioninfo = true;
break;
case '-':
if ( args[i].length() > 2 )
usageExit();
processing = false;
break;
default:
usageExit();
break;
}
}
}
// echo version
if ( versioninfo )
System.out.println(version);
// open output file
OutputStream fos = new FileOutputStream( output );
// process input files
try {
JsePlatform.standardGlobals();
processing = true;
for ( int i=0; i<args.length; i++ ) {
if ( ! processing || ! args[i].startsWith("-") ) {
String chunkname = args[i].substring(0,args[i].length()-4);
processScript( new FileInputStream(args[i]), chunkname, fos );
} else if ( args[i].length() <= 1 ) {
processScript( System.in, "=stdin", fos );
} else {
switch ( args[i].charAt(1) ) {
case 'o':
++i;
break;
case '-':
processing = false;
break;
}
}
}
} finally {
fos.close();
}
} catch ( IOException ioe ) {
System.err.println( ioe.toString() );
System.exit(-2);
}
}
private void processScript( InputStream script, String chunkname, OutputStream out ) throws IOException {
try {
// create the chunk
Prototype chunk = LuaC.instance.compile(script, chunkname);
// list the chunk
if (list)
Print.printCode(chunk);
// write out the chunk
if (!parseonly) {
DumpState.dump(chunk, out, stripdebug, numberformat, littleendian);
}
} catch ( Exception e ) {
e.printStackTrace( System.err );
} finally {
script.close();
}
}
}

View File

@@ -1,245 +0,0 @@
/*******************************************************************************
* 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.
******************************************************************************/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
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) 2009 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" +
" -r recursively compile all\n" +
" -l load classes to verify generated bytecode\n" +
" -v verbose\n";
private static void usageExit() {
System.out.println(usage);
System.exit(-1);
}
private String srcdir = null;
private String destdir = null;
private boolean recurse = false;
private boolean verbose = false;
private boolean loadclasses = false;
private String pkgprefix = null;
private List files = new ArrayList();
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 'r':
recurse = true;
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: "+srcdir);
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 ( int i=0; i<seeds.size(); i++ )
collectFiles( srcdir+"/"+seeds.get(i) );
// check for at least one file
if ( files.size() <= 0 ) {
System.err.println("no files found in "+seeds);
System.exit(-1);
}
// process input files
JsePlatform.standardGlobals();
for ( int i=0,n=files.size(); i<n; i++ )
processFile( (InputFile) files.get(i) );
}
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 ( int i=0; i<f.length; i++ )
scanfile( dir, f[i], 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) );
}
}
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 = LuaJC.getInstance().compileAll(fis, inf.luachunkname, inf.srcfilename);
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 ClassLoader() {
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);
}
};
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

@@ -1,41 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.ast;
import java.util.ArrayList;
import java.util.List;
public class Block extends Stat {
public List<Stat> stats = new ArrayList<Stat>();
public NameScope scope;
public void add(Stat s) {
if ( s == null )
return;
stats.add(s);
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

View File

@@ -1,34 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.ast;
public class Chunk {
public final Block block;
public Chunk(Block b) {
this.block = b;
}
public void accept( Visitor visitor ) {
visitor.visit( this );
}
}

View File

@@ -1,313 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.ast;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaValue;
abstract
public class Exp {
abstract public void accept(Visitor visitor);
public static Exp constant(LuaValue value) {
return new Constant(value);
}
public static Exp numberconstant(String token) {
return new Constant( LuaValue.valueOf(token).tonumber() );
}
public static Exp varargs() {
return new VarargsExp();
}
public static Exp tableconstructor(TableConstructor tc) {
return tc;
}
public static Exp unaryexp(int op, Exp rhs) {
if ( rhs instanceof BinopExp ) {
BinopExp b = (BinopExp) rhs;
if ( precedence(op) > precedence(b.op) )
return binaryexp( unaryexp(op, b.lhs), b.op, b.rhs );
}
return new UnopExp(op, rhs);
}
public static Exp binaryexp(Exp lhs, int op, Exp rhs) {
if ( lhs instanceof UnopExp ) {
UnopExp u = (UnopExp) lhs;
if ( precedence(op) > precedence(u.op) )
return unaryexp( u.op, binaryexp( u.rhs, op, rhs ) );
}
// TODO: cumulate string concatenations together
// TODO: constant folding
if ( lhs instanceof BinopExp ) {
BinopExp b = (BinopExp) lhs;
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)) )
return binaryexp( binaryexp( lhs, op, b.lhs ), b.op, b.rhs );
}
return new BinopExp(lhs, op, rhs);
}
static boolean isrightassoc(int op) {
switch ( op ) {
case Lua.OP_CONCAT:
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);
}
}
public static Exp anonymousfunction(FuncBody funcbody) {
return new AnonFuncDef(funcbody);
}
/** foo */
public static NameExp nameprefix(String name) {
return new NameExp(name);
}
/** ( foo.bar ) */
public static ParensExp parensprefix(Exp exp) {
return new ParensExp(exp);
}
/** foo[exp] */
public static IndexExp indexop(PrimaryExp lhs, Exp exp) {
return new IndexExp(lhs, exp);
}
/** foo.bar */
public static FieldExp fieldop(PrimaryExp lhs, String name) {
return new FieldExp(lhs, name);
}
/** foo(2,3) */
public static FuncCall functionop(PrimaryExp lhs, FuncArgs args) {
return new FuncCall(lhs, args);
}
/** foo:bar(4,5) */
public static MethodCall methodop(PrimaryExp lhs, String name, FuncArgs args) {
return new MethodCall(lhs, name, args);
}
public boolean isvarexp() {
return false;
}
public boolean isfunccall() {
return false;
}
public boolean isvarargexp() {
return false;
}
abstract public static class PrimaryExp extends Exp {
public boolean isvarexp() {
return false;
}
public boolean isfunccall() {
return false;
}
}
abstract public static class VarExp extends PrimaryExp {
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);
}
public void markHasAssignment() {
name.variable.hasassignments = true;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public static class ParensExp extends PrimaryExp {
public final Exp exp;
public ParensExp(Exp exp) {
this.exp = exp;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
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);
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
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;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public static class FuncCall extends PrimaryExp {
public final PrimaryExp lhs;
public final FuncArgs args;
public FuncCall(PrimaryExp lhs, FuncArgs args) {
this.lhs = lhs;
this.args = args;
}
public boolean isfunccall() {
return true;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
public boolean isvarargexp() {
return true;
}
}
public static class MethodCall extends FuncCall {
public final String name;
public MethodCall(PrimaryExp lhs, String name, FuncArgs args) {
super(lhs, args);
this.name = new String(name);
}
public boolean isfunccall() {
return true;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public static class Constant extends Exp {
public final LuaValue value;
public Constant(LuaValue value) {
this.value = value;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public static class VarargsExp extends Exp {
public void accept(Visitor visitor) {
visitor.visit(this);
}
public boolean isvarargexp() {
return true;
}
}
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;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
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;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public static class AnonFuncDef extends Exp {
public final FuncBody body;
public AnonFuncDef(FuncBody funcbody) {
this.body = funcbody;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
}

View File

@@ -1,66 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.ast;
import java.util.ArrayList;
import java.util.List;
import org.luaj.vm2.LuaString;
public class FuncArgs {
public final List<Exp> exps;
/** exp1,exp2... */
public static FuncArgs explist(List<Exp> explist) {
return new FuncArgs(explist);
}
/** {...} */
public static FuncArgs tableconstructor(TableConstructor table) {
return new FuncArgs(table);
}
/** "mylib" */
public static FuncArgs string(LuaString string) {
return new FuncArgs(string);
}
public FuncArgs(List<Exp> exps) {
this.exps = exps;
}
public FuncArgs(LuaString string) {
this.exps = new ArrayList<Exp>();
this.exps.add( Exp.constant(string) );
}
public FuncArgs(TableConstructor table) {
this.exps = new ArrayList<Exp>();
this.exps.add( table );
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

View File

@@ -1,36 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.ast;
public class FuncBody {
public ParList parlist;
public Block block;
public NameScope scope;
public FuncBody(ParList parlist, Block block) {
this.parlist = parlist!=null? parlist: ParList.EMPTY_PARLIST;
this.block = block;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

View File

@@ -1,49 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.ast;
import java.util.ArrayList;
import java.util.List;
public class FuncName {
// example: a.b.c.d:e
// initial base name: "a"
public final Name name;
// intermediate field accesses: "b", "c", "d"
public List<String> dots;
// optional final method name: "e"
public String method;
public FuncName( String name ) {
this.name = new Name(name);
}
public void adddot(String dot) {
if ( dots == null )
dots = new ArrayList<String>();
dots.add(dot);
}
}

View File

@@ -1,31 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.ast;
public class Name {
public final String name;
public Variable variable;
public Name(String name) {
this.name = name;
}
}

View File

@@ -1,127 +0,0 @@
package org.luaj.vm2.ast;
import java.util.List;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.ast.Exp.Constant;
import org.luaj.vm2.ast.Exp.NameExp;
import org.luaj.vm2.ast.Exp.VarExp;
import org.luaj.vm2.ast.Stat.Assign;
import org.luaj.vm2.ast.Stat.FuncDef;
import org.luaj.vm2.ast.Stat.GenericFor;
import org.luaj.vm2.ast.Stat.LocalAssign;
import org.luaj.vm2.ast.Stat.LocalFuncDef;
import org.luaj.vm2.ast.Stat.NumericFor;
/**
* Visitor that resolves names to scopes.
* Each Name is resolved to a NamedVarible, possibly in a NameScope
* if it is a local, or in no named scope if it is a global.
*/
public class NameResolver extends Visitor {
private NameScope scope = null;
private void pushScope() {
scope = new NameScope(scope);
}
private void popScope() {
scope = scope.outerScope;
}
public void visit(NameScope scope) {
}
public void visit(Block block) {
pushScope();
block.scope = scope;
super.visit(block);
popScope();
}
public void visit(FuncBody body) {
pushScope();
scope.functionNestingCount++;
body.scope = scope;
super.visit(body);
popScope();
}
public void visit(LocalFuncDef stat) {
defineLocalVar(stat.name);
super.visit(stat);
}
public void visit(NumericFor stat) {
pushScope();
stat.scope = scope;
defineLocalVar(stat.name);
super.visit(stat);
popScope();
}
public void visit(GenericFor stat) {
pushScope();
stat.scope = scope;
defineLocalVars( stat.names );
super.visit(stat);
popScope();
}
public void visit(NameExp exp) {
exp.name.variable = resolveNameReference(exp.name);
super.visit(exp);
}
public void visit(FuncDef stat) {
stat.name.name.variable = resolveNameReference(stat.name.name);
stat.name.name.variable.hasassignments = true;
super.visit(stat);
}
public void visit(Assign stat) {
super.visit(stat);
for ( int i=0, n=stat.vars.size(); i<n; i++ ) {
VarExp v = (VarExp) stat.vars.get(i);
v.markHasAssignment();
}
}
public void visit(LocalAssign stat) {
visitExps(stat.values);
defineLocalVars( stat.names );
int n = stat.names.size();
int m = stat.values!=null? stat.values.size(): 0;
boolean isvarlist = m>0 && m<n && ((Exp)stat.values.get(m-1)).isvarargexp();
for ( int i=0; i<n && i<(isvarlist?m-1:m); i++ )
if ( stat.values.get(i) instanceof Constant )
((Name)stat.names.get(i)).variable.initialValue = ((Constant) stat.values.get(i)).value;
if ( !isvarlist )
for ( int i=m; i<n; i++ )
((Name)stat.names.get(i)).variable.initialValue = LuaValue.NIL;
}
public void visit(ParList pars) {
if ( pars.names != null )
defineLocalVars(pars.names);
if ( pars.isvararg )
scope.define("arg");
super.visit(pars);
}
protected void defineLocalVars(List<Name> names) {
for ( int i=0, n=names.size(); i<n; i++ )
defineLocalVar((Name) names.get(i));
}
protected void defineLocalVar(Name name) {
name.variable = scope.define(name.name);
}
protected Variable resolveNameReference(Name name) {
Variable v = scope.find(name.name);
if ( v.isLocal() && scope.functionNestingCount != v.definingScope.functionNestingCount )
v.isupvalue = true;
return v;
}
}

View File

@@ -1,85 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.ast;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class NameScope {
private static final Set<String> LUA_KEYWORDS = new HashSet<String>();
static {
String[] k = new String[] {
"and", "break", "do", "else", "elseif", "end",
"false", "for", "function", "if", "in", "local",
"nil", "not", "or", "repeat", "return",
"then", "true", "until", "while" };
for ( int i=0; i<k.length; i++ )
LUA_KEYWORDS.add( k[i] );
}
public final Map<String,Variable> namedVariables = new HashMap<String,Variable>();
public final NameScope outerScope;
public int functionNestingCount;
/** Construct default names scope */
public NameScope() {
this.outerScope = null;
this.functionNestingCount = 0;
}
/** Construct name scope within another scope*/
public NameScope(NameScope outerScope) {
this.outerScope = outerScope;
this.functionNestingCount = outerScope!=null? outerScope.functionNestingCount: 0;
}
/** Look up a name. If it is a global name, then throw IllegalArgumentException. */
public Variable find( String name ) throws IllegalArgumentException {
validateIsNotKeyword(name);
for ( NameScope n = this; n!=null; n=n.outerScope )
if ( n.namedVariables.containsKey(name) )
return (Variable)n.namedVariables.get(name);
Variable value = new Variable(name);
this.namedVariables.put(name, value);
return value;
}
/** Define a name in this scope. If it is a global name, then throw IllegalArgumentException. */
public Variable define( String name ) throws IllegalStateException, IllegalArgumentException {
validateIsNotKeyword(name);
Variable value = new Variable(name, this);
this.namedVariables.put(name, value);
return value;
}
private void validateIsNotKeyword(String name) {
if ( LUA_KEYWORDS.contains(name) )
throw new IllegalArgumentException("name is a keyword: '"+name+"'");
}
}

View File

@@ -1,42 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.ast;
import java.util.ArrayList;
import java.util.List;
public class ParList {
public static final List<Name> EMPTY_NAMELIST = new ArrayList<Name>();
public static final ParList EMPTY_PARLIST = new ParList(EMPTY_NAMELIST,false);
public final List<Name> names;
public final boolean isvararg;
public ParList(List<Name> names, boolean isvararg) {
this.names = names;
this.isvararg = isvararg;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

View File

@@ -1,250 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.ast;
import java.util.List;
import org.luaj.vm2.ast.Exp.VarExp;
abstract
public class Stat {
public abstract void accept(Visitor visitor);
public static Stat block(Block block) {
return block;
}
public static Stat whiledo(Exp exp, Block block) {
return new WhileDo(exp, block);
}
public static Stat repeatuntil(Block block, Exp exp) {
return new RepeatUntil(block, exp);
}
public static Stat breakstat() {
return new Break();
}
public static Stat returnstat(List<Exp> exps) {
return new Return(exps);
}
public static Stat assignment(List<VarExp> vars, List<Exp> exps) {
return new Assign(vars,exps);
}
public static Stat functioncall(Exp.FuncCall funccall) {
return new FuncCallStat(funccall);
}
public static Stat localfunctiondef(String name, FuncBody funcbody) {
return new LocalFuncDef(name, funcbody);
}
public static Stat fornumeric(String name, Exp initial, Exp limit, Exp step, Block block) {
return new NumericFor(name, initial, limit, step, block);
}
public static Stat functiondef(FuncName funcname, FuncBody funcbody) {
return new FuncDef( funcname, funcbody );
}
public static Stat forgeneric(List<Name> names, List<Exp> exps, Block block) {
return new GenericFor(names, exps, block);
}
public static Stat localassignment(List<Name> names, List<Exp> values) {
return new LocalAssign(names, values);
}
public static Stat ifthenelse(Exp ifexp, Block ifblock, List<Exp> elseifexps, List<Block> elseifblocks, Block elseblock) {
return new IfThenElse(ifexp, ifblock, elseifexps, elseifblocks, elseblock);
}
public static class Assign extends Stat {
public final List<VarExp> vars;
public final List<Exp> exps;
public Assign(List<VarExp> vars, List<Exp> exps) {
this.vars = vars;
this.exps = exps;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public static class WhileDo extends Stat {
public final Exp exp;
public final Block block;
public WhileDo( Exp exp, Block block ) {
this.exp = exp;
this.block = block;
}
public void accept(Visitor visitor) {
visitor.visit( this );
}
}
public static class RepeatUntil extends Stat {
public final Block block;
public final Exp exp;
public RepeatUntil( Block block, Exp exp ) {
this.block = block;
this.exp = exp;
}
public void accept(Visitor visitor) {
visitor.visit( this );
}
}
public static class Break extends Stat {
public void accept(Visitor visitor) {
visitor.visit( this );
}
}
public static class Return extends Stat {
public final List<Exp> values;
public Return(List<Exp> values) {
this.values = values;
}
public void accept(Visitor visitor) {
visitor.visit( this );
}
public int nreturns() {
int n = values!=null? values.size(): 0;
if ( n>0 && ((Exp)values.get(n-1)).isvarargexp() )
n = -1;
return n;
}
}
public static class FuncCallStat extends Stat {
public final Exp.FuncCall funccall;
public FuncCallStat(Exp.FuncCall funccall) {
this.funccall = funccall;
}
public void accept(Visitor visitor) {
visitor.visit( this );
}
}
public static class LocalFuncDef extends Stat {
public final Name name;
public final FuncBody body;
public LocalFuncDef(String name, FuncBody body) {
this.name = new Name(name);
this.body = body;
}
public void accept(Visitor visitor) {
visitor.visit( this );
}
}
public static class FuncDef extends Stat {
public final FuncName name;
public final FuncBody body;
public FuncDef(FuncName name, FuncBody body) {
this.name = name;
this.body = body;
}
public void accept(Visitor visitor) {
visitor.visit( this );
}
}
public static class GenericFor extends Stat {
public List<Name> names;
public List<Exp> exps;
public Block block;
public NameScope scope;
public GenericFor(List<Name> names, List<Exp> exps, Block block) {
this.names = names;
this.exps = exps;
this.block = block;
}
public void accept(Visitor visitor) {
visitor.visit( this );
}
}
public static class NumericFor extends Stat {
public final Name name;
public final Exp initial,limit,step;
public final Block block;
public NameScope scope;
public NumericFor(String name, Exp initial, Exp limit, Exp step, Block block) {
this.name = new Name(name);
this.initial = initial;
this.limit = limit;
this.step = step;
this.block = block;
}
public void accept(Visitor visitor) {
visitor.visit( this );
}
}
public static class LocalAssign extends Stat {
public final List<Name> names;
public final List<Exp> values;
public LocalAssign(List<Name> names, List<Exp> values) {
this.names = names;
this.values = values;
}
public void accept(Visitor visitor) {
visitor.visit( this );
}
}
public static class IfThenElse extends Stat {
public final Exp ifexp;
public final Block ifblock;
public final List<Exp> elseifexps;
public final List<Block> elseifblocks;
public final Block elseblock;
public IfThenElse(Exp ifexp, Block ifblock, List<Exp> elseifexps,
List<Block> elseifblocks, Block elseblock) {
this.ifexp = ifexp;
this.ifblock = ifblock;
this.elseifexps = elseifexps;
this.elseifblocks = elseifblocks;
this.elseblock = elseblock;
}
public void accept(Visitor visitor) {
visitor.visit( this );
}
}
}

View File

@@ -1,93 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.ast;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import org.luaj.vm2.LuaString;
public class Str {
private Str() {}
public static LuaString quoteString(String image) {
String s = image.substring(1, image.length()-1);
byte[] bytes = unquote(s);
return LuaString.valueOf(bytes);
}
public static LuaString charString(String image) {
String s = image.substring(1, image.length()-1);
byte[] bytes = unquote(s);
return LuaString.valueOf(bytes);
}
public static LuaString longString(String image) {
int i = image.indexOf('[', image.indexOf('[')+1)+1;
String s = image.substring(i,image.length()-i);
byte[] b = iso88591bytes(s);
return LuaString.valueOf(b);
}
public static byte[] iso88591bytes( String s ) {
try {
return s.getBytes("ISO8859-1");
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("ISO8859-1 not supported");
}
}
public static byte[] unquote(String s) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
char[] c = s.toCharArray();
int n = c.length;
for ( int i=0; i<n; i++ ) {
if ( c[i] == '\\' && i<n ) {
switch ( c[++i] ) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
int d=(int) (c[i++]-'0');
for ( int j=0; i<n && j<2 && c[i]>='0' && c[i]<='9'; i++, j++ )
d = d * 10 + (int) (c[i]-'0');
baos.write( (byte) d );
--i;
continue;
case 'a': baos.write( (byte) 7 ); continue;
case 'b': baos.write( (byte) '\b' ); continue;
case 'f': baos.write( (byte) '\f' ); continue;
case 'n': baos.write( (byte) '\n' ); continue;
case 'r': baos.write( (byte) '\r' ); continue;
case 't': baos.write( (byte) '\t' ); continue;
case 'v': baos.write( (byte) 11 ); continue;
case '"': baos.write( (byte) '"' ); continue;
case '\'': baos.write( (byte) '\'' ); continue;
case '\\': baos.write( (byte) '\\' ); continue;
default: baos.write( (byte) c[i] ); break;
}
} else {
baos.write( (byte) c[i] );
}
}
return baos.toByteArray();
}
}

View File

@@ -1,32 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.ast;
import java.util.List;
public class TableConstructor extends Exp {
public List<TableField> fields;
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

View File

@@ -1,51 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.ast;
public class TableField {
public final Exp index;
public final String name;
public final Exp rhs;
public TableField(Exp index, String name, Exp rhs) {
this.index = index;
this.name = name;
this.rhs = rhs;
}
public static TableField keyedField(Exp index, Exp rhs) {
return new TableField(index, null, rhs);
}
public static TableField namedField(String name, Exp rhs) {
return new TableField(null, name, rhs);
}
public static TableField listField(Exp rhs) {
return new TableField(null, null, rhs);
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

View File

@@ -1,62 +0,0 @@
/*******************************************************************************
* Copyright (c) 2010 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.ast;
import org.luaj.vm2.LuaValue;
/** Variable is created lua name scopes, and is a named, lua variable that
* either refers to a lua local, global, or upvalue storage location.
*/
public class Variable {
/** The name as it appears in lua source code */
public final String name;
/** The lua scope in which this variable is defined. */
public final NameScope definingScope;
/** true if this variable is an upvalue */
public boolean isupvalue;
/** true if there are assignments made to this variable */
public boolean hasassignments;
/** When hasassignments == false, and the initial value is a constant, this is the initial value */
public LuaValue initialValue;
/** Global is named variable not associated with a defining scope */
public Variable(String name) {
this.name = name;
this.definingScope = null;
}
public Variable(String name, NameScope definingScope) {
/** Local variable is defined in a particular scope. */
this.name = name;
this.definingScope = definingScope;
}
public boolean isLocal() {
return this.definingScope != null;
}
public boolean isConstant() {
return ! hasassignments && initialValue != null;
}
}

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