This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
sandius's profile picture

Rembulan, a new Lua 5.3 implementation for the JVM built with sandboxing in mind

Started by sandius, 04 October 2016 - 05:16 PM
sandius #1
Posted 04 October 2016 - 07:16 PM
Hello everyone,

it's been years since I played with ComputerCraft, and have spent countless hours programming my turtles to build me an underwater city. Now there may be the time to give something back.

(To the moderators: I hope this is the right place to post this, if not, please do let me know or move the post to the appropriate place!)

For the past few months I've been working on Rembulan, a new compiler+runtime for Lua 5.3 on the JVM, built from scratch with sandboxing (of the kind you would expect in ComputerCraft) in mind. The project lives on GitHub:I'll just copy the first two paragraphs from the Readme here for your convenience:

Rembulan is an implementation of Lua 5.3 for the Java Virtual Machine (JVM), written in pure Java with minimal dependencies. The goal of the Rembulan project is to develop a correct, complete and scalable Lua implementation for running sandboxed Lua programs on the JVM.

Rembulan implements Lua 5.3 as specified by the Lua Reference Manual, explicitly attempting to mimic the behaviour of PUC-Lua whenever possible. This includes language-level features (such as metamethods and coroutines) and the standard library.

I'd like to invite the ComputerCraft developers (and of course anyone else interested) to take a look and see if the project might be of help to you!

For the purposes of ComputerCraft, there are four significant improvements over LuaJ that may be of interest:
  1. Rembulan implements what I call "CPU accounting": Lua programs may be allocated a number of "ticks" for which they are allowed to run before they are paused (and resumed later). These pauses are transparent to the Lua programs. In other words, Rembulan allows you control over the CPU time spent by the user programs. (I'm not aware of an equivalent functionality in LuaJ.)
  2. Coroutines in Rembulan do not use Java threads (as opposed to LuaJ). They are therefore much lightweight and coroutine switches them do not involve a thread context switch. They work with CPU accounting (above). This should allow you to have an order of magnitude more coroutines than with LuaJ.
  3. Rembulan implements Lua 5.3, whereas (IIRC) LuaJ implements Lua 5.2.
  4. It's possible to have per-state metatables (e.g., for booleans or numbers) in Rembulan, whereas in LuaJ these are accessed via static fields, i.e., by default shared by all programs run on the JVM.
Points 1 and 2 are especially good-to-have (I think). I don't know to what extent you might have addressed similar points in your version of LuaJ, though.

There are of course downsides and caveats:
  • The project is not yet as mature as LuaJ, and a significant part of the standard library is still missing (most notably the module library). However, the runtime is by now mostly stable, and I do not expect it to change much until the release. (A detailed overview of the state of the standard library may be found in the documentation.)
  • Given the fundamentally different implementation strategy, libraries written for Lua in LuaJ will not (at this point) work in Rembulan. It should, however, be possible to implement a LuaJ-to-Rembulan adapter that might do at least part of the job.
That said, it might be worth trying Rembulan out to see how it could be used in ComputerCraft, and perhaps help shaping it.

I'll be happy to answer any questions!

M.
supernicejohn #2
Posted 04 October 2016 - 09:52 PM
Wow! Looking cool :)/>
Much cooler than a bf interpreter…
It seems like it is (almost?) ready for integration into cc, and if so, how would one go about such a task? (As in, when can we expect a developer to give a helping hand ;P) Also it said help was appreciated, but there was an acronym with six capital letters mentioned, and it scares me. Also I don't know Java, but I think the scary acronym might be a bigger problem.

I wish you all the luck and I hope we'll see something great from this huge project!
sandius #3
Posted 04 October 2016 - 10:57 PM
Thanks!!

Which acronym do you mean?

I think that as the first step, a survey of the Lua libraries used in ComputerCraft that are implemented in Java/LuaJ would be necessary, to know what functionality must be supported. Once this is settled, the rest shouldn't be too hard to do.

"End-users" should hopefully not be able to notice much of a difference, the main one being the change from Lua 5.2 to 5.3 :)/>
SquidDev #4
Posted 04 October 2016 - 11:03 PM
Firstly, wow! This is an impressive project: especially the "actual" coroutines rather than LuaJ's threading method (and a clean implementation of Lua in Java).

I've a project which tries to solve some of the same problems named Cobalt. This is a fork of LuaJ and so is harder to adapt to use "actual" coroutines but means the parsing/bytecode/stdlib problem is solved for me :)/>. Anyway, I've also thought about some of the above problems and so thought I'd ask some questions both about this project and also ideas you have about improving CC's Lua runtime.

