Skip to content
This repository has been archived by the owner on Aug 18, 2018. It is now read-only.

Commit

Permalink
Merge from remote
Browse files Browse the repository at this point in the history
  • Loading branch information
wycats committed Apr 21, 2008
2 parents a271005 + 2574fe0 commit d8845f6
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 160 deletions.
6 changes: 2 additions & 4 deletions Manifest.txt
Expand Up @@ -15,16 +15,14 @@ ext/spidermonkey/idhash.h
ext/spidermonkey/immutable_node.c
ext/spidermonkey/immutable_node.c.erb
ext/spidermonkey/immutable_node.h
ext/spidermonkey/js_function_proxy.c
ext/spidermonkey/js_function_proxy.h
ext/spidermonkey/js_land_proxy.c
ext/spidermonkey/js_land_proxy.h
ext/spidermonkey/ruby_land_proxy.c
ext/spidermonkey/ruby_land_proxy.h
ext/spidermonkey/spidermonkey.c
ext/spidermonkey/spidermonkey.h
js/prelude.js
js/template.js
js/johnson/prelude.js
js/johnson/template.js
lib/johnson.rb
lib/johnson/cli/options.rb
lib/johnson/context.rb
Expand Down
17 changes: 4 additions & 13 deletions ext/spidermonkey/conversions.c
@@ -1,6 +1,5 @@
#include "conversions.h"
#include "js_land_proxy.h"
#include "js_function_proxy.h"
#include "ruby_land_proxy.h"

static jsval convert_float_or_bignum_to_js(OurContext* context, VALUE float_or_bignum)
Expand Down Expand Up @@ -79,11 +78,8 @@ jsval convert_to_js(OurContext* context, VALUE ruby)
if (ruby_value_is_proxy(ruby))
return unwrap_ruby_land_proxy(context, ruby);

if (rb_cProc == CLASS_OF(ruby))
return make_js_function_proxy(context, ruby);

// UNIMPLEMENTED BELOW THIS LINE

if (rb_cProc == rb_class_of(ruby) || rb_cMethod == rb_class_of(ruby))
return make_js_land_proxy(context, ruby);

default:
Johnson_Error_raise("unknown ruby type in switch");
Expand All @@ -92,7 +88,7 @@ jsval convert_to_js(OurContext* context, VALUE ruby)
return JSVAL_NULL;
}

