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