Rembulan implements Lua 5.3 as specified by the Lua Reference Manual, explicitly attempting to mimic the behaviour of PUC-Lua whenever possible. This includes language-level features (such as metamethods and coroutines) and the standard library.
My worry with this is that LuaJ isn't standards compliant. Most of the time this is fixable, however sometimes this broken behaviour is relied upon a lot. One common pattern is pcall(error, "", i) to get a traceback (as debug.traceback is blacklisted). This produces different results on LuaJ and Lua. I'd love to fix these but there needs to be a way of doing so without breaking existing programs.

Also, have you tried running against Lua's tests? Those were really useful in ensuring some features worked correctly.

Rembulan implements what I call "CPU accounting": Lua programs may be allocated a number of "ticks" for which they are allowed to run before they are paused (and resumed later).
I haven't looked into this but does it handle string.find and friends on long strings (string.find("a"):rep(1e4), ".-.-.-.-b$"))? I like it as a concept but I'm not sure how it would work in practice: either you keep the "too long without yielding" error or you'd need a way to terminate programmer errors (such as infinite loops).

Coroutines in Rembulan do not use Java threads (as opposed to LuaJ). They are therefore much lightweight and coroutine switches them do not involve a thread context switch. They work with CPU accounting (above). This should allow you to have an order of magnitude more coroutines than with LuaJ.
Yessssssss. This is something I've been wanting to do for ever (especially as it is the next step towards serialisable state). Worth noting that you'd probably want to use a wrapper thread to allow yielding/pulling events from CC functions (such as peripherals) without writing special resuming code. This may prove more problematic then that: all peripheral methods would have to be written to allow resuming.

Rembulan implements Lua 5.3, whereas (IIRC) LuaJ implements Lua 5.2.
CC uses Lua 5.1 (LuaJ 2.0) though I think Dan wants to upgrade to Lua 5.2 (LuaJ 3.0). 5.3 would be awesome!

It's possible to have per-state metatables (e.g., for booleans or numbers) in Rembulan, whereas in LuaJ these are accessed via static fields, i.e., by default shared by all programs run on the JVM.
Again, woot!

The project is not yet as mature as LuaJ, and a significant part of the standard library is still missing (most notably the module library). However, the runtime is by now mostly stable, and I do not expect it to change much until the release. (A detailed overview of the state of the standard library may be found in the documentation.)
Several issues I noted when looking through the list:
  • You're using Java strings: strings are used a lot as byte arrays. Whilst Java strings can handle this it is better not to. You can still do some rudimentary interning of strings to reduce performance issues though.
  • No __gc. This is something I've got stuck on too. It might be possible to use ReferenceQueues to fire them.
  • Tables: it might be worth checking LuaJ 3.0's implementation of tables (or Cobalt's: that fixes some of its bugs).
  • No binary chunks. :(/> That would break jvml-jit.
  • Debug library: whilst current LuaJ doesn't have it, there is no reason to under a custom VM which correctly handles inter-computing sandboxes. It would be really nice to have support for this.
That said, it might be worth trying Rembulan out to see how it could be used in ComputerCraft, and perhaps help shaping it.
I'm looking at putting something together for CCTweaks-Lua which allows using this, just to see how it handles it. Really looking forward to playing with this :)/>.
Edited on 04 October 2016 - 09:36 PM
sandius #5
Posted 05 October 2016 - 02:43 AM
Firstly, wow! This is an impressive project: especially the "actual" coroutines rather than LuaJ's threading method (and a clean implementation of Lua in Java).

I've a project which tries to solve some of the same problems named Cobalt. This is a fork of LuaJ and so is harder to adapt to use "actual" coroutines but means the parsing/bytecode/stdlib problem is solved for me :)/>. Anyway, I've also thought about some of the above problems and so thought I'd ask some questions both about this project and also ideas you have about improving CC's Lua runtime.

Thank you for your kind words!

I was trying to do something similar to Cobalt earlier (before I started Rembulan), but didn't get very far. Moving away from the coroutine implementation used in LuaJ proved to be far too difficult, and fixing the coroutine problem was one of my main motivations. I think I did get quite far on the Lua 5.3 front with it, though, so that's definitely doable, should you choose to go that way.

Rembulan implements Lua 5.3 as specified by the Lua Reference Manual, explicitly attempting to mimic the behaviour of PUC-Lua whenever possible. This includes language-level features (such as metamethods and coroutines) and the standard library.
My worry with this is that LuaJ isn't standards compliant. Most of the time this is fixable, however sometimes this broken behaviour is relied upon a lot. One common pattern is pcall(error, "", i) to get a traceback (as debug.traceback is blacklisted). This produces different results on LuaJ and Lua. I'd love to fix these but there needs to be a way of doing so without breaking existing programs.

Also, have you tried running against Lua's tests? Those were really useful in ensuring some features worked correctly.

I think those things should be fixable: I have quite an extensive test suite (written in Scala) that could with some work be adapted to be run against the ComputerCraft standard library with LuaJ/Cobalt to see where the behaviour diverges. That might help identifying such problematic spots.

Regarding Lua's tests: I have tried them, with good results, but in order to be able to run the entire test suite I'd have to modify them a bit. I have a few issues with them:
  • They depend on what I'd call "implementation details", e.g. the debug library and the way error messages are formatted.
  • They aren't particularly modular. For instance, a lot of test methods use string.gsub or load; until I had the correct implementations of these functions, the tests were failing because of these missing functions.
  • And they terminate on the first error, so you can figure out that the test has terminated on line 235 out of 512, but you don't know whether there would be another 100 failures after this line, or none.
But I should give the tests another try.

Rembulan implements what I call "CPU accounting": Lua programs may be allocated a number of "ticks" for which they are allowed to run before they are paused (and resumed later).
I haven't looked into this but does it handle string.find and friends on long strings (string.find("a"):rep(1e4), ".-.-.-.-b$"))? I like it as a concept but I'm not sure how it would work in practice: either you keep the "too long without yielding" error or you'd need a way to terminate programmer errors (such as infinite loops).

How do you handle this currently, e.g., an infinite loop? When a turtle in ComputerCraft gets stuck in an infinite loop, then the only way to fix that is to destroy it, no? ;)/>

