You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
6.3 KiB

import { Table } from '../Table'
import {
LuaType,
coerceToBoolean,
coerceArgToNumber,
coerceArgToString,
coerceArgToTable,
coerceArgToFunction
} from '../utils'
import { LuaError } from '../LuaError'
function getn(table: LuaType): number {
const TABLE = coerceArgToTable(table, 'getn', 1)
return TABLE.getn()
}
/**
* Given a list where all elements are strings or numbers, returns the string list[i]..sep..list[i+1] ··· sep..list[j].
* The default value for sep is the empty string, the default for i is 1, and the default for j is #list.
* If i is greater than j, returns the empty string.
*/
function concat(table: LuaType, sep: LuaType = '', i: LuaType = 1, j?: LuaType): string {
const TABLE = coerceArgToTable(table, 'concat', 1)
const SEP = coerceArgToString(sep, 'concat', 2)
const I = coerceArgToNumber(i, 'concat', 3)
const J = j === undefined ? maxn(TABLE) : coerceArgToNumber(j, 'concat', 4)
return []
.concat(TABLE.numValues)
.splice(I, J - I + 1)
.join(SEP)
}
/**
* Inserts element value at position pos in list, shifting up the elements list[pos], list[pos+1], ···, list[#list].
* The default value for pos is #list+1, so that a call table.insert(t,x) inserts x at the end of list t.
*/
function insert(table: LuaType, pos: LuaType, value?: LuaType): void {
const TABLE = coerceArgToTable(table, 'insert', 1)
const POS = value === undefined ? TABLE.numValues.length : coerceArgToNumber(pos, 'insert', 2)
const VALUE = value === undefined ? pos : value
TABLE.numValues.splice(POS, 0, undefined)
TABLE.set(POS, VALUE)
}
function maxn(table: LuaType): number {
const TABLE = coerceArgToTable(table, 'maxn', 1)
return TABLE.numValues.length - 1
}
/**
* Moves elements from table a1 to table a2, performing the equivalent to the following multiple assignment:
*
* `a2[t],··· = a1[f],···,a1[e].`
*
* The default for a2 is a1.
* The destination range can overlap with the source range.
* The number of elements to be moved must fit in a Lua integer.
*
* Returns the destination table a2.
*/
function move(a1: LuaType, f: LuaType, e: LuaType, t: LuaType, a2?: LuaType): Table {
const A1 = coerceArgToTable(a1, 'move', 1)
const F = coerceArgToNumber(f, 'move', 2)
const E = coerceArgToNumber(e, 'move', 3)
const T = coerceArgToNumber(t, 'move', 4)
const A2 = a2 === undefined ? A1 : coerceArgToTable(a2, 'move', 5)
if (E >= F) {
if (F <= 0 && E >= Number.MAX_SAFE_INTEGER + F) throw new LuaError('too many elements to move')
const n = E - F + 1 // number of elements to movea
if (T > Number.MAX_SAFE_INTEGER - n + 1) throw new LuaError('destination wrap around')
if (T > E || T <= F || A2 !== A1) {
for (let i = 0; i < n; i++) {
const v = A1.get(F + i)
A2.set(T + i, v)
}
} else {
for (let i = n - 1; i >= 0; i--) {
const v = A1.get(F + i)
A2.set(T + i, v)
}
}
}
return A2
}
/**
* Returns a new table with all arguments stored into keys 1, 2, etc. and with a field "n" with the total number of arguments.
* Note that the resulting table may not be a sequence.
*/
function pack(...args: LuaType[]): Table {
const table = new Table(args)
table.rawset('n', args.length)
return table
}
/**
* Removes from list the element at position pos, returning the value of the removed element.
* When pos is an integer between 1 and #list, it shifts down the elements list[pos+1], list[pos+2], ···, list[#list] and
* erases element list[#list]; The index pos can also be 0 when #list is 0, or #list + 1;
* in those cases, the function erases the element list[pos].
*
* The default value for pos is #list, so that a call table.remove(l) removes the last element of list l.
*/
function remove(table: LuaType, pos?: LuaType): LuaType {
const TABLE = coerceArgToTable(table, 'remove', 1)
const max = TABLE.getn()
const POS = pos === undefined ? max : coerceArgToNumber(pos, 'remove', 2)
if (POS > max || POS < 0) {
return
}
const vals = TABLE.numValues
const result = vals.splice(POS, 1)[0]
let i = POS
while (i < max && vals[i] === undefined) {
delete vals[i]
i += 1
}
return result
}
/**
* Sorts list elements in a given order, in-place, from list[1] to list[#list].
* If comp is given, then it must be a function that receives two list elements and
* returns true when the first element must come before the second in the final order
* (so that, after the sort, i < j implies not comp(list[j],list[i])).
* If comp is not given, then the standard Lua operator < is used instead.
*
* Note that the comp function must define a strict partial order over the elements in the list;
* that is, it must be asymmetric and transitive. Otherwise, no valid sort may be possible.
*
* The sort algorithm is not stable: elements considered equal by the given order may have
* their relative positions changed by the sort.
*/
function sort(table: Table, comp?: Function): void {
const TABLE = coerceArgToTable(table, 'sort', 1)
let sortFunc: (a: LuaType, b: LuaType) => number
if (comp) {
const COMP = coerceArgToFunction(comp, 'sort', 2)
sortFunc = (a, b) => (coerceToBoolean(COMP(a, b)[0]) ? -1 : 1)
} else {
sortFunc = (a, b) => (a < b ? -1 : 1)
}
const arr = TABLE.numValues
arr.shift()
arr.sort(sortFunc).unshift(undefined)
}
/**
* Returns the elements from the given list. This function is equivalent to
*
* `return list[i], list[i+1], ···, list[j]`
*
* By default, i is 1 and j is #list.
*/
function unpack(table: LuaType, i?: LuaType, j?: LuaType): LuaType[] {
const TABLE = coerceArgToTable(table, 'unpack', 1)
const I = i === undefined ? 1 : coerceArgToNumber(i, 'unpack', 2)
const J = j === undefined ? TABLE.getn() : coerceArgToNumber(j, 'unpack', 3)
return TABLE.numValues.slice(I, J + 1)
}
const libTable = new Table({
getn,
concat,
insert,
maxn,
move,
pack,
remove,
sort,
unpack
})
export { libTable }