Detecting emscripten-based interpreters at runtime

Is there a reliable way to detect if the interpreter a T3 game is running in is using emscripten/wasm under the hood?

Reason I ask is that after mentioning it in another thread I decided to clean up the simple interactive debugger code I wrote…only to discover that the runtime compiler behaves differently in interpreters that go through wasm.

Specifically, frobTADS and gargoyle, for example are happy to evaluate an expression like widget.propName = value, but e.g. emglken chucks a wobby if the expression isn’t wrapped in something like function() { widget.propName = value; }.

1 Like

There shouldn’t be any substantial difference between TADS in Gargoyle and in Emglken/Parchment.

I have no idea what could be making a difference like that. Does Emglken display any errors?

It does:

Unhandled Rejection: RuntimeError: null function or function signature mismatch
    at CTcPrsOpUnary::parse_primary() (wasm://wasm/00c279c2:wasm-function[856]:0x128ab2)
    at CTcPrsOpUnary::parse_postfix(int, int) (wasm://wasm/00c279c2:wasm-function[857]:0x12b409)
    at CTcPrsOpUnary::parse() const (wasm://wasm/00c279c2:wasm-function[2302]:0x260c53)
    at CTcPrsOpBinGroup::parse() const (wasm://wasm/00c279c2:wasm-function[2332]:0x26396a)
    at CTcPrsOpBinGroup::parse() const (wasm://wasm/00c279c2:wasm-function[2332]:0x26396a)
    at CTcPrsOpBinGroup::parse() const (wasm://wasm/00c279c2:wasm-function[2332]:0x26396a)
    at CTcPrsOpBinGroup::parse() const (wasm://wasm/00c279c2:wasm-function[2332]:0x26396a)
    at CTcPrsOpBinGroupCompare::parse() const (wasm://wasm/00c279c2:wasm-function[2331]:0x263124)
    at CTcPrsOpBin::parse() const (wasm://wasm/00c279c2:wasm-function[553]:0xab97c)
    at CTcPrsOpBin::parse() const (wasm://wasm/00c279c2:wasm-function[553]:0xab97c)

Simple test code to reproduce:

#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>
#include <dynfunc.h>

foo: object prop = 0;
versionInfo: GameID;
gameMain: GameMainDef
        newGame() {
                local fn, r, txt;

                txt = 'foo.prop = 1';
                try {
                        fn = Compiler.compile(txt);
                        r = fn();
                }
                catch(Exception e) {
                        e.displayException();
                }
                "\n<<toString(r)>>\n ";
        }
;

“Transcript” of frob game.t3 (same output in gargoyle):

1
[Hit any key to exit.]

emglken game.t3 produces the errors quoted above.

Could you attach the game.t3 here?

Not sure; never tried to attach a .t3 to a post. Let’s see:
game.t3 (843.9 KB)

See if that works.

And to be clear there’s a workaround: just wrap the expression in a function() { }. So:

#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>
#include <dynfunc.h>

foo: object prop = 0;
versionInfo: GameID;
gameMain: GameMainDef
        newGame() {
                local fn, r, txt;

                txt = 'foo.prop = 1';
                txt = 'function() { return(' + txt + '); }';
                try {
                        fn = Compiler.compile(txt);
                        r = fn();
                }
                catch(Exception e) {
                        e.displayException();
                }
                "\n<<toString(r)>>\n ";
        }
;

Works fine. But this is not supposed to be required. Or at least not according to the comments in dynfunc.t for the Compiler class, which explicitly say that the string passed to Compiler.compile() can be either an entire function declaration or a bare expression.

I think this error is beyond me, but I’ve raised a bug report for it:

I was able to work it out, and just published Emglken v0.5.1 with the fix.

2 Likes

Oh that’s nice that you fixed an error that seemed too hard at first!

1 Like

Awesome.

This now-fixed problem aside, is there any way of detecting emscripten interpreters at runtime? I got started thinking about it because the issue with compiling expressions, but I’m also sorta casting around for some way to do interpreter capability testing at runtime.

T3 provides some rudimentary capability testing via systemInfo(), but it actually provides very little information.

Sorry, I’m not really sure if there is a way.