opal 0.5.2 → 0.5.4

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 (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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8fd073f86d2b6572a34ed96ac1e8bc35e14be214
4
- data.tar.gz: 5f55dcc5f1e555bc2d53afababdfedd8a1fc480e
3
+ metadata.gz: 77632aecb99342d5830be4046997f6f1c4b57c5a
4
+ data.tar.gz: d0b98b8c4bb8a0cd0e047e45507c4edabdf5a504
5
5
  SHA512:
6
- metadata.gz: 8db2e2f1545e635e7822d52fe6a009ac2d50d335bd7a2855e0ac44f5eff366171106eec3d783ef3600924d60d28c042d634056119b594f54fa44d1f600952776
7
- data.tar.gz: ba90ff768744ca87c6d5a54070292d6d6877dfbf4c3c21bdaa3fe73d13258acfaeea85bf8900251b42d325ce78a7b80b1479606cd1ec504516dd7bb4595f86f3
6
+ metadata.gz: 767a17fdba3738a6dadf6d3d567a5b695ec69bf540d70278af7b0ce1c8a8a529e4c90d1a2f1518486637857dfe8decc1c41ced22d7d99271c4a2b7f727be6db3
7
+ data.tar.gz: 1b17efbff47540101001edb95dc5190bcbf39218a47f4f8f983a4698c3dec4958e1149ba6ddb3e781b2131071dd8f42a04f0b41768ba7ff067c4079ef8c1b315
data/README.md CHANGED
@@ -98,6 +98,8 @@ StringScanner, Date, etc.
98
98
 
99
99
  ## License
100
100
 
101
+ (The MIT License)
102
+
101
103
  Copyright (C) 2013 by Adam Beynon
102
104
 
103
105
  Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -6,11 +6,6 @@ require 'opal/version'
6
6
  # Opal is a ruby to javascript compiler, with a runtime for running
7
7
  # in any javascript environment.
8
8
  module Opal
9
-
10
- def self.compile(source, options = {})
11
- Compiler.new.compile(source, options)
12
- end
13
-
14
9
  def self.gem_dir
15
10
  File.expand_path('..', __FILE__.untaint)
16
11
  end
@@ -1,11 +1,13 @@
1
1
  require 'set'
2
2
  require 'opal/parser'
3
- require 'opal/target_scope'
4
- require 'opal/version'
5
3
  require 'opal/fragment'
6
4
  require 'opal/nodes'
7
5
 
8
6
  module Opal
7
+ def self.compile(source, options = {})
8
+ Compiler.new.compile(source, options)
9
+ end
10
+
9
11
  class Compiler
10
12
  # Generated code gets indented with two spaces on each scope
11
13
  INDENT = ' '
@@ -15,10 +17,8 @@ module Opal
15
17
  COMPARE = %w[< > <= >=]
16
18
 
17
19
  # defines a compiler option, also creating method of form 'name?'
18
- def self.compiler_option(name, default_value)
19
- mid = [true, false].include?(default_value) ? "#{name}?" : name
20
-
21
- define_method(mid) do
20
+ def self.compiler_option(name, default_value, mid = nil)
21
+ define_method(mid || name) do
22
22
  @options.fetch(name) { default_value }
23
23
  end
24
24
  end
@@ -27,16 +27,16 @@ module Opal
27
27
  compiler_option :file, '(file)'
28
28
 
29
29
  # adds method stubs for all used methods in file
30
- compiler_option :method_missing, true
30
+ compiler_option :method_missing, true, :method_missing?
31
31
 
32
32
  # adds an arity check to every method definition
33
- compiler_option :arity_check, false
33
+ compiler_option :arity_check, false, :arity_check?
34
34
 
35
35
  # checks every constant access, delagating to const_missing if needed
36
- compiler_option :const_missing, false
36
+ compiler_option :const_missing, false, :const_missing?
37
37
 
38
38
  # compile top level local vars with support for irb style vars
39
- compiler_option :irb, false
39
+ compiler_option :irb, false, :irb?
40
40
 
41
41
  # how to handle dynamic requires (:error, :warning, :ignore)
42
42
  compiler_option :dynamic_require_severity, :error
@@ -44,13 +44,7 @@ module Opal
44
44
  attr_reader :result, :fragments
45
45
 
46
46
  # Current scope
47
- attr_reader :scope
48
-
49
- # Any helpers required by this file
50
- attr_reader :helpers
51
-
52
- # Method calls made in this file
53
- attr_reader :method_calls
47
+ attr_accessor :scope
54
48
 
55
49
  # Current case_stmt
56
50
  attr_reader :case_stmt
@@ -60,9 +54,6 @@ module Opal
60
54
  @indent = ''
61
55
  @unique = 0
62
56
  @options = {}
63
-
64
- @method_calls = Set.new
65
- @helpers = Set.new([:breaker, :slice])
66
57
  end
67
58
 
68
59
  # Compile some ruby code to a string.
@@ -70,10 +61,9 @@ module Opal
70
61
  @source = source
71
62
  @options.update options
72
63
 
73
- @sexp = Parser.new.parse(@source, self.file)
64
+ @sexp = s(:top, Parser.new.parse(@source, self.file) || s(:nil))
74
65
 
75
- top_node = Nodes::TopNode.new(@sexp, :expr, self)
76
- @fragments = top_node.compile_to_fragments.flatten
66
+ @fragments = process(@sexp).flatten
77
67
 
78
68
  @result = @fragments.map(&:code).join('')
79
69
  end
@@ -82,6 +72,16 @@ module Opal
82
72
  Opal::SourceMap.new(@fragments, source_file || self.file)
83
73
  end
84
74
 
75
+ # Any helpers required by this file
76
+ def helpers
77
+ @helpers ||= Set.new([:breaker, :slice])
78
+ end
79
+
80
+ # Method calls made in this file
81
+ def method_calls
82
+ @method_calls ||= Set.new
83
+ end
84
+
85
85
  # This is called when a parsing/processing error occurs. This
86
86
  # method simply appends the filename and curent line number onto
87
87
  # the message and raises it.
@@ -124,27 +124,7 @@ module Opal
124
124
 
125
125
  # Use the given helper
126
126
  def helper(name)
127
- @helpers << name
128
- end
129
-
130
- # Every time the parser enters a new scope, this is called with
131
- # the scope type as an argument. Valid types are `:top` for the
132
- # top level/file scope; `:class`, `:module` and `:sclass` for the
133
- # obvious ruby classes/modules; `:def` and `:iter` for methods
134
- # and blocks respectively.
135
- #
136
- # This method just pushes a new instance of `Opal::Scope` onto the
137
- # stack, sets the new scope as the `@scope` variable, and yields
138
- # the given block. Once the block returns, the old scope is put
139
- # back on top of the stack.
140
- def in_scope(type)
141
- return unless block_given?
142
-
143
- parent = @scope
144
- @scope = TargetScope.new(type, self).tap { |s| s.parent = parent }
145
- yield @scope
146
-
147
- @scope = parent
127
+ self.helpers << name
148
128
  end
149
129
 
150
130
  # To keep code blocks nicely indented, this will yield a block after
@@ -23,18 +23,15 @@ module Opal
23
23
  end
24
24
  end
25
25
 
26
- attr_reader :compiler
26
+ attr_reader :compiler, :type
27
27
 
28
28
  def initialize(sexp, level, compiler)
29
29
  @sexp = sexp
30
+ @type = sexp.type
30
31
  @level = level
31
32
  @compiler = compiler
32
33
  end
33
34
 
34
- def type
35
- @sexp.type
36
- end
37
-
38
35
  def children
39
36
  @sexp[1..-1]
40
37
  end
@@ -119,15 +116,15 @@ module Opal
119
116
  end
120
117
 
121
118
  def add_local(name)
122
- scope.add_local name.to_sym
119
+ scope.add_scope_local name.to_sym
123
120
  end
124
121
 
125
122
  def add_ivar(name)
126
- scope.add_ivar name
123
+ scope.add_scope_ivar name
127
124
  end
128
125
 
129
126
  def add_temp(temp)
130
- scope.add_temp temp
127
+ scope.add_scope_temp temp
131
128
  end
132
129
 
133
130
  def helper(name)
@@ -1,5 +1,6 @@
1
1
  require 'set'
2
2
  require 'opal/nodes/base'
3
+ require 'opal/nodes/runtime_helpers'
3
4
 
4
5
  module Opal
5
6
  module Nodes
@@ -99,6 +100,9 @@ module Opal
99
100
  push result
100
101
  return true
101
102
  end
103
+ elsif RuntimeHelpers.compatible?(recvr, meth, arglist)
104
+ push(RuntimeHelpers.new(@sexp, @level, @compiler).compile)
105
+ return true
102
106
  end
103
107
  end
104
108
 
@@ -12,13 +12,13 @@ module Opal
12
12
  helper :klass
13
13
 
14
14
  push "(function($base, $super) {"
15
- line " function #{name}(){};"
16
- line " var self = #{name} = $klass($base, $super, '#{name}', #{name});"
15
+ line " function $#{name}(){};"
16
+ line " var self = $#{name} = $klass($base, $super, '#{name}', $#{name});"
17
17
 
18
- in_scope(:class) do
18
+ in_scope do
19
19
  scope.name = name
20
- add_temp "#{scope.proto} = #{name}._proto"
21
- add_temp "$scope = #{name}._scope"
20
+ add_temp "#{scope.proto} = $#{name}._proto"
21
+ add_temp "$scope = $#{name}._scope"
22
22
 
23
23
  body_code = self.body_code
24
24
  empty_line
@@ -35,8 +35,7 @@ module Opal
35
35
  end
36
36
 
37
37
  def body_code
38
- body[1] = s(:nil) unless body[1]
39
- stmt(compiler.returns(body))
38
+ stmt(compiler.returns(body || s(:nil)))
40
39
  end
41
40
  end
42
41
  end
@@ -1,9 +1,9 @@
1
- require 'opal/nodes/base_scope'
1
+ require 'opal/nodes/scope'
2
2
 
3
3
  module Opal
4
4
  module Nodes
5
5
  # FIXME: needs rewrite
6
- class DefNode < BaseScopeNode
6
+ class DefNode < ScopeNode
7
7
  handle :def
8
8
 
9
9
  children :recvr, :mid, :args, :stmts
@@ -40,7 +40,7 @@ module Opal
40
40
  arity_code = arity_check(args, opt, uses_splat, block_name, mid)
41
41
  end
42
42
 
43
- in_scope(:def) do
43
+ in_scope do
44
44
  scope.mid = mid
45
45
  scope.defs = true if recvr
46
46
 
@@ -53,7 +53,7 @@ module Opal
53
53
  scope.block_name = yielder
54
54
 
55
55
  params = process(args)
56
- stmt_code = stmt(stmts)
56
+ stmt_code = stmt(compiler.returns(stmts))
57
57
 
58
58
  add_temp 'self = this'
59
59
 
@@ -13,20 +13,6 @@ module Opal
13
13
  end
14
14
  end
15
15
 
16
- # :scope nodes are actually inside scopes (e.g. :module, :class).
17
- # These are not actually the scopes themselves.
18
- class ScopeNode < Base
19
- handle :scope
20
-
21
- children :body
22
-
23
- def compile
24
- body = self.body || s(:nil)
25
- body = compiler.returns(body) unless scope.class_scope?
26
- push stmt(body)
27
- end
28
- end
29
-
30
16
  class UndefNode < Base
31
17
  handle :undef
32
18
 
@@ -1,25 +1,15 @@
1
- require 'opal/nodes/base_scope'
1
+ require 'opal/nodes/scope'
2
2
 
3
3
  module Opal
4
4
  module Nodes
5
- # FIXME: this needs a rewrite very urgently
6
- class IterNode < BaseScopeNode
5
+ class IterNode < ScopeNode
7
6
  handle :iter
8
7
 
9
8
  children :args_sexp, :body_sexp
10
9
 
11
10
  def compile
12
- # opt args are last (if present) and are a s(:block)
13
- if args.last.is_a?(Sexp) and args.last.type == :block
14
- opt_args = args.pop
15
- opt_args.shift
16
- end
17
-
18
- # does this iter define a block_pass
19
- if args.last.is_a?(Sexp) and args.last.type == :block_pass
20
- block_arg = args.pop
21
- block_arg = block_arg[1][1].to_sym
22
- end
11
+ opt_args = extract_opt_args
12
+ block_arg = extract_block_arg
23
13
 
24
14
  # find any splat args
25
15
  if args.last.is_a?(Sexp) and args.last.type == :splat
@@ -31,31 +21,13 @@ module Opal
31
21
  params = args_to_params(args[1..-1])
32
22
  params << splat if splat
33
23
 
34
- to_vars = identity = nil
24
+ to_vars = identity = body_code = nil
35
25
 
36
- in_scope(:iter) do
26
+ in_scope do
37
27
  identity = scope.identify!
38
28
  add_temp "self = #{identity}._s || this"
39
29
 
40
-
41
- args[1..-1].each_with_index do |arg, idx|
42
- if arg.type == :lasgn
43
- arg = variable(arg[1])
44
-
45
- if opt_args and current_opt = opt_args.find { |s| s[1] == arg.to_sym }
46
- push "if (#{arg} == null) #{arg} = ", expr(current_opt[2]), ";"
47
- else
48
- push "if (#{arg} == null) #{arg} = nil;"
49
- end
50
- elsif arg.type == :array
51
- arg[1..-1].each_with_index do |_arg, _idx|
52
- _arg = variable(_arg[1])
53
- push "#{_arg} = #{params[idx]}[#{_idx}];"
54
- end
55
- else
56
- raise "Bad block arg type"
57
- end
58
- end
30
+ compile_args(args[1..-1], opt_args, params)
59
31
 
60
32
  if splat
61
33
  scope.add_arg splat
@@ -70,13 +42,54 @@ module Opal
70
42
  line "#{block_arg} = #{scope_name}._p || nil, #{scope_name}._p = null;"
71
43
  end
72
44
 
73
- line stmt(body)
45
+ body_code = stmt(body)
74
46
  to_vars = scope.to_vars
75
47
  end
76
48
 
49
+ line body_code
50
+
77
51
  unshift to_vars
78
- unshift "function(#{params.join ', '}) {"
79
- wrap "(#{identity} = ", "}, #{identity}._s = self, #{identity})"
52
+
53
+ unshift "(#{identity} = function(#{params.join ', '}){"
54
+ push "}, #{identity}._s = self, #{identity})"
55
+ end
56
+
57
+ def compile_args(args, opt_args, params)
58
+ args.each_with_index do |arg, idx|
59
+ if arg.type == :lasgn
60
+ arg = variable(arg[1])
61
+
62
+ if opt_args and current_opt = opt_args.find { |s| s[1] == arg.to_sym }
63
+ push "if (#{arg} == null) #{arg} = ", expr(current_opt[2]), ";"
64
+ else
65
+ push "if (#{arg} == null) #{arg} = nil;"
66
+ end
67
+ elsif arg.type == :array
68
+ arg[1..-1].each_with_index do |_arg, _idx|
69
+ _arg = variable(_arg[1])
70
+ push "#{_arg} = #{params[idx]}[#{_idx}];"
71
+ end
72
+ else
73
+ raise "Bad block arg type"
74
+ end
75
+ end
76
+ end
77
+
78
+ # opt args are last (if present) and are a s(:block)
79
+ def extract_opt_args
80
+ if args.last.is_a?(Sexp) and args.last.type == :block
81
+ opt_args = args.pop
82
+ opt_args.shift
83
+ opt_args
84
+ end
85
+ end
86
+
87
+ # does this iter define a block_pass
88
+ def extract_block_arg
89
+ if args.last.is_a?(Sexp) and args.last.type == :block_pass
90
+ block_arg = args.pop
91
+ block_arg = block_arg[1][1].to_sym
92
+ end
80
93
  end
81
94
 
82
95
  def args
@@ -6,51 +6,56 @@ module Opal
6
6
  handle :true, :false, :self, :nil
7
7
 
8
8
  def compile
9
- # :self, :true, :false, :nil
10
9
  push type.to_s
11
10
  end
12
11
  end
13
12
 
14
- class LiteralNode < Base
15
- children :value
16
- end
17
-
18
- class NumericNode < LiteralNode
13
+ class NumericNode < Base
19
14
  handle :int, :float
20
15
 
16
+ children :value
17
+
21
18
  def compile
22
19
  push value.to_s
23
20
  wrap '(', ')' if recv?
24
21
  end
25
22
  end
26
23
 
27
- class StringNode < LiteralNode
24
+ class StringNode < Base
28
25
  handle :str
29
26
 
27
+ children :value
28
+
30
29
  def compile
31
30
  push value.inspect
32
31
  end
33
32
  end
34
33
 
35
- class SymbolNode < LiteralNode
34
+ class SymbolNode < Base
36
35
  handle :sym
37
36
 
37
+ children :value
38
+
38
39
  def compile
39
40
  push value.to_s.inspect
40
41
  end
41
42
  end
42
43
 
43
- class RegexpNode < LiteralNode
44
+ class RegexpNode < Base
44
45
  handle :regexp
45
46
 
47
+ children :value
48
+
46
49
  def compile
47
50
  push((value == // ? /^/ : value).inspect)
48
51
  end
49
52
  end
50
53
 
51
- class XStringNode < LiteralNode
54
+ class XStringNode < Base
52
55
  handle :xstr
53
56
 
57
+ children :value
58
+
54
59
  def needs_semicolon?
55
60
  stmt? and !value.to_s.include?(';')
56
61
  end
@@ -158,35 +163,27 @@ module Opal
158
163
  end
159
164
  end
160
165
 
161
- class ExclusiveRangeNode < Base
162
- handle :dot2
166
+ class InclusiveRangeNode < Base
167
+ handle :irange
163
168
 
164
169
  children :start, :finish
165
170
 
166
171
  def compile
167
172
  helper :range
168
173
 
169
- push "$range("
170
- push expr(start)
171
- push ", "
172
- push expr(finish)
173
- push ", false)"
174
+ push '$range(', expr(start), ', ', expr(finish), ', false)'
174
175
  end
175
176
  end
176
177
 
177
- class InclusiveRangeNode < Base
178
- handle :dot3
178
+ class ExclusiveRangeNode < Base
179
+ handle :erange
179
180
 
180
181
  children :start, :finish
181
182
 
182
183
  def compile
183
184
  helper :range
184
185
 
185
- push "$range("
186
- push expr(start)
187
- push ", "
188
- push expr(finish)
189
- push ", true)"
186
+ push '$range(', expr(start), ', ', expr(finish), ', true)'
190
187
  end
191
188
  end
192
189
  end