quickjs-rs icon indicating copy to clipboard operation
quickjs-rs copied to clipboard

Passing classes defined in JS back to JS result in a type TypeError

Open davebrent opened this issue 2 years ago • 1 comments

Hello I have code that looks like the following:

let context = Context::new().unwrap();

context.eval("
    class Foo {
        bar() {
            return 42;
        }
    }

    function setup() {
        return new Foo();
    }

    function update(foo) {
        return foo.bar();
    }
").unwrap();

let foo = context.call_function("setup", vec![JsValue::Undefined]).unwrap();
let bar = context.call_function("update", vec![foo]).unwrap();

eprintln!("{:?}", bar);

That I would expect to succeed and print 42 but fails with a TypeError: not a functionwhen calling .bar(), as if foo is just a regular object, not a class, in the second .call_function

What I think is the equivelant C version seems to work.

Am I using the API incorrectly?

C version
#include <stdio.h>
#include <string.h>
#include "quickjs.h"

int main() {
  JSRuntime *rt = JS_NewRuntime();
  JSContext *ctx = JS_NewContext(rt);

  char *const code = "\
    class Foo { \
      bar() { \
        return 42; \
      } \
    } \
    \
    function setup() { \
      return new Foo(); \
    } \
    \
    function update(foo) { \
      return foo.bar(); \
    }";

  if (JS_IsException(JS_Eval(ctx, code, strlen(code), "", JS_EVAL_FLAG_STRICT))) {
    JS_FreeContext(ctx);
    JS_FreeRuntime(rt);
    return -1;
  }

  JSValue global = JS_GetGlobalObject(ctx);
  JSValue setup = JS_GetPropertyStr(ctx, global, "setup");
  JSValue update = JS_GetPropertyStr(ctx, global, "update");

  JSValue foo = JS_Call(ctx, setup, global, 0, NULL);
  JSValue bar = JS_Call(ctx, update, global, 1, &foo);

  int32_t result;
  JS_ToInt32(ctx, &result, bar);
  printf("%d\n", result);

  JS_FreeValue(ctx, foo);
  JS_FreeValue(ctx, bar);

  JS_FreeValue(ctx, update);
  JS_FreeValue(ctx, setup);
  JS_FreeValue(ctx, global);

  JS_FreeContext(ctx);
  JS_FreeRuntime(rt);
  return 0;
}

davebrent avatar Aug 30 '21 21:08 davebrent

Hmm it seems when you call setup the returned JSValue is actualy serialized to a JSValue::Object which is a HashMap<String, JSValue> and not a pointer to your instance of Foo

You need to call the raw invoke_function api's instead

andrieshiemstra avatar Aug 31 '21 07:08 andrieshiemstra