diff --git a/projects/core-api/src/main/java/dan200/computercraft/api/lua/IArguments.java b/projects/core-api/src/main/java/dan200/computercraft/api/lua/IArguments.java
index e70527785..f554b05e5 100644
--- a/projects/core-api/src/main/java/dan200/computercraft/api/lua/IArguments.java
+++ b/projects/core-api/src/main/java/dan200/computercraft/api/lua/IArguments.java
@@ -223,6 +223,9 @@ public interface IArguments {
/**
* Get an argument as a table.
+ *
+ * The returned table may be converted into a {@link LuaTable} (using {@link ObjectLuaTable}) for easier parsing of
+ * table keys.
*
* @param index The argument number.
* @return The argument's value.
diff --git a/projects/core-api/src/main/java/dan200/computercraft/api/lua/LuaTable.java b/projects/core-api/src/main/java/dan200/computercraft/api/lua/LuaTable.java
index 006f6f51d..fa42b1395 100644
--- a/projects/core-api/src/main/java/dan200/computercraft/api/lua/LuaTable.java
+++ b/projects/core-api/src/main/java/dan200/computercraft/api/lua/LuaTable.java
@@ -7,15 +7,18 @@ package dan200.computercraft.api.lua;
import org.jspecify.annotations.Nullable;
import java.util.Map;
+import java.util.Optional;
import static dan200.computercraft.api.lua.LuaValues.*;
/**
- * A view of a Lua table, which may be able to access table elements in a more optimised manner than
- * {@link IArguments#getTable(int)}.
+ * A view of a Lua table.
+ *
+ * Much like {@link IArguments}, this allows for convenient parsing of fields from a Lua table.
*
* @param The type of keys in a table, will typically be a wildcard.
* @param The type of values in a table, will typically be a wildcard.
+ * @see ObjectArguments
*/
public interface LuaTable extends Map {
/**
@@ -29,19 +32,47 @@ public interface LuaTable extends Map {
return size;
}
+ /**
+ * Get an array entry as a double.
+ *
+ * @param index The index in the table, starting at 1.
+ * @return The entry's value.
+ * @throws LuaException If the value is not a number.
+ * @see #getFiniteDouble(int) if you require this to be finite (i.e. not infinite or NaN).
+ * @since 1.116
+ */
+ default double getDouble(int index) throws LuaException {
+ Object value = get((double) index);
+ if (!(value instanceof Number number)) throw badTableItem(index, "number", getType(value));
+ return number.doubleValue();
+ }
+
+ /**
+ * Get a table entry as a double.
+ *
+ * @param key The name of the field in the table.
+ * @return The field's value.
+ * @throws LuaException If the value is not a number.
+ * @see #getFiniteDouble(String) if you require this to be finite (i.e. not infinite or NaN).
+ * @since 1.116
+ */
+ default double getDouble(String key) throws LuaException {
+ Object value = get(key);
+ if (!(value instanceof Number number)) throw badField(key, "number", getType(value));
+ return number.doubleValue();
+ }
+
/**
* Get an array entry as an integer.
*
* @param index The index in the table, starting at 1.
- * @return The table's value.
+ * @return The entry's value.
* @throws LuaException If the value is not an integer.
*/
default long getLong(int index) throws LuaException {
Object value = get((double) index);
if (!(value instanceof Number number)) throw badTableItem(index, "number", getType(value));
-
- var asDouble = number.doubleValue();
- if (!Double.isFinite(asDouble)) throw badTableItem(index, "number", getNumericType(asDouble));
+ checkFiniteIndex(index, number.doubleValue());
return number.longValue();
}
@@ -49,15 +80,13 @@ public interface LuaTable extends Map {
* Get a table entry as an integer.
*
* @param key The name of the field in the table.
- * @return The table's value.
+ * @return The field's value.
* @throws LuaException If the value is not an integer.
*/
default long getLong(String key) throws LuaException {
Object value = get(key);
if (!(value instanceof Number number)) throw badField(key, "number", getType(value));
-
- var asDouble = number.doubleValue();
- if (!Double.isFinite(asDouble)) throw badField(key, "number", getNumericType(asDouble));
+ checkFiniteField(key, number.doubleValue());
return number.longValue();
}
@@ -65,7 +94,7 @@ public interface LuaTable extends Map {
* Get an array entry as an integer.
*
* @param index The index in the table, starting at 1.
- * @return The table's value.
+ * @return The entry's value.
* @throws LuaException If the value is not an integer.
*/
default int getInt(int index) throws LuaException {
@@ -76,13 +105,339 @@ public interface LuaTable extends Map {
* Get a table entry as an integer.
*
* @param key The name of the field in the table.
- * @return The table's value.
+ * @return The field's value.
* @throws LuaException If the value is not an integer.
*/
default int getInt(String key) throws LuaException {
return (int) getLong(key);
}
+ /**
+ * Get an argument as a finite number (not infinite or NaN).
+ *
+ * @param index The index in the table, starting at 1.
+ * @return The entry's value.
+ * @throws LuaException If the value is not finite.
+ * @since 1.116
+ */
+ default double getFiniteDouble(int index) throws LuaException {
+ return checkFiniteIndex(index, getDouble(index));
+ }
+
+ /**
+ * Get an argument as a finite number (not infinite or NaN).
+ *
+ * @param key The name of the field in the table.
+ * @return The field's value.
+ * @throws LuaException If the value is not finite.
+ * @since 1.116
+ */
+ default double getFiniteDouble(String key) throws LuaException {
+ return checkFiniteField(key, getDouble(key));
+ }
+
+ /**
+ * Get an array entry as a boolean.
+ *
+ * @param index The index in the table, starting at 1.
+ * @return The entry's value.
+ * @throws LuaException If the value is not a boolean.
+ * @since 1.116
+ */
+ default boolean getBoolean(int index) throws LuaException {
+ Object value = get((double) index);
+ if (!(value instanceof Boolean bool)) throw badTableItem(index, "boolean", getType(value));
+ return bool;
+ }
+
+ /**
+ * Get a table entry as a boolean.
+ *
+ * @param key The name of the field in the table.
+ * @return The field's value.
+ * @throws LuaException If the value is not a boolean.
+ * @since 1.116
+ */
+ default boolean getBoolean(String key) throws LuaException {
+ Object value = get(key);
+ if (!(value instanceof Boolean bool)) throw badField(key, "boolean", getType(value));
+ return bool;
+ }
+
+ /**
+ * Get an array entry as a string.
+ *
+ * @param index The index in the table, starting at 1.
+ * @return The entry's value.
+ * @throws LuaException If the value is not a string.
+ * @since 1.116
+ */
+ default String getString(int index) throws LuaException {
+ Object value = get((double) index);
+ if (!(value instanceof String string)) throw badTableItem(index, "string", getType(value));
+ return string;
+ }
+
+ /**
+ * Get a table entry as a string.
+ *
+ * @param key The name of the field in the table.
+ * @return The field's value.
+ * @throws LuaException If the value is not a string.
+ * @since 1.116
+ */
+ default String getString(String key) throws LuaException {
+ Object value = get(key);
+ if (!(value instanceof String string)) throw badField(key, "string", getType(value));
+ return string;
+ }
+
+ /**
+ * Get an array entry as a table.
+ *
+ * The returned table may be converted into a {@link LuaTable} (using {@link ObjectLuaTable}) for easier parsing of
+ * table keys.
+ *
+ * @param index The index in the table, starting at 1.
+ * @return The entry's value.
+ * @throws LuaException If the value is not a table.
+ * @since 1.116
+ */
+ default Map, ?> getTable(int index) throws LuaException {
+ Object value = get((double) index);
+ if (!(value instanceof Map, ?> table)) throw badTableItem(index, "table", getType(value));
+ return table;
+ }
+
+ /**
+ * Get a table entry as a table.
+ *
+ * The returned table may be converted into a {@link LuaTable} (using {@link ObjectLuaTable}) for easier parsing of
+ * table keys.
+ *
+ * @param key The name of the field in the table.
+ * @return The field's value.
+ * @throws LuaException If the value is not a table.
+ * @since 1.116
+ */
+ default Map, ?> getTable(String key) throws LuaException {
+ Object value = get(key);
+ if (!(value instanceof Map, ?> table)) throw badField(key, "table", getType(value));
+ return table;
+ }
+
+ /**
+ * Get an array entry as a double.
+ *
+ * @param index The index in the table, starting at 1.
+ * @return The entry's value, or {@link Optional#empty()} if not present.
+ * @throws LuaException If the value is not a number.
+ * @see #getFiniteDouble(int) if you require this to be finite (i.e. not infinite or NaN).
+ * @since 1.116
+ */
+ default Optional optDouble(int index) throws LuaException {
+ Object value = get((double) index);
+ if (value == null) return Optional.empty();
+ if (!(value instanceof Number number)) throw badTableItem(index, "number", getType(value));
+ return Optional.of(number.doubleValue());
+ }
+
+ /**
+ * Get a table entry as a double.
+ *
+ * @param key The name of the field in the table.
+ * @return The field's value, or {@link Optional#empty()} if not present.
+ * @throws LuaException If the value is not a number.
+ * @see #getFiniteDouble(String) if you require this to be finite (i.e. not infinite or NaN).
+ * @since 1.116
+ */
+ default Optional optDouble(String key) throws LuaException {
+ Object value = get(key);
+ if (value == null) return Optional.empty();
+ if (!(value instanceof Number number)) throw badField(key, "number", getType(value));
+ return Optional.of(number.doubleValue());
+ }
+
+ /**
+ * Get an array entry as an integer.
+ *
+ * @param index The index in the table, starting at 1.
+ * @return The entry's value, or {@link Optional#empty()} if not present.
+ * @throws LuaException If the value is not an integer.
+ * @since 1.116
+ */
+ default Optional optLong(int index) throws LuaException {
+ Object value = get((double) index);
+ if (value == null) return Optional.empty();
+ if (!(value instanceof Number number)) throw badTableItem(index, "number", getType(value));
+ checkFiniteIndex(index, number.doubleValue());
+ return Optional.of(number.longValue());
+ }
+
+ /**
+ * Get a table entry as an integer.
+ *
+ * @param key The name of the field in the table.
+ * @return The field's value, or {@link Optional#empty()} if not present.
+ * @throws LuaException If the value is not an integer.
+ * @since 1.116
+ */
+ default Optional optLong(String key) throws LuaException {
+ Object value = get(key);
+ if (value == null) return Optional.empty();
+ if (!(value instanceof Number number)) throw badField(key, "number", getType(value));
+ checkFiniteField(key, number.doubleValue());
+ return Optional.of(number.longValue());
+ }
+
+ /**
+ * Get an array entry as an integer.
+ *
+ * @param index The index in the table, starting at 1.
+ * @return The entry's value, or {@link Optional#empty()} if not present.
+ * @throws LuaException If the value is not an integer.
+ * @since 1.116
+ */
+ default Optional optInt(int index) throws LuaException {
+ return optLong(index).map(Long::intValue);
+ }
+
+ /**
+ * Get a table entry as an integer.
+ *
+ * @param key The name of the field in the table.
+ * @return The field's value, or {@link Optional#empty()} if not present.
+ * @throws LuaException If the value is not an integer.
+ * @since 1.116
+ */
+ default Optional optInt(String key) throws LuaException {
+ return optLong(key).map(Long::intValue);
+ }
+
+ /**
+ * Get an argument as a finite number (not infinite or NaN).
+ *
+ * @param index The index in the table, starting at 1.
+ * @return The entry's value, or {@link Optional#empty()} if not present.
+ * @throws LuaException If the value is not finite.
+ * @since 1.116
+ */
+ default Optional optFiniteDouble(int index) throws LuaException {
+ var value = optDouble(index);
+ if (value.isPresent()) checkFiniteIndex(index, value.get());
+ return value;
+ }
+
+ /**
+ * Get an argument as a finite number (not infinite or NaN).
+ *
+ * @param key The name of the field in the table.
+ * @return The field's value, or {@link Optional#empty()} if not present.
+ * @throws LuaException If the value is not finite.
+ * @since 1.116
+ */
+ default Optional optFiniteDouble(String key) throws LuaException {
+ var value = optDouble(key);
+ if (value.isPresent()) checkFiniteField(key, value.get());
+ return value;
+ }
+
+ /**
+ * Get an array entry as a boolean.
+ *
+ * @param index The index in the table, starting at 1.
+ * @return The entry's value, or {@link Optional#empty()} if not present.
+ * @throws LuaException If the value is not a boolean.
+ * @since 1.116
+ */
+ default Optional optBoolean(int index) throws LuaException {
+ Object value = get((double) index);
+ if (value == null) return Optional.empty();
+ if (!(value instanceof Boolean bool)) throw badTableItem(index, "boolean", getType(value));
+ return Optional.of(bool);
+ }
+
+ /**
+ * Get a table entry as a boolean.
+ *
+ * @param key The name of the field in the table.
+ * @return The field's value, or {@link Optional#empty()} if not present.
+ * @throws LuaException If the value is not a boolean.
+ * @since 1.116
+ */
+ default Optional optBoolean(String key) throws LuaException {
+ Object value = get(key);
+ if (value == null) return Optional.empty();
+ if (!(value instanceof Boolean bool)) throw badField(key, "boolean", getType(value));
+ return Optional.of(bool);
+ }
+
+ /**
+ * Get an array entry as a double.
+ *
+ * @param index The index in the table, starting at 1.
+ * @return The entry's value, or {@link Optional#empty()} if not present.
+ * @throws LuaException If the value is not a string.
+ * @since 1.116
+ */
+ default Optional optString(int index) throws LuaException {
+ Object value = get((double) index);
+ if (value == null) return Optional.empty();
+ if (!(value instanceof String string)) throw badTableItem(index, "string", getType(value));
+ return Optional.of(string);
+ }
+
+ /**
+ * Get a table entry as a string.
+ *
+ * @param key The name of the field in the table.
+ * @return The field's value, or {@link Optional#empty()} if not present.
+ * @throws LuaException If the value is not a string.
+ * @since 1.116
+ */
+ default Optional optString(String key) throws LuaException {
+ Object value = get(key);
+ if (value == null) return Optional.empty();
+ if (!(value instanceof String string)) throw badField(key, "string", getType(value));
+ return Optional.of(string);
+ }
+
+ /**
+ * Get an array entry as a table.
+ *
+ * The returned table may be converted into a {@link LuaTable} (using {@link ObjectLuaTable}) for easier parsing of
+ * table keys.
+ *
+ * @param index The index in the table, starting at 1.
+ * @return The entry's value, or {@link Optional#empty()} if not present.
+ * @throws LuaException If the value is not a table.
+ * @since 1.116
+ */
+ default Optional