jbarnette-johnson 1.0.0.200806240111
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +5 -0
- data/MANIFEST +385 -0
- data/MINGW32.mk +124 -0
- data/README.rdoc +51 -0
- data/Rakefile +166 -0
- data/bin/johnson +107 -0
- data/cross-compile.txt +38 -0
- data/ext/spidermonkey/context.c +122 -0
- data/ext/spidermonkey/context.h +19 -0
- data/ext/spidermonkey/conversions.c +286 -0
- data/ext/spidermonkey/conversions.h +18 -0
- data/ext/spidermonkey/debugger.c +208 -0
- data/ext/spidermonkey/debugger.h +9 -0
- data/ext/spidermonkey/extconf.rb +25 -0
- data/ext/spidermonkey/extensions.c +37 -0
- data/ext/spidermonkey/extensions.h +12 -0
- data/ext/spidermonkey/global.c +40 -0
- data/ext/spidermonkey/global.h +11 -0
- data/ext/spidermonkey/idhash.c +16 -0
- data/ext/spidermonkey/idhash.h +8 -0
- data/ext/spidermonkey/immutable_node.c.erb +522 -0
- data/ext/spidermonkey/immutable_node.h +22 -0
- data/ext/spidermonkey/jroot.h +187 -0
- data/ext/spidermonkey/js_land_proxy.c +609 -0
- data/ext/spidermonkey/js_land_proxy.h +20 -0
- data/ext/spidermonkey/ruby_land_proxy.c +537 -0
- data/ext/spidermonkey/ruby_land_proxy.h +17 -0
- data/ext/spidermonkey/runtime.c +304 -0
- data/ext/spidermonkey/runtime.h +25 -0
- data/ext/spidermonkey/spidermonkey.c +20 -0
- data/ext/spidermonkey/spidermonkey.h +29 -0
- data/js/johnson/browser.js +9 -0
- data/js/johnson/browser/env.js +687 -0
- data/js/johnson/browser/jquery.js +3444 -0
- data/js/johnson/browser/xmlsax.js +1564 -0
- data/js/johnson/browser/xmlw3cdom.js +4189 -0
- data/js/johnson/cli.js +30 -0
- data/js/johnson/prelude.js +80 -0
- data/js/johnson/template.js +29 -0
- data/lib/hoe.rb +748 -0
- data/lib/johnson.rb +46 -0
- data/lib/johnson/cli.rb +7 -0
- data/lib/johnson/cli/options.rb +56 -0
- data/lib/johnson/error.rb +4 -0
- data/lib/johnson/nodes.rb +7 -0
- data/lib/johnson/nodes/binary_node.rb +64 -0
- data/lib/johnson/nodes/for.rb +14 -0
- data/lib/johnson/nodes/for_in.rb +12 -0
- data/lib/johnson/nodes/function.rb +13 -0
- data/lib/johnson/nodes/list.rb +27 -0
- data/lib/johnson/nodes/node.rb +68 -0
- data/lib/johnson/nodes/ternary_node.rb +20 -0
- data/lib/johnson/parser.rb +21 -0
- data/lib/johnson/parser/syntax_error.rb +13 -0
- data/lib/johnson/runtime.rb +55 -0
- data/lib/johnson/spidermonkey/context.rb +10 -0
- data/lib/johnson/spidermonkey/debugger.rb +67 -0
- data/lib/johnson/spidermonkey/immutable_node.rb +280 -0
- data/lib/johnson/spidermonkey/js_land_proxy.rb +62 -0
- data/lib/johnson/spidermonkey/mutable_tree_visitor.rb +233 -0
- data/lib/johnson/spidermonkey/ruby_land_proxy.rb +52 -0
- data/lib/johnson/spidermonkey/runtime.rb +94 -0
- data/lib/johnson/version.rb +4 -0
- data/lib/johnson/visitable.rb +16 -0
- data/lib/johnson/visitors.rb +4 -0
- data/lib/johnson/visitors/dot_visitor.rb +167 -0
- data/lib/johnson/visitors/ecma_visitor.rb +315 -0
- data/lib/johnson/visitors/enumerating_visitor.rb +115 -0
- data/lib/johnson/visitors/sexp_visitor.rb +172 -0
- data/lib/rails/init.rb +37 -0
- data/test/assets/index.html +38 -0
- data/test/assets/jquery_test.html +186 -0
- data/test/helper.rb +58 -0
- data/test/johnson/browser_test.rb +38 -0
- data/test/johnson/conversions/array_test.rb +32 -0
- data/test/johnson/conversions/boolean_test.rb +17 -0
- data/test/johnson/conversions/callable_test.rb +34 -0
- data/test/johnson/conversions/file_test.rb +15 -0
- data/test/johnson/conversions/nil_test.rb +20 -0
- data/test/johnson/conversions/number_test.rb +34 -0
- data/test/johnson/conversions/regexp_test.rb +24 -0
- data/test/johnson/conversions/string_test.rb +26 -0
- data/test/johnson/conversions/struct_test.rb +15 -0
- data/test/johnson/conversions/symbol_test.rb +19 -0
- data/test/johnson/conversions/thread_test.rb +24 -0
- data/test/johnson/error_test.rb +9 -0
- data/test/johnson/extensions_test.rb +56 -0
- data/test/johnson/nodes/array_literal_test.rb +57 -0
- data/test/johnson/nodes/array_node_test.rb +26 -0
- data/test/johnson/nodes/binary_node_test.rb +61 -0
- data/test/johnson/nodes/bracket_access_test.rb +16 -0
- data/test/johnson/nodes/delete_test.rb +11 -0
- data/test/johnson/nodes/do_while_test.rb +12 -0
- data/test/johnson/nodes/dot_accessor_test.rb +15 -0
- data/test/johnson/nodes/export_test.rb +9 -0
- data/test/johnson/nodes/for_test.rb +54 -0
- data/test/johnson/nodes/function_test.rb +71 -0
- data/test/johnson/nodes/if_test.rb +41 -0
- data/test/johnson/nodes/import_test.rb +13 -0
- data/test/johnson/nodes/label_test.rb +19 -0
- data/test/johnson/nodes/object_literal_test.rb +110 -0
- data/test/johnson/nodes/return_test.rb +16 -0
- data/test/johnson/nodes/semi_test.rb +8 -0
- data/test/johnson/nodes/switch_test.rb +55 -0
- data/test/johnson/nodes/ternary_test.rb +25 -0
- data/test/johnson/nodes/throw_test.rb +9 -0
- data/test/johnson/nodes/try_node_test.rb +59 -0
- data/test/johnson/nodes/typeof_test.rb +11 -0
- data/test/johnson/nodes/unary_node_test.rb +23 -0
- data/test/johnson/nodes/void_test.rb +11 -0
- data/test/johnson/nodes/while_test.rb +26 -0
- data/test/johnson/nodes/with_test.rb +10 -0
- data/test/johnson/prelude_test.rb +56 -0
- data/test/johnson/runtime_test.rb +46 -0
- data/test/johnson/spidermonkey/context_test.rb +21 -0
- data/test/johnson/spidermonkey/immutable_node_test.rb +34 -0
- data/test/johnson/spidermonkey/js_land_proxy_test.rb +236 -0
- data/test/johnson/spidermonkey/ruby_land_proxy_test.rb +225 -0
- data/test/johnson/spidermonkey/runtime_test.rb +17 -0
- data/test/johnson/version_test.rb +13 -0
- data/test/johnson/visitors/dot_visitor_test.rb +39 -0
- data/test/johnson/visitors/enumerating_visitor_test.rb +12 -0
- data/test/johnson_test.rb +16 -0
- data/test/jquery_units/test.js +27 -0
- data/test/jquery_units/test_helper.js +197 -0
- data/test/jquery_units/units/ajax.js +795 -0
- data/test/jquery_units/units/core.js +1563 -0
- data/test/jquery_units/units/event.js +299 -0
- data/test/jquery_units/units/fx.js +427 -0
- data/test/jquery_units/units/offset.js +112 -0
- data/test/jquery_units/units/selector.js +224 -0
- data/test/jspec/helper.js +7 -0
- data/test/jspec/jspec.js +192 -0
- data/test/jspec/simple_spec.js +68 -0
- data/test/parser_test.rb +276 -0
- data/todo/.keep +0 -0
- metadata +501 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
module Johnson #:nodoc:
|
2
|
+
module SpiderMonkey #:nodoc:
|
3
|
+
class RubyLandProxy # native
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
raise Johnson::Error, "#{self.class.name} is an internal support class."
|
8
|
+
end
|
9
|
+
|
10
|
+
private :initialize
|
11
|
+
|
12
|
+
alias_method :size, :length
|
13
|
+
|
14
|
+
def to_proc
|
15
|
+
@proc ||= Proc.new { |*args| call(*args) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(*args)
|
19
|
+
call_using(runtime.global, *args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def call_using(this, *args)
|
23
|
+
native_call(this, *args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def inspect
|
27
|
+
toString
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(sym, *args, &block)
|
31
|
+
args << block if block_given?
|
32
|
+
|
33
|
+
name = sym.to_s
|
34
|
+
assignment = "=" == name[-1, 1]
|
35
|
+
|
36
|
+
# default behavior if the slot's not there
|
37
|
+
return super unless assignment || respond_to?(sym)
|
38
|
+
|
39
|
+
unless function_property?(name)
|
40
|
+
# for arity 0, treat it as a get
|
41
|
+
return self[name] if args.empty?
|
42
|
+
|
43
|
+
# arity 1 and quacking like an assignment, treat it as a set
|
44
|
+
return self[name[0..-2]] = args[0] if assignment && 1 == args.size
|
45
|
+
end
|
46
|
+
|
47
|
+
# okay, must really be a function
|
48
|
+
call_function_property(name, *args)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Johnson #:nodoc:
|
2
|
+
module SpiderMonkey #:nodoc:
|
3
|
+
class Runtime # native
|
4
|
+
CONTEXT_MAP_KEY = :johnson_context_map
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
@debugger = nil
|
8
|
+
@compiled_scripts = {}
|
9
|
+
@gcthings = {}
|
10
|
+
initialize_native(options)
|
11
|
+
self["Ruby"] = Object
|
12
|
+
end
|
13
|
+
|
14
|
+
# called from js_land_proxy.c:make_js_land_proxy
|
15
|
+
def add_gcthing(thing)
|
16
|
+
@gcthings[thing.object_id] = thing
|
17
|
+
end
|
18
|
+
|
19
|
+
# called from js_land_proxy.c:finalize
|
20
|
+
def remove_gcthing(thing)
|
21
|
+
@gcthings.delete(thing.object_id)
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def current_context
|
26
|
+
contexts = (Thread.current[CONTEXT_MAP_KEY] ||= {})
|
27
|
+
contexts[self.object_id] ||= Context.new(self)
|
28
|
+
end
|
29
|
+
|
30
|
+
def [](key)
|
31
|
+
global[key]
|
32
|
+
end
|
33
|
+
|
34
|
+
def []=(key, value)
|
35
|
+
global[key] = value
|
36
|
+
end
|
37
|
+
|
38
|
+
###
|
39
|
+
# Evaluate +script+ with +filename+ and +linenum+
|
40
|
+
def evaluate(script, filename = nil, linenum = nil)
|
41
|
+
compiled_script = compile(script, filename, linenum)
|
42
|
+
evaluate_compiled_script(compiled_script)
|
43
|
+
end
|
44
|
+
|
45
|
+
###
|
46
|
+
# Compile +script+ with +filename+ and +linenum+
|
47
|
+
def compile(script, filename=nil, linenum=nil)
|
48
|
+
filename ||= 'none'
|
49
|
+
linenum ||= 1
|
50
|
+
@compiled_scripts[filename] = native_compile(script, filename, linenum)
|
51
|
+
end
|
52
|
+
|
53
|
+
###
|
54
|
+
# Yield to +block+ in +filename+ at +linenum+
|
55
|
+
def break(filename, linenum, &block)
|
56
|
+
raise "#{filename} has not been compiled" unless @compiled_scripts.key?(filename)
|
57
|
+
|
58
|
+
compiled_script = @compiled_scripts[filename]
|
59
|
+
set_trap(compiled_script, linenum, block)
|
60
|
+
end
|
61
|
+
|
62
|
+
class << self
|
63
|
+
def raise_js_exception(jsex)
|
64
|
+
raise jsex if Exception === jsex
|
65
|
+
raise Johnson::Error.new(jsex.to_s) unless Johnson::SpiderMonkey::RubyLandProxy === jsex
|
66
|
+
|
67
|
+
stack = jsex.stack rescue nil
|
68
|
+
|
69
|
+
message = jsex['message'] || jsex.to_s
|
70
|
+
at = "(#{jsex['fileName']}):#{jsex['lineNumber']}"
|
71
|
+
ex = Johnson::Error.new("#{message} at #{at}")
|
72
|
+
if stack
|
73
|
+
js_caller = stack.split("\n").find_all { |x| x != '@:0' }
|
74
|
+
ex.set_backtrace(js_caller + caller)
|
75
|
+
else
|
76
|
+
ex.set_backtrace(caller)
|
77
|
+
end
|
78
|
+
|
79
|
+
raise ex
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
# Called by SpiderMonkey's garbage collector to determine whether or
|
85
|
+
# not it should GC
|
86
|
+
def should_sm_gc?
|
87
|
+
return false if Thread.list.find_all { |t|
|
88
|
+
t.key?(CONTEXT_MAP_KEY)
|
89
|
+
}.length > 1
|
90
|
+
true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Johnson
|
2
|
+
module Visitable
|
3
|
+
# Based off the visitor pattern from RubyGarden
|
4
|
+
def accept(visitor, &block)
|
5
|
+
klass = self.class.ancestors.find { |ancestor|
|
6
|
+
visitor.respond_to?("visit_#{ancestor.name.split(/::/)[-1]}")
|
7
|
+
}
|
8
|
+
|
9
|
+
if klass
|
10
|
+
visitor.send(:"visit_#{klass.name.split(/::/)[-1]}", self, &block)
|
11
|
+
else
|
12
|
+
raise "No visitor for '#{self.class}' at line #{line}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module Johnson
|
2
|
+
module Visitors
|
3
|
+
class DotVisitor
|
4
|
+
attr_accessor :nodes, :links
|
5
|
+
|
6
|
+
ESCAPE = /([<>"\\])/
|
7
|
+
|
8
|
+
class Node < Struct.new(:node_id, :label, :fields)
|
9
|
+
def to_s
|
10
|
+
f = fields.map { |field|
|
11
|
+
field.to_s.gsub(ESCAPE, '\\\\\1').gsub(/[\r\n]/, ' ')
|
12
|
+
}.join('\n')
|
13
|
+
f = "\\n#{f}" if f.length > 0
|
14
|
+
"\"#{node_id}\" [ label = \"#{label}#{f}\" ];"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
class Link < Struct.new(:from, :to, :attributes)
|
18
|
+
def to_s
|
19
|
+
attrs = ''
|
20
|
+
if attributes
|
21
|
+
attrs = " [" + attributes.map { |attribute|
|
22
|
+
attribute.join(' = ')
|
23
|
+
}.join("; ") + "]"
|
24
|
+
end
|
25
|
+
"\"#{from}\" -> \"#{to}\"#{attrs};"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
@nodes = []
|
31
|
+
@links = []
|
32
|
+
@color = 'lightblue2'
|
33
|
+
@style = 'filled'
|
34
|
+
yield self if block_given?
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
"digraph parsetree {\n" +
|
39
|
+
" node [color=#{@color}, style=#{@style}];\n" +
|
40
|
+
@nodes.map { |n| n.to_s }.join("\n") +
|
41
|
+
@links.map { |n| n.to_s }.join("\n") +
|
42
|
+
"\n}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def visit_SourceElements(o)
|
46
|
+
@nodes << Node.new(o.object_id, 'SourceElements', [])
|
47
|
+
o.value.each { |x|
|
48
|
+
@links << Link.new(o.object_id, x.object_id)
|
49
|
+
x.accept(self)
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
%w{
|
54
|
+
VarStatement
|
55
|
+
Comma
|
56
|
+
ObjectLiteral
|
57
|
+
ArrayLiteral
|
58
|
+
New
|
59
|
+
FunctionCall
|
60
|
+
Import
|
61
|
+
Export
|
62
|
+
}.each do |type|
|
63
|
+
define_method(:"visit_#{type}") do |o|
|
64
|
+
@nodes << Node.new(o.object_id, type, [])
|
65
|
+
o.value.each { |x|
|
66
|
+
@links << Link.new(o.object_id, x.object_id)
|
67
|
+
x.accept(self)
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
%w{ Name Number Regexp String }.each do |type|
|
73
|
+
define_method(:"visit_#{type}") do |o|
|
74
|
+
@nodes << Node.new(o.object_id, type, [o.value])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
%w{ Break Continue False Null This True }.each do |type|
|
79
|
+
define_method(:"visit_#{type}") do |o|
|
80
|
+
@nodes << Node.new(o.object_id, type, [])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def visit_Try(o)
|
85
|
+
@nodes << Node.new(o.object_id, 'Try', [])
|
86
|
+
@links << Link.new(o.object_id, o.cond.object_id, {'label' => 'cond' })
|
87
|
+
o.cond.accept(self)
|
88
|
+
if o.b_then
|
89
|
+
o.b_then.each { |x|
|
90
|
+
@links << Link.new(o.object_id, x.object_id, {'label' => 'b_then' })
|
91
|
+
x.accept(self)
|
92
|
+
}
|
93
|
+
end
|
94
|
+
if x = o.b_else
|
95
|
+
@links << Link.new(o.object_id, x.object_id, {'label' => 'b_else' })
|
96
|
+
x.accept(self)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
{
|
101
|
+
'For' => [:init, :cond, :update, :body],
|
102
|
+
'ForIn' => [:in_cond, :body],
|
103
|
+
'Ternary' => [:cond, :b_then, :b_else],
|
104
|
+
'If' => [:cond, :b_then, :b_else],
|
105
|
+
'Catch' => [:cond, :b_then, :b_else],
|
106
|
+
}.each do |type,attrs|
|
107
|
+
define_method(:"visit_#{type}") do |o|
|
108
|
+
@nodes << Node.new(o.object_id, type, [])
|
109
|
+
attrs.each do |method|
|
110
|
+
if x = o.send(method)
|
111
|
+
@links << Link.new(o.object_id, x.object_id, {'label' => method })
|
112
|
+
x.accept(self)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
### UNARY NODES ###
|
119
|
+
%w{
|
120
|
+
BitwiseNot Delete Not Parenthesis PostfixDecrement PostfixIncrement
|
121
|
+
PrefixDecrement PrefixIncrement Return Throw Typeof UnaryNegative
|
122
|
+
UnaryPositive Void
|
123
|
+
}.each do |node|
|
124
|
+
define_method(:"visit_#{node}") do |o|
|
125
|
+
@nodes << Node.new(o.object_id, node, [])
|
126
|
+
if x = o.value
|
127
|
+
@links << Link.new(o.object_id, x.object_id)
|
128
|
+
x.accept(self)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
### FUNCTION NODES ###
|
134
|
+
def visit_Function(o)
|
135
|
+
@nodes << Node.new(o.object_id, 'Function', [o.arguments.join(', ')])
|
136
|
+
@links << Link.new(o.object_id, o.body.object_id, { 'label' => 'body' })
|
137
|
+
o.body.accept(self)
|
138
|
+
end
|
139
|
+
|
140
|
+
### BINARY NODES ###
|
141
|
+
%w{
|
142
|
+
And AssignExpr BracketAccess Case Default DoWhile DotAccessor
|
143
|
+
Equal GetterProperty GreaterThan GreaterThanOrEqual In
|
144
|
+
InstanceOf Label LessThan LessThanOrEqual NotEqual OpAdd OpAddEqual
|
145
|
+
OpBitAnd OpBitAndEqual OpBitOr OpBitOrEqual OpBitXor OpBitXorEqual
|
146
|
+
OpDivide OpDivideEqual OpEqual OpLShift OpLShiftEqual OpMod
|
147
|
+
OpModEqual OpMultiply OpMultiplyEqual OpRShift OpRShiftEqual
|
148
|
+
OpSubtract OpSubtractEqual OpURShift OpURShiftEqual Or Property
|
149
|
+
SetterProperty StrictEqual StrictNotEqual Switch While With
|
150
|
+
}.each do |node|
|
151
|
+
define_method(:"visit_#{node}") do |o|
|
152
|
+
@nodes << Node.new(o.object_id, node, [])
|
153
|
+
[:left, :right].each do |side|
|
154
|
+
if x = o.send(side)
|
155
|
+
@links << Link.new(o.object_id, x.object_id, { 'label' => side })
|
156
|
+
x.accept(self)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def accept(target)
|
163
|
+
target.accept(self)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,315 @@
|
|
1
|
+
module Johnson
|
2
|
+
module Visitors
|
3
|
+
class EcmaVisitor
|
4
|
+
def initialize
|
5
|
+
@depth = 0
|
6
|
+
end
|
7
|
+
|
8
|
+
def visit_SourceElements(o)
|
9
|
+
newline = o.value.length > 0 ? "\n" : ' '
|
10
|
+
(@depth == 0 ? '' : "{#{newline}") +
|
11
|
+
indent {
|
12
|
+
o.value.map { |x|
|
13
|
+
code = x.accept(self)
|
14
|
+
semi = case x
|
15
|
+
when Nodes::Function, Nodes::While, Nodes::If, Nodes::Try, Nodes::Switch, Nodes::Case, Nodes::Default, Nodes::For, Nodes::ForIn
|
16
|
+
code =~ /\}\Z/ ? '' : ';'
|
17
|
+
else
|
18
|
+
';'
|
19
|
+
end
|
20
|
+
"#{indent}#{code}#{semi}"
|
21
|
+
}.join("\n")
|
22
|
+
} +
|
23
|
+
(@depth == 0 ? '' : "#{newline}}")
|
24
|
+
end
|
25
|
+
|
26
|
+
def visit_For(o)
|
27
|
+
"for(#{o.init ? o.init.accept(self) : ' '};" \
|
28
|
+
" #{o.cond && o.cond.accept(self)};" \
|
29
|
+
" #{o.update && o.update.accept(self)}) #{o.body.accept(self)}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def visit_ForIn(o)
|
33
|
+
"for(#{o.in_cond.accept(self)}) #{o.body.accept(self)}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def visit_Ternary(o)
|
37
|
+
"#{o.cond.accept(self)} ? #{o.b_then.accept(self)} : " \
|
38
|
+
"#{o.b_else.accept(self)}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def visit_VarStatement(o)
|
42
|
+
"var #{o.value.map { |x| x.accept(self) }.join(', ')}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def visit_ArrayLiteral(o)
|
46
|
+
"[#{o.value.map { |x| x.accept(self) }.join(', ')}]"
|
47
|
+
end
|
48
|
+
|
49
|
+
def visit_New(o)
|
50
|
+
rest = o.value.slice(1..-1)
|
51
|
+
"new #{o.value.first.accept(self)}"\
|
52
|
+
"(#{rest && rest.map { |x| x.accept(self) }.join(', ')})"
|
53
|
+
end
|
54
|
+
|
55
|
+
def visit_FunctionCall(o)
|
56
|
+
rest = o.value.slice(1..-1)
|
57
|
+
stmt =
|
58
|
+
if o.value.first.is_a?(Nodes::Function)
|
59
|
+
"(#{o.value.first.accept(self)})"
|
60
|
+
else
|
61
|
+
"#{o.value.first.accept(self)}"
|
62
|
+
end
|
63
|
+
"#{stmt}(#{rest && rest.map { |x| x.accept(self) }.join(', ')})"
|
64
|
+
end
|
65
|
+
|
66
|
+
def visit_Comma(o)
|
67
|
+
"#{o.value.map { |x| x.accept(self) }.join(', ') }"
|
68
|
+
end
|
69
|
+
|
70
|
+
%w{ Name Number Regexp }.each do |type|
|
71
|
+
define_method(:"visit_#{type}") do |o|
|
72
|
+
o.value
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def visit_If(o)
|
77
|
+
semi = ''
|
78
|
+
semi = ';' if o.b_else && !o.b_then.is_a?(Nodes::SourceElements)
|
79
|
+
|
80
|
+
stmt = "if(#{o.cond.accept(self)}) #{o.b_then.accept(self)}#{semi}"
|
81
|
+
stmt += " else #{o.b_else.accept(self)}" if o.b_else
|
82
|
+
stmt
|
83
|
+
end
|
84
|
+
|
85
|
+
def visit_Function(o)
|
86
|
+
"function#{o.name && ' '}#{o.name}(#{o.arguments.join(', ')}) #{o.body.accept(self)}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def visit_String(o)
|
90
|
+
h = {
|
91
|
+
"\b" => '\b',
|
92
|
+
"\t" => '\t',
|
93
|
+
"\n" => '\n',
|
94
|
+
"\f" => '\f',
|
95
|
+
"\r" => '\r',
|
96
|
+
}
|
97
|
+
"\"#{o.value.gsub(/[\\]/, '\\\\\\').gsub(/"/, '\"').gsub(/[\b\t\n\f\r]/) { |m| h[m] }}\""
|
98
|
+
end
|
99
|
+
|
100
|
+
{
|
101
|
+
'Break' => 'break',
|
102
|
+
'Continue' => 'continue',
|
103
|
+
'Null' => 'null',
|
104
|
+
'True' => 'true',
|
105
|
+
'False' => 'false',
|
106
|
+
'This' => 'this',
|
107
|
+
}.each do |type,sym|
|
108
|
+
define_method(:"visit_#{type}") do |o|
|
109
|
+
sym
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def visit_BracketAccess(o)
|
114
|
+
"#{o.left.accept(self)}[#{o.right.accept(self)}]"
|
115
|
+
end
|
116
|
+
|
117
|
+
def visit_DoWhile(o)
|
118
|
+
semi = o.left.is_a?(Nodes::SourceElements) ? '' : ';'
|
119
|
+
"do #{o.left.accept(self)}#{semi} while(#{o.right.accept(self)})"
|
120
|
+
end
|
121
|
+
|
122
|
+
def visit_Try(o)
|
123
|
+
stmt = "try #{o.cond.accept(self)}"
|
124
|
+
o.b_then.each do |node|
|
125
|
+
stmt << " #{node.accept(self)}"
|
126
|
+
end if o.b_then
|
127
|
+
stmt << "#{o.b_else && ' finally '}" \
|
128
|
+
"#{o.b_else && o.b_else.accept(self)}" if o.b_else
|
129
|
+
stmt
|
130
|
+
end
|
131
|
+
|
132
|
+
def visit_Catch(o)
|
133
|
+
"catch(#{o.cond.accept(self)}) #{o.b_else.accept(self)}"
|
134
|
+
end
|
135
|
+
|
136
|
+
def visit_Delete(o)
|
137
|
+
"delete #{o.value.accept(self)}"
|
138
|
+
end
|
139
|
+
|
140
|
+
def visit_Export(o)
|
141
|
+
"export #{o.value.map { |x| x.accept(self) }.join(', ')}"
|
142
|
+
end
|
143
|
+
|
144
|
+
def visit_Import(o)
|
145
|
+
"import #{o.value.map { |x| x.accept(self) }.join(', ')}"
|
146
|
+
end
|
147
|
+
|
148
|
+
def visit_Throw(o)
|
149
|
+
"throw #{o.value.accept(self)}"
|
150
|
+
end
|
151
|
+
|
152
|
+
def visit_Void(o)
|
153
|
+
"void #{o.value.accept(self)}"
|
154
|
+
end
|
155
|
+
|
156
|
+
def visit_Return(o)
|
157
|
+
"return#{o.value && ' '}#{o.value && o.value.accept(self)}"
|
158
|
+
end
|
159
|
+
|
160
|
+
def visit_Typeof(o)
|
161
|
+
"typeof #{o.value.accept(self)}"
|
162
|
+
end
|
163
|
+
|
164
|
+
{
|
165
|
+
'UnaryPositive' => '+',
|
166
|
+
'UnaryNegative' => '-',
|
167
|
+
'BitwiseNot' => '~',
|
168
|
+
'Not' => '!',
|
169
|
+
}.each do |type,op|
|
170
|
+
define_method(:"visit_#{type}") do |o|
|
171
|
+
"#{op}#{o.value.accept(self)}"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def visit_Parenthesis(o)
|
176
|
+
"(#{o.value.accept(self)})"
|
177
|
+
end
|
178
|
+
|
179
|
+
def visit_While(o)
|
180
|
+
"while(#{o.left.accept(self)}) #{o.right.accept(self)}"
|
181
|
+
end
|
182
|
+
|
183
|
+
def visit_With(o)
|
184
|
+
"with(#{o.left.accept(self)}) #{o.right.accept(self)}"
|
185
|
+
end
|
186
|
+
|
187
|
+
def visit_Switch(o)
|
188
|
+
"switch(#{o.left.accept(self)}) #{o.right.accept(self)}"
|
189
|
+
end
|
190
|
+
|
191
|
+
def visit_Case(o)
|
192
|
+
"case #{o.left.accept(self)}: #{o.right.accept(self)}"
|
193
|
+
end
|
194
|
+
|
195
|
+
def visit_Default(o)
|
196
|
+
"default: #{o.right.accept(self)}"
|
197
|
+
end
|
198
|
+
|
199
|
+
def visit_Label(o)
|
200
|
+
"#{o.left.accept(self)}: #{o.right.accept(self)}"
|
201
|
+
end
|
202
|
+
alias :visit_Property :visit_Label
|
203
|
+
|
204
|
+
def visit_DotAccessor(o)
|
205
|
+
stmt =
|
206
|
+
if o.right.is_a?(Nodes::Function)
|
207
|
+
"(#{o.right.accept(self)})"
|
208
|
+
else
|
209
|
+
"#{o.right.accept(self)}"
|
210
|
+
end
|
211
|
+
|
212
|
+
rhs = o.left.accept(self)
|
213
|
+
if rhs =~ /\A\w+$/
|
214
|
+
stmt << ".#{rhs}"
|
215
|
+
else
|
216
|
+
stmt << "['#{rhs}']"
|
217
|
+
end
|
218
|
+
stmt
|
219
|
+
end
|
220
|
+
|
221
|
+
def visit_GetterProperty(o)
|
222
|
+
"get #{o.left.accept(self)}#{o.right.accept(self).gsub(/function/, '')}"
|
223
|
+
end
|
224
|
+
|
225
|
+
def visit_SetterProperty(o)
|
226
|
+
"set #{o.left.accept(self)}#{o.right.accept(self).gsub(/function/, '')}"
|
227
|
+
end
|
228
|
+
|
229
|
+
def visit_ObjectLiteral(o)
|
230
|
+
indent {
|
231
|
+
"{ #{o.value.map { |x| x.accept(self) }.join(",\n#{indent}")} }"
|
232
|
+
}
|
233
|
+
end
|
234
|
+
|
235
|
+
{
|
236
|
+
'PostfixIncrement' => '++',
|
237
|
+
'PostfixDecrement' => '--',
|
238
|
+
}.each do |type,op|
|
239
|
+
define_method(:"visit_#{type}") do |o|
|
240
|
+
"#{o.value.accept(self)}#{op}"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
{
|
245
|
+
'PrefixIncrement' => '++',
|
246
|
+
'PrefixDecrement' => '--',
|
247
|
+
}.each do |type,op|
|
248
|
+
define_method(:"visit_#{type}") do |o|
|
249
|
+
"#{op}#{o.value.accept(self)}"
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
{
|
254
|
+
'OpEqual' => '=',
|
255
|
+
'StrictNotEqual' => '!==',
|
256
|
+
'StrictEqual' => '===',
|
257
|
+
'Or' => '||',
|
258
|
+
'OpURShift' => '>>>',
|
259
|
+
'OpURShiftEqual' => '>>>=',
|
260
|
+
'OpSubtract' => '-',
|
261
|
+
'OpSubtractEqual' => '-=',
|
262
|
+
'OpRShift' => '>>',
|
263
|
+
'OpRShiftEqual' => '>>=',
|
264
|
+
'OpMultiply' => '*',
|
265
|
+
'OpMultiplyEqual' => '*=',
|
266
|
+
'OpMod' => '%',
|
267
|
+
'OpModEqual' => '%=',
|
268
|
+
'OpLShift' => '<<',
|
269
|
+
'OpLShiftEqual' => '<<=',
|
270
|
+
'OpDivide' => '/',
|
271
|
+
'OpDivideEqual' => '/=',
|
272
|
+
'OpBitXor' => '^',
|
273
|
+
'OpBitXorEqual' => '^=',
|
274
|
+
'OpBitOr' => '|',
|
275
|
+
'OpBitOrEqual' => '|=',
|
276
|
+
'OpBitAnd' => '&',
|
277
|
+
'OpBitAndEqual' => '&=',
|
278
|
+
'OpAdd' => '+',
|
279
|
+
'OpAddEqual' => '+=',
|
280
|
+
'NotEqual' => '!=',
|
281
|
+
'LessThan' => '<',
|
282
|
+
'LessThanOrEqual' => '<=',
|
283
|
+
'GreaterThan' => '>',
|
284
|
+
'GreaterThanOrEqual' => '>=',
|
285
|
+
'And' => '&&',
|
286
|
+
'InstanceOf' => 'instanceof',
|
287
|
+
'In' => 'in',
|
288
|
+
'Equal' => '==',
|
289
|
+
'AssignExpr' => '=',
|
290
|
+
}.each do |type,op|
|
291
|
+
define_method(:"visit_#{type}") do |o|
|
292
|
+
"#{o.left && o.left.accept(self)}" \
|
293
|
+
" #{op} " \
|
294
|
+
"#{o.right && o.right.accept(self)}"
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def accept(target)
|
299
|
+
target.accept(self)
|
300
|
+
end
|
301
|
+
|
302
|
+
private
|
303
|
+
def indent
|
304
|
+
if block_given?
|
305
|
+
@depth += 1
|
306
|
+
x = yield
|
307
|
+
@depth -= 1
|
308
|
+
x
|
309
|
+
else
|
310
|
+
' ' * (@depth - 1) * 2
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|