The point is that even if it does get stuck that way, it shouldn't be using 100% of your actual CPU time. If, for instance, it runs for a few ms every world tick (IIIRC that's how time is measured in MineCraft), it could simply be kept running forever. (Plus, there might be an in-game mechanism like "heat" that could shorten the time slices assigned to the turtle the more the CPU is used, so after a while, even if it is stuck in an infinite loop, it would get slower and slower, becoming less of a burden on the host system.)

For standard library functions, I avoided using CPU accounting as long as there weren't any non-raw Lua operations involved (e.g., string.gsub can pause, but string.find cannot). It also means that standard library functions are "for free"; but they don't have to be.

Coroutines in Rembulan do not use Java threads (as opposed to LuaJ). They are therefore much lightweight and coroutine switches them do not involve a thread context switch. They work with CPU accounting (above). This should allow you to have an order of magnitude more coroutines than with LuaJ.
Yessssssss. This is something I've been wanting to do for ever (especially as it is the next step towards serialisable state). Worth noting that you'd probably want to use a wrapper thread to allow yielding/pulling events from CC functions (such as peripherals) without writing special resuming code. This may prove more problematic then that: all peripheral methods would have to be written to allow resuming.

I'll have to believe you on that one :)/> However, if they aren't using too many Lua operations, it should be doable, if perhaps annoying.

Rembulan implements Lua 5.3, whereas (IIRC) LuaJ implements Lua 5.2.
CC uses Lua 5.1 (LuaJ 2.0) though I think Dan wants to upgrade to Lua 5.2 (LuaJ 3.0). 5.3 would be awesome!

Aha! I really thought CC used LuaJ 3.0.

It's possible to have per-state metatables (e.g., for booleans or numbers) in Rembulan, whereas in LuaJ these are accessed via static fields, i.e., by default shared by all programs run on the JVM.
Again, woot!

Well, isn't that what you also did in Cobalt?

