user2084865
user2084865

Reputation: 697

SpiderMonkey 24: How to call Reflect.parse()?

According to the Parser API you can call Reflect.parse() to get an AST back. Unfortunately, when trying to evaluate a script in C++ it gives me an error saying ReferenceError: Reflect is not defined:

const char *script = "var r = Reflect.parse(\"obj.foo + 42\");";
bool ok = JS_EvaluateScript(cx, global, script, strlen(script), filename, lineno, rval.address());

Actually, I want to parse some simple JS Scripts and get the AST within C++, I don't like the way doing a detour and having it analyzed in JS itself. Do you have any suggestions? The documentation is not very good imho.

I tried using JS_CompileScript(), but it seems like 1) the members of JSScript class are not visible when using the compiled lib 2) don't have information about the tree anymore (?).

I'm tempted to use the very old version 1.6 as there is a very nice parsing tutorial out there. What are your thoughts about that?

Another way would be not to compile SpiderMonkey and use the Parser classes directly.

Any hints/suggestions in what the best way (in your opinion) would be are highly appreciated. Thank you :)

Upvotes: 1

Views: 495

Answers (1)

Tanuva
Tanuva

Reputation: 151

Actually, I want to parse some simple JS Scripts and get the AST within C++, I don't like the way doing a detour and having it analyzed in JS itself. Do you have any suggestions?

If patching the Monkey is (was) an option for you, I have a possible approach. I'm doing this with SpiderMonkey 45, but the Reflect API already existed in 24.

In ReflectParse.cpp:3593, there's the function

static bool reflect_parse(JSContext* cx, uint32_t argc, Value* vp)

Make that non-static and declare it in jsapi.h like this:

extern JS_PUBLIC_API(bool) reflect_parse(JSContext* cx, uint32_t argc, JS::Value* vp);

Actually, this is copy/paste from the JS_InitReflectParse declaration in said file. Now you can call the C implementation of Reflect.parse() from outside.

You'll also need a bunch of private headers, I currently include these: builtin/ModuleObject.h, jscntxt.h, jscompartment.h, jsobj.h, frontend/ParseNode.h

The Value* vp that reflect_parse expects as second parameter is a JS::AutoValueArray<3> constructed as follows:

  • Index 0 will later hold a JSValue to the returned object. CallArgs::rval() retrieves it from there.
  • Index 1 holds some kind of a magic number. Don't touch. (Setting it to something resulted in an assertion for me.)
  • Index 2 holds another JS::AutoValueArray<n> that contains the parameters for Reflect.parse.

So for a simple call like Reflect.parse(code), the parameters can look like this:

JS::RootedString codeJsStr(context); // Empty string for now
JS::AutoValueArray<1> parseParams(context);
parseParams[0].setString(codeJsStr);
JS::AutoValueArray<3> vp(m_context);
vp[2].set(*parseParams.begin());
reflect_parse(m_context, parseParams.length(), vp.begin());

The return value can then be processed with help of CallArgs just like it is documented for calling js functions from C.

Upvotes: 3

Related Questions