opal 0.3.6 → 0.3.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/README.md +69 -97
  2. data/bin/opal +2 -2
  3. data/{lib/core → corelib}/array.rb +85 -56
  4. data/corelib/boolean.rb +20 -0
  5. data/corelib/class.rb +58 -0
  6. data/{lib → corelib}/core.rb +2 -50
  7. data/corelib/dir.rb +22 -0
  8. data/{lib/core → corelib}/enumerable.rb +0 -0
  9. data/corelib/error.rb +19 -0
  10. data/{lib/core → corelib}/file.rb +7 -9
  11. data/{lib/core → corelib}/hash.rb +104 -144
  12. data/{lib/core → corelib}/kernel.rb +38 -44
  13. data/corelib/load_order +21 -0
  14. data/{lib/core → corelib}/match_data.rb +0 -0
  15. data/{lib/core → corelib}/module.rb +12 -8
  16. data/{lib/core → corelib}/nil_class.rb +2 -2
  17. data/{lib/core → corelib}/numeric.rb +37 -100
  18. data/corelib/object.rb +37 -0
  19. data/{lib/core → corelib}/proc.rb +3 -3
  20. data/corelib/range.rb +27 -0
  21. data/{lib/core → corelib}/regexp.rb +1 -1
  22. data/{lib/core → corelib}/string.rb +16 -107
  23. data/{lib/core → corelib}/top_self.rb +0 -0
  24. data/lib/opal.rb +7 -0
  25. data/lib/opal/browserify.rb +34 -0
  26. data/{opal_lib → lib}/opal/builder.rb +70 -24
  27. data/lib/opal/command.rb +52 -0
  28. data/lib/opal/context.rb +197 -0
  29. data/{opal_lib/opal/ruby/parser.rb → lib/opal/lexer.rb} +20 -4
  30. data/{opal_lib/opal/ruby → lib/opal}/nodes.rb +238 -127
  31. data/lib/opal/parser.rb +4894 -0
  32. data/{opal_lib/opal/ruby/ruby_parser.y → lib/opal/parser.y} +38 -18
  33. data/lib/rbp.rb +2 -0
  34. data/lib/rbp/package.rb +49 -0
  35. data/runtime/class.js +216 -189
  36. data/runtime/fs.js +2 -2
  37. data/runtime/init.js +242 -244
  38. data/runtime/loader.js +78 -99
  39. data/runtime/module.js +34 -40
  40. data/runtime/post.js +2 -2
  41. data/runtime/pre.js +1 -1
  42. data/runtime/runtime.js +129 -135
  43. data/{lib → stdlib}/dev.rb +10 -10
  44. data/{lib → stdlib}/racc/parser.rb +0 -6
  45. data/{lib → stdlib}/strscan.rb +4 -4
  46. metadata +57 -105
  47. data/lib/core/basic_object.rb +0 -51
  48. data/lib/core/class.rb +0 -38
  49. data/lib/core/dir.rb +0 -26
  50. data/lib/core/error.rb +0 -75
  51. data/lib/core/false_class.rb +0 -81
  52. data/lib/core/object.rb +0 -6
  53. data/lib/core/range.rb +0 -27
  54. data/lib/core/symbol.rb +0 -42
  55. data/lib/core/true_class.rb +0 -41
  56. data/lib/ospec.rb +0 -7
  57. data/lib/ospec/autorun.rb +0 -8
  58. data/lib/ospec/dsl.rb +0 -15
  59. data/lib/ospec/example.rb +0 -11
  60. data/lib/ospec/example/before_and_after_hooks.rb +0 -56
  61. data/lib/ospec/example/errors.rb +0 -17
  62. data/lib/ospec/example/example_group.rb +0 -12
  63. data/lib/ospec/example/example_group_factory.rb +0 -18
  64. data/lib/ospec/example/example_group_hierarchy.rb +0 -21
  65. data/lib/ospec/example/example_group_methods.rb +0 -100
  66. data/lib/ospec/example/example_group_proxy.rb +0 -15
  67. data/lib/ospec/example/example_methods.rb +0 -46
  68. data/lib/ospec/example/example_proxy.rb +0 -18
  69. data/lib/ospec/expectations.rb +0 -19
  70. data/lib/ospec/expectations/errors.rb +0 -8
  71. data/lib/ospec/expectations/fail_with.rb +0 -9
  72. data/lib/ospec/expectations/handler.rb +0 -33
  73. data/lib/ospec/helpers/scratch.rb +0 -18
  74. data/lib/ospec/matchers.rb +0 -24
  75. data/lib/ospec/matchers/be.rb +0 -1
  76. data/lib/ospec/matchers/generated_descriptions.rb +0 -20
  77. data/lib/ospec/matchers/operator_matcher.rb +0 -54
  78. data/lib/ospec/matchers/raise_error.rb +0 -38
  79. data/lib/ospec/runner.rb +0 -90
  80. data/lib/ospec/runner/example_group_runner.rb +0 -41
  81. data/lib/ospec/runner/formatter/html_formatter.rb +0 -139
  82. data/lib/ospec/runner/formatter/terminal_formatter.rb +0 -48
  83. data/lib/ospec/runner/options.rb +0 -34
  84. data/lib/ospec/runner/reporter.rb +0 -82
  85. data/opal_lib/opal.rb +0 -16
  86. data/opal_lib/opal/build_methods.rb +0 -51
  87. data/opal_lib/opal/bundle.rb +0 -70
  88. data/opal_lib/opal/command.rb +0 -68
  89. data/opal_lib/opal/context.rb +0 -81
  90. data/opal_lib/opal/context/console.rb +0 -10
  91. data/opal_lib/opal/context/file_system.rb +0 -34
  92. data/opal_lib/opal/context/loader.rb +0 -135
  93. data/opal_lib/opal/gem.rb +0 -84
  94. data/opal_lib/opal/rake/builder_task.rb +0 -44
  95. data/opal_lib/opal/rake/spec_task.rb +0 -32
  96. data/opal_lib/opal/ruby/ruby_parser.rb +0 -4862
  97. data/opal_lib/opal/version.rb +0 -4
  98. data/runtime/debug.js +0 -84
