1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-01-10 01:10:30 +00:00

Merge branch 'mc-1.20.x' into mc-1.20.y

This commit is contained in:
Jonathan Coates 2024-02-18 18:45:20 +00:00
commit 83f1f86888
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
15 changed files with 395 additions and 168 deletions

View File

@ -10,7 +10,7 @@ kotlin.jvm.target.validation.mode=error
# Mod properties # Mod properties
isUnstable=true isUnstable=true
modVersion=1.109.5 modVersion=1.109.6
# Minecraft properties: We want to configure this here so we can read it in settings.gradle # Minecraft properties: We want to configure this here so we can read it in settings.gradle
mcVersion=1.20.4 mcVersion=1.20.4

View File

@ -26,7 +26,7 @@ slf4j = "2.0.7"
asm = "9.6" asm = "9.6"
autoService = "1.1.1" autoService = "1.1.1"
checkerFramework = "3.42.0" checkerFramework = "3.42.0"
cobalt = "0.9.0" cobalt = "0.9.1"
commonsCli = "1.6.0" commonsCli = "1.6.0"
jetbrainsAnnotations = "24.1.0" jetbrainsAnnotations = "24.1.0"
jsr305 = "3.0.2" jsr305 = "3.0.2"

View File

@ -105,6 +105,10 @@
/projects/core/src/main/resources/data/computercraft/lua/rom/apis/turtle/turtle.lua) /projects/core/src/main/resources/data/computercraft/lua/rom/apis/turtle/turtle.lua)
(linters -var:deprecated)) (linters -var:deprecated))
;; Suppress unused variable warnings in the parser.
(at /projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/internal/syntax/parser.lua
(linters -var:unused))
(at /projects/core/src/test/resources/test-rom (at /projects/core/src/test/resources/test-rom
; We should still be able to test deprecated members. ; We should still be able to test deprecated members.
(linters -var:deprecated) (linters -var:deprecated)

View File

@ -4,6 +4,8 @@
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import javax.annotation.Nullable;
/** /**
* Represents a Lua object which is stored as a global variable on computer startup. This must either provide * Represents a Lua object which is stored as a global variable on computer startup. This must either provide
* {@link LuaFunction} annotated functions or implement {@link IDynamicLuaObject}. * {@link LuaFunction} annotated functions or implement {@link IDynamicLuaObject}.
@ -15,12 +17,31 @@ package dan200.computercraft.api.lua;
*/ */
public interface ILuaAPI { public interface ILuaAPI {
/** /**
* Get the globals this API will be assigned to. This will override any other global, so you should * Get the globals this API will be assigned to.
* <p>
* This will override any other global, so you should be careful to pick a unique name. Alternatively, you may
* return the empty array here, and instead override {@link #getModuleName()}.
* *
* @return A list of globals this API will be assigned to. * @return A list of globals this API will be assigned to.
*/ */
String[] getNames(); String[] getNames();
/**
* Get the module name this API should be available as.
* <p>
* Rather than (or as well as) making this API available as a global, APIs can be exposed as {@code require}able
* modules. This is generally more idiomatic, as it avoids polluting the global environment.
* <p>
* Modules defined here take precedence over user-defined modules, and so like with {@link #getNames()}, you should
* be careful to pick a unique name. It is recommended that module names should be camel case, and live under a
* namespace associated with your mod. For instance, {@code "mod_id.a_custom_api"}.
*
* @return The module name of this API, or {@code null} if this API should not be loadable as a module.
*/
default @Nullable String getModuleName() {
return null;
}
/** /**
* Called when the computer is turned on. * Called when the computer is turned on.
* <p> * <p>

View File

@ -263,9 +263,9 @@ public final class MemoryMount extends AbstractInMemoryMount<MemoryMount.FileEnt
checkClosed(); checkClosed();
var backing = Nullability.assertNonNull(entry.contents); var backing = Nullability.assertNonNull(entry.contents);
if (position >= backing.length) return -1; if (position >= entry.length) return -1;
var remaining = Math.min(backing.length - (int) position, destination.remaining()); var remaining = Math.min(entry.length - (int) position, destination.remaining());
destination.put(backing, (int) position, remaining); destination.put(backing, (int) position, remaining);
position += remaining; position += remaining;
return remaining; return remaining;
@ -273,7 +273,7 @@ public final class MemoryMount extends AbstractInMemoryMount<MemoryMount.FileEnt
private byte[] ensureCapacity(int capacity) { private byte[] ensureCapacity(int capacity) {
var contents = Nullability.assertNonNull(entry.contents); var contents = Nullability.assertNonNull(entry.contents);
if (capacity >= entry.length) { if (capacity >= contents.length) {
var newCapacity = Math.max(capacity, contents.length << 1); var newCapacity = Math.max(capacity, contents.length << 1);
contents = entry.contents = Arrays.copyOf(contents, newCapacity); contents = entry.contents = Arrays.copyOf(contents, newCapacity);
} }

View File

@ -25,7 +25,6 @@ import org.squiddev.cobalt.lib.Bit32Lib;
import org.squiddev.cobalt.lib.CoreLibraries; import org.squiddev.cobalt.lib.CoreLibraries;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Serial; import java.io.Serial;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -49,7 +48,7 @@ public class CobaltLuaMachine implements ILuaMachine {
private @Nullable String eventFilter = null; private @Nullable String eventFilter = null;
public CobaltLuaMachine(MachineEnvironment environment, InputStream bios) throws MachineException, IOException { public CobaltLuaMachine(MachineEnvironment environment, InputStream bios) throws MachineException {
timeout = environment.timeout(); timeout = environment.timeout();
context = environment.context(); context = environment.context();
luaMethods = environment.luaMethods(); luaMethods = environment.luaMethods();
@ -81,7 +80,7 @@ public class CobaltLuaMachine implements ILuaMachine {
globals.rawset("_CC_DEFAULT_SETTINGS", ValueFactory.valueOf(CoreConfig.defaultComputerSettings)); globals.rawset("_CC_DEFAULT_SETTINGS", ValueFactory.valueOf(CoreConfig.defaultComputerSettings));
// Add default APIs // Add default APIs
for (var api : environment.apis()) addAPI(globals, api); for (var api : environment.apis()) addAPI(state, globals, api);
// And load the BIOS // And load the BIOS
var value = LoadState.load(state, bios, "@bios.lua", globals); var value = LoadState.load(state, bios, "@bios.lua", globals);
@ -93,7 +92,7 @@ public class CobaltLuaMachine implements ILuaMachine {
timeout.addListener(timeoutListener); timeout.addListener(timeoutListener);
} }
private void addAPI(LuaTable globals, ILuaAPI api) { private void addAPI(LuaState state, LuaTable globals, ILuaAPI api) throws LuaError {
// Add the methods of an API to the global table // Add the methods of an API to the global table
var table = wrapLuaObject(api); var table = wrapLuaObject(api);
if (table == null) { if (table == null) {
@ -103,6 +102,9 @@ public class CobaltLuaMachine implements ILuaMachine {
var names = api.getNames(); var names = api.getNames();
for (var name : names) globals.rawset(name, table); for (var name : names) globals.rawset(name, table);
var moduleName = api.getModuleName();
if (moduleName != null) state.registry().getSubTable(Constants.LOADED).rawset(moduleName, table);
} }
private void updateTimeout() { private void updateTimeout() {

View File

@ -1,3 +1,11 @@
# New features in CC: Tweaked 1.109.6
* Improve several Lua parser error messages.
* Allow addon mods to register `require`able modules.
Several bug fixes:
* Fix weak tables becoming malformed when keys are GCed.
# New features in CC: Tweaked 1.109.5 # New features in CC: Tweaked 1.109.5
* Add a new `/computercraft-computer-folder` command to open a computer's folder * Add a new `/computercraft-computer-folder` command to open a computer's folder

View File

@ -1,9 +1,9 @@
New features in CC: Tweaked 1.109.5 New features in CC: Tweaked 1.109.6
* Add a new `/computercraft-computer-folder` command to open a computer's folder * Improve several Lua parser error messages.
in singleplayer. * Allow addon mods to register `require`able modules.
Several bug fixes: Several bug fixes:
* Discard characters being typed into the editor when closing `edit`'s `Run` screen. * Fix weak tables becoming malformed when keys are GCed.
Type "help changelog" to see the full version history. Type "help changelog" to see the full version history.

View File

@ -453,32 +453,53 @@ function errors.local_function_dot(local_start, local_end, dot_start, dot_end)
} }
end end
--[[- A statement of the form `x.y z` --[[- A statement of the form `x.y`
@tparam number token The token id.
@tparam number pos The position right after this name. @tparam number pos The position right after this name.
@return The resulting parse error. @return The resulting parse error.
]] ]]
function errors.standalone_name(pos) function errors.standalone_name(token, pos)
expect(1, pos, "number") expect(1, token, "number")
expect(2, pos, "number")
return { return {
"Unexpected symbol after name.", "Unexpected " .. token_names[token] .. " after name.",
annotate(pos), annotate(pos),
"Did you mean to assign this or call it as a function?", "Did you mean to assign this or call it as a function?",
} }
end end
--[[- A statement of the form `x.y, z`
@tparam number token The token id.
@tparam number pos The position right after this name.
@return The resulting parse error.
]]
function errors.standalone_names(token, pos)
expect(1, token, "number")
expect(2, pos, "number")
return {
"Unexpected " .. token_names[token] .. " after name.",
annotate(pos),
"Did you mean to assign this?",
}
end
--[[- A statement of the form `x.y`. This is similar to [`standalone_name`], but --[[- A statement of the form `x.y`. This is similar to [`standalone_name`], but
when the next token is on another line. when the next token is on another line.
@tparam number token The token id.
@tparam number pos The position right after this name. @tparam number pos The position right after this name.
@return The resulting parse error. @return The resulting parse error.
]] ]]
function errors.standalone_name_call(pos) function errors.standalone_name_call(token, pos)
expect(1, pos, "number") expect(1, token, "number")
expect(2, pos, "number")
return { return {
"Unexpected symbol after variable.", "Unexpected " .. token_names[token] .. " after name.",
annotate(pos + 1, "Expected something before the end of the line."), annotate(pos + 1, "Expected something before the end of the line."),
"Tip: Use " .. code("()") .. " to call with no arguments.", "Tip: Use " .. code("()") .. " to call with no arguments.",
} }

View File

@ -124,13 +124,22 @@ local function make_package(env, dir)
local package = {} local package = {}
package.loaded = { package.loaded = {
_G = _G, _G = _G,
bit32 = bit32,
coroutine = coroutine,
math = math,
package = package, package = package,
string = string,
table = table,
} }
-- Copy everything from the global package table to this instance.
--
-- This table is an internal implementation detail - it is NOT intended to
-- be extended by user code.
local registry = debug.getregistry()
if registry and type(registry._LOADED) == "table" then
for k, v in next, registry._LOADED do
if type(k) == "string" then
package.loaded[k] = v
end
end
end
package.path = "?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua" package.path = "?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua"
if turtle then if turtle then
package.path = package.path .. ";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua" package.path = package.path .. ";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua"

View File

@ -89,6 +89,16 @@ public class MethodTest {
x -> x.addApi(new ReturnFunction()), 50); x -> x.addApi(new ReturnFunction()), 50);
} }
@Test
public void testModule() {
ComputerBootstrap.run(
"""
assert(require "test.module".func() == 123)
""",
x -> x.addApi(new IsModule()), 50);
}
public static class MainThread implements ILuaAPI, IPeripheral { public static class MainThread implements ILuaAPI, IPeripheral {
public final String thread = Thread.currentThread().getName(); public final String thread = Thread.currentThread().getName();
@ -206,7 +216,7 @@ public class MethodTest {
} }
@Override @Override
public MethodResult callMethod(ILuaContext context, int method, IArguments arguments) throws LuaException { public MethodResult callMethod(ILuaContext context, int method, IArguments arguments) {
return MethodResult.of(); return MethodResult.of();
} }
@ -227,4 +237,21 @@ public class MethodTest {
return new String[]{ "func" }; return new String[]{ "func" };
} }
} }
public static class IsModule implements ILuaAPI {
@Override
public String[] getNames() {
return new String[0];
}
@Override
public @Nullable String getModuleName() {
return "test.module";
}
@LuaFunction
public final int func() {
return 123;
}
}
} }

View File

@ -15,6 +15,7 @@ import dan200.computercraft.core.computer.mainthread.MainThreadConfig;
import dan200.computercraft.core.filesystem.MemoryMount; import dan200.computercraft.core.filesystem.MemoryMount;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.test.core.computer.BasicEnvironment; import dan200.computercraft.test.core.computer.BasicEnvironment;
import org.intellij.lang.annotations.Language;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -31,7 +32,7 @@ public class ComputerBootstrap {
private static final int TPS = 20; private static final int TPS = 20;
public static final int MAX_TIME = 10; public static final int MAX_TIME = 10;
public static void run(String program, Consumer<Computer> setup, int maxTimes) { public static void run(@Language("lua") String program, Consumer<Computer> setup, int maxTimes) {
var mount = new MemoryMount() var mount = new MemoryMount()
.addFile("test.lua", program) .addFile("test.lua", program)
.addFile("startup.lua", "assertion.assert(pcall(loadfile('test.lua', nil, _ENV))) os.shutdown()"); .addFile("startup.lua", "assertion.assert(pcall(loadfile('test.lua', nil, _ENV))) os.shutdown()");
@ -39,7 +40,7 @@ public class ComputerBootstrap {
run(mount, setup, maxTimes); run(mount, setup, maxTimes);
} }
public static void run(String program, int maxTimes) { public static void run(@Language("lua") String program, int maxTimes) {
run(program, x -> { run(program, x -> {
}, maxTimes); }, maxTimes);
} }

View File

@ -347,7 +347,7 @@ function ( xyz , while
``` ```
```txt ```txt
Unexpected while. Unexpected while. Expected a variable name.
| |
1 | function ( xyz , while 1 | function ( xyz , while
| ^^^^^ | ^^^^^
@ -483,11 +483,11 @@ xyz , xyz while
``` ```
```txt ```txt
Unexpected symbol after name. Unexpected while after name.
| |
1 | xyz , xyz while 1 | xyz , xyz while
| ^ | ^
Did you mean to assign this or call it as a function? Did you mean to assign this?
``` ```
@ -831,7 +831,7 @@ xyz while
``` ```
```txt ```txt
Unexpected symbol after name. Unexpected while after name.
| |
1 | xyz while 1 | xyz while
| ^ | ^
@ -858,7 +858,7 @@ xyz while
``` ```
```txt ```txt
Unexpected symbol after name. Unexpected while after name.
| |
1 | xyz while 1 | xyz while
| ^ | ^
@ -1056,7 +1056,7 @@ local while
``` ```
```txt ```txt
Unexpected while. Unexpected while. Expected a variable name.
| |
1 | local while 1 | local while
| ^^^^^ | ^^^^^
@ -1272,7 +1272,7 @@ repeat --[[eof]]
``` ```
```txt ```txt
Unexpected end of file. Expected a statement. Unexpected end of file. Expected a variable name.
| |
2 | -- Line 1: 'until' expected near <eof> (program) 2 | -- Line 1: 'until' expected near <eof> (program)
| ^ | ^
@ -1389,7 +1389,7 @@ while
``` ```
```txt ```txt
Unexpected while. Unexpected while. Expected an expression.
| |
1 | while 1 | while
| ^^^^^ | ^^^^^

View File

@ -38,6 +38,20 @@ Unexpected = in expression.
Tip: Wrap the preceding expression in [ and ] to use it as a table key. Tip: Wrap the preceding expression in [ and ] to use it as a table key.
``` ```
and also
```lua
return { x + 1 = 1 }
```
```txt
Unexpected = in expression.
|
1 | return { x + 1 = 1 }
| ^
Tip: Wrap the preceding expression in [ and ] to use it as a table key.
```
Note this doesn't occur if this there's already a table key here: Note this doesn't occur if this there's already a table key here:
```lua ```lua
@ -102,6 +116,7 @@ Unexpected end of file. Are you missing a closing bracket?
``` ```
## Missing commas in tables ## Missing commas in tables
We try to detect missing commas in tables, and print an appropriate error message.
```lua ```lua
return { 1 2 } return { 1 2 }
@ -129,6 +144,39 @@ Unexpected number in table.
1 | return { 1, 2 3 } 1 | return { 1, 2 3 }
| ^ Are you missing a comma here? | ^ Are you missing a comma here?
``` ```
This also works with table keys.
```lua
print({ x = 1 y = 2 })
```
```txt
Unexpected identifier in table.
|
1 | print({ x = 1 y = 2 })
| ^
|
1 | print({ x = 1 y = 2 })
| ^ Are you missing a comma here?
```
```lua
print({ ["x"] = 1 ["y"] = 2 })
```
```txt
Unexpected [ in table.
|
1 | print({ ["x"] = 1 ["y"] = 2 })
| ^
|
1 | print({ ["x"] = 1 ["y"] = 2 })
| ^ Are you missing a comma here?
```
We gracefully handle the case where we are actually missing a closing brace.
```lua ```lua
print({ 1, ) print({ 1, )
``` ```
@ -172,7 +220,7 @@ local _ = 1
``` ```
```txt ```txt
Unexpected symbol after variable. Unexpected local after name.
| |
1 | term.clear 1 | term.clear
| ^ Expected something before the end of the line. | ^ Expected something before the end of the line.
@ -186,7 +234,7 @@ x 1
``` ```
```txt ```txt
Unexpected symbol after name. Unexpected number after name.
| |
1 | x 1 1 | x 1
| ^ | ^
@ -200,13 +248,41 @@ term.clear
``` ```
```txt ```txt
Unexpected symbol after variable. Unexpected end of file after name.
| |
1 | term.clear 1 | term.clear
| ^ Expected something before the end of the line. | ^ Expected something before the end of the line.
Tip: Use () to call with no arguments. Tip: Use () to call with no arguments.
``` ```
When we've got a list of variables, we only suggest assigning it.
```lua
term.clear, foo
```
```txt
Unexpected end of file after name.
|
1 | term.clear, foo
| ^
Did you mean to assign this?
```
And when we've got a partial expression, we only suggest calling it.
```lua
(a + b)
```
```txt
Unexpected end of file after name.
|
1 | (a + b)
| ^ Expected something before the end of the line.
Tip: Use () to call with no arguments.
```
## If statements ## If statements
For if statements, we say when we expected the `then` keyword. For if statements, we say when we expected the `then` keyword.
@ -425,7 +501,7 @@ goto 2
``` ```
```txt ```txt
Unexpected symbol after name. Unexpected number after name.
| |
1 | goto 2 1 | goto 2
| ^ | ^
@ -460,6 +536,31 @@ Unexpected end of file.
| ^ | ^
``` ```
## Missing function arguments
We provide an error message for missing arguments in function definitions:
```lua
function f
```
```txt
Unexpected end of file. Expected ( to start function arguments.
|
1 | function f
| ^
```
```lua
return function
```
```txt
Unexpected end of file. Expected ( to start function arguments.
|
1 | return function
| ^
```
# Function calls # Function calls
## Additional commas ## Additional commas