Compare commits

..

4 Commits

@ -79,6 +79,18 @@ console.log(helloStr)
Check out the [math lib](./src/lib/math.ts) for a more extensive example. Check out the [math lib](./src/lib/math.ts) for a more extensive example.
### Extend a library
Use `extendLib` to add new functions to an existing library without overwriting it.
```js
const extraMath = new luainjs.Table({ tau: Math.PI * 2 })
luaEnv.extendLib('math', extraMath)
const tau = luaEnv.parse('return math.tau').exec()
console.log(tau)
```
## Example ## Example
Check out the [test runner](./tests/test.js) for a concrete example. Check out the [test runner](./tests/test.js) for a concrete example.

@ -10,7 +10,7 @@ import { libTable } from './lib/table'
import { libString, metatable as stringMetatable } from './lib/string' import { libString, metatable as stringMetatable } from './lib/string'
import { getLibOS } from './lib/os' import { getLibOS } from './lib/os'
import { getLibPackage } from './lib/package' import { getLibPackage } from './lib/package'
import { LuaType, ensureArray, Config } from './utils' import { LuaType, ensureArray, Config, hasOwnProperty } from './utils'
import { parse as parseScript } from './parser' import { parse as parseScript } from './parser'
interface Script { interface Script {
@ -56,6 +56,7 @@ function createEnv(
parse: (script: string) => Script parse: (script: string) => Script
parseFile: (path: string) => Script parseFile: (path: string) => Script
loadLib: (name: string, value: Table) => void loadLib: (name: string, value: Table) => void
extendLib: (name: string, value: Table) => void
} { } {
const cfg: Config = { const cfg: Config = {
LUA_PATH: './?.lua', LUA_PATH: './?.lua',
@ -77,6 +78,24 @@ function createEnv(
loaded.rawset(name, value) loaded.rawset(name, value)
} }
const extendLib = (name: string, value: Table): void => {
const lib = _G.rawget(name)
if (lib instanceof Table) {
for (let i = 1; i < value.numValues.length; i++) {
if (hasOwnProperty(value.numValues, i)) lib.rawset(i, value.numValues[i])
}
for (const key in value.strValues) {
if (hasOwnProperty(value.strValues, key)) lib.rawset(key, value.strValues[key])
}
for (let i = 0; i < value.keys.length; i++) {
lib.rawset(value.keys[i], value.values[i])
}
return
}
loadLib(name, value)
}
loadLib('_G', _G) loadLib('_G', _G)
loadLib('package', libPackage) loadLib('package', libPackage)
loadLib('math', libMath) loadLib('math', libMath)
@ -105,7 +124,8 @@ function createEnv(
return { return {
parse, parse,
parseFile, parseFile,
loadLib loadLib,
extendLib
} }
} }

@ -1,7 +1,15 @@
import { sprintf } from 'printj' import { sprintf } from 'printj'
import { Table } from '../Table' import { Table } from '../Table'
import { LuaError } from '../LuaError' import { LuaError } from '../LuaError'
import { tostring, posrelat, coerceArgToNumber, coerceArgToString, hasOwnProperty, LuaType } from '../utils' import {
coerceArgToBoolean,
coerceArgToNumber,
coerceArgToString,
hasOwnProperty,
LuaType,
posrelat,
tostring
} from '../utils'
const ROSETTA_STONE: Record<string, string> = { const ROSETTA_STONE: Record<string, string> = {
'([^a-zA-Z0-9%(])-': '$1*?', '([^a-zA-Z0-9%(])-': '$1*?',
@ -117,7 +125,7 @@ function find(s: LuaType, pattern: LuaType, init: LuaType, plain: LuaType): (num
const S = coerceArgToString(s, 'find', 1) const S = coerceArgToString(s, 'find', 1)
const P = coerceArgToString(pattern, 'find', 2) const P = coerceArgToString(pattern, 'find', 2)
const INIT = init === undefined ? 1 : coerceArgToNumber(init, 'find', 3) const INIT = init === undefined ? 1 : coerceArgToNumber(init, 'find', 3)
const PLAIN = plain === undefined ? false : coerceArgToNumber(plain, 'find', 4) const PLAIN = plain === undefined ? false : coerceArgToBoolean(plain, 'find', 4)
// Regex // Regex
if (!PLAIN) { if (!PLAIN) {

@ -160,7 +160,7 @@ function coerceToString(val: LuaType, errorMessage?: string): string {
function coerceArg<T>( function coerceArg<T>(
value: LuaType, value: LuaType,
coerceFunc: (val: LuaType, errorMessage?: string) => T, coerceFunc: (val: LuaType, errorMessage?: string) => T,
typ: 'number' | 'string', typ: 'number' | 'string' | 'boolean',
funcName: string, funcName: string,
index: number index: number
): T { ): T {
@ -175,6 +175,10 @@ function coerceArgToString(value: LuaType, funcName: string, index: number): str
return coerceArg<string>(value, coerceToString, 'string', funcName, index) return coerceArg<string>(value, coerceToString, 'string', funcName, index)
} }
function coerceArgToBoolean(value: LuaType, funcName: string, index: number): boolean {
return coerceArg<boolean>(value, coerceToBoolean, 'boolean', funcName, index)
}
function coerceArgToTable(value: LuaType, funcName: string, index: number): Table { function coerceArgToTable(value: LuaType, funcName: string, index: number): Table {
if (value instanceof Table) { if (value instanceof Table) {
return value return value
@ -207,6 +211,7 @@ export {
coerceToBoolean, coerceToBoolean,
coerceToNumber, coerceToNumber,
coerceToString, coerceToString,
coerceArgToBoolean,
coerceArgToNumber, coerceArgToNumber,
coerceArgToString, coerceArgToString,
coerceArgToTable, coerceArgToTable,

@ -101,6 +101,13 @@ b = string.find(a, 'The .* fox')
assertTrue (b == 1, 'The dot pattern should match across lines in string.find()') assertTrue (b == 1, 'The dot pattern should match across lines in string.find()')
local ok, plainFind = pcall(function () return string.find('abc', 'a.c', 1, true) end)
assertTrue (ok and plainFind == nil, 'string.find() should accept a boolean plain argument and disable pattern matching')
local literalFind = string.find('a.c', 'a.c', 1, true)
assertTrue (literalFind == 1, 'string.find() should find literal matches when plain is true')
-- format -- format

@ -41,6 +41,16 @@ let exitCode = 0
} }
} }
{
const luaEnv = luainjs.createEnv()
const ext = new luainjs.Table({ foo: () => 'bar' })
luaEnv.extendLib('math', ext)
const val = luaEnv.parse('return math.foo()').exec()
if (val !== 'bar') {
throw Error('extendLib failed!')
}
}
{ {
const luaEnv = luainjs.createEnv() const luaEnv = luainjs.createEnv()
let str let str

Loading…
Cancel
Save