예제 #1
0
JSBool report_ruby_error_in_js(JohnsonRuntime* runtime, int state, VALUE old_errinfo)
{
  JSContext * context = johnson_get_current_context(runtime);
  assert(state);
  switch (state)
  {
    case TAG_RAISE:
      {
        VALUE local_error = ruby_errinfo;
        jsval js_err;
        ruby_errinfo = old_errinfo;
        if (!convert_to_js(runtime, local_error, &js_err))
          return JS_FALSE;
        JS_SetPendingException(context, js_err);
        return JS_FALSE;
      }

    case TAG_THROW:
      // FIXME: This should be propagated to JS... as an exception?

    default:
      {
        JSString* str = JS_NewStringCopyZ(context, "Unexpected longjmp from ruby!");
        if (str)
          JS_SetPendingException(context, STRING_TO_JSVAL(str));
        return JS_FALSE;
      }
  }
}
예제 #2
0
/*
 * call-seq:
 *   []=(name, value)
 *
 * Sets this JavaScript object's +name+ property to +value+.
 */
static VALUE
set(VALUE self, VALUE name, VALUE value)
{
  RubyLandProxy* proxy;
  Data_Get_Struct(self, RubyLandProxy, proxy);
  JSContext * context = johnson_get_current_context(proxy->runtime);
  
  PREPARE_RUBY_JROOTS(context, 2);
  
  jsval proxy_value;
  JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
  JROOT(proxy_value);

  jsval js_value;
  JCHECK(convert_to_js(proxy->runtime, value, &js_value));
  
  JROOT(js_value);

  switch(TYPE(name)) {
    case T_FIXNUM:
      JCHECK(JS_SetElement(context,
              JSVAL_TO_OBJECT(proxy_value), (jsint)(NUM2INT(name)), &js_value));
      break;
    case T_SYMBOL:
      name = RB_FUNCALL_0(name, RB_INTERN("to_s"));
    default:
      CALL_RUBY_WRAPPER(rb_string_value_cstr, &name);
      JCHECK(JS_SetProperty(context,
            JSVAL_TO_OBJECT(proxy_value), StringValueCStr(name), &js_value));
      break;
  }

  JRETURN_RUBY(value);
}
예제 #3
0
static VALUE call_js_function_value(JohnsonRuntime* runtime, jsval target, jsval function, int argc, VALUE* argv)
{
  JSContext * context = johnson_get_current_context(runtime);
  PREPARE_RUBY_JROOTS(context, argc + 2);

  JROOT(target);
  JROOT(function);

  assert(JSVAL_IS_OBJECT(target));

  jsval args[argc];
  jsval result;

  int i;
  for(i = 0; i < argc; ++i)
  {
    JCHECK(convert_to_js(runtime, argv[i], &(args[i])));
    JROOT(args[i]);
  }

  JCHECK(JS_CallFunctionValue(context,
    JSVAL_TO_OBJECT(target), function, (unsigned) argc, args, &result));

  JRETURN_RUBY(CONVERT_TO_RUBY(runtime, result));
}
예제 #4
0
/*
 * call-seq:
 *   native_call(this, *args)
 *
 * Call this Ruby Object as a function, with the given +this+ object and
 * arguments. Equivalent to the call method in JavaScript.
 */
static VALUE
native_call(int argc, VALUE* argv, VALUE self)
{
  if (!function_p(self))
    rb_raise(rb_eRuntimeError,
      "This Johnson::SpiderMonkey::RubyLandProxy isn't a function.");

  if (argc < 1)
    rb_raise(rb_eArgError, "Target object required");

  RubyLandProxy* proxy;
  Data_Get_Struct(self, RubyLandProxy, proxy);

  jsval proxy_value;

  if (!get_jsval_for_proxy(proxy, &proxy_value))
    raise_js_error_in_ruby(proxy->runtime);

  jsval global;

  if (!convert_to_js(proxy->runtime, argv[0], &global))
    raise_js_error_in_ruby(proxy->runtime);

  return call_js_function_value(proxy->runtime, global, proxy_value,
    argc - 1, &(argv[1]));
}
예제 #5
0
JSBool call_ruby_from_js(JohnsonRuntime* runtime, jsval* retval, VALUE self, ID id, int argc, ...)
{
  VALUE result;
  va_list va;
  va_start(va, argc);
  JSBool okay = call_ruby_from_js_va(runtime, &result, self, id, argc, va);
  va_end(va);
  if (!okay) return JS_FALSE;
  return retval ? convert_to_js(runtime, result, retval) : JS_TRUE;
}
예제 #6
0
파일: runtime.c 프로젝트: ripta/johnson
/*
 * call-seq:
 *   set_trap(script, parsecode, block)
 *
 * Set the trap at +script+ and +parsecode+ to +block+
 */
