Docs for stdlib
This commit is contained in:
@@ -6,5 +6,13 @@ export const cryptoApi = new LuaTable({
|
||||
(_sf, s: string | Uint8Array): Promise<string> => {
|
||||
return hashSHA256(s);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Computes the SHA-256 digest of a string or byte buffer.",
|
||||
parameters: [
|
||||
{ name: "data", type: "string|bytes", description: "Data to hash." },
|
||||
],
|
||||
returns: [{ type: "string", description: "Hexadecimal SHA-256 digest." }],
|
||||
},
|
||||
),
|
||||
});
|
||||
|
||||
@@ -6,14 +6,44 @@ export const encodingApi = new LuaTable({
|
||||
(_sf, s: string | Uint8Array): string => {
|
||||
return base64Encode(s);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Encodes a string or byte buffer as Base64.",
|
||||
parameters: [{ name: "data", type: "string|bytes" }],
|
||||
returns: [{ type: "string", description: "Base64-encoded data." }],
|
||||
},
|
||||
),
|
||||
base64Decode: new LuaBuiltinFunction(
|
||||
(_sf, s: string): Uint8Array => {
|
||||
return base64Decode(s);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Decodes a Base64 string into a byte buffer.",
|
||||
parameters: [{ name: "encoded", type: "string" }],
|
||||
returns: [{ type: "bytes", description: "Decoded bytes." }],
|
||||
},
|
||||
),
|
||||
utf8Encode: new LuaBuiltinFunction(
|
||||
(_sf, s: string): Uint8Array => {
|
||||
return new TextEncoder().encode(s);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Encodes a UTF-8 string into a byte buffer.",
|
||||
parameters: [{ name: "value", type: "string" }],
|
||||
returns: [{ type: "bytes", description: "UTF-8 encoded bytes." }],
|
||||
},
|
||||
),
|
||||
utf8Decode: new LuaBuiltinFunction(
|
||||
(_sf, data: Uint8Array): string => {
|
||||
return new TextDecoder().decode(data);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Decodes a UTF-8 byte buffer into a string.",
|
||||
parameters: [{ name: "data", type: "bytes" }],
|
||||
returns: [{ type: "string", description: "Decoded text." }],
|
||||
},
|
||||
),
|
||||
base64Decode: new LuaBuiltinFunction((_sf, s: string): Uint8Array => {
|
||||
return base64Decode(s);
|
||||
}),
|
||||
utf8Encode: new LuaBuiltinFunction((_sf, s: string): Uint8Array => {
|
||||
return new TextEncoder().encode(s);
|
||||
}),
|
||||
utf8Decode: new LuaBuiltinFunction((_sf, data: Uint8Array): string => {
|
||||
return new TextDecoder().decode(data);
|
||||
}),
|
||||
});
|
||||
|
||||
+150
-36
@@ -13,22 +13,60 @@ export const jsApi = new LuaTable({
|
||||
* @param args - The arguments to pass to the constructor.
|
||||
* @returns The new instance.
|
||||
*/
|
||||
new: new LuaBuiltinFunction((sf, constructorFn: any, ...args) => {
|
||||
return new constructorFn(...args.map((v) => luaValueToJS(v, sf)));
|
||||
}),
|
||||
new: new LuaBuiltinFunction(
|
||||
(sf, constructorFn: any, ...args) => {
|
||||
return new constructorFn(...args.map((v) => luaValueToJS(v, sf)));
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Creates an instance of a JavaScript class.",
|
||||
signatures: ["js.new(constructor, ...): userdata"],
|
||||
parameters: [
|
||||
{
|
||||
name: "constructor",
|
||||
type: "userdata",
|
||||
description: "JavaScript constructor function.",
|
||||
},
|
||||
{
|
||||
name: "...",
|
||||
description: "Constructor arguments converted to JavaScript values.",
|
||||
},
|
||||
],
|
||||
returns: [{ type: "userdata", description: "New JavaScript instance." }],
|
||||
examples: [
|
||||
{ code: 'local value = js.new(js.window.Date, "2024-03-14")' },
|
||||
],
|
||||
},
|
||||
),
|
||||
/**
|
||||
* Imports a JavaScript module.
|
||||
* @param url - The URL of the module to import.
|
||||
* @returns The imported module.
|
||||
*/
|
||||
import: new LuaBuiltinFunction(async (_sf, url) => {
|
||||
let m = await import(url);
|
||||
// Unwrap default if it exists
|
||||
if (Object.keys(m).length === 1 && m.default) {
|
||||
m = m.default;
|
||||
}
|
||||
return m;
|
||||
}),
|
||||
import: new LuaBuiltinFunction(
|
||||
async (_sf, url) => {
|
||||
let m = await import(url);
|
||||
// Unwrap default if it exists
|
||||
if (Object.keys(m).length === 1 && m.default) {
|
||||
m = m.default;
|
||||
}
|
||||
return m;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Dynamically imports a JavaScript module from a URL.",
|
||||
parameters: [{ name: "url", type: "string", description: "Module URL." }],
|
||||
returns: [
|
||||
{
|
||||
type: "userdata",
|
||||
description: "Imported module, with a sole default export unwrapped.",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{ code: 'local lib = js.import("https://esm.sh/lodash@4.17.21")' },
|
||||
],
|
||||
},
|
||||
),
|
||||
/**
|
||||
* Like `js.import`, but takes a path to a file in the current space (e.g.
|
||||
* "Library/foo/bar.js") and resolves it to its full same-origin `/.fs` URL
|
||||
@@ -36,51 +74,127 @@ export const jsApi = new LuaTable({
|
||||
* @param path - Space-relative path to the JS module (leading "/" optional).
|
||||
* @returns The imported module (with a sole `default` export unwrapped).
|
||||
*/
|
||||
importFromSpace: new LuaBuiltinFunction(async (_sf, path: string) => {
|
||||
const base = document.baseURI.replace(/\/*$/, "/");
|
||||
const rel = String(path).replace(/^\/+/, "");
|
||||
let m = await import(base + fsEndpoint.slice(1) + "/" + rel);
|
||||
// Unwrap default if it exists (same contract as `js.import`).
|
||||
if (Object.keys(m).length === 1 && m.default) {
|
||||
m = m.default;
|
||||
}
|
||||
return m;
|
||||
}),
|
||||
eachIterable: new LuaBuiltinFunction((_sf, val) => {
|
||||
const iterator = val[Symbol.asyncIterator]();
|
||||
return async () => {
|
||||
const result = await iterator.next();
|
||||
if (result.done) {
|
||||
return;
|
||||
importFromSpace: new LuaBuiltinFunction(
|
||||
async (_sf, path: string) => {
|
||||
const base = document.baseURI.replace(/\/*$/, "/");
|
||||
const rel = String(path).replace(/^\/+/, "");
|
||||
let m = await import(base + fsEndpoint.slice(1) + "/" + rel);
|
||||
// Unwrap default if it exists (same contract as `js.import`).
|
||||
if (Object.keys(m).length === 1 && m.default) {
|
||||
m = m.default;
|
||||
}
|
||||
return result.value;
|
||||
};
|
||||
}),
|
||||
return m;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Imports a JavaScript module from a file in the current space.",
|
||||
parameters: [
|
||||
{
|
||||
name: "path",
|
||||
type: "string",
|
||||
description:
|
||||
"Space-relative module path, with an optional leading slash.",
|
||||
},
|
||||
],
|
||||
returns: [
|
||||
{
|
||||
type: "userdata",
|
||||
description: "Imported module, with a sole default export unwrapped.",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{ code: 'local acme = js.importFromSpace("Library/acme/acme.js")' },
|
||||
],
|
||||
},
|
||||
),
|
||||
eachIterable: new LuaBuiltinFunction(
|
||||
(_sf, val) => {
|
||||
const iterator = val[Symbol.asyncIterator]();
|
||||
return async () => {
|
||||
const result = await iterator.next();
|
||||
if (result.done) {
|
||||
return;
|
||||
}
|
||||
return result.value;
|
||||
};
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Creates a Lua iterator over a JavaScript async iterable.",
|
||||
parameters: [
|
||||
{
|
||||
name: "iterable",
|
||||
type: "userdata",
|
||||
description: "JavaScript async iterable.",
|
||||
},
|
||||
],
|
||||
returns: [
|
||||
{
|
||||
type: "function",
|
||||
description: "Iterator yielding successive JavaScript values.",
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
code: "for value in js.eachIterable(someJsAsyncIterable) do\n print(value)\nend",
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
/**
|
||||
* Converts a JavaScript value to a Lua value.
|
||||
* @param val - The JavaScript value to convert.
|
||||
* @returns The Lua value.
|
||||
*/
|
||||
tolua: new LuaBuiltinFunction((_sf, val) => jsToLuaValue(val)),
|
||||
tolua: new LuaBuiltinFunction((_sf, val) => jsToLuaValue(val), {
|
||||
kind: "builtin",
|
||||
description: "Converts a JavaScript value to its Lua representation.",
|
||||
parameters: [
|
||||
{ name: "value", description: "JavaScript value to convert." },
|
||||
],
|
||||
returns: [{ description: "Converted Lua value." }],
|
||||
examples: [{ code: "local luaTable = js.tolua(jsArray)" }],
|
||||
}),
|
||||
/**
|
||||
* Converts a Lua value to a JavaScript value.
|
||||
* @param val - The Lua value to convert.
|
||||
* @returns The JavaScript value.
|
||||
*/
|
||||
tojs: new LuaBuiltinFunction((sf, val) => luaValueToJS(val, sf)),
|
||||
tojs: new LuaBuiltinFunction((sf, val) => luaValueToJS(val, sf), {
|
||||
kind: "builtin",
|
||||
description: "Converts a Lua value to its JavaScript representation.",
|
||||
parameters: [{ name: "value", description: "Lua value to convert." }],
|
||||
returns: [{ description: "Converted JavaScript value." }],
|
||||
examples: [{ code: "local jsArray = js.tojs({1, 2, 3})" }],
|
||||
}),
|
||||
/**
|
||||
* Logs a message to the console.
|
||||
* @param args - The arguments to log.
|
||||
*/
|
||||
log: new LuaBuiltinFunction((_sf, ...args) => {
|
||||
console.log(...args);
|
||||
}),
|
||||
log: new LuaBuiltinFunction(
|
||||
(_sf, ...args) => {
|
||||
console.log(...args);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Logs values to the JavaScript console.",
|
||||
parameters: [{ name: "...", description: "Values to log." }],
|
||||
examples: [{ code: 'js.log("User data:", {name = "Ada"})' }],
|
||||
},
|
||||
),
|
||||
/**
|
||||
* Converts a Lua value to a JSON string.
|
||||
* @param val - The Lua value to convert.
|
||||
* @returns The JSON string.
|
||||
*/
|
||||
stringify: new LuaBuiltinFunction((_sf, val) => JSON.stringify(val)),
|
||||
stringify: new LuaBuiltinFunction((_sf, val) => JSON.stringify(val), {
|
||||
kind: "builtin",
|
||||
description: "Serializes a value as JSON using JavaScript semantics.",
|
||||
parameters: [{ name: "value", description: "Value to serialize." }],
|
||||
returns: [{ type: "string", description: "JSON representation." }],
|
||||
examples: [{ code: "print(js.stringify({1, 2, 3})) -- [1,2,3]" }],
|
||||
}),
|
||||
|
||||
// Expose the global window object
|
||||
window: globalThis,
|
||||
|
||||
@@ -24,23 +24,35 @@ export function luaLoad(code: LuaValue, sf: LuaStackFrame): LuaValue {
|
||||
|
||||
const globalEnv: LuaEnv = globalEnvMaybe as LuaEnv;
|
||||
|
||||
const runner = new LuaBuiltinFunction(async (innerSf: LuaStackFrame) => {
|
||||
const res = await evalStatement(block, globalEnv, innerSf, true);
|
||||
if (res === undefined) {
|
||||
return null;
|
||||
} else {
|
||||
if (res && typeof res === "object" && (res as any).ctrl === "return") {
|
||||
return new LuaMultiRes((res as any).values);
|
||||
const runner = new LuaBuiltinFunction(
|
||||
async (innerSf: LuaStackFrame) => {
|
||||
const res = await evalStatement(block, globalEnv, innerSf, true);
|
||||
if (res === undefined) {
|
||||
return null;
|
||||
} else {
|
||||
if (
|
||||
res &&
|
||||
typeof res === "object" &&
|
||||
(res as any).ctrl === "return"
|
||||
) {
|
||||
return new LuaMultiRes((res as any).values);
|
||||
}
|
||||
if (res && typeof res === "object" && (res as any).ctrl === "break") {
|
||||
throw new Error("break outside loop");
|
||||
}
|
||||
if (res && typeof res === "object" && (res as any).ctrl === "goto") {
|
||||
throw new Error("unexpected goto signal");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (res && typeof res === "object" && (res as any).ctrl === "break") {
|
||||
throw new Error("break outside loop");
|
||||
}
|
||||
if (res && typeof res === "object" && (res as any).ctrl === "goto") {
|
||||
throw new Error("unexpected goto signal");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Executes the Lua chunk compiled by `load`.",
|
||||
signatures: ["function(...)"],
|
||||
returns: [{ description: "Values returned by the compiled chunk." }],
|
||||
},
|
||||
);
|
||||
|
||||
return runner;
|
||||
} catch (e: any) {
|
||||
|
||||
+369
-107
@@ -23,49 +23,71 @@ export const mathApi = new LuaTable({
|
||||
pi: Math.PI,
|
||||
|
||||
// math.type(x) => "integer" | "float" | nil
|
||||
type: new LuaBuiltinFunction((_sf, x?: any) => {
|
||||
if (x === undefined) {
|
||||
throw new LuaRuntimeError(
|
||||
"bad argument #1 to 'math.type' (value expected)",
|
||||
_sf,
|
||||
);
|
||||
}
|
||||
if (isTaggedFloat(x)) {
|
||||
return "float";
|
||||
}
|
||||
if (typeof x === "number") {
|
||||
if (!Number.isFinite(x) || isNegativeZero(x)) {
|
||||
type: new LuaBuiltinFunction(
|
||||
(_sf, x?: any) => {
|
||||
if (x === undefined) {
|
||||
throw new LuaRuntimeError(
|
||||
"bad argument #1 to 'math.type' (value expected)",
|
||||
_sf,
|
||||
);
|
||||
}
|
||||
if (isTaggedFloat(x)) {
|
||||
return "float";
|
||||
}
|
||||
return Number.isInteger(x) ? "integer" : "float";
|
||||
}
|
||||
if (typeof x === "bigint") {
|
||||
return "integer";
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
if (typeof x === "number") {
|
||||
if (!Number.isFinite(x) || isNegativeZero(x)) {
|
||||
return "float";
|
||||
}
|
||||
return Number.isInteger(x) ? "integer" : "float";
|
||||
}
|
||||
if (typeof x === "bigint") {
|
||||
return "integer";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns `integer` or `float` for a number, or `nil` for other values.",
|
||||
parameters: [{ name: "x", description: "Value to inspect." }],
|
||||
returns: [
|
||||
{ type: "string|nil", description: "Numeric subtype or `nil`." },
|
||||
],
|
||||
},
|
||||
),
|
||||
|
||||
/**
|
||||
* If the value x is representable as a Lua integer, returns an integer
|
||||
* with that value. Otherwise returns nil.
|
||||
* Strings are NOT accepted — only Lua number values.
|
||||
*/
|
||||
tointeger: new LuaBuiltinFunction((_sf, x?: any) => {
|
||||
if (typeof x === "number") {
|
||||
return Number.isInteger(x) && Number.isFinite(x) ? x : null;
|
||||
}
|
||||
if (isTaggedFloat(x)) {
|
||||
const n = x.value;
|
||||
return Number.isInteger(n) && Number.isFinite(n) ? n : null;
|
||||
}
|
||||
if (typeof x === "string") {
|
||||
const n = untagNumber(x); // Number(x) coerces the string
|
||||
if (Number.isNaN(n) || !Number.isFinite(n) || !Number.isInteger(n))
|
||||
return null;
|
||||
return n;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
tointeger: new LuaBuiltinFunction(
|
||||
(_sf, x?: any) => {
|
||||
if (typeof x === "number") {
|
||||
return Number.isInteger(x) && Number.isFinite(x) ? x : null;
|
||||
}
|
||||
if (isTaggedFloat(x)) {
|
||||
const n = x.value;
|
||||
return Number.isInteger(n) && Number.isFinite(n) ? n : null;
|
||||
}
|
||||
if (typeof x === "string") {
|
||||
const n = untagNumber(x); // Number(x) coerces the string
|
||||
if (Number.isNaN(n) || !Number.isFinite(n) || !Number.isInteger(n))
|
||||
return null;
|
||||
return n;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Converts a value to an integer when it has an exact finite integral representation.",
|
||||
parameters: [{ name: "x", description: "Value to convert." }],
|
||||
returns: [
|
||||
{ type: "integer|nil", description: "Converted integer or `nil`." },
|
||||
],
|
||||
},
|
||||
),
|
||||
|
||||
/**
|
||||
* When called without arguments, returns a pseudo-random float with
|
||||
@@ -76,118 +98,345 @@ export const mathApi = new LuaTable({
|
||||
* math.random(1,n). The call math.random(0) produces an integer
|
||||
* with all bits (pseudo)random.
|
||||
*/
|
||||
random: new LuaBuiltinFunction((_sf, m?: number, n?: number) => {
|
||||
if (m !== undefined) m = untagNumber(m);
|
||||
if (n !== undefined) n = untagNumber(n);
|
||||
try {
|
||||
return prng.random(m, n);
|
||||
} catch (e: any) {
|
||||
throw new LuaRuntimeError(e.message, _sf);
|
||||
}
|
||||
}),
|
||||
random: new LuaBuiltinFunction(
|
||||
(_sf, m?: number, n?: number) => {
|
||||
if (m !== undefined) m = untagNumber(m);
|
||||
if (n !== undefined) n = untagNumber(n);
|
||||
try {
|
||||
return prng.random(m, n);
|
||||
} catch (e: any) {
|
||||
throw new LuaRuntimeError(e.message, _sf);
|
||||
}
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns a pseudo-random float or an integer in a requested inclusive range.",
|
||||
signatures: [
|
||||
"math.random(): number",
|
||||
"math.random(n): integer",
|
||||
"math.random(m, n): integer",
|
||||
],
|
||||
parameters: [
|
||||
{ name: "m", type: "integer", optional: true },
|
||||
{ name: "n", type: "integer", optional: true },
|
||||
],
|
||||
returns: [{ type: "number", description: "Pseudo-random result." }],
|
||||
examples: [
|
||||
{
|
||||
code: "print(math.random())\nprint(math.random(10))\nprint(math.random(5, 10))",
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
/**
|
||||
* Seeds the pseudo-random generator. With no arguments, uses a
|
||||
* time-based seed. Returns the two seed integers used (Lua 5.4 contract).
|
||||
*/
|
||||
randomseed: new LuaBuiltinFunction((_sf, x?: number, y?: number) => {
|
||||
if (x !== undefined) x = untagNumber(x);
|
||||
if (y !== undefined) y = untagNumber(y);
|
||||
const [s1, s2] = prng.randomseed(x, y);
|
||||
return new LuaMultiRes([s1, s2]);
|
||||
}),
|
||||
randomseed: new LuaBuiltinFunction(
|
||||
(_sf, x?: number, y?: number) => {
|
||||
if (x !== undefined) x = untagNumber(x);
|
||||
if (y !== undefined) y = untagNumber(y);
|
||||
const [s1, s2] = prng.randomseed(x, y);
|
||||
return new LuaMultiRes([s1, s2]);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Seeds the pseudo-random generator and returns the two seeds used.",
|
||||
signatures: [
|
||||
"math.randomseed(): integer, integer",
|
||||
"math.randomseed(x, y): integer, integer",
|
||||
],
|
||||
parameters: [
|
||||
{ name: "x", type: "integer", optional: true },
|
||||
{ name: "y", type: "integer", optional: true },
|
||||
],
|
||||
returns: [
|
||||
{ type: "integer", description: "First seed." },
|
||||
{ type: "integer", description: "Second seed." },
|
||||
],
|
||||
},
|
||||
),
|
||||
|
||||
// Basic functions
|
||||
abs: new LuaBuiltinFunction((_sf, x: number) => Math.abs(untagNumber(x))),
|
||||
ceil: new LuaBuiltinFunction((_sf, x: number) => Math.ceil(untagNumber(x))),
|
||||
floor: new LuaBuiltinFunction((_sf, x: number) => Math.floor(untagNumber(x))),
|
||||
max: new LuaBuiltinFunction((_sf, ...args: number[]) =>
|
||||
Math.max(...args.map(untagNumber)),
|
||||
abs: new LuaBuiltinFunction((_sf, x: number) => Math.abs(untagNumber(x)), {
|
||||
kind: "builtin",
|
||||
description: "Returns the absolute value of `x`.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "number" }],
|
||||
}),
|
||||
ceil: new LuaBuiltinFunction((_sf, x: number) => Math.ceil(untagNumber(x)), {
|
||||
kind: "builtin",
|
||||
description: "Returns the smallest integer greater than or equal to `x`.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "integer" }],
|
||||
}),
|
||||
floor: new LuaBuiltinFunction(
|
||||
(_sf, x: number) => Math.floor(untagNumber(x)),
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Returns the largest integer less than or equal to `x`.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "integer" }],
|
||||
},
|
||||
),
|
||||
min: new LuaBuiltinFunction((_sf, ...args: number[]) =>
|
||||
Math.min(...args.map(untagNumber)),
|
||||
max: new LuaBuiltinFunction(
|
||||
(_sf, ...args: number[]) => Math.max(...args.map(untagNumber)),
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Returns the greatest of its arguments.",
|
||||
signatures: ["math.max(x, ...): number"],
|
||||
returns: [{ type: "number" }],
|
||||
},
|
||||
),
|
||||
min: new LuaBuiltinFunction(
|
||||
(_sf, ...args: number[]) => Math.min(...args.map(untagNumber)),
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Returns the least of its arguments.",
|
||||
signatures: ["math.min(x, ...): number"],
|
||||
returns: [{ type: "number" }],
|
||||
},
|
||||
),
|
||||
|
||||
// Rounding and remainder
|
||||
fmod: new LuaBuiltinFunction(
|
||||
(_sf, x: number, y: number) => untagNumber(x) % untagNumber(y),
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns the remainder of `x / y` with the quotient rounded toward zero.",
|
||||
parameters: [
|
||||
{ name: "x", type: "number" },
|
||||
{ name: "y", type: "number" },
|
||||
],
|
||||
returns: [{ type: "number" }],
|
||||
},
|
||||
),
|
||||
modf: new LuaBuiltinFunction(
|
||||
(_sf, x: number) => {
|
||||
const xn = untagNumber(x);
|
||||
const int = Math.trunc(xn);
|
||||
// Guarantee that the `frac` part is always Lua float
|
||||
const frac = makeLuaFloat(xn - int);
|
||||
return new LuaMultiRes([int, frac]);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Splits `x` into its integral and fractional parts.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [
|
||||
{ type: "integer", description: "Integral part." },
|
||||
{ type: "float", description: "Fractional part." },
|
||||
],
|
||||
examples: [{ code: "local integer, fraction = math.modf(3.14)" }],
|
||||
},
|
||||
),
|
||||
modf: new LuaBuiltinFunction((_sf, x: number) => {
|
||||
const xn = untagNumber(x);
|
||||
const int = Math.trunc(xn);
|
||||
// Guarantee that the `frac` part is always Lua float
|
||||
const frac = makeLuaFloat(xn - int);
|
||||
return new LuaMultiRes([int, frac]);
|
||||
}),
|
||||
|
||||
// Returns m and e such that x = m * 2^e, 0.5 <= |m| < 1 (or m=0 when x=0).
|
||||
// e is an integer. Mirrors C99/Lua.
|
||||
// Special cases: frexp(0) = (0, 0); frexp(+-inf/nan) = (x, 0).
|
||||
frexp: new LuaBuiltinFunction((_sf, x: number) => {
|
||||
const xn = untagNumber(x);
|
||||
if (xn === 0 || !Number.isFinite(xn) || Number.isNaN(xn)) {
|
||||
return new LuaMultiRes([xn, 0]);
|
||||
}
|
||||
const abs = Math.abs(xn);
|
||||
let e = Math.floor(Math.log2(abs)) + 1;
|
||||
let m = xn / 2 ** e;
|
||||
if (Math.abs(m) >= 1.0) {
|
||||
e += 1;
|
||||
m /= 2;
|
||||
}
|
||||
if (Math.abs(m) < 0.5) {
|
||||
e -= 1;
|
||||
m *= 2;
|
||||
}
|
||||
return new LuaMultiRes([m, e]);
|
||||
}),
|
||||
frexp: new LuaBuiltinFunction(
|
||||
(_sf, x: number) => {
|
||||
const xn = untagNumber(x);
|
||||
if (xn === 0 || !Number.isFinite(xn) || Number.isNaN(xn)) {
|
||||
return new LuaMultiRes([xn, 0]);
|
||||
}
|
||||
const abs = Math.abs(xn);
|
||||
let e = Math.floor(Math.log2(abs)) + 1;
|
||||
let m = xn / 2 ** e;
|
||||
if (Math.abs(m) >= 1.0) {
|
||||
e += 1;
|
||||
m /= 2;
|
||||
}
|
||||
if (Math.abs(m) < 0.5) {
|
||||
e -= 1;
|
||||
m *= 2;
|
||||
}
|
||||
return new LuaMultiRes([m, e]);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Decomposes `x` into a normalized fraction and a power-of-two exponent.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [
|
||||
{ type: "number", description: "Fraction." },
|
||||
{ type: "integer", description: "Exponent." },
|
||||
],
|
||||
},
|
||||
),
|
||||
|
||||
// Returns m * 2^e (the inverse of frexp). Mirrors C99/Lua.
|
||||
ldexp: new LuaBuiltinFunction(
|
||||
(_sf, m: number, e: number) => untagNumber(m) * 2 ** untagNumber(e),
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Returns `m * 2^e`, the inverse of `math.frexp`.",
|
||||
parameters: [
|
||||
{ name: "m", type: "number" },
|
||||
{ name: "e", type: "integer" },
|
||||
],
|
||||
returns: [{ type: "number" }],
|
||||
},
|
||||
),
|
||||
|
||||
// Power and logarithms
|
||||
exp: new LuaBuiltinFunction((_sf, x: number) => Math.exp(untagNumber(x))),
|
||||
log: new LuaBuiltinFunction((_sf, x: number, base?: number) => {
|
||||
if (base === undefined) {
|
||||
return Math.log(untagNumber(x));
|
||||
}
|
||||
return Math.log(untagNumber(x)) / Math.log(untagNumber(base));
|
||||
exp: new LuaBuiltinFunction((_sf, x: number) => Math.exp(untagNumber(x)), {
|
||||
kind: "builtin",
|
||||
description: "Returns `e` raised to `x`.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "number" }],
|
||||
}),
|
||||
log: new LuaBuiltinFunction(
|
||||
(_sf, x: number, base?: number) => {
|
||||
if (base === undefined) {
|
||||
return Math.log(untagNumber(x));
|
||||
}
|
||||
return Math.log(untagNumber(x)) / Math.log(untagNumber(base));
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns the logarithm of `x`, using the natural base unless another base is supplied.",
|
||||
parameters: [
|
||||
{ name: "x", type: "number" },
|
||||
{ name: "base", type: "number", optional: true },
|
||||
],
|
||||
returns: [{ type: "number" }],
|
||||
examples: [{ code: "print(math.log(100, 10)) -- 2" }],
|
||||
},
|
||||
),
|
||||
// Power function (deprecated in Lua 5.4 but retained for compatibility)
|
||||
pow: new LuaBuiltinFunction(
|
||||
(_sf, x: number, y: number) => untagNumber(x) ** untagNumber(y),
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Returns `x` raised to the power `y`.",
|
||||
parameters: [
|
||||
{ name: "x", type: "number" },
|
||||
{ name: "y", type: "number" },
|
||||
],
|
||||
returns: [{ type: "number" }],
|
||||
deprecated: "Use the `^` operator instead.",
|
||||
},
|
||||
),
|
||||
sqrt: new LuaBuiltinFunction((_sf, x: number) => Math.sqrt(untagNumber(x))),
|
||||
|
||||
// Trigonometric functions
|
||||
cos: new LuaBuiltinFunction((_sf, x: number) => Math.cos(untagNumber(x))),
|
||||
sin: new LuaBuiltinFunction((_sf, x: number) => Math.sin(untagNumber(x))),
|
||||
tan: new LuaBuiltinFunction((_sf, x: number) => Math.tan(untagNumber(x))),
|
||||
acos: new LuaBuiltinFunction((_sf, x: number) => Math.acos(untagNumber(x))),
|
||||
asin: new LuaBuiltinFunction((_sf, x: number) => Math.asin(untagNumber(x))),
|
||||
atan: new LuaBuiltinFunction((_sf, y: number, x?: number) => {
|
||||
if (x === undefined) {
|
||||
return Math.atan(untagNumber(y));
|
||||
}
|
||||
return Math.atan2(untagNumber(y), untagNumber(x));
|
||||
sqrt: new LuaBuiltinFunction((_sf, x: number) => Math.sqrt(untagNumber(x)), {
|
||||
kind: "builtin",
|
||||
description: "Returns the square root of `x`.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "number" }],
|
||||
}),
|
||||
|
||||
// Trigonometric functions
|
||||
cos: new LuaBuiltinFunction((_sf, x: number) => Math.cos(untagNumber(x)), {
|
||||
kind: "builtin",
|
||||
description: "Returns the cosine of `x` radians.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "number" }],
|
||||
}),
|
||||
sin: new LuaBuiltinFunction((_sf, x: number) => Math.sin(untagNumber(x)), {
|
||||
kind: "builtin",
|
||||
description: "Returns the sine of `x` radians.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "number" }],
|
||||
}),
|
||||
tan: new LuaBuiltinFunction((_sf, x: number) => Math.tan(untagNumber(x)), {
|
||||
kind: "builtin",
|
||||
description: "Returns the tangent of `x` radians.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "number" }],
|
||||
}),
|
||||
acos: new LuaBuiltinFunction((_sf, x: number) => Math.acos(untagNumber(x)), {
|
||||
kind: "builtin",
|
||||
description: "Returns the arc cosine of `x` in radians.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "number" }],
|
||||
}),
|
||||
asin: new LuaBuiltinFunction((_sf, x: number) => Math.asin(untagNumber(x)), {
|
||||
kind: "builtin",
|
||||
description: "Returns the arc sine of `x` in radians.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "number" }],
|
||||
}),
|
||||
atan: new LuaBuiltinFunction(
|
||||
(_sf, y: number, x?: number) => {
|
||||
if (x === undefined) {
|
||||
return Math.atan(untagNumber(y));
|
||||
}
|
||||
return Math.atan2(untagNumber(y), untagNumber(x));
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns the arc tangent of `y/x` in radians, using `1` for omitted `x`.",
|
||||
parameters: [
|
||||
{ name: "y", type: "number" },
|
||||
{ name: "x", type: "number", optional: true },
|
||||
],
|
||||
returns: [{ type: "number" }],
|
||||
},
|
||||
),
|
||||
|
||||
// Hyperbolic functions (deprecated in Lua 5.4 but retained for compatibility)
|
||||
cosh: new LuaBuiltinFunction((_sf, x: number) => Math.cosh(untagNumber(x))),
|
||||
sinh: new LuaBuiltinFunction((_sf, x: number) => Math.sinh(untagNumber(x))),
|
||||
tanh: new LuaBuiltinFunction((_sf, x: number) => Math.tanh(untagNumber(x))),
|
||||
cosh: new LuaBuiltinFunction((_sf, x: number) => Math.cosh(untagNumber(x)), {
|
||||
kind: "builtin",
|
||||
description: "Returns the hyperbolic cosine of `x`.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "number" }],
|
||||
deprecated: "Retained for compatibility with older Lua versions.",
|
||||
}),
|
||||
sinh: new LuaBuiltinFunction((_sf, x: number) => Math.sinh(untagNumber(x)), {
|
||||
kind: "builtin",
|
||||
description: "Returns the hyperbolic sine of `x`.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "number" }],
|
||||
deprecated: "Retained for compatibility with older Lua versions.",
|
||||
}),
|
||||
tanh: new LuaBuiltinFunction((_sf, x: number) => Math.tanh(untagNumber(x)), {
|
||||
kind: "builtin",
|
||||
description: "Returns the hyperbolic tangent of `x`.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "number" }],
|
||||
deprecated: "Retained for compatibility with older Lua versions.",
|
||||
}),
|
||||
|
||||
// Additional utility
|
||||
deg: new LuaBuiltinFunction(
|
||||
(_sf, x: number) => (untagNumber(x) * 180) / Math.PI,
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Converts an angle from radians to degrees.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "number" }],
|
||||
examples: [{ code: "print(math.deg(math.pi)) -- 180" }],
|
||||
},
|
||||
),
|
||||
rad: new LuaBuiltinFunction(
|
||||
(_sf, x: number) => (untagNumber(x) * Math.PI) / 180,
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Converts an angle from degrees to radians.",
|
||||
parameters: [{ name: "x", type: "number" }],
|
||||
returns: [{ type: "number" }],
|
||||
},
|
||||
),
|
||||
ult: new LuaBuiltinFunction(
|
||||
(_sf, m: number, n: number) => {
|
||||
return untagNumber(m) >>> 0 < untagNumber(n) >>> 0;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Compares two integers as unsigned 32-bit values.",
|
||||
parameters: [
|
||||
{ name: "m", type: "integer" },
|
||||
{ name: "n", type: "integer" },
|
||||
],
|
||||
returns: [{ type: "boolean" }],
|
||||
examples: [{ code: "print(math.ult(2, 3)) -- true" }],
|
||||
},
|
||||
),
|
||||
ult: new LuaBuiltinFunction((_sf, m: number, n: number) => {
|
||||
return untagNumber(m) >>> 0 < untagNumber(n) >>> 0;
|
||||
}),
|
||||
|
||||
// Keep the cosineSimilarity utility function
|
||||
cosineSimilarity: new LuaBuiltinFunction(
|
||||
@@ -215,5 +464,18 @@ export const mathApi = new LuaTable({
|
||||
|
||||
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns the cosine similarity between two equal-length numeric vectors.",
|
||||
parameters: [
|
||||
{ name: "vecA", type: "table" },
|
||||
{ name: "vecB", type: "table" },
|
||||
],
|
||||
returns: [{ type: "number", description: "Cosine similarity." }],
|
||||
examples: [
|
||||
{ code: "print(math.cosineSimilarity({1, 2, 3}, {4, 5, 6}))" },
|
||||
],
|
||||
},
|
||||
),
|
||||
});
|
||||
|
||||
@@ -70,6 +70,29 @@ export const netApi = new LuaTable({
|
||||
body: body,
|
||||
};
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Performs an HTTP request through the SilverBullet server to avoid browser CORS restrictions.",
|
||||
signatures: ["net.proxyFetch(url, options?)"],
|
||||
parameters: [
|
||||
{ name: "url", type: "string", description: "URL to request." },
|
||||
{
|
||||
name: "options",
|
||||
type: "table",
|
||||
description:
|
||||
"Optional method, headers, body, and responseEncoding values.",
|
||||
optional: true,
|
||||
},
|
||||
],
|
||||
returns: [
|
||||
{
|
||||
type: "table",
|
||||
description: "Response status, headers, decoded body, and ok flag.",
|
||||
},
|
||||
],
|
||||
see: "API/net",
|
||||
},
|
||||
),
|
||||
readURI: new LuaNativeJSFunction(
|
||||
(uri: string, options: { uri?: string; encoding?: string } = {}) => {
|
||||
@@ -79,6 +102,22 @@ export const netApi = new LuaTable({
|
||||
options,
|
||||
);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Reads content from a URI using the best matching service.",
|
||||
signatures: ["net.readURI(uri, options?)"],
|
||||
parameters: [
|
||||
{ name: "uri", type: "string", description: "URI to read." },
|
||||
{
|
||||
name: "options",
|
||||
type: "table",
|
||||
description: "Optional service-specific values such as encoding.",
|
||||
optional: true,
|
||||
},
|
||||
],
|
||||
returns: [{ description: "Content returned by the matching service." }],
|
||||
see: "API/net",
|
||||
},
|
||||
),
|
||||
writeURI: new LuaNativeJSFunction(
|
||||
(uri: string, content: string | Uint8Array) => {
|
||||
@@ -87,6 +126,21 @@ export const netApi = new LuaTable({
|
||||
{ uri, content },
|
||||
);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Writes content to a URI using the best matching service.",
|
||||
signatures: ["net.writeURI(uri, content)"],
|
||||
parameters: [
|
||||
{ name: "uri", type: "string", description: "URI to write." },
|
||||
{
|
||||
name: "content",
|
||||
type: "string|userdata",
|
||||
description: "Text or binary content to write.",
|
||||
},
|
||||
],
|
||||
returns: [{ description: "Result returned by the matching service." }],
|
||||
see: "API/net",
|
||||
},
|
||||
),
|
||||
});
|
||||
|
||||
|
||||
+126
-47
@@ -282,39 +282,78 @@ function luaFormatTime(fmt: string, d: Date, utc: boolean): string {
|
||||
}
|
||||
|
||||
export const osApi = new LuaTable({
|
||||
time: new LuaBuiltinFunction((_sf, tbl?: LuaTable) => {
|
||||
if (tbl) {
|
||||
if (!tbl.has("year")) {
|
||||
throw new Error("time(): year is required");
|
||||
time: new LuaBuiltinFunction(
|
||||
(_sf, tbl?: LuaTable) => {
|
||||
if (tbl) {
|
||||
if (!tbl.has("year")) {
|
||||
throw new Error("time(): year is required");
|
||||
}
|
||||
|
||||
if (!tbl.has("month")) {
|
||||
throw new Error("time(): month is required");
|
||||
}
|
||||
|
||||
if (!tbl.has("day")) {
|
||||
throw new Error("time(): day is required");
|
||||
}
|
||||
|
||||
const year = tbl.get("year");
|
||||
const month = tbl.get("month");
|
||||
const day = tbl.get("day");
|
||||
const hour = tbl.get("hour") ?? 12;
|
||||
const min = tbl.get("min") ?? 0;
|
||||
const sec = tbl.get("sec") ?? 0;
|
||||
const date = new Date(year, month - 1, day, hour, min, sec);
|
||||
|
||||
return Math.floor(date.getTime() / 1000);
|
||||
}
|
||||
|
||||
if (!tbl.has("month")) {
|
||||
throw new Error("time(): month is required");
|
||||
}
|
||||
|
||||
if (!tbl.has("day")) {
|
||||
throw new Error("time(): day is required");
|
||||
}
|
||||
|
||||
const year = tbl.get("year");
|
||||
const month = tbl.get("month");
|
||||
const day = tbl.get("day");
|
||||
const hour = tbl.get("hour") ?? 12;
|
||||
const min = tbl.get("min") ?? 0;
|
||||
const sec = tbl.get("sec") ?? 0;
|
||||
const date = new Date(year, month - 1, day, hour, min, sec);
|
||||
|
||||
return Math.floor(date.getTime() / 1000);
|
||||
}
|
||||
|
||||
return Math.floor(Date.now() / 1000);
|
||||
}),
|
||||
return Math.floor(Date.now() / 1000);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns the current Unix timestamp or one built from a local date table.",
|
||||
signatures: ["os.time(): integer", "os.time(dateTable): integer"],
|
||||
parameters: [
|
||||
{
|
||||
name: "dateTable",
|
||||
type: "table",
|
||||
description:
|
||||
"Local date fields `year`, `month`, `day`, and optional `hour`, `min`, and `sec`.",
|
||||
optional: true,
|
||||
},
|
||||
],
|
||||
returns: [
|
||||
{ type: "integer", description: "Seconds since the Unix epoch." },
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
code: "local timestamp = os.time({year = 2020, month = 1, day = 1})",
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
|
||||
// Returns the difference, from time `t1` to time `t2` in seconds
|
||||
// In POSIX and some other systems, this value is exactly $t2-t1$.
|
||||
difftime: new LuaBuiltinFunction((_sf, t2: number, t1: number): number => {
|
||||
return t2 - t1;
|
||||
}),
|
||||
difftime: new LuaBuiltinFunction(
|
||||
(_sf, t2: number, t1: number): number => {
|
||||
return t2 - t1;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns the difference in seconds from timestamp `t1` to `t2`.",
|
||||
parameters: [
|
||||
{ name: "t2", type: "number" },
|
||||
{ name: "t1", type: "number" },
|
||||
],
|
||||
returns: [
|
||||
{ type: "number", description: "The value `t2 - t1` in seconds." },
|
||||
],
|
||||
},
|
||||
),
|
||||
|
||||
// Returns a string or a table containing date and time, formatted
|
||||
// according to the given string format.
|
||||
@@ -336,29 +375,69 @@ export const osApi = new LuaTable({
|
||||
// Otherwise, format specifiers follow ISO C `strftime`.
|
||||
//
|
||||
// If format is absent, it defaults to `%c`.
|
||||
date: new LuaBuiltinFunction((_sf, format?: string, timestamp?: number) => {
|
||||
let fmt = format ?? "%c";
|
||||
let utc = false;
|
||||
date: new LuaBuiltinFunction(
|
||||
(_sf, format?: string, timestamp?: number) => {
|
||||
let fmt = format ?? "%c";
|
||||
let utc = false;
|
||||
|
||||
if (fmt.startsWith("!")) {
|
||||
utc = true;
|
||||
fmt = fmt.slice(1);
|
||||
}
|
||||
if (fmt.startsWith("!")) {
|
||||
utc = true;
|
||||
fmt = fmt.slice(1);
|
||||
}
|
||||
|
||||
const d =
|
||||
timestamp !== undefined && timestamp !== null
|
||||
? new Date(timestamp * 1000)
|
||||
: new Date();
|
||||
const d =
|
||||
timestamp !== undefined && timestamp !== null
|
||||
? new Date(timestamp * 1000)
|
||||
: new Date();
|
||||
|
||||
if (fmt === "*t") {
|
||||
return dateTable(d, utc);
|
||||
}
|
||||
if (fmt === "*t") {
|
||||
return dateTable(d, utc);
|
||||
}
|
||||
|
||||
return luaFormatTime(fmt, d, utc);
|
||||
}),
|
||||
return luaFormatTime(fmt, d, utc);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Formats a timestamp as a date string or date table, optionally in UTC.",
|
||||
parameters: [
|
||||
{
|
||||
name: "format",
|
||||
type: "string",
|
||||
description:
|
||||
"`strftime`-style format, `*t` for a table, and optional leading `!` for UTC.",
|
||||
optional: true,
|
||||
},
|
||||
{
|
||||
name: "timestamp",
|
||||
type: "number",
|
||||
description: "Unix timestamp; defaults to the current time.",
|
||||
optional: true,
|
||||
},
|
||||
],
|
||||
returns: [
|
||||
{ type: "string|table", description: "Formatted date or date fields." },
|
||||
],
|
||||
examples: [
|
||||
{ code: 'print(os.date("%Y-%m-%d"))\nlocal utc = os.date("!*t")' },
|
||||
],
|
||||
},
|
||||
),
|
||||
|
||||
// Returns an approximation of CPU time used by the program in seconds.
|
||||
clock: new LuaBuiltinFunction((_sf): number => {
|
||||
return performance.now() / 1000.0;
|
||||
}),
|
||||
clock: new LuaBuiltinFunction(
|
||||
(_sf): number => {
|
||||
return performance.now() / 1000.0;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Returns a high-resolution elapsed time value in seconds.",
|
||||
returns: [
|
||||
{
|
||||
type: "number",
|
||||
description: "Browser performance timer in seconds.",
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
});
|
||||
|
||||
@@ -28,20 +28,39 @@ function capturesToLua(caps: CaptureResult[]): any {
|
||||
}
|
||||
|
||||
export const stringApi = new LuaTable({
|
||||
byte: new LuaBuiltinFunction((_sf, s: string, i?: number, j?: number) => {
|
||||
i = i ?? 1;
|
||||
j = j ?? i;
|
||||
if (j > s.length) j = s.length;
|
||||
if (i < 1) i = 1;
|
||||
const result = [];
|
||||
for (let k = i; k <= j; k++) {
|
||||
result.push(s.charCodeAt(k - 1));
|
||||
}
|
||||
return new LuaMultiRes(result);
|
||||
}),
|
||||
char: new LuaBuiltinFunction((_sf, ...args: number[]) => {
|
||||
return String.fromCharCode(...args);
|
||||
}),
|
||||
byte: new LuaBuiltinFunction(
|
||||
(_sf, s: string, i?: number, j?: number) => {
|
||||
i = i ?? 1;
|
||||
j = j ?? i;
|
||||
if (j > s.length) j = s.length;
|
||||
if (i < 1) i = 1;
|
||||
const result = [];
|
||||
for (let k = i; k <= j; k++) {
|
||||
result.push(s.charCodeAt(k - 1));
|
||||
}
|
||||
return new LuaMultiRes(result);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns the numeric character codes in the inclusive range from `i` to `j`.",
|
||||
parameters: [
|
||||
{ name: "s", type: "string" },
|
||||
{ name: "i", type: "integer", optional: true },
|
||||
{ name: "j", type: "integer", optional: true },
|
||||
],
|
||||
returns: [{ type: "integer", description: "One result per character." }],
|
||||
},
|
||||
),
|
||||
char: new LuaBuiltinFunction(
|
||||
(_sf, ...args: number[]) => String.fromCharCode(...args),
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Creates a string from numeric character codes.",
|
||||
signatures: ["string.char(...): string"],
|
||||
returns: [{ type: "string" }],
|
||||
},
|
||||
),
|
||||
find: new LuaBuiltinFunction(
|
||||
(_sf, s: string, pattern: string, init = 1, plain = false) => {
|
||||
const r = patternFind(s, pattern, init, plain);
|
||||
@@ -52,13 +71,46 @@ export const stringApi = new LuaTable({
|
||||
}
|
||||
return new LuaMultiRes(result);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Finds the first Lua-pattern match and returns its bounds followed by captures.",
|
||||
parameters: [
|
||||
{ name: "s", type: "string" },
|
||||
{ name: "pattern", type: "string" },
|
||||
{ name: "init", type: "integer", optional: true },
|
||||
{ name: "plain", type: "boolean", optional: true },
|
||||
],
|
||||
returns: [
|
||||
{ type: "integer|nil", description: "Start index or `nil`." },
|
||||
{ type: "integer", description: "End index." },
|
||||
],
|
||||
},
|
||||
),
|
||||
format: new LuaBuiltinFunction(
|
||||
(_sf, format: string, ...args: any[]) => {
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
args[i] = untagNumber(args[i]);
|
||||
}
|
||||
return luaFormat(format, ...args);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Formats values according to a C-style format string.",
|
||||
signatures: ["string.format(format, ...): string"],
|
||||
parameters: [
|
||||
{ name: "format", type: "string" },
|
||||
{
|
||||
name: "...",
|
||||
description: "Values consumed by conversion specifiers.",
|
||||
},
|
||||
],
|
||||
returns: [{ type: "string" }],
|
||||
examples: [
|
||||
{ code: 'print(string.format("Name: %s, score: %.1f", "Ada", 9.5))' },
|
||||
],
|
||||
},
|
||||
),
|
||||
format: new LuaBuiltinFunction((_sf, format: string, ...args: any[]) => {
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
args[i] = untagNumber(args[i]);
|
||||
}
|
||||
return luaFormat(format, ...args);
|
||||
}),
|
||||
gmatch: new LuaBuiltinFunction(
|
||||
(_sf, s: string, pattern: string, init = 1) => {
|
||||
const iter = patternGmatch(s, pattern, init);
|
||||
@@ -68,6 +120,22 @@ export const stringApi = new LuaTable({
|
||||
return capturesToLua(caps);
|
||||
};
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns an iterator over successive Lua-pattern matches and captures.",
|
||||
parameters: [
|
||||
{ name: "s", type: "string" },
|
||||
{ name: "pattern", type: "string" },
|
||||
{ name: "init", type: "integer", optional: true },
|
||||
],
|
||||
returns: [{ type: "function", description: "Match iterator." }],
|
||||
examples: [
|
||||
{
|
||||
code: 'for word in string.gmatch("hello world", "%w+") do\n print(word)\nend',
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
gsub: new LuaBuiltinFunction(
|
||||
async (sf, s: string, pattern: string, repl: any, n?: number) => {
|
||||
@@ -103,61 +171,156 @@ export const stringApi = new LuaTable({
|
||||
const [result, count] = await patternGsub(s, pattern, callbacks, n);
|
||||
return new LuaMultiRes([result, count]);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Replaces Lua-pattern matches using a string, table, or function replacement.",
|
||||
parameters: [
|
||||
{ name: "s", type: "string" },
|
||||
{ name: "pattern", type: "string" },
|
||||
{ name: "replacement", type: "string|table|function" },
|
||||
{ name: "n", type: "integer", optional: true },
|
||||
],
|
||||
returns: [
|
||||
{ type: "string", description: "Result string." },
|
||||
{ type: "integer", description: "Number of replacements." },
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
code: 'local result, count = string.gsub("hello hello", "hello", "hi", 1)\nprint(result, count) -- hi hello 1',
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
len: new LuaBuiltinFunction((_sf, s: string) => {
|
||||
return s.length;
|
||||
}),
|
||||
lower: new LuaBuiltinFunction((_sf, s: string) => {
|
||||
return luaToString(s.toLowerCase());
|
||||
}),
|
||||
upper: new LuaBuiltinFunction((_sf, s: string) => {
|
||||
return luaToString(s.toUpperCase());
|
||||
}),
|
||||
match: new LuaBuiltinFunction((_sf, s: string, pattern: string, init = 1) => {
|
||||
const caps = patternMatch(s, pattern, init);
|
||||
if (!caps) return null;
|
||||
return capturesToLua(caps);
|
||||
}),
|
||||
rep: new LuaBuiltinFunction((_sf, s: string, n: number, sep?: string) => {
|
||||
if (n <= 0) return "";
|
||||
sep = sep ?? "";
|
||||
const parts: string[] = [];
|
||||
for (let i = 0; i < n; i++) {
|
||||
parts.push(s);
|
||||
}
|
||||
return parts.join(sep);
|
||||
}),
|
||||
reverse: new LuaBuiltinFunction((_sf, s: string) => {
|
||||
return s.split("").reverse().join("");
|
||||
}),
|
||||
sub: new LuaBuiltinFunction((_sf, s: string, i: number, j?: number) => {
|
||||
const len = s.length;
|
||||
let start: number;
|
||||
if (i > 0) {
|
||||
start = i;
|
||||
} else if (i < -len) {
|
||||
start = 1;
|
||||
} else {
|
||||
start = i === 0 ? 1 : len + i + 1;
|
||||
}
|
||||
let end: number;
|
||||
if (j === undefined || j === null || j > len) {
|
||||
end = len;
|
||||
} else if (j >= 0) {
|
||||
end = j;
|
||||
} else if (j < -len) {
|
||||
end = 0;
|
||||
} else {
|
||||
end = len + j + 1;
|
||||
}
|
||||
if (start <= end) {
|
||||
return s.substring(start - 1, end);
|
||||
}
|
||||
return "";
|
||||
len: new LuaBuiltinFunction((_sf, s: string) => s.length, {
|
||||
kind: "builtin",
|
||||
description: "Returns the length of a string.",
|
||||
parameters: [{ name: "s", type: "string" }],
|
||||
returns: [{ type: "integer" }],
|
||||
}),
|
||||
lower: new LuaBuiltinFunction(
|
||||
(_sf, s: string) => luaToString(s.toLowerCase()),
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Returns a copy of a string converted to lowercase.",
|
||||
parameters: [{ name: "s", type: "string" }],
|
||||
returns: [{ type: "string" }],
|
||||
},
|
||||
),
|
||||
upper: new LuaBuiltinFunction(
|
||||
(_sf, s: string) => luaToString(s.toUpperCase()),
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Returns a copy of a string converted to uppercase.",
|
||||
parameters: [{ name: "s", type: "string" }],
|
||||
returns: [{ type: "string" }],
|
||||
},
|
||||
),
|
||||
match: new LuaBuiltinFunction(
|
||||
(_sf, s: string, pattern: string, init = 1) => {
|
||||
const caps = patternMatch(s, pattern, init);
|
||||
if (!caps) return null;
|
||||
return capturesToLua(caps);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns captures from the first Lua-pattern match, or `nil` when none is found.",
|
||||
parameters: [
|
||||
{ name: "s", type: "string" },
|
||||
{ name: "pattern", type: "string" },
|
||||
{ name: "init", type: "integer", optional: true },
|
||||
],
|
||||
returns: [{ description: "Pattern captures, whole match, or `nil`." }],
|
||||
examples: [
|
||||
{ code: 'local year, month = string.match("2024-03", "(%d+)%-(%d+)")' },
|
||||
],
|
||||
},
|
||||
),
|
||||
rep: new LuaBuiltinFunction(
|
||||
(_sf, s: string, n: number, sep?: string) => {
|
||||
if (n <= 0) return "";
|
||||
sep = sep ?? "";
|
||||
const parts: string[] = [];
|
||||
for (let i = 0; i < n; i++) {
|
||||
parts.push(s);
|
||||
}
|
||||
return parts.join(sep);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns `n` copies of a string joined by an optional separator.",
|
||||
parameters: [
|
||||
{ name: "s", type: "string" },
|
||||
{ name: "n", type: "integer" },
|
||||
{ name: "sep", type: "string", optional: true },
|
||||
],
|
||||
returns: [{ type: "string" }],
|
||||
},
|
||||
),
|
||||
reverse: new LuaBuiltinFunction(
|
||||
(_sf, s: string) => s.split("").reverse().join(""),
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Returns a string with its characters in reverse order.",
|
||||
parameters: [{ name: "s", type: "string" }],
|
||||
returns: [{ type: "string" }],
|
||||
},
|
||||
),
|
||||
sub: new LuaBuiltinFunction(
|
||||
(_sf, s: string, i: number, j?: number) => {
|
||||
const len = s.length;
|
||||
let start: number;
|
||||
if (i > 0) {
|
||||
start = i;
|
||||
} else if (i < -len) {
|
||||
start = 1;
|
||||
} else {
|
||||
start = i === 0 ? 1 : len + i + 1;
|
||||
}
|
||||
let end: number;
|
||||
if (j === undefined || j === null || j > len) {
|
||||
end = len;
|
||||
} else if (j >= 0) {
|
||||
end = j;
|
||||
} else if (j < -len) {
|
||||
end = 0;
|
||||
} else {
|
||||
end = len + j + 1;
|
||||
}
|
||||
if (start <= end) {
|
||||
return s.substring(start - 1, end);
|
||||
}
|
||||
return "";
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns the substring from inclusive index `i` through `j`, supporting negative indices.",
|
||||
parameters: [
|
||||
{ name: "s", type: "string" },
|
||||
{ name: "i", type: "integer" },
|
||||
{ name: "j", type: "integer", optional: true },
|
||||
],
|
||||
returns: [{ type: "string" }],
|
||||
},
|
||||
),
|
||||
|
||||
split: new LuaBuiltinFunction((_sf, s: string, sep: string) => {
|
||||
return s.split(sep);
|
||||
split: new LuaBuiltinFunction((_sf, s: string, sep: string) => s.split(sep), {
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Splits a string on a literal separator and returns the substrings.",
|
||||
parameters: [
|
||||
{ name: "s", type: "string" },
|
||||
{ name: "sep", type: "string" },
|
||||
],
|
||||
returns: [{ type: "table" }],
|
||||
examples: [
|
||||
{
|
||||
code: 'for part in each(string.split("a,b,c", ",")) do\n print(part)\nend',
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
||||
pack: strPackFn,
|
||||
@@ -165,34 +328,97 @@ export const stringApi = new LuaTable({
|
||||
packsize: strPackSizeFn,
|
||||
|
||||
// Non-standard extensions
|
||||
startsWith: new LuaBuiltinFunction((_sf, s: string, prefix: string) => {
|
||||
return s.startsWith(prefix);
|
||||
startsWith: new LuaBuiltinFunction(
|
||||
(_sf, s: string, prefix: string) => s.startsWith(prefix),
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Returns whether a string starts with a literal prefix.",
|
||||
parameters: [
|
||||
{ name: "s", type: "string" },
|
||||
{ name: "prefix", type: "string" },
|
||||
],
|
||||
returns: [{ type: "boolean" }],
|
||||
},
|
||||
),
|
||||
endsWith: new LuaBuiltinFunction(
|
||||
(_sf, s: string, suffix: string) => s.endsWith(suffix),
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Returns whether a string ends with a literal suffix.",
|
||||
parameters: [
|
||||
{ name: "s", type: "string" },
|
||||
{ name: "suffix", type: "string" },
|
||||
],
|
||||
returns: [{ type: "boolean" }],
|
||||
},
|
||||
),
|
||||
trim: new LuaBuiltinFunction((_sf, s: string) => s.trim(), {
|
||||
kind: "builtin",
|
||||
description: "Removes whitespace from both ends of a string.",
|
||||
parameters: [{ name: "s", type: "string" }],
|
||||
returns: [{ type: "string" }],
|
||||
}),
|
||||
endsWith: new LuaBuiltinFunction((_sf, s: string, suffix: string) => {
|
||||
return s.endsWith(suffix);
|
||||
trimStart: new LuaBuiltinFunction((_sf, s: string) => s.trimStart(), {
|
||||
kind: "builtin",
|
||||
description: "Removes whitespace from the beginning of a string.",
|
||||
parameters: [{ name: "s", type: "string" }],
|
||||
returns: [{ type: "string" }],
|
||||
}),
|
||||
trim: new LuaBuiltinFunction((_sf, s: string) => {
|
||||
return s.trim();
|
||||
}),
|
||||
trimStart: new LuaBuiltinFunction((_sf, s: string) => {
|
||||
return s.trimStart();
|
||||
}),
|
||||
trimEnd: new LuaBuiltinFunction((_sf, s: string) => {
|
||||
return s.trimEnd();
|
||||
}),
|
||||
matchRegex: new LuaBuiltinFunction((_sf, s: string, pattern: string) => {
|
||||
const regex = new RegExp(pattern);
|
||||
const result = s.match(regex);
|
||||
return jsToLuaValue(result);
|
||||
}),
|
||||
matchRegexAll: new LuaBuiltinFunction((_sf, s: string, pattern: string) => {
|
||||
const regex = new RegExp(pattern, "g");
|
||||
return () => {
|
||||
const match = regex.exec(s);
|
||||
if (!match) {
|
||||
return;
|
||||
}
|
||||
return jsToLuaValue(match);
|
||||
};
|
||||
trimEnd: new LuaBuiltinFunction((_sf, s: string) => s.trimEnd(), {
|
||||
kind: "builtin",
|
||||
description: "Removes whitespace from the end of a string.",
|
||||
parameters: [{ name: "s", type: "string" }],
|
||||
returns: [{ type: "string" }],
|
||||
}),
|
||||
matchRegex: new LuaBuiltinFunction(
|
||||
(_sf, s: string, pattern: string) => {
|
||||
const regex = new RegExp(pattern);
|
||||
const result = s.match(regex);
|
||||
return jsToLuaValue(result);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Matches a string with a JavaScript regular expression and returns the match array.",
|
||||
parameters: [
|
||||
{ name: "s", type: "string" },
|
||||
{ name: "pattern", type: "string" },
|
||||
],
|
||||
returns: [{ type: "table|nil" }],
|
||||
examples: [
|
||||
{
|
||||
code: 'local match = string.matchRegex("hello123", "([a-z]+)([0-9]+)")\nprint(match[1], match[2], match[3])',
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
matchRegexAll: new LuaBuiltinFunction(
|
||||
(_sf, s: string, pattern: string) => {
|
||||
const regex = new RegExp(pattern, "g");
|
||||
return () => {
|
||||
const match = regex.exec(s);
|
||||
if (!match) {
|
||||
return;
|
||||
}
|
||||
return jsToLuaValue(match);
|
||||
};
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns an iterator over all JavaScript regular-expression matches.",
|
||||
parameters: [
|
||||
{ name: "s", type: "string" },
|
||||
{ name: "pattern", type: "string" },
|
||||
],
|
||||
returns: [
|
||||
{ type: "function", description: "Iterator yielding match arrays." },
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
code: 'for match in string.matchRegexAll("a1b2", "([a-z])([0-9])") do\n print(match[1], match[2], match[3])\nend',
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
});
|
||||
|
||||
@@ -364,6 +364,17 @@ export const strPackFn = new LuaBuiltinFunction(
|
||||
for (let i = 0; i < out.length; i++) result += String.fromCharCode(out[i]);
|
||||
return result;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Packs values into a binary string according to a Lua 5.4 format string.",
|
||||
signatures: ["string.pack(format, ...): string"],
|
||||
parameters: [
|
||||
{ name: "format", type: "string", description: "Binary packing format." },
|
||||
{ name: "...", description: "Values consumed by the format options." },
|
||||
],
|
||||
returns: [{ type: "string", description: "Packed binary string." }],
|
||||
},
|
||||
);
|
||||
|
||||
export const strUnpackFn = new LuaBuiltinFunction(
|
||||
@@ -468,23 +479,60 @@ export const strUnpackFn = new LuaBuiltinFunction(
|
||||
results.push(pos + 1);
|
||||
return new LuaMultiRes(results);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Unpacks values from a binary string according to a Lua 5.4 format string.",
|
||||
parameters: [
|
||||
{
|
||||
name: "format",
|
||||
type: "string",
|
||||
description: "Binary unpacking format.",
|
||||
},
|
||||
{ name: "data", type: "string", description: "Packed binary string." },
|
||||
{
|
||||
name: "init",
|
||||
type: "integer",
|
||||
description: "One-based starting position.",
|
||||
optional: true,
|
||||
},
|
||||
],
|
||||
returns: [
|
||||
{ description: "Unpacked values followed by the next unread position." },
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
export const strPackSizeFn = new LuaBuiltinFunction((_sf, fmt: string) => {
|
||||
const h = makeHeader();
|
||||
let totalsize = 0;
|
||||
let pos = 0;
|
||||
export const strPackSizeFn = new LuaBuiltinFunction(
|
||||
(_sf, fmt: string) => {
|
||||
const h = makeHeader();
|
||||
let totalsize = 0;
|
||||
let pos = 0;
|
||||
|
||||
while (pos < fmt.length) {
|
||||
let opt: ParsedOption;
|
||||
[opt, pos] = getDetails(fmt, pos, h, totalsize);
|
||||
while (pos < fmt.length) {
|
||||
let opt: ParsedOption;
|
||||
[opt, pos] = getDetails(fmt, pos, h, totalsize);
|
||||
|
||||
if (opt.opt === "string" || opt.opt === "zstr") {
|
||||
throw new LuaRuntimeError("variable-length format", _sf);
|
||||
if (opt.opt === "string" || opt.opt === "zstr") {
|
||||
throw new LuaRuntimeError("variable-length format", _sf);
|
||||
}
|
||||
|
||||
totalsize += opt.ntoalign + opt.size;
|
||||
}
|
||||
|
||||
totalsize += opt.ntoalign + opt.size;
|
||||
}
|
||||
|
||||
return totalsize;
|
||||
});
|
||||
return totalsize;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns the byte size of a fixed-length Lua 5.4 packing format.",
|
||||
parameters: [
|
||||
{
|
||||
name: "format",
|
||||
type: "string",
|
||||
description: "Fixed-length binary packing format.",
|
||||
},
|
||||
],
|
||||
returns: [{ type: "integer", description: "Packed byte count." }],
|
||||
},
|
||||
);
|
||||
|
||||
@@ -108,6 +108,18 @@ export const tableApi = new LuaTable({
|
||||
}
|
||||
return out.join(sep);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Concatenates table elements from `i` through `j` using an optional separator.",
|
||||
parameters: [
|
||||
{ name: "table", type: "table" },
|
||||
{ name: "sep", type: "string", optional: true },
|
||||
{ name: "i", type: "integer", optional: true },
|
||||
{ name: "j", type: "integer", optional: true },
|
||||
],
|
||||
returns: [{ type: "string" }],
|
||||
},
|
||||
),
|
||||
|
||||
/**
|
||||
@@ -159,6 +171,32 @@ export const tableApi = new LuaTable({
|
||||
|
||||
await luaSet(tbl, pos, v, sf);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Inserts a value at a position, shifting later elements, or appends it when no position is supplied.",
|
||||
signatures: [
|
||||
"table.insert(table, value)",
|
||||
"table.insert(table, pos, value)",
|
||||
],
|
||||
parameters: [
|
||||
{ name: "table", type: "table" },
|
||||
{
|
||||
name: "posOrValue",
|
||||
description: "Insertion position or appended value.",
|
||||
},
|
||||
{
|
||||
name: "value",
|
||||
description: "Value for positional insertion.",
|
||||
optional: true,
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
code: 'local fruits = {"apple", "orange"}\ntable.insert(fruits, 2, "banana")\nprint(table.concat(fruits, ", "))',
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
|
||||
/**
|
||||
@@ -202,6 +240,21 @@ export const tableApi = new LuaTable({
|
||||
|
||||
return v;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Removes and returns an element, shifting later elements down.",
|
||||
parameters: [
|
||||
{ name: "table", type: "table" },
|
||||
{
|
||||
name: "pos",
|
||||
type: "integer",
|
||||
description: "Position; defaults to the last element.",
|
||||
optional: true,
|
||||
},
|
||||
],
|
||||
returns: [{ description: "Removed value." }],
|
||||
},
|
||||
),
|
||||
|
||||
/**
|
||||
@@ -252,6 +305,24 @@ export const tableApi = new LuaTable({
|
||||
|
||||
return a2;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Moves an inclusive element range to a destination table while handling overlaps.",
|
||||
parameters: [
|
||||
{ name: "a1", type: "table", description: "Source table." },
|
||||
{ name: "f", type: "integer", description: "First source index." },
|
||||
{ name: "e", type: "integer", description: "Last source index." },
|
||||
{ name: "t", type: "integer", description: "Destination start index." },
|
||||
{
|
||||
name: "a2",
|
||||
type: "table",
|
||||
description: "Destination table; defaults to `a1`.",
|
||||
optional: true,
|
||||
},
|
||||
],
|
||||
returns: [{ type: "table", description: "Destination table." }],
|
||||
},
|
||||
),
|
||||
|
||||
/**
|
||||
@@ -311,6 +382,23 @@ export const tableApi = new LuaTable({
|
||||
|
||||
return tbl;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Sorts a table in place using ascending order or an optional comparison function.",
|
||||
parameters: [
|
||||
{ name: "table", type: "table" },
|
||||
{ name: "comp", type: "function", optional: true },
|
||||
],
|
||||
returns: [
|
||||
{ type: "table", description: "The sorted table in Space Lua." },
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
code: "local numbers = {3, 1, 2}\ntable.sort(numbers, function(a, b) return a > b end)",
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
|
||||
/**
|
||||
@@ -319,12 +407,21 @@ export const tableApi = new LuaTable({
|
||||
* @param tbl - The table to get the keys from.
|
||||
* @returns The keys of the table.
|
||||
*/
|
||||
keys: new LuaBuiltinFunction((_sf, tbl: LuaTable | LuaEnv | any) => {
|
||||
if (tbl.keys) {
|
||||
return tbl.keys();
|
||||
}
|
||||
return Object.keys(tbl);
|
||||
}),
|
||||
keys: new LuaBuiltinFunction(
|
||||
(_sf, tbl: LuaTable | LuaEnv | any) => {
|
||||
if (tbl.keys) {
|
||||
return tbl.keys();
|
||||
}
|
||||
return Object.keys(tbl);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns an array containing all keys of a table or JavaScript object.",
|
||||
parameters: [{ name: "table", type: "table" }],
|
||||
returns: [{ type: "table", description: "Array of keys." }],
|
||||
},
|
||||
),
|
||||
|
||||
/**
|
||||
* Checks if a table (used as an array) contains a value.
|
||||
@@ -355,6 +452,16 @@ export const tableApi = new LuaTable({
|
||||
sf,
|
||||
);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns whether any table value is Lua-equal to a requested value.",
|
||||
parameters: [
|
||||
{ name: "table", type: "table" },
|
||||
{ name: "value", description: "Value to find." },
|
||||
],
|
||||
returns: [{ type: "boolean" }],
|
||||
},
|
||||
),
|
||||
|
||||
/**
|
||||
@@ -383,21 +490,57 @@ export const tableApi = new LuaTable({
|
||||
}
|
||||
return resultTable;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description: "Copies selected keys from a table into a new table.",
|
||||
signatures: [
|
||||
"table.select(table, ...keys): table",
|
||||
"table.select(table, keys): table",
|
||||
],
|
||||
parameters: [
|
||||
{ name: "table", type: "table" },
|
||||
{
|
||||
name: "keys",
|
||||
description: "Individual keys or one array-like table of keys.",
|
||||
},
|
||||
],
|
||||
returns: [{ type: "table" }],
|
||||
examples: [
|
||||
{
|
||||
code: '${query[[\n from p = index.pages()\n limit 3\n select table.select(p, "name", "lastModified")\n]]}',
|
||||
language: "markdown",
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
|
||||
/**
|
||||
* Returns a new table with all arguments stored in keys 1, 2, ..., n
|
||||
* and t.n = n (the total number of arguments).
|
||||
*/
|
||||
pack: new LuaBuiltinFunction(async (sf, ...args: any[]) => {
|
||||
const tbl = new LuaTable();
|
||||
const n = args.length;
|
||||
for (let i = 0; i < n; i++) {
|
||||
await luaSet(tbl, i + 1, args[i], sf);
|
||||
}
|
||||
void tbl.rawSet("n", n);
|
||||
return tbl;
|
||||
}),
|
||||
pack: new LuaBuiltinFunction(
|
||||
async (sf, ...args: any[]) => {
|
||||
const tbl = new LuaTable();
|
||||
const n = args.length;
|
||||
for (let i = 0; i < n; i++) {
|
||||
await luaSet(tbl, i + 1, args[i], sf);
|
||||
}
|
||||
void tbl.rawSet("n", n);
|
||||
return tbl;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Packs all arguments into a table with a count stored in field `n`.",
|
||||
signatures: ["table.pack(...): table"],
|
||||
returns: [
|
||||
{
|
||||
type: "table",
|
||||
description: "Arguments at integer keys plus field `n`.",
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
|
||||
/**
|
||||
* Returns all values t[i], t[i+1], ..., t[j].
|
||||
@@ -425,6 +568,20 @@ export const tableApi = new LuaTable({
|
||||
}
|
||||
return new LuaMultiRes(result);
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Returns the table values from index `i` through `j` as separate results.",
|
||||
parameters: [
|
||||
{ name: "table", type: "table" },
|
||||
{ name: "i", type: "integer", optional: true },
|
||||
{ name: "j", type: "integer", optional: true },
|
||||
],
|
||||
returns: [{ description: "One result per selected element." }],
|
||||
examples: [
|
||||
{ code: 'local second, third = table.unpack({"a", "b", "c"}, 2, 3)' },
|
||||
],
|
||||
},
|
||||
),
|
||||
|
||||
// Non-standard Lua functions
|
||||
@@ -457,5 +614,28 @@ export const tableApi = new LuaTable({
|
||||
}
|
||||
return null;
|
||||
},
|
||||
{
|
||||
kind: "builtin",
|
||||
description:
|
||||
"Finds the first array element accepted by a predicate and returns its index and value.",
|
||||
parameters: [
|
||||
{ name: "table", type: "table" },
|
||||
{
|
||||
name: "criteriaFn",
|
||||
type: "function",
|
||||
description: "Predicate called with each value.",
|
||||
},
|
||||
{ name: "fromIndex", type: "integer", optional: true },
|
||||
],
|
||||
returns: [
|
||||
{ type: "integer|nil", description: "Matching index or `nil`." },
|
||||
{ description: "Matching value." },
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
code: "local index, value = table.find({1, 2, 3, 4}, function(n) return n % 2 == 0 end)",
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user