@@ -0,0 +1,52 @@
1
+ module Opal
2
+
3
+ class Command
4
+
5
+ # Valid command line arguments
6
+ COMMANDS = [:help, :irb, :compile, :bundle, :exec, :eval]
7
+
8
+ def initialize(args)
9
+ command = args.shift
10
+
11
+ if command and COMMANDS.include?(command.to_sym)
12
+ __send__ command.to_sym, *args
13
+ elsif command and File.exists? command
14
+ eval command
15
+ else
16
+ help
17
+ end
18
+ end
19
+
20
+ def help
21
+ puts "need to print help"
22
+ end
23
+
24
+ # desc "irb", "Opens interactive opal/ruby repl"
25
+ def irb
26
+ ctx = Opal::Context.new
27
+ ctx.start_repl
28
+ end
29
+
30
+ def eval(path = nil)
31
+ return "no path given for eval" unless path
32
+
33
+ abort "path does not exist `#{path}'" unless File.exist? path
34
+
35
+ ctx = Opal::Context.new
36
+ ctx.require_file File.expand_path(path)
37
+ end
38
+
39
+ def compile(path)
40
+ puts Opal::Parser.new(File.read(path)).parse!.generate_top
41
+ end
42
+
43
+ # desc "bundle", "Bundle the gem in the given directory ready for browser"
44
+ # method_options :out => :string
45
+ def bundle
46
+ opts = options
47
+ bundle = Opal::Bundle.new(Opal::Gem.new(Dir.getwd))
48
+ bundle.build opts
49
+ end
50
+ end
51
+ end
52
+
@@ -0,0 +1,197 @@
1
+ module Opal
2
+ class Context
3
+
4
+ def initialize(root_dir = Dir.getwd)
5
+ @root_dir = root_dir
6
+ @builder = Opal::Builder.new
7
+
8
+ @load_paths = resolve_load_paths
9
+ end
10
+
11
+ # Looks through vendor/ directory and adds all relevant load paths
12
+ def resolve_load_paths
13
+ Dir['vendor/*/package.yml'].map do |package|
14
+ File.expand_path File.join(File.dirname(package), 'lib')
15
+ end
16
+ end
17
+
18
+ # Setup the context. This basically loads opal.js into our context, and
19
+ # replace the loader etc with our custom loader for a Ruby environment. The
20
+ # default "browser" loader cannot access files from disk.
21
+ def setup_v8
22
+ return if @v8
23
+
24
+ begin
25
+ require 'v8'
26
+ rescue LoadError => e
27
+ abort "therubyracer is required for running javascript. Install it with `gem install therubyracer`"
28
+ end
29
+
30
+ @v8 = V8::Context.new
31
+ @v8['console'] = Console.new
32
+
33
+ eval @builder.build_core, '(opal)'
34
+ opal = @v8['opal']
35
+ opal['fs'] = FileSystem.new self
36
+
37
+ # FIXME: we cant use a ruby array as a js array :(
38
+ opal['loader'] = Loader.new self, eval("[]")
39
+
40
+ @load_paths.each do |path|
41
+ eval "opal.loader.paths.push('#{path}')"
42
+ end
43
+
44
+ end
45
+
46
+ def eval(code, file = nil)
47
+ @v8.eval code, file
48
+ end
49
+
50
+ # Require the given id as if it was required in the context. This simply
51
+ # passes the require through to the underlying context.
52
+ def require_file(path)
53
+ setup_v8
54
+ eval "opal.run(function() {opal.require('#{path}');});", path
55
+ finish
56
+ end
57
+
58
+ # Set ARGV for the context
59
+ def argv=(args)
60
+ puts "setting argv to #{args.inspect}"
61
+ eval "opal.runtime.cs(opal.runtime.Object, 'ARGV', #{args.inspect});"
62
+ end
63
+
64
+ # Start normal js repl
65
+ def start_repl
66
+ require 'readline'
67
+ setup_v8
68
+
69
+ loop do
70
+ # on SIGINT lets just return from the loop..
71
+ trap("SIGINT") { finish; return }
72
+ line = Readline.readline '>> ', true
73
+
74
+ # if we type exit, then we need to close down context
75
+ if line == "exit"
76
+ break
77
+ end
78
+
79
+ puts "=> #{eval_ruby line, '(opal)'}"
80
+ end
81
+
82
+ finish
83
+ end
84
+
85
+ def eval_ruby(content, line = "")
86
+ begin
87
+ code = Opal::Parser.new(content).parse!.generate_top
88
+ code = "opal.run(function() {var $rb = opal.runtime, self = $rb.top, __FILE__ = '(opal)';" + code + "});"
89
+ # puts code
90
+ @v8['$opal_irb_result'] = eval code, line
91
+ eval "!($opal_irb_result == null || !$opal_irb_result.m$inspect) ? $opal_irb_result.m$inspect() : '(Object does not support #inspect)'"
92
+ rescue => e
93
+ puts e
94
+ puts("\t" + e.backtrace.join("\n\t"))
95
+ end
96
+ end
97
+
98
+ # Finishes the context, i.e. tidy everything up. This will cause
99
+ # the opal runtime to do it's at_exit() calls (if applicable) and
100
+ # then the v8 context will de removed. It can be reset by calling
101
+ # #setup_v8
102
+ def finish
103
+ return unless @v8
104
+ eval "opal.runtime.do_at_exit()", "(opal)"
105
+
106
+ @v8 = nil
107
+ end
108
+
109
+ # Console class is used to mimic the console object in web browsers
110
+ # to allow simple debugging to the stdout.
111
+ class Console
112
+ def log(*str)
113
+ puts str.join("\n")
114
+ nil
115
+ end
116
+ end
117
+
118
+ # FileSystem is used to interact with the file system from the ruby
119
+ # version of opal. The methods on this class replace the default ones
120
+ # made available in the web browser.
121
+ class FileSystem
122
+
123
+ def initialize(context)
124
+ @context = context
125
+ end
126
+
127
+ def cwd
128
+ Dir.getwd
129
+ end
130
+
131
+ def glob(*arr)
132
+ Dir.glob arr
133
+ end
134
+
135
+ def exist_p(path)
136
+ File.exist? path
137
+ end
138
+
139
+ def expand_path(filename, dir_string = nil)
140
+ File.expand_path filename, dir_string
141
+ end
142
+
143
+ def dirname(file)
144
+ File.dirname file
145
+ end
146
+
147
+ def join(*parts)
148
+ File.join *parts
149
+ end
150
+ end
151
+
152
+ # Loader for v8 context
153
+ class Loader
154
+
155
+ attr_reader :paths
156
+
157
+ def initialize(context, paths)
158
+ @context = context
159
+ @paths = paths
160
+ end
161
+
162
+ def resolve_lib(id)
163
+ resolved = find_lib id
164
+ raise "Cannot find lib `#{id}'" unless resolved
165
+
166
+ resolved
167
+ end
168
+
169
+ def find_lib(id)
170
+ @paths.each do |path|
171
+ candidate = File.join path, "#{id}.rb"
172
+ return candidate if File.exists? candidate
173
+
174
+ candidate = File.join path, id
175
+ return candidate if File.exists? candidate
176
+ end
177
+
178
+ return File.expand_path id if File.exists? id
179
+ return File.expand_path(id + '.rb') if File.exists?(id + '.rb')
180
+
181
+ nil
182
+ end
183
+
184
+ def ruby_file_contents(filename)
185
+ Opal::Parser.new(File.read(filename)).parse!.generate_top
186
+ end
187
+
188
+ def wrap(content, filename)
189
+ code = "(function($rb, self, __FILE__) { #{content} });"
190
+ @context.eval code, filename
191
+ # code
192
+ end
193
+ end
194
+
195
+ end
196
+ end
197
+
@@ -1,11 +1,12 @@
1
1
 