static VALUE make_ruby_regexp(OurContext* context, jsval regexp)
static VALUE convert_regexp_to_ruby(OurContext* context, jsval regexp)
{
JSRegExp* re = (JSRegExp*)JS_GetPrivate(context->js, JSVAL_TO_OBJECT(regexp));

Expand Down Expand Up @@ -132,11 +128,6 @@ VALUE convert_to_ruby(OurContext* context, jsval js)
return Qnil;

case JSTYPE_FUNCTION:
if (js_value_is_function_proxy(context, js))
return unwrap_js_function_proxy(context, js);

// NOTE: intentional fall-through to JSTYPE_OBJECT

case JSTYPE_OBJECT:
if (OBJECT_TO_JSVAL(context->global) == js)
// global gets special treatment, since the Prelude might not be loaded
Expand All @@ -150,7 +141,7 @@ VALUE convert_to_ruby(OurContext* context, jsval js)
return unwrap_js_land_proxy(context, js);

if (js_value_is_regexp(context, js))
return make_ruby_regexp(context, js);
return convert_regexp_to_ruby(context, js);

return make_ruby_land_proxy(context, js);

Expand Down
90 changes: 0 additions & 90 deletions ext/spidermonkey/js_function_proxy.c

This file was deleted.

15 changes: 0 additions & 15 deletions ext/spidermonkey/js_function_proxy.h

This file was deleted.

78 changes: 67 additions & 11 deletions ext/spidermonkey/js_land_proxy.c
Expand Up @@ -4,6 +4,7 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
static JSBool set(JSContext* context, JSObject* obj, jsval id, jsval* retval);
static JSBool construct(JSContext* js_context, JSObject* obj, uintN argc, jsval* argv, jsval* retval);
static JSBool resolve(JSContext *js_context, JSObject *obj, jsval id, uintN flags, JSObject **objp);
static JSBool call(JSContext* js_context, JSObject* obj, uintN argc, jsval* argv, jsval* retval);
static void finalize(JSContext* context, JSObject* obj);

static JSClass JSLandProxyClass = {
Expand Down Expand Up @@ -34,6 +35,21 @@ static JSClass JSLandClassProxyClass = {
construct
};

static JSClass JSLandCallableProxyClass = {
"JSLandCallableProxy", JSCLASS_HAS_PRIVATE,
JS_PropertyStub,
JS_PropertyStub,
JS_PropertyStub,
JS_PropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
finalize,
NULL,
NULL,
call
};

static JSBool autovivified_p(VALUE ruby_context, VALUE self, char* name)
{
return rb_funcall(Johnson_SpiderMonkey_JSLandProxy(), rb_intern("autovivified?"), 2,
Expand Down Expand Up @@ -107,6 +123,14 @@ static JSBool respond_to_p(JSContext* js_context, JSObject* obj, char* name)
|| has_key_p(self, name);
}

static jsval evaluate_js_property_expression(OurContext * context, char * property) {
jsval retval;
JSBool ok = JS_EvaluateScript(context->js, context->global,
property, strlen(property), NULL, 1,
&retval);
return retval;
}

static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
{
// pull out our Ruby context, which is embedded in js_context
Expand Down Expand Up @@ -135,19 +159,13 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
return JS_TRUE;
}

// Trying to call JS_GetStringBytes on a non-string causes a segfault
char* name = JS_GetStringBytes(JSVAL_TO_STRING(id));
VALUE ruby_id = rb_intern(name);

// FIXME: this is necessarily ugly. Maybe we should write something like
// jsval foo = property_expression(context->js, context->global, "Johnson.Generator.create")
// this would make the code where we look up Johnson.Symbol cleaner too (in conversions.c)

// FIXME: we should probably just JS_DefineProperty this, and it shouldn't be enumerable

if (!strcasecmp("__iterator__", name)) {
JS_EvaluateScript(context->js, context->global, "Johnson.Generator.create",
24, "js_land_proxy.c", 149, retval);
*retval = evaluate_js_property_expression(context, "Johnson.Generator.create");
return JS_TRUE;
}

Expand Down Expand Up @@ -197,11 +215,13 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
// 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))
{
*retval = convert_to_js(context,
rb_funcall(Johnson_SpiderMonkey_JSLandProxy(), rb_intern("wrap"),
2, self, rb_str_new2(name)));
rb_funcall(self, rb_intern("method"), 1, rb_str_new2(name)));
}

// else it's undefined (JS_VOID) by default
Expand Down Expand Up @@ -343,10 +363,37 @@ static JSBool method_missing(JSContext* js_context, JSObject* obj, uintN argc, j
return JS_TRUE;
}

static JSBool call(JSContext* js_context, JSObject* obj, uintN argc, jsval* argv, jsval* retval)
{
VALUE ruby_context;
assert(ruby_context = (VALUE)JS_GetContextPrivate(js_context));

OurContext* context;
Data_Get_Struct(ruby_context, OurContext, context);

VALUE self;// = convert_to_ruby(context, JS_ARGV_CALLEE(argv));
assert(self = (VALUE)JS_GetInstancePrivate(context->js, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), &JSLandCallableProxyClass, NULL));

VALUE args = rb_ary_new();
int i;

for (i = 0; i < argc; ++i)
rb_ary_push(args, convert_to_ruby(context, argv[i]));

*retval = convert_to_js(context,
rb_funcall(Johnson_SpiderMonkey_JSLandProxy(), rb_intern("send_with_possible_block"),
3, self, ID2SYM(rb_intern("call")), args));

return JS_TRUE;
}

JSBool js_value_is_proxy(OurContext* context, jsval maybe_proxy)
{
JSClass* klass = JS_GET_CLASS(context->js, JSVAL_TO_OBJECT(maybe_proxy));
return &JSLandProxyClass == klass || &JSLandClassProxyClass == klass;

return &JSLandProxyClass == klass
|| &JSLandClassProxyClass == klass
|| &JSLandCallableProxyClass == klass;
}

VALUE unwrap_js_land_proxy(OurContext* context, jsval proxy)
Expand Down Expand Up @@ -397,14 +444,23 @@ jsval make_js_land_proxy(OurContext* context, VALUE value)
JSClass *klass = &JSLandProxyClass;
if (T_CLASS == TYPE(value)) klass = &JSLandClassProxyClass;

// FIXME: hack; should happen in Rubyland
if (T_STRUCT == TYPE(value))
rb_funcall(Johnson_SpiderMonkey_JSLandProxy(),
rb_intern("treat_all_properties_as_methods"), 1, value);

JSBool callable_p = rb_class_of(value) == rb_cMethod
|| rb_class_of(value) == rb_cProc;

if (callable_p)
klass = &JSLandCallableProxyClass;

assert(jsobj = JS_NewObject(context->js, klass, NULL, NULL));
assert(JS_SetPrivate(context->js, jsobj, (void*)value));

assert(JS_DefineFunction(context->js, jsobj, "__noSuchMethod__", method_missing, 2, 0));
if (!callable_p)
assert(JS_DefineFunction(context->js, jsobj,
"__noSuchMethod__", method_missing, 2, 0));

js = OBJECT_TO_JSVAL(jsobj);

Expand Down
17 changes: 12 additions & 5 deletions js/prelude.js → js/johnson/prelude.js
Expand Up @@ -41,16 +41,23 @@ Johnson.Generator.create = function() {
Johnson.required = {};

Johnson.require = function(file) {
file = Ruby.File.join(Ruby.File.dirname(file),
Ruby.File.basename(file, ".js") + ".js");

if(Johnson.required[file]) return false;
for(var directory in Ruby['$LOAD_PATH']) {
var filename = directory + "/" + Ruby.File.basename(file, ".js") + ".js";
if(Ruby.File['exists?'](filename)) {

for(var directory in Ruby["$LOAD_PATH"]) {
var path = Ruby.File.join(directory, file);

if(Ruby.File.send("file?", path)) {
Johnson.required[file] = true;
eval(Ruby.File.read(filename));
eval(Ruby.File.read(path));

return true;
}
}
throw FileNotFound;

throw LoadError;
}

null; // no need to marshal a result
File renamed without changes.
4 changes: 2 additions & 2 deletions lib/johnson.rb
Expand Up @@ -25,10 +25,10 @@
require "johnson/context"
require "johnson/parser"

$LOAD_PATH.push File.expand_path("#{File.dirname(__FILE__)}/../js")
$LOAD_PATH.push(File.expand_path("#{File.dirname(__FILE__)}/../js"))

module Johnson
PRELUDE = IO.read(File.dirname(__FILE__) + "/../js/prelude.js")
PRELUDE = IO.read(File.dirname(__FILE__) + "/../js/johnson/prelude.js")

def self.evaluate(expression, vars={})
context = Johnson::Context.new
Expand Down
4 changes: 0 additions & 4 deletions lib/johnson/spidermonkey/js_land_proxy.rb
@@ -1,10 +1,6 @@
module Johnson
module SpiderMonkey
module JSLandProxy #:nodoc:
def self.wrap(target, name)
Proc.new { |*args| send_with_possible_block(target, name, args) }
end

def self.send_with_possible_block(target, symbol, args)
block = args.pop if args.last.is_a?(RubyLandProxy) && args.last.function?
target.__send__(symbol, *args, &block)
Expand Down
2 changes: 1 addition & 1 deletion test/johnson/conversions/proc_test.rb
Expand Up @@ -20,7 +20,7 @@ def test_procs_roundtrip
def test_proc_js_function_proxy_gets_reused
@context[:k] = k = lambda { |x| x }
@context[:kk] = k
assert_js("k == kk")
assert_js("k === kk")
end
end
end
Expand Down

0 comments on commit d8845f6

Please sign in to comment.