mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-11-01 06:03:00 +00:00
Update Cobalt to 0.8.0
- Update Cobalt to 0.8.0, switching our Lua version to 5.2(ish). - Remove our `load` wrapper, as we no longer need to inject _ENV into the enviroment table. - Update the parser to handle labels and goto. This doesn't check that gotos are well formed, but at least means the parser doesn't fall over on them. - Update our docs to reflect the changes to Cobalt.
This commit is contained in:
@@ -73,20 +73,20 @@ public class CobaltLuaMachine implements ILuaMachine {
|
||||
.build();
|
||||
|
||||
// Set up our global table.
|
||||
var globals = state.getMainThread().getfenv();
|
||||
CoreLibraries.debugGlobals(state);
|
||||
Bit32Lib.add(state, globals);
|
||||
globals.rawset("_HOST", ValueFactory.valueOf(environment.hostString()));
|
||||
globals.rawset("_CC_DEFAULT_SETTINGS", ValueFactory.valueOf(CoreConfig.defaultComputerSettings));
|
||||
|
||||
// Add default APIs
|
||||
for (var api : environment.apis()) addAPI(globals, api);
|
||||
|
||||
// And load the BIOS
|
||||
try {
|
||||
var globals = state.globals();
|
||||
CoreLibraries.debugGlobals(state);
|
||||
Bit32Lib.add(state, globals);
|
||||
globals.rawset("_HOST", ValueFactory.valueOf(environment.hostString()));
|
||||
globals.rawset("_CC_DEFAULT_SETTINGS", ValueFactory.valueOf(CoreConfig.defaultComputerSettings));
|
||||
|
||||
// Add default APIs
|
||||
for (var api : environment.apis()) addAPI(globals, api);
|
||||
|
||||
// And load the BIOS
|
||||
var value = LoadState.load(state, bios, "@bios.lua", globals);
|
||||
mainRoutine = new LuaThread(state, value, globals);
|
||||
} catch (CompileException e) {
|
||||
mainRoutine = new LuaThread(state, value);
|
||||
} catch (LuaError | CompileException e) {
|
||||
throw new MachineException(Nullability.assertNonNull(e.getMessage()));
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ public class CobaltLuaMachine implements ILuaMachine {
|
||||
return found ? table : null;
|
||||
}
|
||||
|
||||
private LuaValue toValue(@Nullable Object object, @Nullable IdentityHashMap<Object, LuaValue> values) {
|
||||
private LuaValue toValue(@Nullable Object object, @Nullable IdentityHashMap<Object, LuaValue> values) throws LuaError {
|
||||
if (object == null) return Constants.NIL;
|
||||
if (object instanceof Number num) return ValueFactory.valueOf(num.doubleValue());
|
||||
if (object instanceof Boolean bool) return ValueFactory.valueOf(bool);
|
||||
@@ -235,7 +235,7 @@ public class CobaltLuaMachine implements ILuaMachine {
|
||||
return Constants.NIL;
|
||||
}
|
||||
|
||||
Varargs toValues(@Nullable Object[] objects) {
|
||||
Varargs toValues(@Nullable Object[] objects) throws LuaError {
|
||||
if (objects == null || objects.length == 0) return Constants.NONE;
|
||||
if (objects.length == 1) return toValue(objects[0], null);
|
||||
|
||||
|
||||
@@ -18,33 +18,6 @@ do
|
||||
expect = f().expect
|
||||
end
|
||||
|
||||
if _VERSION == "Lua 5.1" then
|
||||
-- If we're on Lua 5.1, install parts of the Lua 5.2/5.3 API so that programs can be written against it
|
||||
local nativeload = load
|
||||
|
||||
function load(x, name, mode, env)
|
||||
expect(1, x, "function", "string")
|
||||
expect(2, name, "string", "nil")
|
||||
expect(3, mode, "string", "nil")
|
||||
expect(4, env, "table", "nil")
|
||||
|
||||
local ok, p1, p2 = pcall(function()
|
||||
local result, err = nativeload(x, name, mode, env)
|
||||
if result and env then
|
||||
env._ENV = env
|
||||
end
|
||||
return result, err
|
||||
end)
|
||||
if ok then
|
||||
return p1, p2
|
||||
else
|
||||
error(p1, 2)
|
||||
end
|
||||
end
|
||||
|
||||
loadstring = function(string, chunkname) return nativeload(string, chunkname) end
|
||||
end
|
||||
|
||||
-- Inject a stub for the old bit library
|
||||
_G.bit = {
|
||||
bnot = bit32.bnot,
|
||||
|
||||
@@ -535,6 +535,28 @@ function errors.unexpected_end(start_pos, end_pos)
|
||||
}
|
||||
end
|
||||
|
||||
--[[- A label statement was opened but not closed.
|
||||
|
||||
@tparam number open_start The start position of the opening label.
|
||||
@tparam number open_end The end position of the opening label.
|
||||
@tparam number tok_start The start position of the current token.
|
||||
@return The resulting parse error.
|
||||
]]
|
||||
function errors.unclosed_label(open_start, open_end, token, start_pos, end_pos)
|
||||
expect(1, open_start, "number")
|
||||
expect(2, open_end, "number")
|
||||
expect(3, token, "number")
|
||||
expect(4, start_pos, "number")
|
||||
expect(5, end_pos, "number")
|
||||
|
||||
return {
|
||||
"Unexpected " .. token_names[token] .. ".",
|
||||
annotate(open_start, open_end, "Label was started here."),
|
||||
annotate(start_pos, end_pos, "Tip: Try adding " .. code("::") .. " here."),
|
||||
|
||||
}
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Generic parsing errors
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@@ -32,12 +32,12 @@ local tokens = require "cc.internal.syntax.parser".tokens
|
||||
local sub, find = string.sub, string.find
|
||||
|
||||
local keywords = {
|
||||
["and"] = tokens.AND, ["break"] = tokens.BREAK, ["do"] = tokens.DO, ["else"] = tokens.ELSE,
|
||||
["elseif"] = tokens.ELSEIF, ["end"] = tokens.END, ["false"] = tokens.FALSE, ["for"] = tokens.FOR,
|
||||
["function"] = tokens.FUNCTION, ["if"] = tokens.IF, ["in"] = tokens.IN, ["local"] = tokens.LOCAL,
|
||||
["nil"] = tokens.NIL, ["not"] = tokens.NOT, ["or"] = tokens.OR, ["repeat"] = tokens.REPEAT,
|
||||
["return"] = tokens.RETURN, ["then"] = tokens.THEN, ["true"] = tokens.TRUE, ["until"] = tokens.UNTIL,
|
||||
["while"] = tokens.WHILE,
|
||||
["and"] = tokens.AND, ["break"] = tokens.BREAK, ["do"] = tokens.DO, ["else"] = tokens.ELSE,
|
||||
["elseif"] = tokens.ELSEIF, ["end"] = tokens.END, ["false"] = tokens.FALSE, ["for"] = tokens.FOR,
|
||||
["function"] = tokens.FUNCTION, ["goto"] = tokens.GOTO, ["if"] = tokens.IF, ["in"] = tokens.IN,
|
||||
["local"] = tokens.LOCAL, ["nil"] = tokens.NIL, ["not"] = tokens.NOT, ["or"] = tokens.OR,
|
||||
["repeat"] = tokens.REPEAT, ["return"] = tokens.RETURN, ["then"] = tokens.THEN, ["true"] = tokens.TRUE,
|
||||
["until"] = tokens.UNTIL, ["while"] = tokens.WHILE,
|
||||
}
|
||||
|
||||
--- Lex a newline character
|
||||
@@ -292,12 +292,15 @@ local function lex_token(context, str, pos)
|
||||
local next_pos = pos + 1
|
||||
if sub(str, next_pos, next_pos) == "=" then return tokens.LE, next_pos end
|
||||
return tokens.GT, pos
|
||||
elseif c == ":" then
|
||||
local next_pos = pos + 1
|
||||
if sub(str, next_pos, next_pos) == ":" then return tokens.DOUBLE_COLON, next_pos end
|
||||
return tokens.COLON, pos
|
||||
elseif c == "~" and sub(str, pos + 1, pos + 1) == "=" then return tokens.NE, pos + 1
|
||||
|
||||
-- Single character tokens
|
||||
elseif c == "," then return tokens.COMMA, pos
|
||||
elseif c == ";" then return tokens.SEMICOLON, pos
|
||||
elseif c == ":" then return tokens.COLON, pos
|
||||
elseif c == "(" then return tokens.OPAREN, pos
|
||||
elseif c == ")" then return tokens.CPAREN, pos
|
||||
elseif c == "]" then return tokens.CSQUARE, pos
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -10,6 +10,8 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.squiddev.cobalt.LuaError;
|
||||
import org.squiddev.cobalt.LuaState;
|
||||
import org.squiddev.cobalt.Prototype;
|
||||
import org.squiddev.cobalt.compiler.CompileException;
|
||||
import org.squiddev.cobalt.compiler.LuaC;
|
||||
@@ -108,9 +110,9 @@ class LuaCoverage {
|
||||
Queue<Prototype> queue = new ArrayDeque<>();
|
||||
|
||||
try (InputStream stream = new FileInputStream(file)) {
|
||||
var proto = LuaC.compile(stream, "@" + file.getPath());
|
||||
var proto = LuaC.compile(new LuaState(), stream, "@" + file.getPath());
|
||||
queue.add(proto);
|
||||
} catch (CompileException e) {
|
||||
} catch (LuaError | CompileException e) {
|
||||
throw new IllegalStateException("Cannot compile", e);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ package dan200.computercraft.core.lua;
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.squiddev.cobalt.Constants;
|
||||
import org.squiddev.cobalt.LuaError;
|
||||
import org.squiddev.cobalt.LuaTable;
|
||||
import org.squiddev.cobalt.ValueFactory;
|
||||
|
||||
@@ -18,7 +19,11 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
class VarargArgumentsTest {
|
||||
private static LuaTable tableWithCustomType() {
|
||||
var metatable = new LuaTable();
|
||||
metatable.rawset(Constants.NAME, ValueFactory.valueOf("some type"));
|
||||
try {
|
||||
metatable.rawset(Constants.NAME, ValueFactory.valueOf("some type"));
|
||||
} catch (LuaError e) {
|
||||
throw new IllegalStateException("Cannot create metatable", e);
|
||||
}
|
||||
|
||||
var table = new LuaTable();
|
||||
table.setMetatable(null, metatable);
|
||||
|
||||
@@ -188,6 +188,9 @@ local function format(value)
|
||||
-- TODO: Look into something like mbs's pretty printer.
|
||||
if type(value) == "string" and value:find("\n") then
|
||||
return "<<<\n" .. value .. "\n>>>"
|
||||
elseif type(value) == "string" then
|
||||
local escaped = value:gsub("[^%g ]", function(x) return ("\\x%02x"):format(x:byte()) end)
|
||||
return "\"" .. escaped .. "\""
|
||||
else
|
||||
local ok, res = pcall(textutils.serialise, value)
|
||||
if ok then return res else return tostring(value) end
|
||||
|
||||
@@ -79,20 +79,6 @@ describe("The Lua base library", function()
|
||||
end)
|
||||
|
||||
describe("load", function()
|
||||
it("validates arguments", function()
|
||||
load("")
|
||||
load(function()
|
||||
end)
|
||||
load("", "")
|
||||
load("", "", "")
|
||||
load("", "", "", _ENV)
|
||||
|
||||
expect.error(load, nil):eq("bad argument #1 (function or string expected, got nil)")
|
||||
expect.error(load, "", false):eq("bad argument #2 (string expected, got boolean)")
|
||||
expect.error(load, "", "", false):eq("bad argument #3 (string expected, got boolean)")
|
||||
expect.error(load, "", "", "", false):eq("bad argument #4 (table expected, got boolean)")
|
||||
end)
|
||||
|
||||
local function generator(parts)
|
||||
return coroutine.wrap(function()
|
||||
for i = 1, #parts do
|
||||
|
||||
@@ -8,32 +8,6 @@ An exhaustive list of all error states in the parser, and the error messages we
|
||||
generate for each one. This is _not_ a complete collection of all possible
|
||||
errors, but is a useful guide for where we might be providing terrible messages.
|
||||
|
||||
```lua
|
||||
break while
|
||||
-- Line 1: unexpected symbol near <eof> (program)
|
||||
```
|
||||
|
||||
```txt
|
||||
Unexpected while. Expected a statement.
|
||||
|
|
||||
1 | break while
|
||||
| ^^^^^
|
||||
```
|
||||
|
||||
|
||||
```lua
|
||||
do end true
|
||||
-- Line 1: unexpected symbol near 'true' (program)
|
||||
```
|
||||
|
||||
```txt
|
||||
Unexpected true. Expected a statement.
|
||||
|
|
||||
1 | do end true
|
||||
| ^^^^
|
||||
```
|
||||
|
||||
|
||||
```lua
|
||||
do until
|
||||
-- Line 1: 'end' expected near 'until' (program)
|
||||
@@ -63,6 +37,35 @@ Unexpected true.
|
||||
```
|
||||
|
||||
|
||||
```lua
|
||||
:: xyz while
|
||||
-- Line 1: '::' expected near 'while' (program)
|
||||
```
|
||||
|
||||
```txt
|
||||
Unexpected while.
|
||||
|
|
||||
1 | :: xyz while
|
||||
| ^^ Label was started here.
|
||||
|
|
||||
1 | :: xyz while
|
||||
| ^^^^^ Tip: Try adding :: here.
|
||||
```
|
||||
|
||||
|
||||
```lua
|
||||
:: while
|
||||
-- Line 1: <name> expected near 'while' (program)
|
||||
```
|
||||
|
||||
```txt
|
||||
Unexpected while.
|
||||
|
|
||||
1 | :: while
|
||||
| ^^^^^
|
||||
```
|
||||
|
||||
|
||||
```lua
|
||||
for xyz , xyz while
|
||||
-- Line 1: 'in' expected near 'while' (program)
|
||||
@@ -849,6 +852,20 @@ Unexpected while.
|
||||
```
|
||||
|
||||
|
||||
```lua
|
||||
xyz while
|
||||
-- Line 1: syntax error near 'while' (program)
|
||||
```
|
||||
|
||||
```txt
|
||||
Unexpected symbol after name.
|
||||
|
|
||||
1 | xyz while
|
||||
| ^
|
||||
Did you mean to assign this or call it as a function?
|
||||
```
|
||||
|
||||
|
||||
```lua
|
||||
if xyz then else until
|
||||
-- Line 1: 'end' expected near 'until' (program)
|
||||
@@ -1059,22 +1076,6 @@ Unexpected while. Expected an expression.
|
||||
```
|
||||
|
||||
|
||||
```lua {repl_exprs}
|
||||
{ xyz , while
|
||||
-- Line 1: unexpected symbol near 'while' (repl_exprs)
|
||||
```
|
||||
|
||||
```txt
|
||||
Unexpected while. Are you missing a closing bracket?
|
||||
|
|
||||
1 | { xyz , while
|
||||
| ^ Brackets were opened here.
|
||||
|
|
||||
1 | { xyz , while
|
||||
| ^^^^^ Unexpected while here.
|
||||
```
|
||||
|
||||
|
||||
```lua {repl_exprs}
|
||||
{ xyz = xyz while
|
||||
-- Line 1: '}' expected near 'while' (repl_exprs)
|
||||
@@ -1104,6 +1105,22 @@ Unexpected while. Expected an expression.
|
||||
```
|
||||
|
||||
|
||||
```lua {repl_exprs}
|
||||
{ xyz ; while
|
||||
-- Line 1: unexpected symbol near 'while' (repl_exprs)
|
||||
```
|
||||
|
||||
```txt
|
||||
Unexpected while. Are you missing a closing bracket?
|
||||
|
|
||||
1 | { xyz ; while
|
||||
| ^ Brackets were opened here.
|
||||
|
|
||||
1 | { xyz ; while
|
||||
| ^^^^^ Unexpected while here.
|
||||
```
|
||||
|
||||
|
||||
```lua {repl_exprs}
|
||||
{ xyz while
|
||||
-- Line 1: '}' expected near 'while' (repl_exprs)
|
||||
|
||||
@@ -417,6 +417,49 @@ Unexpected end.
|
||||
Your program contains more ends than needed. Check each block (if, for, function, ...) only has one end.
|
||||
```
|
||||
|
||||
## `goto` and labels
|
||||
We `goto` the same as normal identifiers.
|
||||
|
||||
```lua
|
||||
goto 2
|
||||
```
|
||||
|
||||
```txt
|
||||
Unexpected symbol after name.
|
||||
|
|
||||
1 | goto 2
|
||||
| ^
|
||||
Did you mean to assign this or call it as a function?
|
||||
```
|
||||
|
||||
Labels have a basic closing check:
|
||||
```lua
|
||||
::foo
|
||||
```
|
||||
|
||||
```txt
|
||||
Unexpected end of file.
|
||||
|
|
||||
1 | ::foo
|
||||
| ^^ Label was started here.
|
||||
|
|
||||
1 | ::foo
|
||||
| ^ Tip: Try adding :: here.
|
||||
```
|
||||
|
||||
But we do nothing fancy for just a `::`
|
||||
|
||||
```lua
|
||||
::
|
||||
```
|
||||
|
||||
```txt
|
||||
Unexpected end of file.
|
||||
|
|
||||
1 | ::
|
||||
| ^
|
||||
```
|
||||
|
||||
# Function calls
|
||||
|
||||
## Additional commas
|
||||
|
||||
Reference in New Issue
Block a user