rubyjs 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. data/README +128 -0
  2. data/Rakefile +9 -0
  3. data/bin/rubyjs +140 -0
  4. data/examples/ex1/Rakefile +7 -0
  5. data/examples/ex1/ex1.js +771 -0
  6. data/examples/ex1/ex1.rb +42 -0
  7. data/examples/ex1/index.html +7 -0
  8. data/examples/hw/Rakefile +9 -0
  9. data/examples/hw/hw.js +635 -0
  10. data/examples/hw/hw.rb +7 -0
  11. data/examples/hw/index.html +7 -0
  12. data/patches/parse_tree.rb.diff +34 -0
  13. data/rubyjs.gemspec +24 -0
  14. data/src/rubyjs.rb +4 -0
  15. data/src/rubyjs/code_generator.rb +474 -0
  16. data/src/rubyjs/compiler.rb +2007 -0
  17. data/src/rubyjs/debug_name_generator.rb +75 -0
  18. data/src/rubyjs/encoder.rb +171 -0
  19. data/src/rubyjs/eval_into.rb +59 -0
  20. data/src/rubyjs/lib/core.rb +1008 -0
  21. data/src/rubyjs/lib/json.rb +101 -0
  22. data/src/rubyjs/model.rb +287 -0
  23. data/src/rubyjs/name_generator.rb +71 -0
  24. data/src/rwt/AbsolutePanel.rb +161 -0
  25. data/src/rwt/DOM.Konqueror.rb +89 -0
  26. data/src/rwt/DOM.Opera.rb +65 -0
  27. data/src/rwt/DOM.rb +1044 -0
  28. data/src/rwt/Event.Opera.rb +35 -0
  29. data/src/rwt/Event.rb +429 -0
  30. data/src/rwt/HTTPRequest.IE6.rb +5 -0
  31. data/src/rwt/HTTPRequest.rb +74 -0
  32. data/src/rwt/Label.rb +164 -0
  33. data/src/rwt/Panel.rb +90 -0
  34. data/src/rwt/RootPanel.rb +16 -0
  35. data/src/rwt/UIObject.rb +495 -0
  36. data/src/rwt/Widget.rb +193 -0
  37. data/src/rwt/ported-from/AbsolutePanel.java +158 -0
  38. data/src/rwt/ported-from/DOM.java +571 -0
  39. data/src/rwt/ported-from/DOMImpl.java +426 -0
  40. data/src/rwt/ported-from/DOMImplOpera.java +82 -0
  41. data/src/rwt/ported-from/DOMImplStandard.java +234 -0
  42. data/src/rwt/ported-from/HTTPRequest.java +81 -0
  43. data/src/rwt/ported-from/HTTPRequestImpl.java +103 -0
  44. data/src/rwt/ported-from/Label.java +163 -0
  45. data/src/rwt/ported-from/Panel.java +99 -0
  46. data/src/rwt/ported-from/UIObject.java +614 -0
  47. data/src/rwt/ported-from/Widget.java +221 -0
  48. data/test/benchmark/bm_call_conv1.js +16 -0
  49. data/test/benchmark/bm_call_conv2.js +14 -0
  50. data/test/benchmark/bm_var_acc1.js +13 -0
  51. data/test/benchmark/bm_var_acc2.js +11 -0
  52. data/test/benchmark/bm_vm1_block.js +15 -0
  53. data/test/benchmark/bm_vm1_block.rb +15 -0
  54. data/test/benchmark/bm_vm1_const.js +13 -0
  55. data/test/benchmark/bm_vm1_const.rb +13 -0
  56. data/test/benchmark/bm_vm1_ensure.js +17 -0
  57. data/test/benchmark/bm_vm1_ensure.rb +15 -0
  58. data/test/benchmark/common.js +4 -0
  59. data/test/benchmark/common.rb +5 -0
  60. data/test/benchmark/params.yaml +7 -0
  61. data/test/browser.test.html +4059 -0
  62. data/test/browser.test.js +3225 -0
  63. data/test/common.Browser.rb +13 -0
  64. data/test/common.rb +8 -0
  65. data/test/gen_browser_test_suite.rb +129 -0
  66. data/test/gen_test_suite.rb +41 -0
  67. data/test/run_benchs.rb +58 -0
  68. data/test/run_tests.rb +22 -0
  69. data/test/test_args.rb +24 -0
  70. data/test/test_array.rb +26 -0
  71. data/test/test_case.rb +35 -0
  72. data/test/test_class.rb +55 -0
  73. data/test/test_eql.rb +9 -0
  74. data/test/test_exception.rb +61 -0
  75. data/test/test_expr.rb +12 -0
  76. data/test/test_hash.rb +29 -0
  77. data/test/test_if.rb +28 -0
  78. data/test/test_inspect.rb +10 -0
  79. data/test/test_lebewesen.rb +39 -0
  80. data/test/test_massign.rb +66 -0
  81. data/test/test_new.rb +12 -0
  82. data/test/test_range.rb +53 -0
  83. data/test/test_regexp.rb +22 -0
  84. data/test/test_send.rb +65 -0
  85. data/test/test_simple_output.rb +5 -0
  86. data/test/test_splat.rb +21 -0
  87. data/test/test_string.rb +51 -0
  88. data/test/test_yield.rb +152 -0
  89. data/utils/js/Makefile +9 -0
  90. data/utils/js/RunScript.class +0 -0
  91. data/utils/js/RunScript.java +73 -0
  92. data/utils/js/js.jar +0 -0
  93. data/utils/js/run.sh +3 -0
  94. data/utils/jsc/Makefile +7 -0
  95. data/utils/jsc/README +3 -0
  96. data/utils/jsc/RunScript.c +93 -0
  97. data/utils/jsc/run.sh +15 -0
  98. data/utils/yuicompressor/README +1 -0
  99. data/utils/yuicompressor/yuicompressor-2.2.5.jar +0 -0
  100. data/vendor/ParseTree-1.7.1-patched/History.txt +217 -0
  101. data/vendor/ParseTree-1.7.1-patched/Manifest.txt +22 -0
  102. data/vendor/ParseTree-1.7.1-patched/README.txt +110 -0
  103. data/vendor/ParseTree-1.7.1-patched/Rakefile +41 -0
  104. data/vendor/ParseTree-1.7.1-patched/bin/parse_tree_abc +89 -0
  105. data/vendor/ParseTree-1.7.1-patched/bin/parse_tree_audit +28 -0
  106. data/vendor/ParseTree-1.7.1-patched/bin/parse_tree_deps +62 -0
  107. data/vendor/ParseTree-1.7.1-patched/bin/parse_tree_show +49 -0
  108. data/vendor/ParseTree-1.7.1-patched/demo/printer.rb +20 -0
  109. data/vendor/ParseTree-1.7.1-patched/lib/composite_sexp_processor.rb +49 -0
  110. data/vendor/ParseTree-1.7.1-patched/lib/parse_tree.rb +1013 -0
  111. data/vendor/ParseTree-1.7.1-patched/lib/sexp.rb +235 -0
  112. data/vendor/ParseTree-1.7.1-patched/lib/sexp_processor.rb +330 -0
  113. data/vendor/ParseTree-1.7.1-patched/lib/unique.rb +15 -0
  114. data/vendor/ParseTree-1.7.1-patched/test/pt_testcase.rb +1221 -0
  115. data/vendor/ParseTree-1.7.1-patched/test/something.rb +53 -0
  116. data/vendor/ParseTree-1.7.1-patched/test/test_all.rb +13 -0
  117. data/vendor/ParseTree-1.7.1-patched/test/test_composite_sexp_processor.rb +69 -0
  118. data/vendor/ParseTree-1.7.1-patched/test/test_parse_tree.rb +216 -0
  119. data/vendor/ParseTree-1.7.1-patched/test/test_sexp.rb +291 -0
  120. data/vendor/ParseTree-1.7.1-patched/test/test_sexp_processor.rb +244 -0
  121. data/vendor/ParseTree-1.7.1-patched/validate.sh +31 -0
  122. data/vendor/ParseTree-1.7.1/History.txt +217 -0
  123. data/vendor/ParseTree-1.7.1/Manifest.txt +22 -0
  124. data/vendor/ParseTree-1.7.1/README.txt +110 -0
  125. data/vendor/ParseTree-1.7.1/Rakefile +41 -0
  126. data/vendor/ParseTree-1.7.1/bin/parse_tree_abc +89 -0
  127. data/vendor/ParseTree-1.7.1/bin/parse_tree_audit +28 -0
  128. data/vendor/ParseTree-1.7.1/bin/parse_tree_deps +62 -0
  129. data/vendor/ParseTree-1.7.1/bin/parse_tree_show +49 -0
  130. data/vendor/ParseTree-1.7.1/demo/printer.rb +20 -0
  131. data/vendor/ParseTree-1.7.1/lib/composite_sexp_processor.rb +49 -0
  132. data/vendor/ParseTree-1.7.1/lib/parse_tree.rb +1004 -0
  133. data/vendor/ParseTree-1.7.1/lib/sexp.rb +235 -0
  134. data/vendor/ParseTree-1.7.1/lib/sexp_processor.rb +330 -0
  135. data/vendor/ParseTree-1.7.1/lib/unique.rb +15 -0
  136. data/vendor/ParseTree-1.7.1/test/pt_testcase.rb +1221 -0
  137. data/vendor/ParseTree-1.7.1/test/something.rb +53 -0
  138. data/vendor/ParseTree-1.7.1/test/test_all.rb +13 -0
  139. data/vendor/ParseTree-1.7.1/test/test_composite_sexp_processor.rb +69 -0
  140. data/vendor/ParseTree-1.7.1/test/test_parse_tree.rb +216 -0
  141. data/vendor/ParseTree-1.7.1/test/test_sexp.rb +291 -0
  142. data/vendor/ParseTree-1.7.1/test/test_sexp_processor.rb +244 -0
  143. data/vendor/ParseTree-1.7.1/validate.sh +31 -0
  144. metadata +230 -0