The project is not yet as mature as LuaJ, and a significant part of the standard library is still missing (most notably the module library). However, the runtime is by now mostly stable, and I do not expect it to change much until the release. (A detailed overview of the state of the standard library may be found in the documentation.)
Several issues I noted when looking through the list:
  • You're using Java strings: strings are used a lot as byte arrays. Whilst Java strings can handle this it is better not to. You can still do some rudimentary interning of strings to reduce performance issues though.
  • No __gc. This is something I've got stuck on too. It might be possible to use ReferenceQueues to fire them.
  • Tables: it might be worth checking LuaJ 3.0's implementation of tables (or Cobalt's: that fixes some of its bugs).
  • No binary chunks. :(/> That would break jvml-jit.
  • Debug library: whilst current LuaJ doesn't have it, there is no reason to under a custom VM which correctly handles inter-computing sandboxes. It would be really nice to have support for this.

Yes, Java strings will probably need to go. I'd really, really prefer to keep them, though, if there was a reasonable way of making them work. They make useful things such as Java interop much easier, and I'm slightly worried about the performance impact of conversions between Java strings and Lua strings (especially for Lua strings not backed by a Java string). (Just as a note: Rembulan does not use types such as LuaBoolean or LuaNumber for its values: all values are Objects, e.g. Lua booleans are java.lang.Boolean. Having strings represented by java.lang.String is very convenient, even if Java strings are Unicode and Lua strings are not.)

About __gc: yes, that's the mechanism I intend to use for it. I haven't done anything on that front, though, because I didn't want to commit too early to an implementation strategy. (I'm also hoping not to close any doors w.r.t. to a possible future implementation of heap memory sandboxing.)

Tables: indeed! The current default implementation is really just a placeholder backed by java.util.Map. I did look at LuaJ's tables, but that's about it :)/> I haven't got a test suite for checking that a table implementation is valid, so I'm mostly postponing this until I have one. (I don't like writing tests.)

Binary chunks: yea, that's one of the things I'd file under "implementation details of PUC-Lua". I don't use the Lua bytecode (the compiler has its own intermediate representation), so that might be a problem. That said, I used to have a recompiler in Rembulan that was compiling Lua bytecode into Java bytecode; but I took it out, because effectively this meant having two compilers instead of one. Just so you know that it's definitely technically possible to have it there (but probably not a good idea maintenance-wise). But wow, JVML-JIT is cool!

Debug library: parts of the PUC-Lua debug library are there, implementing the things that do have an equivalent in Rembulan. But it's highly unlikely Rembulan will ever support things such as debug.getlocal, debug.getinfo or instruction hooks. These are highly implementation-dependent; I'd have to change a lot about the implementation strategy, almost always to the detriment of performance.

That said, it might be worth trying Rembulan out to see how it could be used in ComputerCraft, and perhaps help shaping it.
I'm looking at putting something together for CCTweaks-Lua which allows using this, just to see how it handles it. Really looking forward to playing with this :)/>.

This is exactly the reaction I was hoping for! Do let me know if I can help with anything! The JavaDocs for the runtime module should be mostly complete, so hopefully it won't be too frustrating! ;)/>
supernicejohn #6
Posted 05 October 2016 - 08:39 AM
Was talking about the OSSRH, which is obviously 6 letters.
As for the lua libraries it would be a fun challenge to recreate them from simpler functions, like making the string library from string.sub… But I suppose there will always be ones that have to be done at a lower level, if not just for efficiency ;)/>
SquidDev #7
Posted 05 October 2016 - 11:11 AM
Regarding Lua's tests: I have tried them, with good results, but in order to be able to run the entire test suite I'd have to modify them a bit. I have a few issues with them
Yeah, they aren't great. I'm happy for you to borrow Cobalt's version of them which comments out some of the implementation specific bits. Lots of tests being bundled in one file is a pain, just one which wasn't worth fixing for me.

How do you handle this currently, e.g., an infinite loop? When a turtle in ComputerCraft gets stuck in an infinite loop, then the only way to fix that is to destroy it, no?

The point is that even if it does get stuck that way, it shouldn't be using 100% of your actual CPU time. If, for instance, it runs for a few ms every world tick (IIIRC that's how time is measured in MineCraft), it could simply be kept running forever.
It depends, if it yields (such as calling a turtle.* method) then you can use Ctrl+T to terminate it, otherwise it'll shutdown after a while (or error in the case of Cobalt). I haven't looked too hard into your implementation of continuations: would it be possible to throw an error when continuing instead of returning a function? This would allow terminating erroneous scripts.

For standard library functions, I avoided using CPU accounting as long as there weren't any non-raw Lua operations involved (e.g., string.gsub can pause, but string.find cannot). It also means that standard library functions are "for free"; but they don't have to be.
I think in the above case there should be some accounting, though I realise that then requires rewriting the pattern matching to allow continuations. The code I used takes well over 10 seconds to complete, but doesn't trigger the "too long without yielding" error correctly. In Cobalt I just added a checkIn() method to ensure that it hadn't taken too much time, though I realise that is less feasible for your execution model.

