jbarnette-johnson 1.0.0.200806240111

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. data/CHANGELOG +5 -0
  2. data/MANIFEST +385 -0
  3. data/MINGW32.mk +124 -0
  4. data/README.rdoc +51 -0
  5. data/Rakefile +166 -0
  6. data/bin/johnson +107 -0
  7. data/cross-compile.txt +38 -0
  8. data/ext/spidermonkey/context.c +122 -0
  9. data/ext/spidermonkey/context.h +19 -0
  10. data/ext/spidermonkey/conversions.c +286 -0
  11. data/ext/spidermonkey/conversions.h +18 -0
  12. data/ext/spidermonkey/debugger.c +208 -0
  13. data/ext/spidermonkey/debugger.h +9 -0
  14. data/ext/spidermonkey/extconf.rb +25 -0
  15. data/ext/spidermonkey/extensions.c +37 -0
  16. data/ext/spidermonkey/extensions.h +12 -0
  17. data/ext/spidermonkey/global.c +40 -0
  18. data/ext/spidermonkey/global.h +11 -0
  19. data/ext/spidermonkey/idhash.c +16 -0
  20. data/ext/spidermonkey/idhash.h +8 -0
  21. data/ext/spidermonkey/immutable_node.c.erb +522 -0
  22. data/ext/spidermonkey/immutable_node.h +22 -0
  23. data/ext/spidermonkey/jroot.h +187 -0
  24. data/ext/spidermonkey/js_land_proxy.c +609 -0
  25. data/ext/spidermonkey/js_land_proxy.h +20 -0
  26. data/ext/spidermonkey/ruby_land_proxy.c +537 -0
  27. data/ext/spidermonkey/ruby_land_proxy.h +17 -0
  28. data/ext/spidermonkey/runtime.c +304 -0
  29. data/ext/spidermonkey/runtime.h +25 -0
  30. data/ext/spidermonkey/spidermonkey.c +20 -0
  31. data/ext/spidermonkey/spidermonkey.h +29 -0
  32. data/js/johnson/browser.js +9 -0
  33. data/js/johnson/browser/env.js +687 -0
  34. data/js/johnson/browser/jquery.js +3444 -0
  35. data/js/johnson/browser/xmlsax.js +1564 -0
  36. data/js/johnson/browser/xmlw3cdom.js +4189 -0
  37. data/js/johnson/cli.js +30 -0
  38. data/js/johnson/prelude.js +80 -0
  39. data/js/johnson/template.js +29 -0
  40. data/lib/hoe.rb +748 -0
  41. data/lib/johnson.rb +46 -0
  42. data/lib/johnson/cli.rb +7 -0
  43. data/lib/johnson/cli/options.rb +56 -0
  44. data/lib/johnson/error.rb +4 -0
  45. data/lib/johnson/nodes.rb +7 -0
  46. data/lib/johnson/nodes/binary_node.rb +64 -0
  47. data/lib/johnson/nodes/for.rb +14 -0
  48. data/lib/johnson/nodes/for_in.rb +12 -0
  49. data/lib/johnson/nodes/function.rb +13 -0
  50. data/lib/johnson/nodes/list.rb +27 -0
  51. data/lib/johnson/nodes/node.rb +68 -0
  52. data/lib/johnson/nodes/ternary_node.rb +20 -0
  53. data/lib/johnson/parser.rb +21 -0
  54. data/lib/johnson/parser/syntax_error.rb +13 -0
  55. data/lib/johnson/runtime.rb +55 -0
  56. data/lib/johnson/spidermonkey/context.rb +10 -0
  57. data/lib/johnson/spidermonkey/debugger.rb +67 -0
  58. data/lib/johnson/spidermonkey/immutable_node.rb +280 -0
  59. data/lib/johnson/spidermonkey/js_land_proxy.rb +62 -0
  60. data/lib/johnson/spidermonkey/mutable_tree_visitor.rb +233 -0
  61. data/lib/johnson/spidermonkey/ruby_land_proxy.rb +52 -0
  62. data/lib/johnson/spidermonkey/runtime.rb +94 -0
  63. data/lib/johnson/version.rb +4 -0
  64. data/lib/johnson/visitable.rb +16 -0
  65. data/lib/johnson/visitors.rb +4 -0
  66. data/lib/johnson/visitors/dot_visitor.rb +167 -0
  67. data/lib/johnson/visitors/ecma_visitor.rb +315 -0
  68. data/lib/johnson/visitors/enumerating_visitor.rb +115 -0
  69. data/lib/johnson/visitors/sexp_visitor.rb +172 -0
  70. data/lib/rails/init.rb +37 -0
  71. data/test/assets/index.html +38 -0
  72. data/test/assets/jquery_test.html +186 -0
  73. data/test/helper.rb +58 -0
  74. data/test/johnson/browser_test.rb +38 -0
  75. data/test/johnson/conversions/array_test.rb +32 -0
  76. data/test/johnson/conversions/boolean_test.rb +17 -0
  77. data/test/johnson/conversions/callable_test.rb +34 -0
  78. data/test/johnson/conversions/file_test.rb +15 -0
  79. data/test/johnson/conversions/nil_test.rb +20 -0
  80. data/test/johnson/conversions/number_test.rb +34 -0
  81. data/test/johnson/conversions/regexp_test.rb +24 -0
  82. data/test/johnson/conversions/string_test.rb +26 -0
  83. data/test/johnson/conversions/struct_test.rb +15 -0
  84. data/test/johnson/conversions/symbol_test.rb +19 -0
  85. data/test/johnson/conversions/thread_test.rb +24 -0
  86. data/test/johnson/error_test.rb +9 -0
  87. data/test/johnson/extensions_test.rb +56 -0
  88. data/test/johnson/nodes/array_literal_test.rb +57 -0
  89. data/test/johnson/nodes/array_node_test.rb +26 -0
  90. data/test/johnson/nodes/binary_node_test.rb +61 -0
  91. data/test/johnson/nodes/bracket_access_test.rb +16 -0
  92. data/test/johnson/nodes/delete_test.rb +11 -0
  93. data/test/johnson/nodes/do_while_test.rb +12 -0
  94. data/test/johnson/nodes/dot_accessor_test.rb +15 -0
  95. data/test/johnson/nodes/export_test.rb +9 -0
  96. data/test/johnson/nodes/for_test.rb +54 -0
  97. data/test/johnson/nodes/function_test.rb +71 -0
  98. data/test/johnson/nodes/if_test.rb +41 -0
  99. data/test/johnson/nodes/import_test.rb +13 -0
  100. data/test/johnson/nodes/label_test.rb +19 -0
  101. data/test/johnson/nodes/object_literal_test.rb +110 -0
  102. data/test/johnson/nodes/return_test.rb +16 -0
  103. data/test/johnson/nodes/semi_test.rb +8 -0
  104. data/test/johnson/nodes/switch_test.rb +55 -0
  105. data/test/johnson/nodes/ternary_test.rb +25 -0
  106. data/test/johnson/nodes/throw_test.rb +9 -0
  107. data/test/johnson/nodes/try_node_test.rb +59 -0
  108. data/test/johnson/nodes/typeof_test.rb +11 -0
  109. data/test/johnson/nodes/unary_node_test.rb +23 -0
  110. data/test/johnson/nodes/void_test.rb +11 -0
  111. data/test/johnson/nodes/while_test.rb +26 -0
  112. data/test/johnson/nodes/with_test.rb +10 -0
  113. data/test/johnson/prelude_test.rb +56 -0
  114. data/test/johnson/runtime_test.rb +46 -0
  115. data/test/johnson/spidermonkey/context_test.rb +21 -0
  116. data/test/johnson/spidermonkey/immutable_node_test.rb +34 -0
  117. data/test/johnson/spidermonkey/js_land_proxy_test.rb +236 -0
  118. data/test/johnson/spidermonkey/ruby_land_proxy_test.rb +225 -0
  119. data/test/johnson/spidermonkey/runtime_test.rb +17 -0
  120. data/test/johnson/version_test.rb +13 -0
  121. data/test/johnson/visitors/dot_visitor_test.rb +39 -0
  122. data/test/johnson/visitors/enumerating_visitor_test.rb +12 -0
  123. data/test/johnson_test.rb +16 -0
  124. data/test/jquery_units/test.js +27 -0
  125. data/test/jquery_units/test_helper.js +197 -0
  126. data/test/jquery_units/units/ajax.js +795 -0
  127. data/test/jquery_units/units/core.js +1563 -0
  128. data/test/jquery_units/units/event.js +299 -0
  129. data/test/jquery_units/units/fx.js +427 -0
  130. data/test/jquery_units/units/offset.js +112 -0
  131. data/test/jquery_units/units/selector.js +224 -0
  132. data/test/jspec/helper.js +7 -0
  133. data/test/jspec/jspec.js +192 -0
  134. data/test/jspec/simple_spec.js +68 -0
  135. data/test/parser_test.rb +276 -0
  136. data/todo/.keep +0 -0
  137. metadata +501 -0
