opal 0.5.2 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/lib/opal.rb +0 -5
  4. data/lib/opal/compiler.rb +24 -44
  5. data/lib/opal/nodes/base.rb +5 -8
  6. data/lib/opal/nodes/call.rb +4 -0
  7. data/lib/opal/nodes/class.rb +6 -7
  8. data/lib/opal/nodes/def.rb +4 -4
  9. data/lib/opal/nodes/definitions.rb +0 -14
  10. data/lib/opal/nodes/iter.rb +51 -38
  11. data/lib/opal/nodes/literal.rb +21 -24
  12. data/lib/opal/nodes/module.rb +4 -4
  13. data/lib/opal/nodes/runtime_helpers.rb +45 -0
  14. data/lib/opal/nodes/scope.rb +280 -0
  15. data/lib/opal/nodes/singleton_class.rb +4 -5
  16. data/lib/opal/nodes/super.rb +1 -1
  17. data/lib/opal/nodes/top.rb +9 -7
  18. data/lib/opal/nodes/yield.rb +14 -3
  19. data/lib/opal/parser.rb +4 -18
  20. data/lib/opal/parser/grammar.rb +3745 -3667
  21. data/lib/opal/parser/grammar.y +1692 -1778
  22. data/lib/opal/parser/keywords.rb +35 -35
  23. data/lib/opal/parser/lexer.rb +356 -325
  24. data/lib/opal/parser/sexp.rb +1 -1
  25. data/lib/opal/version.rb +1 -1
  26. data/opal.gemspec +1 -0
  27. data/opal/core/array.rb +320 -81
  28. data/opal/core/enumerable.rb +46 -5
  29. data/opal/core/hash.rb +6 -64
  30. data/opal/core/helpers.rb +67 -0
  31. data/opal/core/method.rb +1 -1
  32. data/opal/core/module.rb +4 -4
  33. data/opal/core/range.rb +1 -12
  34. data/opal/core/regexp.rb +2 -8
  35. data/opal/core/runtime.js +74 -3
  36. data/opal/core/string.rb +99 -74
  37. data/opal/opal.rb +3 -72
  38. data/spec/filters/bugs/array.rb +2 -30
  39. data/spec/filters/bugs/basic_object.rb +0 -1
  40. data/spec/filters/bugs/string.rb +26 -21
  41. data/spec/filters/unsupported/enumerator.rb +3 -0
  42. data/spec/filters/unsupported/float.rb +1 -0
  43. data/spec/filters/unsupported/immutable_strings.rb +15 -0
  44. data/spec/filters/unsupported/tainted.rb +58 -30
  45. data/spec/filters/unsupported/trusted.rb +35 -15
  46. data/spec/opal/parser/class_spec.rb +4 -4
  47. data/spec/opal/parser/def_spec.rb +4 -4
  48. data/spec/opal/parser/lvar_spec.rb +6 -6
  49. data/spec/opal/parser/module_spec.rb +4 -4
  50. data/spec/opal/parser/sclass_spec.rb +2 -2
  51. data/spec/stdlib/native/exposure_spec.rb +33 -0
  52. data/stdlib/buffer.rb +1 -1
  53. data/stdlib/buffer/view.rb +1 -1
  54. data/stdlib/native.rb +193 -174
  55. data/stdlib/opal-parser.rb +0 -6
  56. data/stdlib/pp.rb +9 -0
  57. data/tasks/mspec.rake +3 -1
  58. metadata +9 -9
  59. data/lib/opal/nodes/base_scope.rb +0 -11
  60. data/lib/opal/target_scope.rb +0 -281
  61. data/spec/filters/20.rb +0 -4
  62. data/spec/filters/unsupported/array_subclasses.rb +0 -37
@@ -1,8 +1,8 @@
1
- require 'opal/nodes/base_scope'
1
+ require 'opal/nodes/scope'
2
2
 
3
3
  module Opal
4
4
  module Nodes
5
- class ModuleNode < BaseScopeNode
5
+ class ModuleNode < ScopeNode
6
6
  handle :module
7
7
 
8
8
  children :cid, :body
@@ -14,12 +14,12 @@ module Opal
14
14
  push "(function($base) {"
15
15
  line " var self = $module($base, '#{name}');"
16
16
 