I'll have to believe you on that one :)/> However, if they aren't using too many Lua operations, it should be doable, if perhaps annoying.
Most of the times a peripheral function yields is to execute a task on the world thread rather than computer thread. I guess you could change the IPeripheral/ILuaObject interface to return a "result" or "next tick" object and handle that: this would avoid having to handle resuming.

Well, isn't that what you also did in Cobalt?
Yeah, but it is nice having it.

Yes, Java strings will probably need to go. I'd really, really prefer to keep them, though, if there was a reasonable way of making them work. They make useful things such as Java interop much easier, and I'm slightly worried about the performance impact of conversions between Java strings and Lua strings (especially for Lua strings not backed by a Java string).
It should be fine to use Strings as long as you encode them the same way as CC's version of LuaJ and Cobalt do (see encode and decode in LuaString). I'm not sure the cost of conversion is that great: it depends on how often CC methods are called.

(I don't like writing tests.)
Does anyone? Feel free to copy Cobalt's table tests though I realise they will require heavy adaptation. These test the semantics of weak tables pretty thoroughly

Binary chunks: yea, that's one of the things I'd file under "implementation details of PUC-Lua". I don't use the Lua bytecode (the compiler has its own intermediate representation), so that might be a problem.
I noticed you're doing some type hinting in this. Would you mind dropping me a PM/putting something up explaining how it works/what is tracked? This is something I want to add to luaj.luajc, though probably using information gathered at runtime as well.

That said, I used to have a recompiler in Rembulan that was compiling Lua bytecode into Java bytecode; but I took it out, because effectively this meant having two compilers instead of one. But wow, JVML-JIT is cool!
Do you still have the code lying around? I maintain a fork of LuaJ's LuaJC so it would be interesting looking at your code to see if there were any optimisations I could 'borrow' :)/>.

-Debug stuff-
:(/>.

This is exactly the reaction I was hoping for! Do let me know if I can help with anything! The JavaDocs for the runtime module should be mostly complete, so hopefully it won't be too frustrating! ;)/>
It was pretty intuitive, though I couldn't find a nice way of installing libraries without including the "package"/"require" library (which CC doesn't include). It doesn't build yet (I need to find a way to handle yielding) and I'll need to modify the bios so I can't tell you how it runs yet.
Edited on 05 October 2016 - 09:12 AM
sandius #8
Posted 06 October 2016 - 02:17 AM
Ah, sorry for the late reply, I thought I had email notifications set up.

Regarding Lua's tests: I have tried them, with good results, but in order to be able to run the entire test suite I'd have to modify them a bit. I have a few issues with them
Yeah, they aren't great. I'm happy for you to borrow Cobalt's version of them which comments out some of the implementation specific bits. Lots of tests being bundled in one file is a pain, just one which wasn't worth fixing for me.

Aren't you targeting Lua 5.1 in Cobalt? I think the tests do change between Lua versions – I'd be worried that I'd end up passing 5.1 tests but not 5.3 ;)/>/>/>/>/>/> But I'll take a look at the diff between vanilla 5.1 tests and Cobalt tests, to see whether I might see a pattern there to take over.

But ultimately I think I'll have to look at all the assertion errors the tests may throw and check whether the cause is simply "not being PUC-Lua".

How do you handle this currently, e.g., an infinite loop? When a turtle in ComputerCraft gets stuck in an infinite loop, then the only way to fix that is to destroy it, no?

The point is that even if it does get stuck that way, it shouldn't be using 100% of your actual CPU time. If, for instance, it runs for a few ms every world tick (IIIRC that's how time is measured in MineCraft), it could simply be kept running forever.
It depends, if it yields (such as calling a turtle.* method) then you can use Ctrl+T to terminate it, otherwise it'll shutdown after a while (or error in the case of Cobalt). I haven't looked too hard into your implementation of continuations: would it be possible to throw an error when continuing instead of returning a function? This would allow terminating erroneous scripts.

