fengari-lua / fengari-interop

Fengari <=> JS Interop
MIT License
98 stars 13 forks source link
fengari javascript js lua

Build Status npm License: MIT #fengari on libera.chat

JS library for Fengari

Fengari is a lua VM written in Javascript. Its implementation makes use of the JS garbage collector, which means it is fully capable of cross language interop.

Features

js library

js = require "js"

null

A userdata representing JavaScript null

global

A reference to the JavaScript global context. In the browser, this is usually equivalent to the window object. In node.js it's equal to global.

new(constructor, ...)

Invokes the JavaScript new operator on constructor passing the arguments specified.

Returns the created object.

of(iterable)

Returns a iterating function and an iterator state that behave like a JavaScript for...of loop. Suitable for use as a lua iterator. e.g.

for f in js.of(js.global:Array(10,20,30)) do
    print(f)
end

Note: this function only exists if the JavaScript runtime supports Symbols

createproxy(x[, type])

Note: Only available if your JS environment has the Proxy constructor

Creates a JavaScript Proxy object. The proxy supports configuring traps by setting them as metamethods on your object.

type may be "function" (the default) "arrow_function" or "object":

Note that JavaScript coerces all types except Symbols to strings before using them as a key in an indexing operation.

tonumber(x)

Coerces the value x to a number using JavaScript coercion rules.

tostring(x)

Coerces the value x to a string using JavaScript coercion rules.

instanceof(x, y)

Returns if the value x is an instance of the class y via use of the JavaScript instanceof operator

typeof(x)

Returns what JavaScript sees as the type of x. Uses the JavaScript typeof operator

JavaScript API

push(L, value)

Pushes an arbitrary JavaScript object value as the most suitable lua type onto the lua stack L. Performs deduplication so that the same JavaScript objects are pushed as the same lua objects.

pushjs(L, value)

Pushes an arbitrary JavaScript object value as a userdata onto the lua stack L. Rarely used; see push(L, value) instead.

checkjs(L, idx)

If the value on the lua stack L at index idx is a JavaScript userdata object (as pushed by push or pushjs) then return it. Otherwise throw an error.

testjs(L, idx)

If the value on the lua stack L at index idx is a JavaScript userdata object (as pushed by push or pushjs) then return it. Otherwise returns undefined.

tojs(L, idx)

Returns the object on the lua stack L at index idx as the most suitable javascript type.

luaopen_js

The entrypoint for loading the js library into a fengari lua_State. Usually passed to luaL_requiref.

Symbols

If the JavaScript environment supports Symbols, then some runtime-wide symbols can be used to customise behaviour:

__pairs

The __pairs Symbol can be used to describe how to iterate over a JavaScript object. Use Symbol.for("__pairs") to get the symbol. It should be used as a key on your objects, where the value is a function returning an object with three properties: "iter", "state" and "first".

"iter" should be a function that follows the standard Lua generic for protocol, that is, it gets called with your state (as this) and the previous value produced; it should return an array of values or undefined if done.

e.g. to make pairs on a Map return entries in the map via the iterator symbol:

Map.prototype[Symbol.for("__pairs")] = function() {
    return {
        iter: function(last) {
            var v = this.next();
            if (v.done) return;
            return v.value;
        },
        state: this[Symbol.iterator]()
    };
};

If there is no __pairs Symbol attached to an object, an iterator over Object.keys is returned.

__len

The __len Symbol can be used to describe how to get the length (used by the lua # operator) of a JavaScript object. Use Symbol.for("__len") to get the symbol. It should be used as a key on your objects, where the value is a function returning the length of your objects (passed as this).

e.g. to have the lua # operator applied to a Map return the size field:

Map.prototype[Symbol.for("__len")] = function() {
    return this.size;
};

If there is no __len Symbol attached to an object, the value of the .length property is returned.