@@ -0,0 +1,9 @@
1
+ #ifndef JOHNSON_SPIDERMONKEY_DEBUGGER_H
2
+ #define JOHNSON_SPIDERMONKEY_DEBUGGER_H
3
+
4
+ #include "spidermonkey.h"
5
+ #include "jsdbgapi.h"
6
+
7
+ void init_Johnson_SpiderMonkey_Debugger(VALUE spidermonkey);
8
+
9
+ #endif
@@ -0,0 +1,25 @@
1
+ # this needs to happen before mkmf is required.
2
+ ENV["ARCHFLAGS"] = "-arch #{`uname -p` =~ /powerpc/ ? 'ppc' : 'i386'}"
3
+
4
+ require "mkmf"
5
+
6
+ if Config::CONFIG['target_os'] == 'mingw32'
7
+ $libs = append_library($libs, "winmm")
8
+ $CFLAGS << " -DXP_WIN -DXP_WIN32"
9
+ else
10
+ $CFLAGS << " -g -DXP_UNIX"
11
+ end
12
+ $CFLAGS << " -O3 -Wall -Wextra -Wcast-qual -Wwrite-strings -Wconversion -Wmissing-noreturn -Winline"
13
+
14
+ spidermonkey_base_dir = "../../vendor/spidermonkey"
15
+
16
+ spidermonkey_obj_dir = Dir[spidermonkey_base_dir + "/#{ENV['CROSS'] || ''}*.OBJ"].first
17
+
18
+ dir_config("johnson/spidermonkey")
19
+
20
+ find_header("jsautocfg.h", spidermonkey_obj_dir)
21
+ find_header("jsapi.h", spidermonkey_base_dir)
22
+
23
+ $LOCAL_LIBS << spidermonkey_obj_dir + "/libjs.a"
24
+
25
+ create_makefile("johnson/spidermonkey")
@@ -0,0 +1,37 @@
1
+ #include "extensions.h"
2
+
3
+ static JSBool /* Object.defineProperty(target, name, value, flags) */
4
+ define_property(JSContext *js_context, JSObject* UNUSED(obj), uintN argc, jsval *argv, jsval *retval) {
5
+ assert(argc > 1);
6
+ char *name = JS_GetStringBytes(JSVAL_TO_STRING(argv[1]));
7
+
8
+ // READ_ONLY | ITERABLE | NON_DELETABLE
9
+ jsuint flags = argc > 3 ? (unsigned) JSVAL_TO_INT(argv[3]) : 0;
10
+
11
+ *retval = JSVAL_VOID;
12
+ return JS_DefineProperty(js_context, JSVAL_TO_OBJECT(argv[0]), name, argc > 2 ? argv[2] : JSVAL_VOID, NULL, NULL, flags);
13
+ }
14
+
15
+ VALUE init_spidermonkey_extensions(JohnsonContext* context, VALUE self)
16
+ {
17
+ PREPARE_RUBY_JROOTS(context->js, 1);
18
+
19
+ jsval Object;
20
+ JSObject * global = JS_GetGlobalObject(context->js);
21
+ JCHECK(JS_GetProperty(context->js, global, "Object", &Object));
22
+ JROOT(Object);
23
+
24
+ JCHECK(JS_DefineFunction(context->js, JSVAL_TO_OBJECT(Object),
25
+ "defineProperty", define_property, 4, 0));
26
+
27
+ JCHECK(JS_DefineProperty(context->js, JSVAL_TO_OBJECT(Object), "READ_ONLY",
28
+ INT_TO_JSVAL(0x02), NULL, NULL, JSPROP_READONLY));
29
+
30
+ JCHECK(JS_DefineProperty(context->js, JSVAL_TO_OBJECT(Object), "ITERABLE",
31
+ INT_TO_JSVAL(0x01), NULL, NULL, JSPROP_READONLY));
32
+
33
+ JCHECK(JS_DefineProperty(context->js, JSVAL_TO_OBJECT(Object), "NON_DELETABLE",
34
+ INT_TO_JSVAL(0x04), NULL, NULL, JSPROP_READONLY));
35
+
36
+ JRETURN_RUBY(self);
37
+ }
@@ -0,0 +1,12 @@
1
+ #ifndef JOHNSON_SPIDERMONKEY_EXTENSIONS_H
2
+ #define JOHNSON_SPIDERMONKEY_EXTENSIONS_H
3
+
4
+ #include "spidermonkey.h"
5
+ #include "context.h"
6
+ #include "conversions.h"
7
+
8
+ // A context is passed here because there might not be a current context
9
+ // for the runtime when the function is called.
10
+ VALUE init_spidermonkey_extensions(JohnsonContext* context, VALUE self);
11
+
12
+ #endif
@@ -0,0 +1,40 @@
1
+ #include "global.h"
2
+
3
+ static JSBool enumerate(JSContext *js_context, JSObject *obj)
4
+ {
5
+ return JS_EnumerateStandardClasses(js_context, obj);
6
+ }
7
+
8
+ static JSBool resolve(JSContext *js_context, JSObject *obj, jsval id, uintN flags, JSObject **objp)
9
+ {
10
+ if ((flags & JSRESOLVE_ASSIGNING) == 0)
11
+ {
12
+ JSBool resolved_p;
13
+
14
+ if (!JS_ResolveStandardClass(js_context, obj, id, &resolved_p))
15
+ return JS_FALSE;
16
+
17
+ if (resolved_p)
18
+ *objp = obj;
19
+ }
20
+
21
+ return JS_TRUE;
22
+ }
23
+
24
+ static JSClass OurGlobalClass = {
25
+ "global", JSCLASS_NEW_RESOLVE | JSCLASS_GLOBAL_FLAGS,
26
+ JS_PropertyStub, // addProperty
27
+ JS_PropertyStub, // delProperty
28
+ JS_PropertyStub, // getProperty
29
+ JS_PropertyStub, // setProperty
30
+ enumerate,
31
+ (JSResolveOp) resolve,
32
+ JS_ConvertStub,
33
+ JS_FinalizeStub,
34
+ JSCLASS_NO_OPTIONAL_MEMBERS
35
+ };
36
+
37
+ JSObject* johnson_create_global_object(JSContext* context)
38
+ {
39
+ return JS_NewObject(context, &OurGlobalClass, NULL, NULL);
40
+ }
@@ -0,0 +1,11 @@
1
+ #ifndef JOHNSON_SPIDERMONKEY_GLOBAL_H
2
+ #define JOHNSON_SPIDERMONKEY_GLOBAL_H
3
+
4
+ #include "spidermonkey.h"
5
+ #include "context.h"
6
+ #include "runtime.h"
7
+
8
+ // NOTE: one of the FEW places a context should be passed around
9
+ JSObject* johnson_create_global_object(JSContext* context);
10
+
11
+ #endif
@@ -0,0 +1,16 @@
1
+ #include "idhash.h"
2
+
3
+ static JSHashNumber key_hash(const void *key)
4
+ {
5
+ return (JSHashNumber)key;
6
+ }
7
+
8
+ static intN comparator(const void *v1, const void *v2)
9
+ {
10
+ return v1 == v2;
11
+ }
12
+
13
+ JSHashTable* create_id_hash()
14
+ {
15
+ return JS_NewHashTable(0, key_hash, comparator, comparator, NULL, NULL);
16
+ }
@@ -0,0 +1,8 @@
1
+ #ifndef JOHNSON_SPIDERMONKEY_IDHASH_H
2
+ #define JOHNSON_SPIDERMONKEY_IDHASH_H
3
+
4
+ #include "spidermonkey.h"
5
+
6
+ JSHashTable* create_id_hash();
7
+
8
+ #endif
@@ -0,0 +1,522 @@
1
+ #include "immutable_node.h"
2
+
3
+ static VALUE cNode;
4
+
5
+ static void deallocate(ImmutableNodeContext* context)
6
+ {
7
+ if (context->pc)
8
+ {
9
+ js_FinishParseContext(context->js, context->pc);
10
+ free(context->pc);
11
+ }
12
+
13
+ JS_DestroyContext(context->js);
14
+ JS_DestroyRuntime(context->runtime);
15
+ free(context);
16
+ }
17
+
18
+ static VALUE allocate(VALUE klass)
19
+ {
20
+ ImmutableNodeContext * context = calloc(1, sizeof(ImmutableNodeContext));
21
+
22
+ VALUE self = Data_Wrap_Struct(klass, 0, deallocate, context);
23
+
24
+ assert(context->runtime = JS_NewRuntime(0x100000));
25
+ assert(context->js = JS_NewContext(context->runtime, 8192));
26
+
27
+ return self;
28
+ }
29
+
30
+ /*
31
+ * call-seq:
32
+ * parse_io(stream, filename=nil, line_number=0)
33
+ *
34
+ * Parses an IO object, returning a native spidermonkey parse tree.
35
+ */
36
+ static VALUE parse_io(int argc, VALUE *argv, VALUE klass) {
37
+ VALUE self = allocate(klass);
38
+ VALUE stream, filename, linenum;
39
+
40
+ ImmutableNodeContext* context;
41
+ Data_Get_Struct(self, ImmutableNodeContext, context);
42
+
43
+ assert(context->pc = calloc(1, sizeof(JSParseContext)));
44
+
45
+ rb_scan_args( argc, argv, "12", &stream, &filename, &linenum );
46
+
47
+ VALUE file_contents = rb_funcall(stream, rb_intern("read"), 0);
48
+ size_t length = NUM2INT(rb_funcall(file_contents, rb_intern("length"), 0));
49
+
50
+ jschar* chars;
51
+ assert(chars = js_InflateString(context->js, StringValuePtr(file_contents), &length));
52
+
53
+ if(!filename && rb_respond_to(stream, rb_intern("path"))) {
54
+ filename = rb_funcall(stream, rb_intern("path"), 0);
55
+ }
56
+ char* filenamez = RTEST(filename) ? StringValueCStr(filename) : NULL;
57
+ int linenumi = RTEST(linenum) ? NUM2INT(linenum) : 1;
58
+
59
+ assert(js_InitParseContext(context->js, context->pc,
60
+ NULL,
61
+ chars,
62
+ length,
63
+ NULL, filenamez, (unsigned)linenumi));
64
+
65
+ context->node = js_ParseScript(context->js,
66
+ JS_NewObject(context->js, NULL, NULL, NULL),
67
+ context->pc);
68
+ if(JS_IsExceptionPending(context->js)) {
69
+ jsval exception, message, file_name, line_number;
70
+ JS_GetPendingException(context->js, &exception);
71
+ JS_GetProperty(context->js, JSVAL_TO_OBJECT(exception), "message",&message);
72
+ JS_GetProperty(context->js, JSVAL_TO_OBJECT(exception), "fileName",&file_name);
73
+ JS_GetProperty(context->js, JSVAL_TO_OBJECT(exception), "lineNumber",&line_number);
74
+ JS_ClearPendingException(context->js);
75
+
76
+ rb_funcall( self,
77
+ rb_intern("raise_parse_error"),
78
+ 3,
79
+ message == JSVAL_NULL ?
80
+ Qnil :
81
+ rb_str_new2(JS_GetStringBytes(JSVAL_TO_STRING(message))),
82
+ rb_str_new2(JS_GetStringBytes(JSVAL_TO_STRING(file_name))),
83
+ INT2NUM(JSVAL_TO_INT(line_number))
84
+ );
85
+
86
+ }
87
+ return self;
88
+ }
89
+
90
+ /*
91
+ * call-seq:
92
+ * line
93
+ *
94
+ * Returns the line number of the node.
95
+ */
96
+ static VALUE line(VALUE self) {
97
+ ImmutableNodeContext * ctx;
98
+
99
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
100
+ return INT2NUM(ctx->node->pn_pos.begin.lineno);
101
+ }
102
+
103
+ /*
104
+ * call-seq:
105
+ * index
106
+ *
107
+ * Returns the column number of the node.
108
+ */
109
+ static VALUE begin_index(VALUE self) {
110
+ ImmutableNodeContext * ctx;
111
+
112
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
113
+ return INT2NUM(ctx->node->pn_pos.begin.index);
114
+ }
115
+
116
+ /*
117
+ * call-seq:
118
+ * pn_arity
119
+ *
120
+ * Returns the arity of the node as a symbol.
121
+ */
122
+ static VALUE pn_arity(VALUE self) {
123
+ ImmutableNodeContext * ctx;
124
+
125
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
126
+ switch(ctx->node->pn_arity) {
127
+ case PN_FUNC:
128
+ return ID2SYM(rb_intern("pn_func"));
129
+ case PN_LIST:
130
+ return ID2SYM(rb_intern("pn_list"));
131
+ case PN_TERNARY:
132
+ return ID2SYM(rb_intern("pn_ternary"));
133
+ case PN_BINARY:
134
+ return ID2SYM(rb_intern("pn_binary"));
135
+ case PN_UNARY:
136
+ return ID2SYM(rb_intern("pn_unary"));
137
+ case PN_NAME:
138
+ return ID2SYM(rb_intern("pn_name"));
139
+ case PN_NULLARY:
140
+ return ID2SYM(rb_intern("pn_nullary"));
141
+ }
142
+ return Qnil;
143
+ }
144
+
145
+ /*
146
+ * call-seq:
147
+ * pn_type
148
+ *
149
+ * Returns the type of the node as a symbol.
150
+ */
151
+ static VALUE pn_type(VALUE self) {
152
+ ImmutableNodeContext * ctx;
153
+
154
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
155
+ switch(ctx->node->pn_type) {
156
+ <% tokens.each do |token| %>
157
+ case <%= token %>: return ID2SYM(rb_intern("<%= token.downcase %>"));
158
+ <% end %>
159
+ }
160
+ return INT2NUM(ctx->node->pn_type);
161
+ }
162
+
163
+ /*
164
+ * call-seq:
165
+ * pn_expr
166
+ *
167
+ * Returns the parse node expression as an ImmutableNode.
168
+ */
169
+ static VALUE data_pn_expr(VALUE self) {
170
+ ImmutableNodeContext * ctx;
171
+
172
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
173
+ if(ctx->node->pn_expr) {
174
+ ImmutableNodeContext *roc;
175
+ VALUE node = Data_Make_Struct(cNode, ImmutableNodeContext, NULL, NULL, roc);
176
+ roc->js = ctx->js;
177
+ roc->node = ctx->node->pn_expr;
178
+ return node;
179
+ }
180
+ return Qnil;
181
+ }
182
+
183
+ /*
184
+ * call-seq:
185
+ * pn_kid
186
+ *
187
+ * Returns the child ImmutableNode.
188
+ */
189
+ static VALUE data_pn_kid(VALUE self) {
190
+ ImmutableNodeContext * ctx;
191
+
192
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
193
+ if(ctx->node->pn_kid) {
194
+ ImmutableNodeContext *roc;
195
+ VALUE node = Data_Make_Struct(cNode, ImmutableNodeContext, NULL, NULL, roc);
196
+ roc->js = ctx->js;
197
+ roc->node = ctx->node->pn_kid;
198
+ return node;
199
+ }
200
+ return Qnil;
201
+ }
202
+
203
+ /*
204
+ * call-seq:
205
+ * pn_kid1
206
+ *
207
+ * Returns the first child ImmutableNode.
208
+ */
209
+ static VALUE data_pn_kid1(VALUE self) {
210
+ ImmutableNodeContext * ctx;
211
+
212
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
213
+ if(ctx->node->pn_kid1) {
214
+ ImmutableNodeContext *roc;
215
+ VALUE node = Data_Make_Struct(cNode, ImmutableNodeContext, NULL, NULL, roc);
216
+ roc->js = ctx->js;
217
+ roc->node = ctx->node->pn_kid1;
218
+ return node;
219
+ }
220
+ return Qnil;
221
+ }
222
+
223
+ /*
224
+ * call-seq:
225
+ * pn_kid2
226
+ *
227
+ * Returns the second child ImmutableNode.
228
+ */
229
+ static VALUE data_pn_kid2(VALUE self) {
230
+ ImmutableNodeContext * ctx;
231
+
232
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
233
+ if(ctx->node->pn_kid2) {
234
+ ImmutableNodeContext *roc;
235
+ VALUE node = Data_Make_Struct(cNode, ImmutableNodeContext, NULL, NULL, roc);
236
+ roc->js = ctx->js;
237
+ roc->node = ctx->node->pn_kid2;
238
+ return node;
239
+ }
240
+ return Qnil;
241
+ }
242
+
243
+ /*
244
+ * call-seq:
245
+ * pn_kid3
246
+ *
247
+ * Returns the third child ImmutableNode.
248
+ */
249
+ static VALUE data_pn_kid3(VALUE self) {
250
+ ImmutableNodeContext * ctx;
251
+
252
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
253
+ if(ctx->node->pn_kid3) {
254
+ ImmutableNodeContext *roc;
255
+ VALUE node = Data_Make_Struct(cNode, ImmutableNodeContext, NULL, NULL, roc);
256
+ roc->js = ctx->js;
257
+ roc->node = ctx->node->pn_kid3;
258
+ return node;
259
+ }
260
+ return Qnil;
261
+ }
262
+
263
+ /*
264
+ * call-seq:
265
+ * pn_dval
266
+ *
267
+ * Returns the numeric value of the node.
268
+ */
269
+ static VALUE data_pn_dval(VALUE self) {
270
+ ImmutableNodeContext * ctx;
271
+
272
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
273
+ if(JSVAL_IS_NUMBER(ATOM_KEY(ctx->node->pn_atom))) {
274
+ return rb_float_new(ctx->node->pn_dval);
275
+ } else {
276
+ return INT2NUM((int)(ctx->node->pn_dval));
277
+ }
278
+ }
279
+
280
+ /*
281
+ * call-seq:
282
+ * pn_op
283
+ *
284
+ * Returns the op code for the node as a symbol.
285
+ */
286
+ static VALUE data_pn_op(VALUE self) {
287
+ ImmutableNodeContext * ctx;
288
+
289
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
290
+ return jsop_to_symbol(ctx->node->pn_op);
291
+ }
292
+
293
+ /*
294
+ * call-seq:
295
+ * pn_left
296
+ *
297
+ * Returns the left side ImmutableNode.
298
+ */
299
+ static VALUE data_pn_left(VALUE self) {
300
+ ImmutableNodeContext * ctx;
301
+
302
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
303
+
304
+ if(ctx->node->pn_left) {
305
+ ImmutableNodeContext *roc;
306
+ VALUE node = Data_Make_Struct(cNode, ImmutableNodeContext, NULL, NULL, roc);
307
+ roc->js = ctx->js;
308
+ roc->node = ctx->node->pn_left;
309
+ return node;
310
+ }
311
+ return Qnil;
312
+ }
313
+
314
+ /*
315
+ * call-seq:
316
+ * pn_extra
317
+ *
318
+ * Returns extra informaton about the node as an Integer.
319
+ */
320
+ static VALUE data_pn_extra(VALUE self) {
321
+ ImmutableNodeContext * ctx;
322
+
323
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
324
+
325
+ return UINT2NUM(ctx->node->pn_extra);
326
+ }
327
+
328
+ /*
329
+ * call-seq:
330
+ * name
331
+ *
332
+ * Returns the name of the node.
333
+ */
334
+ static VALUE name(VALUE self) {
335
+ ImmutableNodeContext * ctx;
336
+
337
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
338
+ return rb_str_new2(JS_GetStringBytes(ATOM_TO_STRING(ctx->node->pn_atom)));
339
+ }
340
+
341
+ /*
342
+ * call-seq:
343
+ * regexp
344
+ *
345
+ * Returns the regexp value as a String.
346
+ */
347
+ static VALUE regexp(VALUE self) {
348
+ ImmutableNodeContext * ctx;
349
+ jsval result;
350
+
351
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
352
+ js_regexp_toString(ctx->js, ctx->node->pn_pob->object, &result);
353
+ return rb_str_new2(JS_GetStringBytes(JSVAL_TO_STRING(result)));
354
+ }
355
+
356
+ /*
357
+ * call-seq:
358
+ * function_name
359
+ *
360
+ * Returns the function name as a String.
361
+ */
362
+ static VALUE function_name(VALUE self) {
363
+ ImmutableNodeContext * ctx;
364
+ JSFunction * f;
365
+ JSObject * object;
366
+
367
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
368
+ object = ctx->node->pn_funpob->object;
369
+ f = (JSFunction *)JS_GetPrivate(ctx->js, ctx->node->pn_funpob->object);
370
+
371
+ if(f->atom) {
372
+ return rb_str_new2(JS_GetStringBytes(ATOM_TO_STRING(f->atom)));
373
+ } else {
374
+ return Qnil;
375
+ }
376
+ }
377
+
378
+ /*
379
+ * call-seq:
380
+ * function_args
381
+ *
382
+ * Returns the function argument names as an Array of String.
383
+ */
384
+ static VALUE function_args(VALUE self) {
385
+ ImmutableNodeContext * ctx;
386
+ JSFunction * f;
387
+ JSObject * object;
388
+ jsuword* names;
389
+ VALUE func_args;
390
+ int i;
391
+
392
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
393
+ object = ctx->node->pn_funpob->object;
394
+ f = (JSFunction *)JS_GetPrivate(ctx->js, ctx->node->pn_funpob->object);
395
+
396
+ func_args = rb_ary_new2(f->nargs);
397
+ if(f->nargs > 0) {
398
+ names = js_GetLocalNameArray(ctx->js, f, &ctx->js->tempPool);
399
+ for(i = 0; i < f->nargs; i++) {
400
+ rb_ary_push(func_args,
401
+ rb_str_new2(JS_GetStringBytes(ATOM_TO_STRING(names[i])))
402
+ );
403
+ }
404
+ }
405
+ return func_args;
406
+ }
407
+
408
+ /*
409
+ * call-seq:
410
+ * function_body
411
+ *
412
+ * Returns the function body as an ImmutableNode.
413
+ */
414
+ static VALUE function_body(VALUE self) {
415
+ ImmutableNodeContext * ctx;
416
+ JSFunction * f;
417
+ JSObject * object;
418
+
419
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
420
+ object = ctx->node->pn_funpob->object;
421
+ f = (JSFunction *)JS_GetPrivate(ctx->js, ctx->node->pn_funpob->object);
422
+
423
+ if(ctx->node->pn_body) {
424
+ ImmutableNodeContext *roc;
425
+ VALUE node = Data_Make_Struct(cNode, ImmutableNodeContext, NULL, NULL, roc);
426
+ roc->js = ctx->js;
427
+ roc->node = ctx->node->pn_body;
428
+ return node;
429
+ }
430
+ return Qnil;
431
+ }
432
+
433
+ /*
434
+ * call-seq:
435
+ * pn_right
436
+ *
437
+ * Returns right side as an ImmutableNode.
438
+ */
439
+ static VALUE data_pn_right(VALUE self)
440
+ {
441
+ ImmutableNodeContext * ctx;
442
+
443
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
444
+
445
+ if(ctx->node->pn_right) {
446
+ ImmutableNodeContext *roc;
447
+ VALUE node = Data_Make_Struct(cNode, ImmutableNodeContext, NULL, NULL, roc);
448
+ roc->js = ctx->js;
449
+ roc->node = ctx->node->pn_right;
450
+ return node;
451
+ }
452
+ return Qnil;
453
+ }
454
+
455
+ /*
456
+ * call-seq:
457
+ * children
458
+ *
459
+ * Returns children as an Array of ImmutableNode.
460
+ */
461
+ static VALUE children(VALUE self) {
462
+ ImmutableNodeContext * ctx;
463
+ JSParseNode * p;
464
+ VALUE children;
465
+
466
+ Data_Get_Struct(self, ImmutableNodeContext, ctx);
467
+ children = rb_ary_new();
468
+ for(p = ctx->node->pn_head; p != NULL; p = p->pn_next) {
469
+ ImmutableNodeContext *roc;
470
+ VALUE node = Data_Make_Struct(cNode, ImmutableNodeContext, NULL, NULL, roc);
471
+ roc->js = ctx->js;
472
+ roc->node = p;
473
+
474
+ rb_ary_push(children, node);
475
+ }
476
+
477
+ return children;
478
+ }
479
+
480
+ VALUE jsop_to_symbol(JSUint32 jsop)
481
+ {
482
+ switch(jsop) {
483
+ <% jsops.each do |jsop| %>
484
+ case <%= jsop %>: return ID2SYM(rb_intern("<%= jsop.downcase %>"));
485
+ <% end %>
486
+ }
487
+ return UINT2NUM(jsop);
488
+ }
489
+
490
+ void init_Johnson_SpiderMonkey_Immutable_Node(VALUE spidermonkey)
491
+ {
492
+ /* HACK: These comments are *only* to make RDoc happy.
493
+ VALUE johnson = rb_define_module("Johnson");
494
+ VALUE spidermonkey = rb_define_module_under(johnson, "SpiderMonkey");
495
+ */
496
+
497
+ /* ImmutableNode class. */
498
+ cNode = rb_define_class_under(spidermonkey, "ImmutableNode", rb_cObject);
499
+
500
+ rb_define_alloc_func(cNode, allocate);
501
+ rb_define_singleton_method(cNode, "parse_io", parse_io, -1);
502
+ rb_define_method(cNode, "line", line, 0);
503
+ rb_define_method(cNode, "index", begin_index, 0);
504
+ rb_define_method(cNode, "pn_arity", pn_arity, 0);
505
+ rb_define_method(cNode, "pn_type", pn_type, 0);
506
+ rb_define_method(cNode, "pn_expr", data_pn_expr, 0);
507
+ rb_define_method(cNode, "pn_kid", data_pn_kid, 0);
508
+ rb_define_method(cNode, "pn_kid1", data_pn_kid1, 0);
509
+ rb_define_method(cNode, "pn_kid2", data_pn_kid2, 0);
510
+ rb_define_method(cNode, "pn_kid3", data_pn_kid3, 0);
511
+ rb_define_method(cNode, "pn_dval", data_pn_dval, 0);
512
+ rb_define_method(cNode, "pn_op", data_pn_op, 0);
513
+ rb_define_method(cNode, "pn_left", data_pn_left, 0);
514
+ rb_define_method(cNode, "pn_extra", data_pn_extra, 0);
515
+ rb_define_method(cNode, "name", name, 0);
516
+ rb_define_method(cNode, "regexp", regexp, 0);
517
+ rb_define_method(cNode, "function_name", function_name, 0);
518
+ rb_define_method(cNode, "function_args", function_args, 0);
519
+ rb_define_method(cNode, "function_body", function_body, 0);
520
+ rb_define_method(cNode, "pn_right", data_pn_right, 0);
521
+ rb_define_method(cNode, "children", children, 0);
522
+ }