2
- require 'opal/ruby/ruby_parser'
3
- require 'opal/ruby/nodes'
2
+ require 'opal/parser'
3
+ require 'opal/nodes'
4
+
4
5
 
5
6
  require 'strscan'
6
7
 
7
8
  module Opal
8
- class RubyParser < Racc::Parser
9
+ class Parser < Racc::Parser
9
10
 
10
11
  class RubyLexingError < StandardError
11
12
 
@@ -29,7 +30,6 @@ module Opal
29
30
 
30
31
  def next_token
31
32
  t = get_next_token
32
- # puts "returning token #{t.inspect}"
33
33
  t[1] = { :value => t[1], :line => @line_number }
34
34
  t
35
35
  end
@@ -725,6 +725,14 @@ module Opal
725
725
  @lex_state = :expr_end
726
726
  return :NIL, scanner.matched
727
727
 
728
+ when 'undefined'
729
+ @lex_state = :expr_end
730
+ return :UNDEFINED, scanner.matched
731
+
732
+ when 'null'
733
+ @lex_state = :expr_end
734
+ return :NULL, scanner.matched
735
+
728
736
  when '__LINE__'
729
737
  @lex_state = :expr_end
730
738
  return :LINE, @line_number.to_s
@@ -809,6 +817,14 @@ module Opal
809
817
  @lex_state = :expr_beg
810
818
  return :WHILE_MOD, scanner.matched
811
819
 
820
+ when 'for'
821
+ @lex_state = :expr_beg
822
+ return :FOR, scanner.matched
823
+
824
+ when 'in'
825
+ @lex_state = :expr_beg
826
+ return :IN, scanner.matched
827
+
812
828
  when 'until'
813
829
  return :WHILE, scanner.matched if @lex_state == :expr_beg
814
830
  @lex_state = :expr_beg
@@ -1,5 +1,5 @@
1
1
  module Opal
2
- class RubyParser < Racc::Parser
2
+ class Parser < Racc::Parser
3
3
 
4
4
  # Indent for generated code scopes; 2 spaces, never use tabs
5
5
  INDENT = ' '
@@ -8,6 +8,7 @@ module Opal
8
8
  LEVEL_TOP_CLOSURE = 1 # normal top level, but wrapped in js closure
9
9
  LEVEL_LIST = 2
10
10
  LEVEL_EXPR = 3
11
+ LEVEL_COMPARE = 4 # comparison of if statement etc
11
12
 
12
13
  # Base node for generators. All other nodes inherit from this
13
14
  class BaseNode
@@ -69,6 +70,27 @@ module Opal
69
70
 
70
71
  code
71
72
  end
73
+
74
+ # Reserved js words - we cannot just generate properties with these names
75
+ # as they will cause a parse error, so we need to wrap them in brackets.
76
+ def js_reserved_words
77
+ %w[break case catch continue debugger default delete do else finally
78
+ for function if in instanceof new return switch this throw try typeof
79
+ var void while with class enum export extends import super true false]
80
+ end
81
+
82
+ def generate_truthy_test(expr, opts)
83
+ if expr.is_a? ComparisonNode
84
+ expr.generate opts, LEVEL_EXPR
85
+ else
86
+ tmp = opts[:scope].temp_local
87
+ code = expr.generate opts, LEVEL_EXPR
88
+ res = "(#{tmp} = #{code}, #{tmp} !== false && #{tmp} !== nil)"
89
+ opts[:scope].queue_temp tmp
90
+ res
91
+ end
92
+ end
93
+
72
94
  end
73
95
 
74
96
  # Scope nodes. All scope nodes inherit from this node, including: method,
@@ -194,26 +216,6 @@ module Opal
194
216
  super nil, statements
195
217
  @file_helpers = []
196
218
  @line = 1