@@ -0,0 +1,75 @@
1
+ #
2
+ # A NameGenerator that outputs readable, non-obfuscated names.
3
+ #
4
+ # Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de).
5
+ # All rights reserved.
6
+ #
7
+
8
+ class DebugNameGenerator
9
+
10
+ def initialize
11
+ @tmp_counter = 0
12
+ end
13
+
14
+ def fresh
15
+ name = "tmp_" + @tmp_counter.to_s
16
+ @tmp_counter += 1
17
+ return name
18
+ end
19
+
20
+ MAP = [
21
+ %w($ dollar),
22
+ %w(? quest),
23
+ %w(+ plus),
24
+ %w(+@ uplus),
25
+ %w(- minus),
26
+ %w(-@ uminus),
27
+ %w(@ ivar),
28
+ %w(/ div),
29
+ %w(% mod),
30
+ %w(* mul),
31
+ %w(~ neg),
32
+ %w(^ xor),
33
+ %w(&& and),
34
+ %w(& band),
35
+ %w(|| or),
36
+ %w(| bor),
37
+ %w(! not),
38
+ %w(=== eqq),
39
+ %w(== eq),
40
+ %w(!== neqq),
41
+ %w(!= neq),
42
+ %w(=~ match),
43
+ %w(!~ nmatch),
44
+ %w(<<< lshift3),
45
+ %w(>>> rshift3),
46
+ %w(<< lshift),
47
+ %w(>> rshift),
48
+ %w(<= le),
49
+ %w(>= ge),
50
+ %w(> gt),
51
+ %w(< lt),
52
+ %w([]= set),
53
+ %w([] at),
54
+ %w(= eq)
55
+ ]
56
+
57
+ #
58
+ # Generate a name for +name+. Return the same name for the same
59
+ # +name+.
60
+ #
61
+
62
+ def get(name)
63
+ raise unless name.is_a?(String)
64
+ MAP.each do |pat, rep|
65
+ name = name.gsub(pat, "$" + rep)
66
+ end
67
+
68
+ if name !~ /^[A-Za-z_\$0-9]+$/
69
+ STDERR.puts name
70
+ end
71
+
72
+ return name
73
+ end
74
+
75
+ end
@@ -0,0 +1,171 @@
1
+ #
2
+ # Encode all kind of variables or symbols for Javascript generation.
3
+ #
4
+ # Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de).
5
+ # All rights reserved.
6
+ #
7
+
8
+ if $RUBYJS__DEBUG
9
+ require 'rubyjs/debug_name_generator'
10
+ NameGenerator = DebugNameGenerator
11
+ else
12
+ require 'rubyjs/name_generator'
13
+ end
14
+
15
+ class Encoder
16
+ def initialize
17
+ @method_and_ivar_name_generator = NameGenerator.new
18
+ @attribute_name_generator = NameGenerator.new
19
+ @global_attribute_name_generator = NameGenerator.new
20
+ @global_name_generator = NameGenerator.new
21
+ reset_local_name_generator!
22
+
23
+ @unique_scope_ids = 0
24
+ end
25
+
26
+ def next_unique_scope_id()
27
+ n = @unique_scope_ids
28
+ @unique_scope_ids += 1
29
+ n
30
+ end
31
+
32
+ def reset_local_name_generator!
33
+ @local_name_generator = NameGenerator.new
34
+ end
35
+
36
+ def with_local
37
+ reset_local_name_generator!
38
+ res = yield
39
+ reset_local_name_generator!
40
+ return res
41
+ end
42
+
43
+ def encode_nil
44
+ 'nil'
45
+ end
46
+
47
+ def encode_self
48
+ 'self'
49
+ end
50
+
51
+ #
52
+ # Constants are encoded with a preceding "$". Doesn't conflict with
53
+ # methods or instance variables, as they are always used in dot
54
+ # notation while constants not.
55
+ #
56
+ # Constants use the global_name_generator. They use the same namespace
57
+ # as global variables do. There is no nameclash, as global variables
58
+ # are prefixed in Ruby with a $ character, so the generated name will
59
+ # always differ (e.g. Constant vs. $Constant leads two two different
60
+ # names).
61
+ #
62
+ def encode_constant(name)
63
+ "$" + @global_name_generator.get(name.to_s)
64
+ end
65
+
66
+ #
67
+ # Encode global variable.
68
+ #
69
+ # See encode_constant().
70
+ #
71
+ def encode_global_variable(name)
72
+ raise if name.to_s[0,1] != '$'
73
+ "$" + @global_name_generator.get(name.to_s)
74
+ end
75
+
76
+ #
77
+ # Encodes a Javascript attribute name.
78
+ # This is used in the runtime environment of RubyJS to obfuscate
79
+ # attribute names. They have their own namespace and don't clash
80
+ # with method names or instance variable names!
81
+ #
82
+ # Attributes are encoded with a preceding "a$". This doesn't conflict
83
+ # with methods or instance variables, as they use "$".
84
+ #
85
+ def encode_attr(name)
86
+ "a$" + @attribute_name_generator.get(name.to_s)
87
+ end
88
+
89
+ #
90
+ # A global attribute. Similar to encode_attr(), but for the global
91
+ # scope (used by the def_class() Javascript function).
92
+ #
93
+ # Global attributes are encoded with a "a$" prefix. They don't
94
+ # conflict with attributes, because attributes are always used in dot
95
+ # notation, wheres global attributes not.
96
+ #
97
+ def encode_globalattr(name)
98
+ "a$" + @global_attribute_name_generator.get(name.to_s)
99
+ end
100
+
101
+ #
102
+ # Method names and instance variable names use the same generator.
103
+ # They don't clash, as instance variables are prefixed with '@' (not
104
+ # in the Javascript code, but in the Parse tree from Ruby). That's why
105
+ # a different symbol name is generated.
106
+ #
107
+ def encode_method(name)
108
+ "$" + @method_and_ivar_name_generator.get(name.to_s)
109
+ end
110
+
111
+ def reverse_lookup_method_name(encoded_name)
112
+ raise unless encoded_name[0,1] == "$"
113
+ @method_and_ivar_name_generator.reverse_lookup(encoded_name[1..-1])
114
+ end
115
+
116
+ def all_method_names
117
+ @method_and_ivar_name_generator.cache.each_pair do |k,v|
118
+ yield(k, "$" + v) if k[0,1] != '@'
119
+ end
120
+ end
121
+
122
+ def encode_instance_variable(name)
123
+ raise unless name.to_s[0,1] == '@'
124
+ "$" + @method_and_ivar_name_generator.get(name.to_s)
125
+ end
126
+
127
+ def encode_local_variable(name)
128
+ "_" + @local_name_generator.get(name.to_s)
129
+ end
130
+
131
+ def encode_fresh_local_variable
132
+ "_" + @local_name_generator.fresh()
133
+ end
134
+
135
+ #
136
+ # Interpolate a string that contains #<...> expressions.
137
+ #
138
+ # Supported expressions:
139
+ #
140
+ # #<method()> # => encode_method("method")
141
+ # #<self> # => encode_self()
142
+ # #<nil> # => encode_nil()
143
+ # #<@ivar> # => encode_instance_variable("@ivar")
144
+ # #<Constant> # => encode_constant("Constant")
145
+ # #<attr:name> # => encode_attr("name")
146
+ # #<globalattr:name> # => encode_globalattr("name")
147
+ # #<variable> # => encode_local_variable("variable")
148
+ #
149
+ # FIXME: You can't interpolate methods like ">" yet.
150
+ #
151
+ def interpolate(str)
152
+ str = str.gsub(/#<(.*?)>/) {
153
+ case s = $1.strip
154
+ when /^(\w+)\(\)$/ then encode_method($1)
155
+ when /^m:(.+)$/ then encode_method($1)
156
+ when /^self$/ then encode_self()
157
+ when /^nil$/ then encode_nil()
158
+ when /^(@\w+)$/ then encode_instance_variable($1)
159
+ when /^(\$.+)$/ then encode_global_variable($1)
160
+ when /^([A-Z]\w*)$/ then encode_constant($1)
161
+ when /^attr:(\w+)$/ then encode_attr($1)
162
+ when /^globalattr:(\w+)$/ then encode_globalattr($1)
163
+ when /^([a-z_]\w*)$/ then encode_local_variable($1)
164
+ else
165
+ raise s
166
+ end
167
+ }
168
+ return str
169
+ end
170
+
171
+ end
@@ -0,0 +1,59 @@
1
+ #
2
+ # Evals into the given module_scope.
3
+ #
4
+ # Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de).
5
+ # All rights reserved.
6
+ #
7
+
8
+ def eval_into(module_scope, &block)
9
+ $RUBYJS__MODULE_SCOPE = module_scope
10
+ $RUBYJS__LOADED ||= [] # avoids recursive loads
11
+
12
+ $RUBYJS__EVAL = proc {|str|
13
+ $RUBYJS__MODULE_SCOPE.module_eval(str)
14
+ }
15
+
16
+ # install "require" handler
17
+ alias old_require require
18
+ def require(file)
19
+ ($RUBYJS__LOAD_PATH||['.']).each do |path|
20
+ name = File.expand_path(File.join(path, file + ".rb"))
21
+ if File.exists?(name)
22
+ if $RUBYJS__LOADED.include?(name)
23
+ return false
24
+ else
25
+ $RUBYJS__LOADED << name
26
+ STDERR.puts "loading file: #{name}" if $DEBUG
27
+ $RUBYJS__EVAL.call(File.read(name))
28
+
29
+ #
30
+ # load also platform specific file
31
+ # load first matching platform
32
+ #
33
+
34
+ ($RUBYJS__PLATFORM||[]).each do |plat|
35
+ plat_name = File.expand_path(File.join(path, file + "." + plat + ".rb"))
36
+ next unless File.exists?(plat_name)
37
+ unless $RUBYJS__LOADED.include?(plat_name)
38
+ $RUBYJS__LOADED << plat_name
39
+ STDERR.puts "loading platform specific file: #{plat_name}" if $DEBUG
40
+ $RUBYJS__EVAL.call(File.read(plat_name))
41
+ break
42
+ end
43
+ end
44
+
45
+ return true
46
+ end
47
+ else
48
+ next
49
+ end
50
+ end
51
+ raise ::RuntimeError, "require: #{file} not found"
52
+ end
53
+
54
+
55
+ block.call($RUBYJS__EVAL)
56
+
57
+ # change "require" handler back to original
58
+ alias require old_require
59
+ end
@@ -0,0 +1,1008 @@
1
+ #
2
+ # Core classes for the Javascript side
3
+ #
4
+ # Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de).
5
+ # All rights reserved.
6
+ #
7
+
8
+ class Proc
9
+ OBJECT_CONSTRUCTOR__ = "Function"
10
+
11
+ def self.new(&block)
12
+ raise ArgumentError, "tried to create Proc object without a block" unless block
13
+ #
14
+ # wrap block inside another function, that catches iter_break returns.
15
+ #
16
+ `return (function() {
17
+ try {
18
+ return #<block>.#<m:call>.apply(#<block>, arguments);
19
+ } catch(e)
20
+ {
21
+ if (e instanceof #<globalattr:iter_jump>)
22
+ {
23
+ if (e.#<attr:scope> == null)
24
+ {`
25
+ raise LocalJumpError, "break from proc-closure"
26
+ `}
27
+ return e.#<attr:return_value>;
28
+ }
29
+ else throw(e);
30
+ }
31
+ })`
32
+ end
33
+
34
+ def call(*args) `
35
+ // TODO: use switch/case
36
+ if (#<args>.length == 0) return #<self>();
37
+ else if (#<args>.length == 1) return #<self>(#<args>[0]);
38
+ else return #<self>(#<args>);`
39
+ end
40
+ end
41
+
42
+ class Boolean
43
+ OBJECT_CONSTRUCTOR__ = "Boolean"
44
+
45
+ class << self
46
+ undef_method :new
47
+ undef_method :allocate
48
+ end
49
+
50
+ def to_s
51
+ `return (#<self> == true ? 'true' : 'false')`
52
+ end
53
+
54
+ def ==(obj)
55
+ `return (#<self> == #<obj>)`
56
+ end
57
+
58
+ =begin
59
+ def &(other)
60
+ `return (#<self> == true ? (#<other>!==#<nil> ...`
61
+ end
62
+ =end
63
+
64
+ alias inspect to_s
65
+ end
66
+
67
+ class NilClass
68
+ OBJECT_CONSTRUCTOR__ = "NilClass"
69
+
70
+ class << self
71
+ undef_method :new
72
+ undef_method :allocate
73
+ end
74
+
75
+ def nil?
76
+ true
77
+ end
78
+
79
+ def to_s
80
+ ""
81
+ end
82
+
83
+ def to_i
84
+ 0
85
+ end
86
+
87
+ def to_f
88
+ 0.0
89
+ end
90
+
91
+ def to_a
92
+ []
93
+ end
94
+
95
+ def to_splat
96
+ []
97
+ end
98
+
99
+ def inspect
100
+ "nil"
101
+ end
102
+ end
103
+
104
+ class Class
105
+ def allocate
106
+ `return (new #<self>.#<attr:object_constructor>())`
107
+ end
108
+
109
+ def new(*args, &block)
110
+ obj = allocate()
111
+ obj.initialize(*args, &block)
112
+ obj
113
+ end
114
+
115
+ def ===(other)
116
+ eql?(other) or other.kind_of?(self)
117
+ end
118
+
119
+ def name
120
+ `return #<self>.#<attr:classname>`
121
+ end
122
+
123
+ alias inspect name
124
+
125
+ def self.new(superclass, classname, object_constructor=nil)
126
+ unless object_constructor
127
+ object_constructor = `(function() {})`
128
+ end
129
+ `return new #<self>.#<attr:object_constructor>(#<Class>, #<superclass>, #<classname>, #<object_constructor>);`
130
+ end
131
+ end
132
+
133
+ module Kernel
134
+ def nil?
135
+ false
136
+ end
137
+
138
+ def loop
139
+ while true
140
+ yield
141
+ end
142
+ end
143
+
144
+ def puts(str)
145
+ str = str.to_s
146
+ `alert(#<str>); return #<nil>`
147
+ end
148
+
149
+ def p(*args)
150
+ args.each do |arg|
151
+ puts arg.inspect
152
+ end
153
+ nil
154
+ end
155
+
156
+ def method_missing(id, *args, &block)
157
+ raise NoMethodError, "undefined method `#{id}' for #{self.inspect}"
158
+ end
159
+
160
+ # id is a Javascript name, e.g. $aaa
161
+ def __invoke(id, args, &block) `
162
+ var m = #<self>[#<id>];
163
+ if (m)
164
+ return m.apply(#<self>, [#<block>].concat(#<args>));
165
+ else
166
+ return #<self>.#<m:method_missing>.apply(#<self>,
167
+ [#<block>].concat([#<globalattr:mm>[#<id>]]).concat(#<args>));`
168
+ end
169
+
170
+ # NOTE: In Ruby __send is __send__
171
+ def __send(id, *args, &block) `
172
+ var m = #<self>[#<globalattr:mm_reverse>[#<id>]];
173
+ if (m)
174
+ return m.apply(#<self>, [#<block>].concat(#<args>));
175
+ else
176
+ return #<self>.#<m:method_missing>.apply(#<self>, [#<block>].concat([#<id>]).concat(#<args>));`
177
+ end
178
+ alias send __send
179
+
180
+ def respond_to?(id) `
181
+ var m = #<globalattr:mm_reverse>[#<id>];
182
+ return (m !== undefined && #<self>[m] !== undefined && !#<self>[m].#<attr:_mm>)`
183
+ end
184
+
185
+ def proc(&block)
186
+ Proc.new(&block)
187
+ end
188
+
189
+ def raise(*args)
190
+ ex =
191
+ if args.empty?
192
+ RuntimeError.new("")
193
+ else
194
+ first = args.shift
195
+ if first.kind_of?(Class) # FIXME: subclass of Exception
196
+ first.new(*args)
197
+ elsif first.instance_of?(Exception)
198
+ if args.empty?
199
+ first
200
+ else
201
+ ArgumentError.new("to many arguments given to raise")
202
+ end
203
+ elsif first.instance_of?(String)
204
+ if args.empty?
205
+ RuntimeError.new(first)
206
+ else
207
+ ArgumentError.new("to many arguments given to raise")
208
+ end
209
+ else
210
+ TypeError.new("exception class/object expected")
211
+ end
212
+ end
213
+
214
+ `throw(#<ex>)`
215
+ end
216
+ end
217
+
218
+ class Object
219
+ include Kernel
220
+
221
+ def eql?(other)
222
+ `return (#<self>.constructor == #<other>.constructor && #<self> == #<other>)`
223
+ end
224
+
225
+ def ===(other)
226
+ eql?(other) or kind_of?(other)
227
+ end
228
+
229
+ def instance_of?(klass)
230
+ `return (#<self>.#<attr:_class> === #<klass>)`
231
+ end
232
+
233
+ def kind_of?(klass)
234
+ `return #<globalattr:kind_of>(#<self>, #<klass>)`
235
+ end
236
+ alias is_a? kind_of?
237
+
238
+ # Ruby 1.9
239
+ def tap
240
+ yield self
241
+ self
242
+ end
243
+
244
+ def initialize
245
+ end
246
+
247
+ def class
248
+ `return #<self>.#<attr:_class>`
249
+ end
250
+
251
+ def to_s
252
+ `return #<self>.toString()`
253
+ end
254
+
255
+ alias inspect to_s
256
+ alias hash to_s
257
+
258
+ def method(id)
259
+ Method.new(self, id)
260
+ end
261
+ end
262
+
263
+ class Method
264
+ def initialize(object, method_id)
265
+ @object, @method_id = object, method_id
266
+
267
+ m = nil
268
+ `#<m> = #<object>[#<globalattr:mm_reverse>[#<method_id>]];
269
+ if (#<m>==null) #<m> = #<nil>;`
270
+ if m
271
+ @method = m
272
+ else
273
+ raise NameError, "undefined method `#{method_id}' for class `#{object.class.name}'"
274
+ end
275
+ end
276
+
277
+ def call(*args, &block)
278
+ `return #<self>.#<@method>.apply(#<self>.#<@object>, [#<block>].concat(#<args>))`
279
+ end
280
+
281
+ def inspect
282
+ "#<Method: #{@object.class.name}##{@method_id}>"
283
+ end
284
+ end
285
+
286
+ module Enumerable
287
+ def map(&block)
288
+ result = []
289
+ each {|elem| result << (block ? block.call(elem) : elem) }
290
+ result
291
+ end
292
+ alias collect map
293
+
294
+ def select
295
+ result = []
296
+ each {|elem|
297
+ if yield(elem)
298
+ result << elem
299
+ end
300
+ }
301
+ result
302
+ end
303
+ alias find_all select
304
+
305
+ def reject
306
+ result = []
307
+ each {|elem|
308
+ unless yield(elem)
309
+ result << elem
310
+ end
311
+ }
312
+ result
313
+ end
314
+
315
+ def to_a
316
+ result = []
317
+ each {|elem| result << elem}
318
+ result
319
+ end
320
+ end
321
+
322
+ class Range
323
+ def initialize(first, last, exclude_last=false)
324
+ @first, @last = first, last
325
+ @exclude_last = exclude_last ? true : false
326
+ end
327
+
328
+ def exclude_end?
329
+ @exclude_last
330
+ end
331
+
332
+ def first
333
+ @first
334
+ end
335
+ alias begin first
336
+
337
+ def last
338
+ @last
339
+ end
340
+ alias end last
341
+
342
+ def ==(obj)
343
+ `if (#<self>.constructor != #<obj>.constructor) return false;`
344
+ @first == obj.first and @last == obj.last and @exclude_last == obj.exclude_end?
345
+ end
346
+
347
+ def eql?(obj)
348
+ `if (#<self>.constructor != #<obj>.constructor) return false;`
349
+ @first.eql?(obj.first) and @last.eql?(obj.last) and @exclude_last == obj.exclude_end?
350
+ end
351
+
352
+ def include?(obj)
353
+ return false if obj < @first
354
+ if @exclude_last
355
+ obj < @last
356
+ else
357
+ obj <= @last
358
+ end
359
+ end
360
+
361
+ alias member? include?
362
+ alias === include?
363
+
364
+ def each
365
+ current = @first
366
+ return if @first > @last
367
+ if @exclude_last
368
+ while current < @last
369
+ yield current
370
+ current = current.succ
371
+ end
372
+ else
373
+ while current <= @last
374
+ yield current
375
+ current = current.succ
376
+ end
377
+ end
378
+ end
379
+
380
+ def to_a
381
+ arr = []
382
+ return arr if @first > @last
383
+ current = @first
384
+ if @exclude_last
385
+ while current < @last
386
+ arr << current
387
+ current = current.succ
388
+ end
389
+ else
390
+ while current <= @last
391
+ arr << current
392
+ current = current.succ
393
+ end
394
+ end
395
+ return arr
396
+ end
397
+
398
+ def to_s
399
+ if @exclude_last
400
+ "#{@first}...#{@last}"
401
+ else
402
+ "#{@first}..#{@last}"
403
+ end
404
+ end
405
+
406
+ def inspect
407
+ if @exclude_last
408
+ "#{@first.inspect}...#{@last.inspect}"
409
+ else
410
+ "#{@first.inspect}..#{@last.inspect}"
411
+ end
412
+ end
413
+
414
+ end
415
+
416
+ class Exception
417
+ attr_reader :message
418
+ def initialize(message=nil)
419
+ if message.nil?
420
+ @message = self.class.name
421
+ else
422
+ @message = message
423
+ end
424
+ end
425
+ alias to_s message
426
+
427
+ def inspect
428
+ "#<#{self.class.name}: #{@message}>"
429
+ end
430
+ end
431
+
432
+ class StandardError < Exception; end
433
+ class NameError < StandardError; end
434
+ class NoMethodError < NameError; end
435
+ class RuntimeError < StandardError; end
436
+ class ArgumentError < StandardError; end
437
+ class TypeError < StandardError; end
438
+ class LocalJumpError < StandardError; end
439
+
440
+ #
441
+ # NOTE: Strings in RubyJS are immutable!!!
442
+ #
443
+ class String
444
+ OBJECT_CONSTRUCTOR__ = "String"
445
+
446
+ def +(str)
447
+ `return(#<self> + #<str>)`
448
+ end
449
+
450
+ def empty?
451
+ `return(#<self> === "")`
452
+ end
453
+
454
+ def rjust(len, pad=" ")
455
+ raise ArgumentError, "zero width padding" if pad.empty?
456
+
457
+ n = len - self.length
458
+ return self if n <= 0
459
+
460
+ fillstr = ""
461
+ `while(#<fillstr>.length < #<n>) #<fillstr> += #<pad>;`
462
+
463
+ return fillstr[0,n] + self
464
+ end
465
+
466
+ def ljust(len, pad=" ")
467
+ raise ArgumentError, "zero width padding" if pad.empty?
468
+
469
+ n = len - self.length
470
+ return self if n <= 0
471
+
472
+ fillstr = ""
473
+ `while(#<fillstr>.length < #<n>) #<fillstr> += #<pad>;`
474
+
475
+ return self + fillstr[0,n]
476
+ end
477
+
478
+ def inspect
479
+ # prototype.js
480
+ specialChar = `{
481
+ '\\b': '\\\\b',
482
+ '\\t': '\\\\t',
483
+ '\\n': '\\\\n',
484
+ '\\f': '\\\\f',
485
+ '\\r': '\\\\r',
486
+ '\\\\': '\\\\\\\\'
487
+ };`
488
+
489
+ escapedString = self.gsub(/[\x00-\x1f\\]/) {|match|
490
+ character = `#<specialChar>[#<match>]`
491
+ `return #<character> ? #<character> :
492
+ '\\\\u00' + ("0" + #<match>.charCodeAt().toString(16)).substring(0,2);`
493
+ }
494
+
495
+ `return ('"' + #<escapedString>.replace(/"/g, '\\\\"') + '"');`
496
+ end
497
+
498
+ def to_s
499
+ self
500
+ end
501
+
502
+ def strip
503
+ `return #<self>.replace(/^\\s+/, '').replace(/\\s+$/, '')`
504
+ end
505
+
506
+ def split(str)
507
+ `return #<self>.split(#<str>)`
508
+ end
509
+
510
+ def length
511
+ `return #<self>.length`
512
+ end
513
+ alias size length
514
+
515
+ def index(substring, offset=0) `
516
+ var i = #<self>.indexOf(#<substring>, #<offset>);
517
+ return (i == -1) ? #<nil> : i`
518
+ end
519
+
520
+ def =~(pattern) `
521
+ var i = #<self>.search(#<pattern>);
522
+ return (i == -1 ? #<nil> : i)`
523
+ end
524
+
525
+ def gsub(pattern, replacement=nil)
526
+ # from prototype.js
527
+ result, source, match = "", self, nil
528
+ `while(#<source>.length > 0) {
529
+ if (#<match> = #<source>.match(#<pattern>)) {
530
+ #<result> += #<source>.slice(0, #<match>.index);`
531
+ if replacement
532
+ result += replacement
533
+ else
534
+ result += yield(match.first).to_s
535
+ end
536
+ `#<source> = #<source>.slice(#<match>.index + #<match>[0].length);
537
+ } else {
538
+ #<result> += #<source>; #<source> = '';
539
+ }
540
+ } return #<result>`
541
+ end
542
+
543
+ def sub(pattern, replacement)
544
+ # FIXME: block
545
+ `#<self>.replace(pattern, replacement)`
546
+ end
547
+
548
+ def [](index, len=nil)
549
+ if len.nil?
550
+ # single character access
551
+ # FIXME: returns a string and not a Fixnum!
552
+ # But: Ruby 1.9+ has this behaviour!!!
553
+ `return #<self>.charAt(#<index>) || #<nil>`
554
+ else
555
+ # substring access
556
+ return nil if len < 0
557
+ `return #<self>.substring(#<index>, #<index>+#<len>)`
558
+ end
559
+ end
560
+ end
561
+
562
+ class Number
563
+ OBJECT_CONSTRUCTOR__ = "Number"
564
+
565
+ class << self
566
+ undef_method :new
567
+ undef_method :allocate
568
+ end
569
+
570
+ def to_s(base=10)
571
+ `return #<self>.toString(#<base>)`
572
+ end
573
+
574
+ def inspect
575
+ `return #<self>.toString()`
576
+ end
577
+
578
+ def +(x) `return #<self> + #<x>` end
579
+ def -(x) `return #<self> - #<x>` end
580
+ def -@() `return -#<self>` end
581
+ def +@() `return #<self>` end
582
+ def *(x) `return #<self> * #<x>` end
583
+ def /(x) `return #<self> / #<x>` end
584
+ def <(x) `return #<self> < #<x>` end
585
+ def <=(x) `return #<self> <= #<x>` end
586
+ def >(x) `return #<self> > #<x>` end
587
+ def >=(x) `return #<self> >= #<x>` end
588
+ def ==(x) `return #<self> == #<x>` end
589
+ def %(x) `return #<self> % #<x>` end
590
+ def |(x) `return #<self> | #<x>` end
591
+ def &(x) `return #<self> & #<x>` end
592
+ def ^(x) `return #<self> ^ #<x>` end
593
+ def ~() `return ~#<self>` end
594
+
595
+ def succ() `return #<self>+1` end
596
+
597
+ def times
598
+ i = 0
599
+ while i < self
600
+ yield i
601
+ i += 1
602
+ end
603
+ return self
604
+ end
605
+
606
+ def downto(x)
607
+ i = self
608
+ while i >= x
609
+ yield i
610
+ i -= 1
611
+ end
612
+ return self
613
+ end
614
+
615
+ def upto(x)
616
+ i = self
617
+ while i <= x
618
+ yield i
619
+ i += 1
620
+ end
621
+ return self
622
+ end
623
+
624
+ end
625
+
626
+ # for compatibility
627
+ class Fixnum < Number; end
628
+ class Bignum < Number; end
629
+ class Float < Number; end
630
+
631
+ #
632
+ # Every method that returns an element has to
633
+ # check this element for +null+. This is required
634
+ # to seamlessly use Javascript data without needing
635
+ # to convert it before usage.
636
+ #
637
+ # The reverse, passing a RubyJS Array to Javascript
638
+ # without conversion of +nil+ to +null+ is of course
639
+ # not possible!
640
+ #
641
+ # NOTE: Following condition holds true:
642
+ # v == null <=> v=null || v=undefined
643
+ #
644
+ class Array
645
+ OBJECT_CONSTRUCTOR__ = "Array"
646
+
647
+ include Enumerable
648
+
649
+ def each() `
650
+ var elem;
651
+ for (var i=0; i < #<self>.length; i++) {
652
+ elem = #<self>[i];`
653
+ yield `(elem == null ? #<nil> : elem)`
654
+ `}
655
+ return #<self>`
656
+ end
657
+
658
+ def each_with_index() `
659
+ var elem;
660
+ for (var i=0; i < #<self>.length; i++) {
661
+ elem = #<self>[i];`
662
+ yield `(elem == null ? #<nil> : elem)`, `i`
663
+ `}
664
+ return #<self>`
665
+ end
666
+
667
+ def join(sep="")
668
+ str = ""
669
+ self.each_with_index {|elem, i|
670
+ str += elem.to_s
671
+ str += sep if i != self.length-1
672
+ }
673
+ str
674
+ end
675
+
676
+ def to_a
677
+ self
678
+ end
679
+
680
+ def to_ary
681
+ self
682
+ end
683
+
684
+ def self.new
685
+ `return []`
686
+ end
687
+
688
+ # TODO: test that otherArray is array
689
+ def +(otherArray)
690
+ `return #<self>.concat(#<otherArray>)`
691
+ end
692
+
693
+ def dup
694
+ `return #<self>.concat()`
695
+ end
696
+
697
+ def reverse
698
+ `return #<self>.concat().reverse()`
699
+ end
700
+
701
+ def reverse!
702
+ `#<self>.reverse(); return #<self>`
703
+ end
704
+
705
+ def length
706
+ `return #<self>.length`
707
+ end
708
+
709
+ alias size length
710
+
711
+ def first
712
+ `var v = #<self>[0]; return (v == null ? #<nil> : v)`
713
+ end
714
+
715
+ def last
716
+ `var v = #<self>[#<self>.length - 1]; return (v == null ? #<nil> : v)`
717
+ end
718
+
719
+ def clear
720
+ `#<self>.length=0; return #<self>`
721
+ end
722
+
723
+ # TODO: check arrary bounds
724
+ def [](i)
725
+ `var v = #<self>[#<i>]; return (v == null ? #<nil> : v)`
726
+ end
727
+
728
+ def []=(i, val)
729
+ `return (#<self>[#<i>] = #<val>)`
730
+ end
731
+
732
+ def push(*args)
733
+ `#<self>.push.apply(#<self>, #<args>); return #<self>`
734
+ end
735
+
736
+ def <<(arg)
737
+ `#<self>.push(#<arg>); return #<self>`
738
+ end
739
+
740
+ def pop() `
741
+ var elem = #<self>.pop();
742
+ return (elem == null ? #<nil> : elem)`
743
+ end
744
+
745
+ def shift() `
746
+ var elem = #<self>.shift();
747
+ return (elem == null ? #<nil> : elem)`
748
+ end
749
+
750
+ def delete(obj) `
751
+ var del = false;
752
+ for (var i=0; i < #<self>.length; i++)
753
+ {
754
+ if (#<obj>.#<m:eql?>(#<nil>, #<self>[i]))
755
+ {
756
+ #<self>.splice(i,1);
757
+ del = true;
758
+ // stay at the current index unless we are at the last element!
759
+ if (i < #<self>.length-1) --i;
760
+ }
761
+ }
762
+ return del ? #<obj> : #<nil>`
763
+ end
764
+
765
+ def unshift(*args)
766
+ `#<self>.unshift.apply(#<self>, #<args>); return #<self>`
767
+ end
768
+
769
+ def empty?
770
+ `return (#<self>.length == 0)`
771
+ end
772
+
773
+ def to_s
774
+ map {|i| i.to_s}.join
775
+ end
776
+
777
+ def inspect
778
+ str = "["
779
+ str += self.map {|elem| elem.inspect}.join(", ")
780
+ str += "]"
781
+ str
782
+ end
783
+
784
+ def eql?(other)
785
+ `
786
+ if (!(#<other> instanceof Array)) return false;
787
+ if (#<self>.length != #<other>.length) return false;
788
+
789
+ //
790
+ // compare element-wise
791
+ //
792
+ for (var i = 0; i < #<self>.length; i++)
793
+ {
794
+ if (! #<self>[i].#<m:eql?>(#<nil>, #<other>[i]))
795
+ {
796
+ //
797
+ // at least for one element #eql? holds not true
798
+ //
799
+ return false;
800
+ }
801
+ }
802
+
803
+ return true;
804
+ `
805
+ end
806
+ end
807
+
808
+ class Regexp
809
+ OBJECT_CONSTRUCTOR__ = "RegExp"
810
+ end
811
+
812
+ class MatchData
813
+ def initialize(match)
814
+ @match = match
815
+ end
816
+ end
817
+
818
+ #
819
+ # We prefix every element by a ":"
820
+ #
821
+ class Hash
822
+ include Enumerable
823
+
824
+ #
825
+ # Construct an empty Hash
826
+ #
827
+ def initialize() `
828
+ #<self>.#<attr:items> = {};
829
+ #<self>.#<attr:default_value> = #<nil>;
830
+ return #<nil>`
831
+ end
832
+
833
+ #
834
+ # Construct a Hash from key, value pairs, e.g.
835
+ #
836
+ # Hash.new_from_key_value_list(1,2, 3,4, 5,6)
837
+ #
838
+ # will result in
839
+ #
840
+ # {1 => 2, 3 => 4, 5 => 6}
841
+ #
842
+ def self.new_from_key_value_list(*list)
843
+ raise ArgumentError if list.length % 2 != 0
844
+ obj = allocate()
845
+ `
846
+ //
847
+ // we use an associate array to store the items. But unlike
848
+ // Javascript, the entries are arrays which contain the collisions.
849
+ // NOTE that we have to prefix the hash code with a prefix so that
850
+ // there are no collisions with methods etc.
851
+ // I prefix it for now with ":".
852
+ //
853
+ var items = {};
854
+ var hashed_key, current_key, current_val;
855
+
856
+ for (var i = 0; i < #<list>.length; i += 2)
857
+ {
858
+ current_key = #<list>[i];
859
+ current_val = #<list>[i+1];
860
+ hashed_key = ":" + current_key.#<m:hash>();
861
+
862
+ // make sure that a bucket exists
863
+ if (!items[hashed_key]) items[hashed_key] = [];
864
+
865
+ items[hashed_key].push(current_key, current_val);
866
+ }
867
+
868
+ #<obj>.#<attr:items> = items;
869
+ #<obj>.#<attr:default_value> = #<nil>;
870
+ return #<obj>;
871
+ `
872
+ end
873
+
874
+ def self.new_from_jsobject(jsobj)
875
+ obj = new()
876
+ end
877
+
878
+ def [](key) `
879
+ if (!#<self>.#<attr:items>)
880
+ {
881
+ // this is a Javascript Object, not a RubyJS Hash object.
882
+ // we directly look the key up. it's fast but not Ruby-like,
883
+ // so be careful!
884
+
885
+ var elem = #<self>[#<key>];
886
+ return (elem == null ? #<nil> : elem);
887
+ }
888
+
889
+ var hashed_key = ":" + #<key>.#<m:hash>();
890
+ var bucket = #<self>.#<attr:items>[hashed_key];
891
+
892
+ if (bucket)
893
+ {
894
+ //
895
+ // find the matching element inside the bucket
896
+ //
897
+
898
+ for (var i = 0; i < bucket.length; i += 2)
899
+ {
900
+ if (bucket[i].#<m:eql?>(#<nil>,#<key>))
901
+ return bucket[i+1];
902
+ }
903
+ }
904
+
905
+ // no matching key found -> return default value
906
+ return #<self>.#<attr:default_value>;
907
+ `
908
+ end
909
+
910
+ def []=(key, value) `
911
+ if (!#<self>.#<attr:items>)
912
+ {
913
+ // this is a Javascript Object, not a RubyJS Hash object.
914
+ // we directly look the key up. it's fast but not Ruby-like,
915
+ // so be careful!
916
+
917
+ #<self>[#<key>] = #<value>;
918
+ return #<value>;
919
+ }
920
+
921
+ var hashed_key = ":" + #<key>.#<m:hash>();
922
+ var bucket = #<self>.#<attr:items>[hashed_key];
923
+
924
+ if (bucket)
925
+ {
926
+ //
927
+ // find the matching element inside the bucket
928
+ //
929
+
930
+ for (var i = 0; i < bucket.length; i += 2)
931
+ {
932
+ if (bucket[i].#<m:eql?>(#<nil>,#<key>))
933
+ {
934
+ // overwrite value
935
+ bucket[i+1] = #<value>;
936
+ return #<value>;
937
+ }
938
+ }
939
+ // key not found in this bucket. append key, value pair to bucket
940
+ bucket.push(#<key>, #<value>);
941
+ }
942
+ else
943
+ {
944
+ //
945
+ // create new bucket
946
+ //
947
+ #<self>.#<attr:items>[hashed_key] = [#<key>, #<value>];
948
+ }
949
+ return #<value>;
950
+ `
951
+ end
952
+
953
+ def keys
954
+ map {|k,v| k}
955
+ end
956
+
957
+ def values
958
+ map {|k,v| v}
959
+ end
960
+
961
+ def each() `
962
+ if (!#<self>.#<attr:items>)
963
+ {
964
+ // this is a Javascript Object, not a RubyJS Hash object.
965
+ // we directly look the key up. it's fast but not Ruby-like,
966
+ // so be careful!
967
+ var key, value;
968
+ for (key in #<self>)
969
+ {
970
+ value = #<self>[key];`
971
+ yield `(key == null ? #<nil> : key)`, `(value == null ? #<nil> : value)`;
972
+ `
973
+ }
974
+
975
+ return #<nil>;
976
+ }
977
+
978
+ var key, bucket, i;
979
+ for (key in #<self>.#<attr:items>)
980
+ {
981
+ if (key.charAt(0) == ":")
982
+ {
983
+ bucket = #<self>.#<attr:items>[key];
984
+ for (i=0; i<bucket.length; i+=2)
985
+ {`
986
+ yield `bucket[i]`, `bucket[i+1]`
987
+ `
988
+ }
989
+ }
990
+ }
991
+ return #<nil>;
992
+ `
993
+ end
994
+
995
+ def inspect
996
+ str = "{"
997
+ str += map {|k, v| (k.inspect + "=>" + v.inspect) }.join(", ")
998
+ str += "}"
999
+ str
1000
+ end
1001
+
1002
+ def to_s
1003
+ strs = []
1004
+ each {|k, v| strs << k; strs << v}
1005
+ strs.join("")
1006
+ end
1007
+
1008
+ end