@@ -6,9 +6,9 @@ This is a Lua 5.3 VM and compiler written in [Go](http://golang.org/). This is i
66programs, with minimal fuss and bother.
77
88I have been using this VM/compiler as the primary script host in Rubble (a scripted templating system used to generate
9- data files for the game Dwarf Fortress) for over a year now, so they are fairly well tested. Speaking of tests: No formal
10- unit tests are provided. Testing was done by running under real-world conditions with Rubble, and in Rubble's built-in
11- template testing system (it is not appropriate to distribute these tests with this library for obvious reasons) .
9+ data files for the game Dwarf Fortress) for over a year now, so they are fairly well tested. In addition to the real-world
10+ "testing" that this has received I am slowly adding proper tests based on the official Lua test suite. These tests are
11+ far from complete, but are slowly getting more so as time passes .
1212
1313Most (if not all) of the API functions may cause a panic, but only if things go REALLY wrong. If a function does not
1414state that it can panic or "raise an error" it will only do so if a critical internal assumption proves to be wrong
@@ -47,16 +47,45 @@ If you want to use a third-party compiler it will need to produce binaries with
4747
4848When building the reference compiler on most systems these settings should be the default.
4949
50+ The VM API has a function that wraps ` luac ` to load code, but the way it does this may or may not fit your needs. To use
51+ this wrapper you will need to have ` luac ` on your path or otherwise placed so the VM can find it. See the documentation
52+ for ` State.LoadTextExternal ` for more information. Keep in mind that due to limitations in Go and ` luac ` , this function
53+ is not reentrant! If you need concurrency support it would be better to use ` State.LoadBinary ` and write your own wrapper.
54+
5055The default compiler provided by this library does not support constant folding, and some special instructions are not
5156used at all (instead preferring simpler sequences of other instructions). For example TESTSET is never generated, TEST
5257is used in all cases (largely because it would greatly complicate the compiler if I tried to use TESTSET where possible).
5358Expressions use a simple "recursive" code generation style, meaning that it wastes registers like crazy in some (rare)
5459cases.
5560
61+ One of the biggest code quality offenders is ` or ` and ` and ` , as they can result in sequences like this one:
62+
63+ [4] LT A:1 B:r(0) C:k(2) ; CK:5
64+ [5] JMP A:0 SBX:1 ; to:7
65+ [6] LOADBOOL A:2 B:1 C:1
66+ [7] LOADBOOL A:2 B:0 C:0
67+ [8] TEST A:2 C:1
68+ [9] JMP A:0 SBX:7 ; to:17
69+ [10] EQ A:1 B:r(1) C:k(3) ; CK:<nil>
70+ ... (7 more instructions to implement next part of condition)
71+
72+ As you can see this is terrible. That sequence would be better written as:
73+
74+ [4] LT A:1 B:r(0) C:k(2) ; CK:5
75+ [5] JMP A:0 SBX:2 ; to:8
76+ [6] EQ A:1 B:r(1) C:k(3) ; CK:<nil>
77+ ... (1 more instruction to implement next part of condition)
78+
79+ But the current expression compiler is not smart enough to do it that way. Luckily this is the worst offender, most
80+ things produce code that is very close or identical to what ` luac ` produces. Note that the reason why this code is so
81+ bad is entirely because the expression used ` or ` (and the implementation of ` and ` and ` or ` is very bad).
82+
5683The compiler provides an implementation of a ` continue ` keyword, but the keyword definition in the lexer is commented
5784out. If you want ` continue ` all you need to do is uncomment the indicated line (near the top of ` ast/lexer.go ` ). There
5885is also a flag in the VM that * should* make tables use 0 based indexing. This feature has received minimal testing, so
5986it probably doesn't work properly. If you want to try 0 based indexing just set the variable ` TableIndexOffset ` to 0.
87+ Note that ` TableIndexOffset ` is strictly a VM setting, the standard modules do not respect this setting (for example the
88+ ` table ` module and ` ipairs ` will still insist on using 1 as the first index).
6089
6190
6291Missing Stuff:
@@ -142,6 +171,34 @@ to rework the error handler...
142171Changes:
143172------------------------------------------------------------------------------------------------------------------------
144173
174+ 1.0.2
175+
176+ More tests, more (compiler) bugs fixed. Damn compiler will be the death of me yet...
177+
178+ In addition to the inevitable compiler bugs I also fixed the way the VM handles upvalues. Before I was giving each
179+ closure its own copy of each upvalue, so multiple closures never properly shared values. This change fixes several
180+ subtle (and several not so subtle) bugs.
181+
182+ Oh, and ` pcall ` works now (it didn't work at all before. Sorry, I never used it).
183+
184+ * Added more script tests. I still have a lot more to do... (script_test.go)
185+ * Fixed incorrect compilation of method declarations (` function a:x() end ` ). Depressingly the issue was only one
186+ incorrect word, but it resulted in * very* wrong results (I am really starting to remember why I hated writing the
187+ compiler, the VM was fun, the compiler... not.) (ast/parse.go)
188+ * Parenthesized expression that would normally (without the parenthesis) return multiple values (for example: ` (...) ` )
189+ were not properly truncating the result to a single value. (compile_expr.go)
190+ * Fixed a semi-major VM issue with upvalues. Closures that should have a single shared upvalue were instead each using
191+ their own private copy after said upvalue was closed. This required an almost total rewrite of the way upvalues are
192+ stored internally. (all over the place, but mainly callframe.go, function.go, api.go, and vm.go)
193+ * JMP instructions created by ` break ` and ` continue ` statements are now properly patched by the compiler to close any
194+ upvalues there may be. (compile.go)
195+ * Fixed the ` pcall ` script function so it actually works. (lmodbase/functions.go)
196+ * On a recovered error each stack frame's upvalues are closed before the stack is stripped. This corrects incorrect
197+ behavior that arises when a function stores a closure to an unclosed upvalue then errors out (the closure may still be
198+ referenced, but it's upvalues may be invalid). (api.go, callframe.go)
199+
200+ * * *
201+
1452021.0.1
146203
147204This version adds a bunch of tests (still not nearly as many as I would like), and fixes a ton of minor compiler errors.
0 commit comments