Recognizing JavaScript functions with GJS (Spidermonkey 1.7)

574 views Asked by At

I am playing around Christian Hergert GtkBuilder + Inline JavaScript and I write a Glade plugin to edit JavaScript code. Here is an screenshot:


(source: googlecode.com)

I want to recognize the functions of an JavaScript with GJS (Spidermonker 1.7 GObject binding). The main idea is separate the script in functions to create an source code editor like this (like Visual Basic):


(source: googlecode.com)

I don't want evaluate the script, then and try the follow test code:

#include <gjs/gjs-module.h>
#include <gjs/gjs.h>
#include <string.h>
#include <stdio.h>

const char *script = 
    "const Gtk = imports.gi.Gtk;"
    ""
    "function onClicked(widget, data) {"
    "  let w = new Gtk.Window();"
    "  w.set_default_size(320, 240);"
    "  let l = new Gtk.Label();"
    "  l.set_text('You clicked on ' + widget.get_label());"
    "  w.add(l);"
    "  w.show_all();"
    "}"
    ""
    "var onQuit = function() {"
    "  Gtk.main_quit();"
    "}";

int
main (int argc, char *artv[])
{
  GjsContext *context;
  JSContext *native;
  JSScript *compiled;
  JSObject *object;
  JSObject *global;
  JSObject *callable = NULL;
  JSIdArray *array;
  JSBool status;
  jsval val = { 0 };
  int i;

  context = gjs_context_new();

  native = gjs_context_get_native_context(context);

  JS_BeginRequest(native);

  global = gjs_get_import_global(native);

  compiled = JS_CompileScript(native, global, script, strlen(script), "__test__", 0);

  if (compiled == NULL)
  {
    printf("error\n");
  }

  object =  JS_GetGlobalFromScript(compiled);

  array = JS_Enumerate(native, global);

  for (i = 0; i < JS_IdArrayLength(native, array); i++)
  {
    status = JS_GetPropertyById(native, object, JS_IdArrayGet(native, array, i), &val);

    callable = JSVAL_TO_OBJECT(val);

    if (JS_ObjectIsFunction(native, callable))
    {
      JSString *str = JS_ValueToString(native, val);
      printf("%s\n", JS_EncodeString(native, str));
      printf("%d, %p\n", status, callable);
    }
  }

  JS_EndRequest(native);

  return 0;
}

I need to get onClicked and onClick but I get:

function log() {
    [native code]
}
1, 0xb4c186c0
function logError() {
    [native code]
}
1, 0xb4c186e0
function print() {
    [native code]
}
1, 0xb4c18700
function printerr() {
    [native code]
}
1, 0xb4c18720

These functions are internally created by GJS, but my functions? What are wrong? Is possible get the functions with SpiderMonkey 1.7? If is possible, how to I can get the body (code) of each function? I need to implement my own JS parser?

Thanks in advance.

Finally, I resolve this using Reflect from Spidermonkey:

const Gio = imports.gi.Gio;
const Mainloop = imports.mainloop;

function load (filename)
{
  var file = Gio.file_new_for_path(filename);
  var contents;

  file.load_contents_async(null, function(file, result)
  {
    try
    {
      contents = file.load_contents_finish(result)[1];
    }
    catch (exception)
    {
      printerr(exception.message);
      Mainloop.quit('');

      return null;
    }
    Mainloop.quit('');

    return null; /* to avoid warning */
  });

  Mainloop.run('');

  return contents;
}

function print_function_info (node)
{
  print('function ' + node.id.name + ' at ' +
    node.loc.start.line + ':' + node.loc.start.column + '-' +
        node.loc.end.line + ':' + node.loc.end.column);
}

function parse_source (source)
{
  var reflect = Reflect.parse(load(ARGV[0]));

  for (var element in reflect.body)
  {
    var node = reflect.body[element];

    if (node.type == 'VariableDeclaration')
    {
      for (element in node.declarations)
      {
        var declaration = node.declarations[element];

        if (declaration.init.type == 'FunctionExpression')
        {
          print_function_info(declaration);
        }
      }
    }
    else if (node.type == 'FunctionDeclaration')
    {
      print_function_info(node);
    }
  }
}

function parse_file (file)
{
  parse_source(load(file));
}

function main ()
{
  if (ARGV.length != 1)
  {
    printerr("Usage: introspect.js filename");
  }
  else
  {
    parse_file(ARGV[0]);
  }
}

main ();
0

There are 0 answers