197
- @mm_ids = []
198
-
199
- @symbol_refs = {}
200
- @symbol_count = 1
201
-
202
- @regexp_refs = []
203
- end
204
-
205
- def register_mm_id(mid)
206
- @mm_ids << mid unless @mm_ids.include? mid
207
- end
208
-
209
- def register_symbol(sym)
210
- if ref = @symbol_refs[sym]
211
- ref
212
- else
213
- ref = @symbol_refs[sym] = "$symbol_#{@symbol_count}"
214
- @symbol_count += 1
215
- ref
216
- end
217
219
  end
218
220
 
219
221
  def generate(opts, level)
@@ -225,32 +227,26 @@ module Opal
225
227
 
226
228
  pre = 'function $$(){'
227
229
  post = "\n}\n"
228
- # post = "\n\n}\nvar nil, $ac, $super, $break, $class, $def, $symbol, $range, "
229
- # post += '$hash, $B, Qtrue, Qfalse, $cg;'
230
- # local vars... only if we used any..
230
+
231
231
  unless @scope_vars.empty?
232
232
  post += "var #{@scope_vars.join ', '};"
233
233
  end
234
234
 
235
- post += 'var nil = $rb.Qnil, $ac = $rb.ac, $super = $rb.S, $break = $rb.B, '
236
- post += '$class = $rb.dc, $defn = $rb.dm, $defs = $rb.ds, $symbol = $rb.Y, '
237
- post += '$hash = $rb.H, $B = $rb.P, Qtrue = $rb.Qtrue, Qfalse = $rb.Qfalse, '
238
- post += '$cg = $rb.cg, $range = $rb.G'
239
-
240
- # symbols
241
- @symbol_refs.each do |val, sym|
242
- post += ", #{sym} = $symbol('#{val}')"
243
- end
235
+ post += 'var nil = $rb.Qnil, $super = $rb.S, $break = $rb.B, '
236
+ post += '$class = $rb.dc, $defn = $rb.dm, $defs = $rb.ds, $cg = $rb.cg, '
237
+ post += '$range = $rb.G, $hash = $rb.H, $B = $rb.P'
244
238
 
245
239
  post += ';'
246
240
 
247
- if @mm_ids.length > 0
248
- post += "$rb.mm(['#{ @mm_ids.join "', '" }']);"
249
- end
250
-
251
241
  # ivars
252
242
  @ivars.each do |ivar|
253
- post += "if (self['#{ivar}'] == undefined) { self['#{ivar}'] = nil; }"
243
+ if js_reserved_words.include? ivar
244
+ ivar_name = "self['#{ivar}']"
245
+ else
246
+ ivar_name = "self.#{ivar}"
247
+ end
248
+
249
+ post += "#{ivar_name}===undefined&&(#{ivar_name}=nil);"
254
250
  end
255
251
 
256
252
  post += "return $$();\n"
@@ -348,7 +344,7 @@ module Opal
348
344
  end
349
345
 
350
346
  def generate(opts, level)
351
- opts[:top].register_symbol @value
347
+ "'#{@value}'"
352
348
  end
353
349
  end
354
350
 
@@ -369,20 +365,10 @@ module Opal
369
365
  end
370
366
 
371
367
  def mid_to_jsid(id)
372
- return ".$m['#{id}']" if /[\!\=\?\+\-\*\/\^\&\%\@\|\[\]\<\>\~]/ =~ id
373
-
374
- return ".$m['#{id}']" if js_reserved_words.include? id
368
+ return "['#{id}']" if /[\!\=\?\+\-\*\/\^\&\%\@\|\[\]\<\>\~]/ =~ id
375
369
 
376
370
  # default we just do .method_name
377
- '.$m.' + id
378
- end
379
-
380
- # Reserved js words - we cannot just generate properties with these names
381
- # as they will cause a parse error, so we need to wrap them in brackets.
382
- def js_reserved_words
383
- %w[break case catch continue debugger default delete do else finally
384
- for function if in instanceof new return switch this throw try typeof
385
- var void while with class enum export extends import super]
371
+ '.' + id
386
372
  end
387
373
 
388
374
  def generate(opts, level)
@@ -393,16 +379,13 @@ module Opal
393
379
 
394
380
  elsif @mid == "block_given?"
395
381
  # name = opts[:scope].set_uses_block
396
- return "($yy == $y.y ? Qfalse : Qtrue)"
382
+ return "($yy !== $y.y)"
397
383
  end
398
384
 
399
385
  code = ''
400
386
  arg_res = []
401
387
  recv = nil
402
- mid = @mid
403
- tmp_recv = opts[:scope].temp_local
404
-
405
- opts[:top].register_mm_id @mid
388
+ mid = 'm$' + @mid
406
389
 
407
390
  # receiver
408
391
  if @recv.is_a? NumericNode
@@ -410,25 +393,11 @@ module Opal
410
393
  elsif @recv
411
394
  recv = @recv.process opts, LEVEL_EXPR
412
395
  else
413
- @recv = SelfNode.new
414
396
  recv = "self"
415
- mid = '$' + mid
416
397
  end
417
398
 
418
399
  mid = mid_to_jsid(mid)
419
400
 
420
- if @recv.is_a? SelfNode
421
- recv_code = recv
422
- recv_arg = recv
423
- elsif @recv.is_a?(IdentifierNode) and @recv.local_variable?(opts)
424
- recv_code = recv
425
- recv_arg = recv
426
- else
427
- recv_code = "(#{tmp_recv} = #{recv})"
428
- recv_arg = "#{tmp_recv}"
429
- end
430
-
431
-
432
401
  args = @args
433
402
  # normal args
434
403
  if args[0]
@@ -443,11 +412,12 @@ module Opal
443
412
  end
444
413
 
445
414
  if @block
415
+ tmp_recv = opts[:scope].temp_local
446
416
  block = @block.generate opts, LEVEL_TOP
447
- arg_res.unshift recv_arg
417
+ arg_res.unshift tmp_recv
448
418
 
