Skip to content

Commit

Permalink
publish: 1.18.0, readme
Browse files Browse the repository at this point in the history
  • Loading branch information
X3ZvaWQ committed Feb 13, 2024
1 parent 8dbb9f4 commit 9651244
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 49 deletions.
60 changes: 52 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@

## From

[ceifa/wasmoon](https://github.com/ceifa/wasmoon)
[ceifa/wasmoon](https://github.com/ceifa/wasmoon)

This repository has made some modifications based on this repository, adapting it to the lua5.1 version. At the same time, some functions of this repository have been optimized/adapted/adjusted.

This package aims to provide a way to:

- Embed Lua to any Node.js, Deno or Web Application.
- Run lua code in any operational system
- Interop Lua and JS without memory leaks (including the DOM)
- Embed Lua to any Node.js, Deno or Web Application.
- Run lua code in any operational system
- Interop Lua and JS without memory leaks (including the DOM)

## API Usage

Expand All @@ -40,6 +40,50 @@ try {
}
```

### About data interaction

Regarding the issue of interacting between JavaScript objects and Lua tables, the previous solution before version 1.18.0 was to perform a one-time conversion, such as:

```js
const obj = { name: 233 };
lua.ctx.obj = obj; // table
const o = lua.ctx.obj; // object, but not the same object as obj, it is a new object with the same value but different reference.
```

This approach has some problems. First of all, Lua tables are more flexible in that they allow keys of any type and their array indices start from 1.

Furthermore, it is not possible to achieve data binding. After adding a JavaScript object to Lua, it is not possible to manipulate the Lua table from the JavaScript layer. Also, modifying an extracted table in JavaScript does not affect the values of the table by modifying the JavaScript object.

Therefore, starting from version 1.18.0, when attempting to inject a plainObject from JavaScript into the Lua environment, a table will be created just like before. However, when exporting a table from Lua, instead of trying to convert it into an object as before, a proxy class called "LuaTable" will be generated which allows arbitrary index and newindex operations on its underlying Lua table.

The "LuaTable" class provides a series of methods:

- `$get` for getting values because when indexing an object in JavaScript,
the key will be automatically converted to string and cannot access keys of number type properly.
- `$set` for setting values for similar reasons as above.
- `$detach` similar operation as before version 1.18.0,
returns a Map detached from the Lua environment (can pass parameters to return an object or array).
- `$istable` used for determining if it is a table.
- `$getRef` gets the index of this table in lua's registry.

It can be used like this:

```js
import { Lua } from '../dist/index.js';
// This file was created as a sandbox to test and debug on vscode

const lua = await Lua.create();

const obj = {};
lua.ctx.obj = obj;

const o = lua.ctx.obj;
o.name = 23333;
console.log(o.name); // 23333

lua.doStringSync('print(obj.name)'); // 23333
```

## CLI Usage

Although Wasmoon has been designed to be embedded, you can run it on command line as well, but, if you want something more robust on this, we recommend to take a look at [demoon](https://github.com/ceifa/demoon).
Expand All @@ -50,8 +94,8 @@ $: wasmoon [options] [file] [args]

Available options are:

- `-l`: Include a file or directory
- `-i`: Enter interactive mode after running the files
- `-l`: Include a file or directory
- `-i`: Enter interactive mode after running the files

### Example

Expand Down Expand Up @@ -219,7 +263,7 @@ print("res", res:await())

Which will throw an error like this:

``` js
```js
Error: Lua Error(ErrorRun/2): cannot resume dead coroutine
at Thread.assertOk (/home/tstableford/projects/wasmoon/dist/index.js:409:23)
at Thread.<anonymous> (/home/tstableford/projects/wasmoon/dist/index.js:142:22)
Expand All @@ -229,7 +273,7 @@ Error: Lua Error(ErrorRun/2): cannot resume dead coroutine

Or like this:

``` js
```js
attempt to yield across a C-call boundary
```

Expand Down
38 changes: 38 additions & 0 deletions README_zhcn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
### 关于数据交互

关于js的object与lua的table交互的问题,1.18.0以前的方案是做一次性的转换,如

```js
const obj = { name: 233 };
lua.ctx.obj = obj; //table
const o = lua.ctx.obj; // object,但是和obj不是一个对象,是一个值相同但是引用不同的新对象。
```

这样会存在一些问题,首先lua的table相对更奔放一些,它允许任意类型的键,以及他的数组索引是从1开始的。
以及无法实现数据绑定,即把js的object加入lua之后,无法再从js层面操作lua的table。以及在js修改提取出的table后无法通过修改js的对象影响table的值。
所以从1.18.0开始,当尝试把js的plainObject注入lua环境中时,像之前一样会创建一个table。但是当从lua中导出一个table时,不会再尝试将其组成一个对象,而是生成一个代理的LuaTable类,可以对其进行任意的index,newindex操作以修改lua内的table。
这个LuaTable类提供了一系列方法:

- `$get` 获取值,因为js如果对对象index的时候,key会被自动转换为string。无法正常访问number类型的键。
- `$set` 设置值,理由同上
- `$detach` 类似1.18.0以前的操作,返回一个与lua环境脱钩的Map(可以传入参数返回object或者array)
- `$istable` 用于判断是不是一个table
- `$getRef` 获取table在lua环境注册表中的索引

可以像这样使用:

```js
import { Lua } from '../dist/index.js';
// This file was created as a sandbox to test and debug on vscode

const lua = await Lua.create();

const obj = {};
lua.ctx.obj = obj;

const o = lua.ctx.obj;
o.name = 23333;
console.log(o.name); // 23333

lua.doStringSync('print(obj.name)'); // 23333
```
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wasmoon-lua5.1",
"version": "1.17.2",
"version": "1.18.0",
"description": "A real lua 5.1 VM with JS bindings made with webassembly",
"main": "dist/index.js",
"scripts": {
Expand Down
80 changes: 45 additions & 35 deletions src/table.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DictType, mapTransform } from './utils/map-transform';
import { LUA_REGISTRYINDEX, LuaType } from './definitions';
import LuaThread from './thread';
import { DictType, mapTransform } from './utils/map-transform';

export class LuaTable {
private thread: LuaThread;
Expand All @@ -16,6 +16,34 @@ export class LuaTable {
this.pointer = pointer;
}

public $get(key: any): any {
return this.getTableValue(key);
}

public $set(key: any, value: any): boolean {
return this.setTableValue(key, value);
}

public $istable(): true {
return true;
}

public $getRef(): number {
return this.ref;
}

public $detach(dictType?: DictType): Map<any, any> {
this.thread.luaApi.lua_rawgeti(this.thread.address, LUA_REGISTRYINDEX, this.ref);
let map = this.detachTable(-1);
this.thread.pop();
map = mapTransform(map, { dictType: dictType ?? DictType.Map }) as Map<any, any>;
return map;
}

public toString(): string {
return `[LuaTable *${this.ref} 0x${this.pointer.toString(16)}]`;
}

private getTableValue(key: any): any {
this.thread.luaApi.lua_rawgeti(this.thread.address, LUA_REGISTRYINDEX, this.ref);
this.thread.pushValue(key);
Expand All @@ -38,9 +66,13 @@ export class LuaTable {

private detachTable(index: number, refs?: Map<number, any>): Map<any, any> {
index = this.thread.luaApi.lua_absindex(this.thread.address, index);
if (!refs) refs = new Map();
if (!refs) {
refs = new Map();
}
const pointer = this.thread.luaApi.lua_topointer(this.thread.address, index);
if (refs.has(pointer)) return refs.get(pointer);
if (refs.has(pointer)) {
return refs.get(pointer);
}
const result = new Map();
refs.set(pointer, result);

Expand All @@ -53,39 +85,11 @@ export class LuaTable {
}
return result;
}

public $get(key: any): any {
return this.getTableValue(key);
}

public $set(key: any, value: any): boolean {
return this.setTableValue(key, value);
}

public $istable(): true {
return true;
}

public $getRef(): number {
return this.ref;
}

public $detach(dictType?: DictType): Map<any, any> {
this.thread.luaApi.lua_rawgeti(this.thread.address, LUA_REGISTRYINDEX, this.ref);
let map = this.detachTable(-1);
this.thread.pop();
map = mapTransform(map, { dictType: dictType ?? DictType.Map }) as Map<any, any>;
return map;
}

public toString(): string {
return `[LuaTable *${this.ref} 0x${this.pointer.toString(16)}]`;
}
}

export const getTable = (thread: LuaThread, index: number): LuaTable => {
// 根据内存地址,判断是否已经get过,如果有直接从引用表中返回
let pointer = thread.luaApi.lua_topointer(thread.address, index);
const pointer = thread.luaApi.lua_topointer(thread.address, index);
if (thread.luaApi.pointerRefs.has(pointer)) {
return thread.luaApi.pointerRefs.get(pointer).proxy;
}
Expand All @@ -97,9 +101,15 @@ export const getTable = (thread: LuaThread, index: number): LuaTable => {
const table = new LuaTable(thread, ref, pointer);
const { proxy, revoke } = Proxy.revocable(table, {
get: (target, key) => {
if (target[key]) return target[key];
if (key === Symbol.toStringTag) return () => 'LuaTable';
if (typeof key === 'symbol') return undefined;
if (target[key]) {
return target[key];
}
if (key === Symbol.toStringTag) {
return () => 'LuaTable';
}
if (typeof key === 'symbol') {
return undefined;
}
return target.$get(key);
},
set: (target, key, value) => target.$set(key, value),
Expand Down
8 changes: 3 additions & 5 deletions test/debug.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LUA_REGISTRYINDEX, Lua } from '../dist/index.js';
import { Lua } from '../dist/index.js';
// This file was created as a sandbox to test and debug on vscode

const lua = await Lua.create();
Expand All @@ -7,9 +7,7 @@ const obj = {};
lua.ctx.obj = obj;

const o = lua.ctx.obj;
o.name = 114514;
o.name = 23333;
console.log(o.name);

lua.doStringSync(`
print(obj.name)
`);
lua.doStringSync('print(obj.name)');

0 comments on commit 9651244

Please sign in to comment.