Fengari <=> JS Interop
Switch branches/tags
Clone or download
Latest commit 8e59efb Apr 22, 2018

README.md

Build Status License: MIT #fengari on Freenode

JS library for Fengari

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

Features

  • Call any JS function from Lua
  • Give Lua tables/functions/userdata to Javascript

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":

  • "function":
    • typeof p === "function"
    • Can be used as a constructor
  • "arrow_function":
    • typeof p === "function"
    • Can not be used as a constructor
  • "object":
    • typeof p === "object"
    • Can not be used as a constructor

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.

  • nil is returned as undefined
  • booleans are returned as booleans
  • numbers are returned as numbers
  • strings are returned as JavaScript strings (Note: this can throw an error if the lua string is not represenable as a JavaScript string)
  • JavaScript userdata object (as pushed by push or pushjs) returns the pushed JavaScript object
  • Other objects are returned wrapped in a JavaScript function object with methods:
    • apply(this, [args...]): calls the lua object. Returns only the first return value
    • invoke(this, [args...]): calls the lua object. Returns results as an array
    • get(key): indexes the lua object
    • has(key): checks if indexing the lua object results in nil
    • set(key, value)
    • delete(key): sets the key to nil
    • toString() JavaScript arguments to these methods are passed in via push() and results are returned via tojs(). Calling the function is equivalent to calling the lua function wrapped.

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.