449
- code = "($B.f = #{recv_code}#{mid}, ($B.p ="
450
- code += "#{block}).$proc =[self], $B.f)(#{arg_res.join ', '})"
419
+ code = "(#{tmp_recv} = #{recv}, $B.f = #{tmp_recv}#{mid}, ($B.p ="
420
+ code += "#{block}).$self=self, $B.f).call(#{arg_res.join ', '})"
451
421
 
452
422
  opts[:scope].queue_temp tmp_recv
453
423
  code
@@ -457,10 +427,11 @@ module Opal
457
427
  #
458
428
  # FIXME need to actually call to_proc.
459
429
  elsif args[3]
460
- arg_res.unshift recv_arg
430
+ tmp_recv = opts[:scope].temp_local
431
+ arg_res.unshift tmp_recv
461
432
 
462
433
  code = "($B.p = #{args[3].process opts, LEVEL_LIST}, "
463
- code += "$B.f = #{recv_code}#{mid})(#{arg_res.join ', '})"
434
+ code += "$B.f = (#{tmp_recv} = #{recv})#{mid}).call(#{arg_res.join ', '})"
464
435
 
465
436
  opts[:scope].queue_temp tmp_recv
466
437
 
@@ -470,21 +441,18 @@ module Opal
470
441
  else
471
442
  # splat args
472
443
  if args[1]
473
- arg_res.unshift recv_arg
444
+ tmp_recv = opts[:scope].temp_local
474
445
  splat = args[1].generate(opts, LEVEL_EXPR)
475
446
  splat_args = arg_res.empty? ? "#{splat}" : "[#{arg_res.join ', '}].concat(#{splat})"
476
447
  # when using splat, our this val for apply may need a tmp var
477
448
  # to save just outputting it twice (have to follow recv path twice)
478
449
  splat_recv = recv
479
- result = "#{recv_code}" + mid + ".apply(nil, #{splat_args})"
450
+ result = "(#{tmp_recv} = #{recv})" + mid + ".apply(#{tmp_recv}, #{splat_args})"
480
451
 
481
452
  opts[:scope].queue_temp tmp_recv
482
453
  result
483
454
  else
484
- arg_res.unshift recv_arg
485
-
486
- result = "#{recv_code}#{mid}(#{arg_res.join(', ')})"
487
- opts[:scope].queue_temp tmp_recv
455
+ result = "#{recv}#{mid}(#{arg_res.join(', ')})"
488
456
  result
489
457
  end
490
458
  end
@@ -514,6 +482,28 @@ module Opal
514
482
  end
515
483
  end
516
484
 
485
+ class UndefinedNode < BaseNode
486
+
487
+ def initialize(val)
488
+ @line = val[:line]
489
+ end
490
+
491
+ def generate(opts, level)
492
+ 'undefined'
493
+ end
494
+ end
495
+
496
+ class NullNode < BaseNode
497
+
498
+ def initialize(val)
499
+ @line = val[:line]
500
+ end
501
+
502
+ def generate(opts, level)
503
+ 'null'
504
+ end
505
+ end
506
+
517
507
  class ModuleNode < ScopeNode
518
508
 
519
509
  def initialize(mod, path, body, _end)
@@ -688,7 +678,13 @@ module Opal
688
678
  args[1].each do |arg|
689
679
  param_variable arg[0][:value]
690
680
  method_args << arg[0][:value]
691
- pre_code += "if (#{arg[0][:value]} == undefined) {#{arg[0][:value]} = #{arg[1].generate(opts, LEVEL_EXPR)};}"
681
+
682
+ # undefined is a special case... we use it to make core libs have
683
+ # right arity, but we dont want overhead of checking for no arg.
684
+ # i.e. non given arg will be undefined, not nil..
685
+ unless arg[1].is_a? UndefinedNode
686
+ pre_code += "if (#{arg[0][:value]} == undefined) {#{arg[0][:value]} = #{arg[1].generate(opts, LEVEL_EXPR)};}"
687
+ end
692
688
  end
693
689
  end
694
690
 
@@ -697,10 +693,11 @@ module Opal
697
693
  if args[2][:value] != "*"
698
694
  param_variable args[2][:value]
699
695
  method_args << args[2][:value]
700
- pre_code += "#{args[2][:value]} = [].slice.call(arguments, #{method_args.length});"
696
+ pre_code += "#{args[2][:value]} = [].slice.call(arguments, #{method_args.length - 1});"
701
697
  end
702
698
  end
703
699
 
700
+ # arity not currently used..could use it for debug mode?
704
701
  arity = (-arity) - 1 if args[1] or args[2]
705
702
 
706
703
  # block arg
@@ -712,9 +709,8 @@ module Opal
712
709
 
713
710
  @body.returns
714
711
  stmt = @body.generate scope, LEVEL_TOP
715
- method_args.unshift 'self'
716
712
 
717
- code += "function(#{method_args.join ', '}) {"
713
+ code += "function(#{method_args.join ', '}) { var self = this;"
718
714
 
719
715
  # local vars... only if we used any..
720
716
  unless @scope_vars.empty?
@@ -723,7 +719,13 @@ module Opal
723
719
 
724
720
  # ivars
725
721
  @ivars.each do |ivar|
726
- pre_code += "self['#{ivar}']==undefined&&(self['#{ivar}']=nil);"
722
+ if js_reserved_words.include? ivar
723
+ ivar_name = "self['#{ivar}']"
724
+ else
725
+ ivar_name = "self.#{ivar}"
726
+ end
727
+
728
+ pre_code += "if (#{ivar_name} == undefined) { #{ivar_name} = nil; }"
727
729
  end
728
730
 
729
731
  # block support
@@ -732,14 +734,14 @@ module Opal
732
734
  block_code = "var $y = $B, $yy, $ys, $yb = $y.b;"
733
735
  block_code += "if ($y.f == arguments.callee) { $yy = $y.p; }"
734
736
  block_code += "else { $yy = $y.y; }"