17
- in_scope(:module) do
17
+ in_scope do
18
18
  scope.name = name
19
19
  add_temp "#{scope.proto} = self._proto"
20
20
  add_temp '$scope = self._scope'
21
21
 
22
- body_code = stmt(body)
22
+ body_code = stmt(body || s(:nil))
23
23
  empty_line
24
24
 
25
25
  line scope.to_vars
@@ -0,0 +1,45 @@
1
+ require 'set'
2
+ require 'opal/nodes/base'
3
+
4
+ module Opal
5
+ module Nodes
6
+ class RuntimeHelpers < Base
7
+ HELPERS = Set.new
8
+
9
+ children :recvr, :meth, :arglist
10
+
11
+ def self.compatible?(recvr, meth, arglist)
12
+ recvr == [:const, :Opal] and HELPERS.include?(meth.to_sym)
13
+ end
14
+
15
+ def self.helper(name, &block)
16
+ HELPERS << name
17
+ define_method("compile_#{name}", &block)
18
+ end
19
+
20
+ def compile
21
+ if HELPERS.include?(meth.to_sym)
22
+ __send__("compile_#{meth}")
23
+ else
24
+ raise "Helper not supported: #{meth}"
25
+ end
26
+ end
27
+
28
+ helper :truthy? do
29
+ unless sexp = arglist[1]
30
+ raise "truthy? requires an object"
31
+ end
32
+
33
+ js_truthy(sexp)
34
+ end
35
+
36
+ helper :falsy? do
37
+ unless sexp = arglist[1]
38
+ raise "falsy? requires an object"
39
+ end
40
+
41
+ js_falsy(sexp)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,280 @@
1
+ require 'opal/nodes/base'
2
+
3
+ module Opal
4
+ module Nodes
5
+ class ScopeNode < Base
6
+
7
+ # Every scope can have a parent scope
8
+ attr_accessor :parent
9
+
10
+ # The class or module name if this scope is a class scope
11
+ attr_accessor :name
12
+
13
+ # The given block name for a def scope
14
+ attr_accessor :block_name
15
+
16
+ attr_reader :scope_name
17
+ attr_reader :ivars
18
+
19
+ attr_accessor :mid
20
+
21
+ # true if singleton def, false otherwise
22
+ attr_accessor :defs
23
+
24
+ # used by modules to know what methods to donate to includees
25
+ attr_reader :methods
26
+
27
+ # uses parents super method
28
+ attr_accessor :uses_super
29
+ attr_accessor :uses_zuper
30
+
31
+ attr_accessor :catch_return
32
+
33
+ def initialize(*)
34
+ super
35
+
36
+ @locals = []
37
+ @temps = []
38
+ @args = []
39
+ @ivars = []
40
+ @parent = nil
41
+ @queue = []
42
+ @unique = 'a'
43
+ @while_stack = []
44
+
45
+ @methods = []
46
+
47
+ @uses_block = false
48
+
49
+ # used by classes to store all ivars used in direct def methods
50
+ @proto_ivars = []
51
+ end
52
+
53
+ def in_scope(&block)
54
+ indent do
55
+ @parent = compiler.scope
56
+ compiler.scope = self
57
+ block.call self
58
+ compiler.scope = @parent
59
+ end
60
+ end
61
+
62
+ # Returns true if this scope is a class/module body scope
63
+ def class_scope?
64
+ @type == :class or @type == :module
65
+ end
66
+
67
+ # Returns true if this is strictly a class scope
68
+ def class?
69
+ @type == :class
70
+ end
71
+
72
+ # True if this is a module scope
73
+ def module?
74
+ @type == :module
75
+ end
76
+
77
+ def sclass?
78
+ @type == :sclass
79
+ end
80
+
81
+ # Returns true if this is a top scope (main file body)
82
+ def top?
83
+ @type == :top
84
+ end
85
+
86
+ # True if a block/iter scope
87
+ def iter?
88
+ @type == :iter
89
+ end
90
+
91
+ def def?
92
+ @type == :def
93
+ end
94
+
95
+ # Is this a normal def method directly inside a class? This is
96
+ # used for optimizing ivars as we can set them to nil in the
97
+ # class body
98
+ def def_in_class?
99
+ !@defs && @type == :def && @parent && @parent.class?
100
+ end
101
+
102
+ # Inside a class or module scope, the javascript variable name returned
103
+ # by this function points to the classes' prototype. This is the target
104
+ # to where methods are actually added inside a class body.
105
+ def proto
106
+ "def"
107
+ end
108
+
109
+ # A scope donates its methods if it is a module, or the core Object
110
+ # class. Modules donate their methods to classes or objects they are
111
+ # included in. Object donates methods to bridged classes whose native
112
+ # prototypes do not actually inherit from Opal.Object.prototype.
113
+ def should_donate?
114
+ @type == :module
115
+ end
116
+
117
+ ##
118
+ # Vars to use inside each scope
119
+ def to_vars
120
+ vars = @temps.dup
121
+ vars.push(*@locals.map { |l| "#{l} = nil" })
122
+
123
+ iv = ivars.map do |ivar|
124
+ "if (self#{ivar} == null) self#{ivar} = nil;\n"
125
+ end
126
+
127
+ indent = @compiler.parser_indent
128
+ res = vars.empty? ? '' : "var #{vars.join ', '};"
129
+ str = ivars.empty? ? res : "#{res}\n#{indent}#{iv.join indent}"
130
+
131
+ if class? and !@proto_ivars.empty?
132
+ #raise "FIXME to_vars"
133
+ pvars = @proto_ivars.map { |i| "#{proto}#{i}"}.join(' = ')
134
+ result = "%s\n%s%s = nil;" % [str, indent, pvars]
135
+ else
136
+ result = str
137
+ end
138
+
139
+ fragment(result)
140
+ end
141
+
142
+ # Generates code for this module to donate methods
143
+ def to_donate_methods
144
+ if should_donate? and !@methods.empty?
145
+ fragment("%s;$opal.donate(self, [%s]);" % [@compiler.parser_indent, @methods.map(&:inspect).join(', ')])
146
+ else
147
+ fragment("")
148
+ end
149
+ end
150
+
151
+ def add_scope_ivar(ivar)
152
+ if def_in_class?
153
+ @parent.add_proto_ivar ivar
154
+ else
155
+ @ivars << ivar unless @ivars.include? ivar
156
+ end
157
+ end
158
+
159
+ def add_proto_ivar(ivar)
160
+ @proto_ivars << ivar unless @proto_ivars.include? ivar
161
+ end
162
+
163
+ def add_arg(arg)
164
+ @args << arg unless @args.include? arg
165
+ arg
166
+ end
167
+
168
+ def add_scope_local(local)
169
+ return if has_local? local
170
+
171
+ @locals << local
172
+ end
173
+
174
+ def has_local?(local)
175
+ return true if @locals.include? local or @args.include? local
176
+ return @parent.has_local?(local) if @parent and @type == :iter
177
+
178
+ false
179
+ end
180
+
181
+ def add_scope_temp(*tmps)
182
+ @temps.push(*tmps)
183
+ end
184
+
185
+ def has_temp?(tmp)
186
+ @temps.include? tmp
187
+ end
188
+
189
+ def new_temp
190
+ return @queue.pop unless @queue.empty?
191
+
192
+ tmp = next_temp
193
+ @temps << tmp
194
+ tmp
195
+ end
196
+
197
+ def next_temp
198
+ tmp = "$#{@unique}"
199
+ @unique = @unique.succ
200
+ tmp
201
+ end
202
+
203
+ def queue_temp(name)
204
+ @queue << name
205
+ end
206
+
207
+ def push_while
208
+ info = {}
209
+ @while_stack.push info
210
+ info
211
+ end
212
+
213
+ def pop_while
214
+ @while_stack.pop
215
+ end
216
+
217
+ def in_while?
218
+ !@while_stack.empty?
219
+ end
220
+
221
+ def uses_block!
222
+ if @type == :iter && @parent
223
+ @parent.uses_block!
224
+ else
225
+ @uses_block = true
226
+ identify!
227
+ end
228
+ end
229
+
230
+ def identify!
231
+ return @identity if @identity
232
+
233
+ @identity = @compiler.unique_temp
234
+ @parent.add_scope_temp @identity if @parent
235
+
236
+ @identity
237
+ end
238
+
239
+ def identity
240
+ @identity
241
+ end
242
+
243
+ def find_parent_def
244
+ scope = self
245
+ while scope = scope.parent
246
+ if scope.def?
247
+ return scope
248
+ end
249
+ end
250
+
251
+ nil
252
+ end
253
+
254
+ def get_super_chain
255
+ chain, scope, defn, mid = [], self, 'null', 'null'
256
+
257
+ while scope
258
+ if scope.type == :iter
259
+ chain << scope.identify!
260
+ scope = scope.parent if scope.parent
261
+
262
+ elsif scope.type == :def
263
+ defn = scope.identify!
264
+ mid = "'#{scope.mid}'"
265
+ break
266
+
267
+ else
268
+ break
269
+ end
270
+ end
271
+
272
+ [chain, defn, mid]
273
+ end
274
+
275
+ def uses_block?
276
+ @uses_block
277
+ end
278
+ end
279
+ end
280
+ end
@@ -1,8 +1,8 @@
1
- require 'opal/nodes/base_scope'
1
+ require 'opal/nodes/scope'
2
2
 