Right now the continuation can only be resumed (you can't even pass values to them as arguments). Hmm. The problem with throwing errors when continuing is that errors can be caught (e.g., via pcall). And if you don't catch them, you'll empty out the call stack anyway, so it seems to me almost as good as simply throwing the entire continuation away and having it GC'd…

For standard library functions, I avoided using CPU accounting as long as there weren't any non-raw Lua operations involved (e.g., string.gsub can pause, but string.find cannot). It also means that standard library functions are "for free"; but they don't have to be.
I think in the above case there should be some accounting, though I realise that then requires rewriting the pattern matching to allow continuations. The code I used takes well over 10 seconds to complete, but doesn't trigger the "too long without yielding" error correctly. In Cobalt I just added a checkIn() method to ensure that it hadn't taken too much time, though I realise that is less feasible for your execution model.

You're probably right; it does make sense to do these checks in such methods. (The same goes for the methods in the table library.)

I'll have to believe you on that one :)/>/>/>/>/>/>/> However, if they aren't using too many Lua operations, it should be doable, if perhaps annoying.
Most of the times a peripheral function yields is to execute a task on the world thread rather than computer thread. I guess you could change the IPeripheral/ILuaObject interface to return a "result" or "next tick" object and handle that: this would avoid having to handle resuming.

Would ExecuteContext.resumeAfter() be helpful in those scenarios?

Yes, Java strings will probably need to go. I'd really, really prefer to keep them, though, if there was a reasonable way of making them work. They make useful things such as Java interop much easier, and I'm slightly worried about the performance impact of conversions between Java strings and Lua strings (especially for Lua strings not backed by a Java string).
It should be fine to use Strings as long as you encode them the same way as CC's version of LuaJ and Cobalt do (see encode and decode in LuaString). I'm not sure the cost of conversion is that great: it depends on how often CC methods are called.

I think you can do this in CC (since you have full control over the environment), but I should be more defensive.
The trouble starts when I start considering the general case: I can't guarantee that a string I got from who-knows-where is actually raw 8-bit. You can, though!

(I don't like writing tests.)
Does anyone? Feel free to copy Cobalt's table tests though I realise they will require heavy adaptation. These test the semantics of weak tables pretty thoroughly

Thanks! I'll definitely try to reuse as much as I can of that!

Binary chunks: yea, that's one of the things I'd file under "implementation details of PUC-Lua". I don't use the Lua bytecode (the compiler has its own intermediate representation), so that might be a problem.
I noticed you're doing some type hinting in this. Would you mind dropping me a PM/putting something up explaining how it works/what is tracked? This is something I want to add to luaj.luajc, though probably using information gathered at runtime as well.

Indeed I do: underneath the IR, there's a type system similar to that of Typed Lua. I'm doing the type analysis in order to reduce the number of calls that may call metamethods. And it could be used for performance improvements, especially when it comes to boxing and unboxing (I don't do that yet, though).

I'll try to write it up and put it to the docs.

That said, I used to have a recompiler in Rembulan that was compiling Lua bytecode into Java bytecode; but I took it out, because effectively this meant having two compilers instead of one. But wow, JVML-JIT is cool!
Do you still have the code lying around? I maintain a fork of LuaJ's LuaJC so it would be interesting looking at your code to see if there were any optimisations I could 'borrow' :)/>/>/>/>/>/>/>.

Sure: this is the last commit with the recompiler:
https://github.com/mjanicek/rembulan/tree/47a50ee6fcef8e8839eec8a152fef50f42296284

But beware: the code is quite bad. It's very different from what it is now: the bytecode loader is needlessly complicated (uses visitors too much), and the recompiler is unmaintainable (doesn't use visitors nearly enough).

This is exactly the reaction I was hoping for! Do let me know if I can help with anything! The JavaDocs for the runtime module should be mostly complete, so hopefully it won't be too frustrating! ;)/>/>/>/>/>/>/>
It was pretty intuitive, though I couldn't find a nice way of installing libraries without including the "package"/"require" library (which CC doesn't include). It doesn't build yet (I need to find a way to handle yielding) and I'll need to modify the bios so I can't tell you how it runs yet.

That's in the works! I need to revamp the system quite a bit to be compatible with the behaviour of the package library, with loader functions and searchers and all that stuff. It's mainly about striking the right balance between loading libraries from the client Lua code and the host Java code.
sandius #9
Posted 06 October 2016 - 02:27 PM
I noticed you're doing some type hinting in this. Would you mind dropping me a PM/putting something up explaining how it works/what is tracked? This is something I want to add to luaj.luajc, though probably using information gathered at runtime as well.

I've added an overview of the compiler with pointers to the relevant classes here:
https://github.com/mjanicek/rembulan/blob/master/doc/CompilerOverview.md Hope it will be useful!