rubyjs 0.7.0

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.
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