3
3
  module Opal
4
4
  module Nodes
5
- class SingletonClassNode < BaseScopeNode
5
+ class SingletonClassNode < ScopeNode
6
6
  handle :sclass
7
7
 
8
8
  children :object, :body
@@ -10,17 +10,16 @@ module Opal
10
10
  def compile
11
11
  push "(function(self) {"
12
12
 
13
- in_scope(:sclass) do
13
+ in_scope do
14
14
  add_temp '$scope = self._scope'
15
15
  add_temp 'def = self._proto'
16
16
 
17
17
  line scope.to_vars
18
- line stmt(body)
18
+ line stmt(compiler.returns(body))
19
19
  end
20
20
 
21
21
  line "})(", recv(object), ".$singleton_class())"
22
22
  end
23
23
  end
24
-
25
24
  end
26
25
  end
@@ -18,7 +18,7 @@ module Opal
18
18
  if scope.def?
19
19
  scope.uses_block!
20
20
  scope_name = scope.identify!
21
- class_name = scope.parent.name || 'self._klass._proto'
21
+ class_name = scope.parent.name ? "$#{scope.parent.name}" : 'self._klass._proto'
22
22
 
23
23
  if scope.defs
24
24
  push "$opal.find_super_dispatcher(self, '#{scope.mid.to_s}', #{scope_name}, "