735
- block_code += "$y.f = nil ;$ys = $yy.$proc[0];"
737
+ block_code += "$y.f = nil ;$ys = $yy.$self;"
736
738
  pre_code = block_code + pre_code
737
739
  end
738
740
 
739
741
  code += (pre_code + stmt)
740
742
 
741
743
  # fix trailing end and 0/1 for normal/singleton
742
- code += (fix_line_number(opts, @end_line) + "}, #{arity})")
744
+ code += (fix_line_number(opts, @end_line) + "})")
743
745
 
744
746
  code
745
747
  end
@@ -748,6 +750,7 @@ module Opal
748
750
  class BodyStatementsNode < BaseNode
749
751
 
750
752
  attr_reader :opt_rescue
753
+ attr_reader :opt_ensure
751
754
 
752
755
  def initialize(stmt, optrescue, optelse, optensure)
753
756
  @statements = stmt
@@ -777,7 +780,7 @@ module Opal
777
780
  def generate(opts, level)
778
781
  res = '(('
779
782
  tmp = opts[:scope].temp_local
780
- res += "#{tmp} = #{@lhs.generate opts, LEVEL_LIST}).$r ? "
783
+ res += "(#{tmp} = #{@lhs.generate opts, LEVEL_LIST}), #{tmp} != false && #{tmp} != nil) ? "
781
784
  res += "#{tmp} : #{@rhs.generate opts, LEVEL_LIST})"
782
785
  opts[:scope].queue_temp tmp
783
786
  res
@@ -795,7 +798,7 @@ module Opal
795
798
  def generate(opts, level)
796
799
  res = '(('
797
800
  tmp = opts[:scope].temp_local
798
- res += "#{tmp} = #{@lhs.generate opts, LEVEL_LIST}).$r ? "
801
+ res += "(#{tmp} = #{@lhs.generate opts, LEVEL_LIST}), #{tmp} != false && #{tmp} != nil) ? "
799
802
  res += "#{@rhs.generate opts, LEVEL_LIST} : #{tmp})"
800
803
  opts[:scope].queue_temp tmp
801
804
  res
@@ -822,7 +825,7 @@ module Opal
822
825
  res = code
823
826
  end
824
827
 
825
- res
828
+ "#{res}"
826
829
  end
827
830
  end
828
831
 
@@ -884,20 +887,18 @@ module Opal
884
887
  @level_expr = true
885
888
  end
886
889
 
887
- expr = @expr.generate opts, LEVEL_EXPR
888
- expr = "(#{expr})" if @expr.is_a? NumericNode
889
-
890
+ expr = generate_truthy_test @expr, opts
890
891
  # code += "if ((#{@expr.generate opts, LEVEL_EXPR}).$r) {#{@stmt.process opts, stmt_level}"
891
- code += "if (#{@type == 'if' ? '' : '!'}#{expr}.$r) {#{@stmt.process opts, stmt_level}"
892
+ code += "if (#{@type == 'if' ? '' : '!'}#{expr}) {#{@stmt.process opts, stmt_level}"
892
893
 
893
894
  @tail.each do |tail|
894
895
  opts[:indent] = old_indent
895
896
  code = code + fix_line_number(opts, tail[0][:line])
896
897
 
897
898
  if tail[0][:value] == 'elsif'
898
- expr = tail[1].generate opts, LEVEL_EXPR
899
- expr = "(#{expr})" if tail[1].is_a? NumericNode
900
- code += "} else if (#{expr}.$r) {"
899
+ expr = generate_truthy_test tail[1], opts
900
+
901
+ code += "} else if (#{expr}) {"
901
902
  # code += "} else if ((#{tail[1].generate opts, LEVEL_EXPR}).$r) {"
902
903
  opts[:indent] = opts[:indent] + INDENT
903
904
  code = code + tail[2].process(opts, stmt_level)
@@ -971,10 +972,10 @@ module Opal
971
972
  if part[0][:value] == 'when'
972
973
  code += (idx == 0 ? "if" : "} else if")
973
974
  parts = part[1].map do |expr|
974
- CallNode.new(expr,
975
+ generate_truthy_test CallNode.new(expr,
975
976
  {:value => '===' },
976
977
  [[TempNode.new(case_ref)]]
977
- ).generate(opts, LEVEL_EXPR) + '.$r'
978
+ ), opts
978
979
  end
979
980
  opts[:indent] = opts[:indent] + INDENT
980
981
  code += " (#{parts.join ' || '}) {#{part[2].process opts, stmt_level}"
@@ -988,7 +989,7 @@ module Opal
988
989
  opts[:scope].queue_temp case_ref
989
990
  code += (fix_line_number(opts, @end_line) + '}')
990
991
 
991
- code = "(function() {#{code})()" if level == LEVEL_EXPR
992
+ code = "(function() {#{code}})()" if level == LEVEL_EXPR
992
993
  code
993
994
  end
994
995
  end
@@ -1057,7 +1058,14 @@ module Opal
1057
1058
 
1058
1059
  def generate(opts, level)
1059
1060
  if @lhs.is_a? IvarNode
1060
- return "#{SelfNode.new.generate(opts, level)}['#{@lhs.value}'] = #{@rhs.generate(opts, LEVEL_EXPR)}"
1061
+ ivar_name = @lhs.value.slice 1, @lhs.value.length
1062
+ ivar_rhs = @rhs.generate opts, LEVEL_EXPR
1063
+
1064
+ return "self['#{ivar_name}'] = #{ivar_rhs}" if js_reserved_words.include? ivar_name
1065
+ return "self.#{ivar_name} = #{ivar_rhs}"
1066
+
1067
+ elsif @lhs.is_a? CvarNode
1068
+ return "$rb.cvs('#{@lhs.value}', #{@rhs.generate opts, LEVEL_EXPR})"
1061
1069
 
1062
1070
  elsif @lhs.is_a? GvarNode
1063
1071
  return "$rb.gs('#{@lhs.value}', #{@rhs.generate(opts, LEVEL_EXPR)})"