static VALUE set_trap(VALUE self, VALUE script, VALUE linenum, VALUE block)
{
  JohnsonRuntime* runtime;
  Data_Get_Struct(self, JohnsonRuntime, runtime);

  JSContext * context = johnson_get_current_context(runtime);
  jsval compiled_js;
  if(!convert_to_js(runtime, script, &compiled_js))
    rb_raise(rb_eRuntimeError, "Couldn't get compiled script.");
  JSScript * js_script = (JSScript *)JS_GetPrivate(context, JSVAL_TO_OBJECT(compiled_js));

  jsbytecode * pc = JS_LineNumberToPC(context, js_script, (uintN)NUM2INT(linenum));
  return JS_SetTrap(context, js_script, pc, trap_handler, (void*)block) ? Qtrue : Qfalse;
}
예제 #7
0
파일: runtime.c 프로젝트: ripta/johnson
/*
 * call-seq:
 *   evaluate_compiled_script(script)
 *
 * Evaluate +script+
 */
static VALUE evaluate_compiled_script(VALUE self, VALUE compiled_script)
{
  JohnsonRuntime* runtime;
  Data_Get_Struct(self, JohnsonRuntime, runtime);

  JSContext * context = johnson_get_current_context(runtime);
  JohnsonContext * johnson_context = OUR_CONTEXT(context);

  // clean things up first
  johnson_context->ex = 0;
  memset(johnson_context->msg, 0, MAX_EXCEPTION_MESSAGE_SIZE);

  jsval compiled_js;
  if(!convert_to_js(runtime, compiled_script, &compiled_js))
    rb_raise(rb_eRuntimeError, "Script compilation failed");

  JSScript * js_script = (JSScript *)JS_GetPrivate(context, JSVAL_TO_OBJECT(compiled_js));

  jsval js;
  JSBool ok = JS_ExecuteScript(context, runtime->global, js_script, &js);

  if (!ok)
  {
    if (JS_IsExceptionPending(context))
    {
      // If there's an exception pending here, it's a syntax error.
      JS_GetPendingException(context, &johnson_context->ex);
      JS_ClearPendingException(context);
    }

    if (johnson_context->ex) {
      RAISE_JS_ERROR(self, johnson_context->ex);
      return Qnil;
    }
  }

  return convert_to_ruby(runtime, js);
}
예제 #8
0
static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
{
  // pull out our Ruby context, which is embedded in js_context
  
  VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
  
  // get our struct, which is embedded in ruby_context
  
  JohnsonContext* context;
  JohnsonRuntime* runtime;
  Data_Get_Struct(ruby_context, JohnsonContext, context);

  VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context));
  Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime);

  PREPARE_JROOTS(js_context, 1);
  JROOT(id);
    
  // get the Ruby object that backs this proxy
  
  VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL);
  
  // Short-circuit for numeric indexes
  
  if (JSVAL_IS_INT(id))
  {
    if (indexable_p(self)) {
      VALUE idx = INT2FIX(JSVAL_TO_INT(id));
      JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("[]"), 1, idx));
    }
    
    JRETURN;
  }
  
  char* name = JS_GetStringBytes(JSVAL_TO_STRING(id));
  VALUE ruby_id = rb_intern(name);

  // FIXME: we should probably just JS_DefineProperty this, and it shouldn't be enumerable
  
  if (!strcasecmp("__iterator__", name)) {
    JCHECK(evaluate_js_property_expression(runtime, "Johnson.Generator.create", retval));
  }
  
  // if the Ruby object has a dynamic js property with a key
  // matching the property we're looking for, pull the value out of
  // that map.
  
  else if (autovivified_p(ruby_context, self, name))
  {
    JCHECK(call_ruby_from_js(runtime, retval, Johnson_SpiderMonkey_JSLandProxy(),
      rb_intern("autovivified"), 2, self, rb_str_new2(name)));
  }

  // if the Ruby object is a Module or Class and has a matching
  // const defined, return the converted result of const_get
  
  else if (const_p(self, name))
  {
    JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("const_get"),
      1, ID2SYM(ruby_id)));
  }  

  // otherwise, if it's a global, return the global
  else if (global_p(name))
  {
    JCHECK(convert_to_js(runtime, rb_gv_get(name), retval));
  }
  
  // otherwise, if the Ruby object has a an attribute method matching
  // the property we're trying to get, call it and return the converted result
  
  else if (attribute_p(self, name))
  {
    JCHECK(call_ruby_from_js(runtime, retval, self, ruby_id, 0));
  }

  // otherwise, if the Ruby object quacks sorta like a hash (it responds to
  // "[]" and "key?"), index it by key and return the converted result
  
  else if (has_key_p(self, name))
  {
    JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("[]"), 1, rb_str_new2(name)));
  }
  
  // otherwise, it's a method being accessed as a property, which means
  // we need to return a lambda
  
  // FIXME: this should really wrap the Method  for 'name' in a JS class
  // rather than generating a wrapper Proc
  
  else if (method_p(self, name))
  {
    JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("method"), 1, rb_str_new2(name)));
  }

  // else it's undefined (JS_VOID) by default
  JRETURN;
}