@@ -1,15 +1,20 @@
1
- require 'opal/nodes/base_scope'
1
+ require 'opal/version'
2
+ require 'opal/nodes/scope'
2
3
 
3
4
  module Opal
4
5
  module Nodes
5
6
  # Generates code for an entire file, i.e. the base sexp
6
- class TopNode < BaseScopeNode
7
+ class TopNode < ScopeNode
8
+ handle :top
9
+
10
+ children :body
11
+
7
12
  def compile
8
13
  push version_comment
9
14
 
10
15
  line "(function($opal) {"
11
16
 
12
- in_scope(:top) do
17
+ in_scope do
13
18
  body_code = stmt(stmts)
14
19
  body_code = [body_code] unless body_code.is_a?(Array)
15
20
 
@@ -30,10 +35,7 @@ module Opal
30
35
  end
31
36
 
32
37
  def stmts
33
- sexp = @sexp || s(:nil)
34
- scope = s(:scope, sexp)
35
- scope.line = sexp.line
36
- scope
38
+ compiler.returns(body)
37
39
  end
38
40
 
39
41
  def compile_irb_vars
@@ -4,7 +4,10 @@ module Opal
4
4
  module Nodes
5
5
  class BaseYieldNode < Base
6
6
  def compile_call(children, level)
7
- scope.uses_block!
7
+ yielding_scope = find_yielding_scope
8
+
9
+ yielding_scope.uses_block!
10
+ block_name = yielding_scope.block_name || '$yield'
8
11
 
9
12
  if yields_single_arg?(children)
10
13
  push expr(children.first)
@@ -20,8 +23,16 @@ module Opal
20
23
  end
21
24
  end
22
25
 
23
- def block_name
24
- scope.block_name || '$yield'
26
+ def find_yielding_scope
27
+ working = scope
28
+ while working
29
+ if working.block_name or working.def?
30
+ break
31
+ end
32
+ working = working.parent
33
+ end
34
+
35
+ working
25
36
  end
26
37
 
27
38
  def yields_single_arg?(children)