@@ -1167,8 +1175,25 @@ module Opal
1167
1175
  end
1168
1176
 
1169
1177
  def generate(opts, level)
1170
- opts[:scope].ensure_ivar @value
1171
- "#{SelfNode.new.generate(opts, level)}['#{@value}']"
1178
+ var_name = @value.slice 1, @value.length
1179
+ opts[:scope].ensure_ivar var_name
1180
+
1181
+ return "self['#{var_name}']" if js_reserved_words.include? var_name
1182
+ "self.#{var_name}"
1183
+ end
1184
+ end
1185
+
1186
+ class CvarNode < BaseNode
1187
+
1188
+ attr_reader :value
1189
+
1190
+ def initialize(val)
1191
+ @line = val[:line]
1192
+ @value = val[:value]
1193
+ end
1194
+
1195
+ def generate(opts, level)
1196
+ "$rb.cvg('#{@value}')"
1172
1197
  end
1173
1198
  end
1174
1199
 
@@ -1228,7 +1253,8 @@ module Opal
1228
1253
  if part[0] == 'string_content'
1229
1254
  @join + part[1][:value] + @join
1230
1255
  elsif part[0] == 'string_dbegin'
1231
- CallNode.new(part[1], { :value => 'to_s', :line => 0 }, [[]]).generate(opts, level)
1256
+ "(" + part[1].generate(opts, LEVEL_EXPR) + ").m$to_s()"
1257
+ # CallNode.new(part[1], { :value => 'to_s', :line => 0 }, [[]]).generate(opts, level)
1232
1258
  end
1233
1259
  end
1234
1260
 
@@ -1237,6 +1263,49 @@ module Opal
1237
1263
  end
1238
1264
  end
1239
1265
 
1266
+ class ComparisonNode < BaseNode
1267
+
1268
+ def initialize(op, lhs, rhs)
1269
+ @line = op[:line]
1270
+ @op = op[:value]
1271
+ @lhs = lhs
1272
+ @rhs = rhs
1273
+ end
1274
+
1275
+ def generate(opts, level)
1276
+ lhs = @lhs.generate opts, LEVEL_EXPR
1277
+ lhs = "(#{lhs})" if @lhs.is_a? NumericNode
1278
+ rhs = @rhs.generate opts, LEVEL_EXPR
1279
+
1280
+ if @op == '!='
1281
+ "!#{lhs}['m$=='](#{rhs})"
1282
+ else
1283
+ "#{lhs}['m$#{@op}'](#{rhs})"
1284
+ end
1285
+ end
1286
+ end
1287
+
1288
+ class UnaryNode < BaseNode
1289
+
1290
+ def initialize(op, val)
1291
+ @line = op[:line]
1292
+ @op = op[:value]
1293
+ @val = val
1294
+ end
1295
+
1296
+ def generate(opts, level)
1297
+ if @op == '!'
1298
+ tmp = opts[:scope].temp_local
1299
+ expr = @val.generate opts, LEVEL_EXPR
1300
+ res = "(#{tmp} = #{expr}, #{tmp} === false || #{tmp} === nil)"
1301
+ opts[:scope].queue_temp tmp
1302
+ res
1303
+ else
1304
+ "#{@op}#{@val.generate opts, level}"
1305
+ end
1306
+ end
1307
+ end
1308
+
1240
1309
  class TrueNode < BaseNode
1241
1310
 
1242
1311
  def initialize(val)
@@ -1244,7 +1313,7 @@ module Opal
1244
1313
  end
1245
1314
 
1246
1315
  def generate(opts, level)
1247
- "Qtrue"
1316
+ "true"
1248
1317
  end
1249
1318
  end
1250
1319
 
@@ -1255,7 +1324,7 @@ module Opal
1255
1324
  end
1256
1325
 
1257
1326
  def generate(opts, level)
1258
- "Qfalse"
1327
+ "false"
1259
1328
  end
1260
1329
  end
1261
1330
 
@@ -1293,7 +1362,7 @@ module Opal
1293
1362
  #
1294
1363
  # Also, this is optional, and can be turned on/off for
1295
1364
  # performance gains.
1296
- if true
1365
+ if false
1297
1366
  pre_code += "if (#{arg[:value]} === undefined) { #{arg[:value]} = nil; }"
1298
1367
  end
1299
1368
  end
@@ -1317,7 +1386,7 @@ module Opal
1317
1386
  # FIXME if we just pass '*', then we make a tmp variable name for it..
1318
1387
  param_variable rest_arg_name
1319
1388
  method_args << rest_arg_name
1320
- pre_code += "#{rest_arg_name} = [].slice.call($A, #{method_args.length});"
1389
+ pre_code += "#{rest_arg_name} = [].slice.call(arguments, #{method_args.length - 1});"
1321
1390
  end
1322
1391
  end
1323
1392
 
@@ -1325,17 +1394,17 @@ module Opal
1325
1394
  if args[3]
1326
1395
  param_variable args[3][:value]
1327
1396
  @block_arg_name = args[3][:value]
1397
+ pre_code += "var #{args[3][:value]} = (($yy == $y.y) ? nil: $yy);"
1328
1398
  end
1329
1399
  end
1330
1400
 
1331
1401
  @stmt.returns
1332
1402
  stmt = @stmt.process scope, LEVEL_TOP
1333
- method_args.unshift 'self'
1334
1403
 
1335
1404
  block_var = opts[:scope].temp_local
1336
1405
  # code += "(#{block_var} = "
1337
1406
 
1338
- code += "function(#{method_args.join ', '}) {"
1407
+ code += "function(#{method_args.join ', '}) { var self = this;"
1339
1408
 
1340
1409
  unless @scope_vars.empty?
1341
1410
  code += " var #{@scope_vars.join ', '};"
@@ -1343,15 +1412,11 @@ module Opal
1343
1412
 
1344
1413
  # block arg
1345
1414
  if @block_arg_name
1346
- pre_code += "var $yield, #@block_arg_name; if ($B.f == arguments.callee && $B.p != nil) { #@block_arg_name = "
1347
- pre_code += "$yield = $B.p; } else { #@block_arg_name = nil; "
1348
- pre_code += "$yield = $B.y; } $B.p = $B.f = nil;"
1349
- pre_code += "var $yself = $yield.$proc[0];"
1350
-
1351
- stmt = "try{" + stmt
1352
-
1353
- # catch break statements
1354
- stmt += "} catch (__err__) {if(__err__.$keyword == 2) {return __err__.$value;} throw __err__;}"
1415
+ block_code = "var $y = $B, $yy, $ys, $yb = $y.b;"
1416
+ block_code += "if ($y.f == arguments.callee) { $yy = $y.p; }"
1417
+ block_code += "else { $yy = $y.y; }"
1418
+ block_code += "$y.f = nil ;$ys = $yy.o$s;"
1419
+ pre_code = block_code + pre_code
1355
1420
  end
1356
1421
 
1357
1422
  code += (pre_code + stmt + fix_line_number(opts, @end_line) + "}")
@@ -1471,8 +1536,10 @@ module Opal
1471
1536
  # if we return, make sure our stmt does
1472
1537
  @stmt.returns if @returns
1473
1538
 
1474
- r = "if(#{@type == 'if' ? '' : '!'}(#{@expr.generate(opts, LEVEL_EXPR)}"
1475
- r += ").$r) {#{@stmt.process(opts, LEVEL_TOP)}}"
1539
+ expr = generate_truthy_test @expr, opts
1540
+
1541
+ r = "if(#{@type == 'if' ? '' : '!'}(#{expr}"
1542
+ r += ")) {#{@stmt.process(opts, LEVEL_TOP)}}"
1476
1543
 
1477
1544
  # also, if we return, we need to ensure we have an else conditional
1478
1545
  r += " else { return nil; }" if @returns
@@ -1499,10 +1566,10 @@ module Opal
1499
1566
 
1500
1567
  if @args[1]
1501
1568
  parts.unshift '$ys'
1502
- code = "#{block_code}(null, [#{parts.join ', '}].concat(#{@args[1].generate(opts, LEVEL_EXPR)}))"
1569
+ code = "#{block_code}.apply($ys, [#{parts.join ', '}].concat(#{@args[1].generate(opts, LEVEL_EXPR)}))"
1503
1570
  else
1504
1571
  parts.unshift '$ys'
1505
- code = "#{block_code}(#{parts.join ', '})"
1572
+ code = "#{block_code}.call(#{parts.join ', '})"
1506
1573
  end
1507
1574
 
1508
1575
  code
@@ -1671,8 +1738,8 @@ module Opal
1671
1738
 
1672
1739
  @redo_var = eval_expr = opts[:scope].temp_local
1673
1740
  code = "#{eval_expr} = false; while (#{eval_expr} || #{truthy}("
1674
- code += @expr.generate opts, LEVEL_EXPR
1675
- code += ").$r) {#{eval_expr} = false;"
1741
+ code += generate_truthy_test @expr, opts
1742
+ code += ")) {#{eval_expr} = false;"
1676
1743
 
1677
1744
  opts[:scope].push_while_scope self
1678
1745
 
@@ -1698,6 +1765,43 @@ module Opal
1698
1765
  end
1699
1766
  end
1700
1767
 
1768
+ class ForNode < BaseNode
1769
+
1770
+ def initialize(begn, vars, expr, compstmt, endn)
1771
+ @line = begn[:line]
1772
+ @vars = vars
1773
+ @expr = expr
1774
+ @stmt = compstmt
1775
+ @end_line = endn[:line]
1776
+ end
1777
+
1778
+ def returns
1779
+ @returns = true
1780
+ self
1781
+ end
1782
+
1783
+ def generate(opts, level)
1784
+ @current_scope = opts[:scope]
1785
+ stmt_level = (level == LEVEL_EXPR ? LEVEL_TOP_CLOSURE : LEVEL_TOP)
1786
+
1787
+ if stmt_level == LEVEL_TOP_CLOSURE
1788
+ returns
1789
+ @level_expr = true
1790
+ end
1791
+
1792
+ idx = opts[:scope].temp_local
1793
+ ref = opts[:scope].temp_local
1794
+ len = opts[:scope].temp_local
1795
+ code = "for (#{idx} = 0, #{ref} = #{@expr.generate opts, LEVEL_EXPR}"
1796
+ code += ", #{len} = #{ref}.length; #{idx} < #{len}; #{idx}++) {"
1797
+
1798
+ code += @stmt.process opts, LEVEL_TOP
1799
+
1800
+ code += fix_line_number opts, @end_line
1801
+ code += "}"
1802
+ end
1803
+ end
1804
+
1701
1805
  class SuperNode < BaseNode
1702
1806
 
1703
1807
  def initialize(start, args)
@@ -1781,6 +1885,12 @@ module Opal
1781
1885
  opts[:indent] = old_indent + INDENT
1782
1886
  end
1783
1887
 
1888
+ if opt_ensure = @body.opt_ensure
1889
+ # puts "optional ensure!"
1890
+ code += "} finally {"
1891
+ code += opt_ensure.process opts, LEVEL_TOP
1892
+ end
1893
+
1784
1894
 
1785
1895
  opts[:indent] = old_indent
1786
1896
  code += (fix_line_number(opts, @end_line) + "}")
@@ -1798,7 +1908,8 @@ module Opal
1798
1908
  end
1799
1909
 
1800
1910
  def generate(opts, level)
1801
- "(#{@expr.generate opts, LEVEL_EXPR}.$r ? #{@true.generate opts, LEVEL_EXPR} : #{@false.generate opts, LEVEL_EXPR})"
1911
+ test = generate_truthy_test @expr, opts
1912
+ "(#{test} ? #{@true.generate opts, LEVEL_EXPR} : #{@false.generate opts, LEVEL_EXPR})"
1802
1913
  end
1803
1914
  end
1804
1915