opal 0.3.19 → 0.3.20

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 (66) hide show
  1. data/.gitignore +3 -1
  2. data/Gemfile +3 -2
  3. data/README.md +304 -48
  4. data/Rakefile +1 -2
  5. data/core/alpha.rb +2 -1
  6. data/core/array.rb +92 -96
  7. data/core/basic_object.rb +1 -10
  8. data/core/boolean.rb +6 -18
  9. data/core/class.rb +9 -10
  10. data/core/comparable.rb +1 -1
  11. data/core/enumerable.rb +11 -11
  12. data/core/enumerator.rb +2 -10
  13. data/core/error.rb +16 -31
  14. data/core/hash.rb +32 -36
  15. data/core/json.rb +50 -0
  16. data/core/kernel.rb +48 -57
  17. data/core/load_order +3 -5
  18. data/core/module.rb +37 -35
  19. data/core/nil_class.rb +4 -0
  20. data/core/numeric.rb +10 -30
  21. data/core/proc.rb +1 -1
  22. data/core/range.rb +3 -4
  23. data/core/regexp.rb +21 -6
  24. data/core/runtime.js +278 -370
  25. data/core/string.rb +21 -37
  26. data/core/struct.rb +11 -3
  27. data/core/time.rb +44 -37
  28. data/lib/opal.rb +3 -3
  29. data/lib/opal/builder.rb +48 -27
  30. data/lib/opal/builder_task.rb +3 -20
  31. data/lib/opal/grammar.rb +18 -13
  32. data/lib/opal/grammar.y +7 -4
  33. data/lib/opal/parser.rb +290 -199
  34. data/lib/opal/scope.rb +187 -176
  35. data/lib/opal/version.rb +1 -1
  36. data/test/core/kernel/define_singleton_method_spec.rb +21 -0
  37. data/test/core/time/at_spec.rb +7 -0
  38. data/test/core/time/day_spec.rb +5 -0
  39. data/test/core/time/friday_spec.rb +9 -0
  40. data/test/core/time/hour_spec.rb +5 -0
  41. data/test/core/time/min_spec.rb +5 -0
  42. data/test/core/time/monday_spec.rb +9 -0
  43. data/test/core/time/month_spec.rb +5 -0
  44. data/test/core/time/now_spec.rb +5 -0
  45. data/test/core/time/saturday_spec.rb +9 -0
  46. data/test/index.html +2 -1
  47. data/test/language/singleton_class_spec.rb +0 -16
  48. data/test/opal/array/to_json_spec.rb +7 -0
  49. data/test/opal/boolean/singleton_class_spec.rb +9 -0
  50. data/test/opal/boolean/to_json_spec.rb +9 -0
  51. data/test/opal/hash/to_json_spec.rb +9 -0
  52. data/test/opal/json/parse_spec.rb +31 -0
  53. data/test/opal/kernel/to_json_spec.rb +5 -0
  54. data/test/opal/nil/to_json_spec.rb +5 -0
  55. data/test/opal/numeric/to_json_spec.rb +6 -0
  56. data/test/opal/runtime/call_spec.rb +16 -0
  57. data/test/opal/runtime/defined_spec.rb +11 -0
  58. data/test/opal/runtime/super_spec.rb +16 -0
  59. data/test/opal/string/to_json_spec.rb +6 -0
  60. data/test/spec_helper.rb +1 -3
  61. metadata +48 -15
  62. data/core/dir.rb +0 -89
  63. data/core/file.rb +0 -85
  64. data/core/match_data.rb +0 -35
  65. data/core/rational.rb +0 -16
  66. data/test/core/file/expand_path_spec.rb +0 -20
@@ -1,225 +1,236 @@
1
- module Opal; class Parser
2
- class Scope
3
- attr_reader :locals
4
- attr_reader :temps
5
- attr_accessor :parent
1
+ module Opal
2
+ class Parser
3
+ class Scope
4
+ attr_reader :locals
5
+ attr_reader :temps
6
+ attr_accessor :parent
6
7
 
7
- attr_accessor :name
8
+ attr_accessor :name
8
9
 
9
- attr_accessor :block_name
10
+ attr_accessor :block_name
10
11
 
11
- attr_reader :scope_name
12
- attr_reader :ivars
12
+ attr_reader :scope_name
13
+ attr_reader :ivars
13
14
 
14
- attr_accessor :donates_methods
15
+ attr_accessor :donates_methods
15
16
 
16
- attr_reader :type
17
+ attr_reader :type
17
18
 
18
- attr_accessor :defines_defn
19
- attr_accessor :defines_defs
19
+ attr_accessor :defines_defn
20
+ attr_accessor :defines_defs
20
21
 
21
- # used by modules to know what methods to donate to includees
22
- attr_reader :methods
22
+ attr_accessor :mid
23
23
 
24
- def initialize(type, parser)
25
- @parser = parser
26
- @type = type
27
- @locals = []
28
- @temps = []
29
- @args = []
30
- @ivars = []
31
- @parent = nil
32
- @queue = []
33
- @unique = "a"
34
- @while_stack = []
24
+ # true if singleton def, false otherwise
25
+ attr_accessor :defs
35
26
 
36
- @defines_defs = false
37
- @defines_defn = false
27
+ # used by modules to know what methods to donate to includees
28
+ attr_reader :methods
38
29
 
39
- @methods = []
30
+ # singleton methods defined on classes/modules
31
+ attr_reader :smethods
40
32
 
41
- @uses_block = false
42
- @catches_break = false
43
- end
33
+ def initialize(type, parser)
34
+ @parser = parser
35
+ @type = type
36
+ @locals = []
37
+ @temps = []
38
+ @args = []
39
+ @ivars = []
40
+ @parent = nil
41
+ @queue = []
42
+ @unique = "a"
43
+ @while_stack = []
44
44
 
45
- # Returns true if this scope is a class/module body scope
46
- def class_scope?
47
- @type == :class or @type == :module
48
- end
45
+ @defines_defs = false
46
+ @defines_defn = false
49
47
 
50
- ##
51
- # Vars to use inside each scope
52
- def to_vars
53
- vars = []
54
-
55
- if @type == :class
56
- vars << '__class = this'
57
- vars << '__scope = this._scope'
58
- vars << 'def = this._proto'
59
- elsif @type == :module
60
- vars << '__class = this'
61
- vars << '__scope = this._scope'
62
- vars << 'def = this._proto'
63
- elsif @type == :sclass
64
- vars << '__scope = this._scope'
65
- elsif @type == :iter
66
- vars << 'def = (this._isObject ? this._klass._proto : this._proto)' if @defines_defn
67
- else
68
- vars << 'def = (this._isObject ? this._klass._proto : this._proto)' if @defines_defn
69
- end
70
-
71
- locals.each { |l| vars << "#{l} = nil" }
72
- temps.each { |t| vars << t }
73
-
74
- iv = ivars.map do |ivar|
75
- "if (this#{ivar} == null) this#{ivar} = nil;\n"
76
- end
77
-
78
- indent = @parser.parser_indent
79
- res = vars.empty? ? '' : "var #{vars.join ', '}; "
80
- ivars.empty? ? res : "#{res}\n#{indent}#{iv.join indent}"
81
- end
48
+ @methods = []
49
+ @smethods = []
82
50
 
83
- # Generates code for this module to donate methods
84
- def to_donate_methods
85
- "#{@parser.parser_indent};__donate(this, [#{@methods.map { |m| m.inspect }.join ', '}]);"
86
- end
51
+ @uses_block = false
87
52
 
88
- def add_ivar ivar
89
- @ivars << ivar unless @ivars.include? ivar
90
- end
53
+ # used by classes to store all ivars used in direct def methods
54
+ @proto_ivars = []
55
+ end
91
56
 
92
- def add_arg(arg)
93
- @args << arg unless @args.include? arg
94
- end
57
+ # Returns true if this scope is a class/module body scope
58
+ def class_scope?
59
+ @type == :class or @type == :module
60
+ end
95
61
 
96
- def add_local(local)
97
- return if has_local? local
62
+ def class?
63
+ @type == :class
64
+ end
98
65
 
99
- @locals << local
100
- end
66
+ def module?
67
+ @type == :module
68
+ end
101
69
 
102
- def has_local?(local)
103
- return true if @locals.include? local or @args.include? local
104
- return @parent.has_local?(local) if @parent and @type == :iter
70
+ def top?
71
+ @type == :top
72
+ end
105
73
 
106
- false
107
- end
74
+ def iter?
75
+ @type == :iter
76
+ end
108
77
 
109
- def add_temp(tmp)
110
- @temps << tmp
111
- end
78
+ # Is this a normal def method directly inside a class? This is
79
+ # used for optimizing ivars as we can set them to nil in the
80
+ # class body
81
+ def def_in_class?
82
+ @type == :def && @parent && @parent.class?
83
+ end
112
84
 
113
- def new_temp
114
- return @queue.pop unless @queue.empty?
85
+ def proto
86
+ "#{ @name }_prototype"
87
+ end
115
88
 
116
- tmp = "__#{@unique}"
117
- @unique = @unique.succ
118
- @temps << tmp
119
- tmp
120
- end
89
+ ##
90
+ # Vars to use inside each scope
91
+ def to_vars
92
+ vars = locals.map { |l| "#{l} = nil" }
93
+ vars.push *temps
121
94
 
122
- def queue_temp(name)
123
- @queue << name
124
- end
95
+ iv = ivars.map do |ivar|
96
+ "if (this#{ivar} == null) this#{ivar} = nil;\n"
97
+ end
125
98
 
126
- def push_while
127
- info = {}
128
- @while_stack.push info
129
- info
130
- end
99
+ indent = @parser.parser_indent
100
+ res = vars.empty? ? '' : "var #{vars.join ', '};"
101
+ str = ivars.empty? ? res : "#{res}\n#{indent}#{iv.join indent}"
131
102
 
132
- def pop_while
133
- @while_stack.pop
134
- end
103
+ if class? and !@proto_ivars.empty?
104
+ pvars = @proto_ivars.map { |i| "#{proto}#{i}"}.join(' = ')
105
+ "%s\n%s%s = nil;" % [str, indent, pvars]
106
+ else
107
+ str
108
+ end
109
+ end
135
110
 
136
- def in_while?
137
- !@while_stack.empty?
138
- end
111
+ # Generates code for this module to donate methods
112
+ def to_donate_methods
113
+ out = ""
139
114
 
140
- def uses_block!
141
- if @type == :iter && @parent
142
- @parent.uses_block!
143
- else
144
- @uses_block = true
145
- identify!
115
+ unless @methods.empty?
116
+ out += "%s;#{@name}._donate([%s]);" %
117
+ [@parser.parser_indent, @methods.map(&:inspect).join(', ')]
118
+ end
119
+
120
+ unless @smethods.empty?
121
+ out += "%s;#{@name}._sdonate([%s]);" %
122
+ [@parser.parser_indent, @smethods.map(&:inspect).join(', ')]
123
+ end
124
+
125
+ out
146
126
  end
147
- end
148
127
 
149
- def identify!
150
- @identity ||= @parser.unique_temp
151
- end
128
+ def add_ivar(ivar)
129
+ if def_in_class?
130
+ @parent.add_proto_ivar ivar
131
+ else
132
+ @ivars << ivar unless @ivars.include? ivar
133
+ end
134
+ end
152
135
 
153
- def identity
154
- @identity
155
- end
136
+ def add_proto_ivar(ivar)
137
+ @proto_ivars << ivar unless @proto_ivars.include? ivar
138
+ end
139
+
140
+ def add_arg(arg)
141
+ @args << arg unless @args.include? arg
142
+ end
143
+
144
+ def add_local(local)
145
+ return if has_local? local
146
+
147
+ @locals << local
148
+ end
149
+
150
+ def has_local?(local)
151
+ return true if @locals.include? local or @args.include? local
152
+ return @parent.has_local?(local) if @parent and @type == :iter
153
+
154
+ false
155
+ end
156
+
157
+ def add_temp(*tmps)
158
+ @temps.push *tmps
159
+ end
160
+
161
+ def new_temp
162
+ return @queue.pop unless @queue.empty?
163
+
164
+ tmp = "__#{@unique}"
165
+ @unique = @unique.succ
166
+ @temps << tmp
167
+ tmp
168
+ end
169
+
170
+ def queue_temp(name)
171
+ @queue << name
172
+ end
156
173
 
157
- def get_super_chain
158
- chain = []
159
- scope = self
160
- defn = 'null'
161
- mid = 'null'
174
+ def push_while
175
+ info = {}
176
+ @while_stack.push info
177
+ info
178
+ end
162
179
 
163
- while scope
164
- if scope.type == :iter
165
- chain << scope.identify!
166
- scope = scope.parent if scope.parent
180
+ def pop_while
181
+ @while_stack.pop
182
+ end
167
183
 
168
- elsif scope.type == :def
169
- defn = scope.identify!
170
- mid = "'#{scope.mid}'"
171
- break
184
+ def in_while?
185
+ !@while_stack.empty?
186
+ end
172
187
 
188
+ def uses_block!
189
+ if @type == :iter && @parent
190
+ @parent.uses_block!
173
191
  else
174
- break
192
+ @uses_block = true
193
+ identify!
175
194
  end
176
195
  end
177
196
 
178
- [chain, defn, mid]
179
- end
197
+ def identify!
198
+ return @identity if @identity
180
199
 
181
- def identify_def
182
- if @type == :iter && @parent
183
- identify!
184
- @parent.identify_def
185
- elsif @type == :def
186
- identify!
187
- end
188
- end
200
+ @identity = @parser.unique_temp
201
+ @parent.add_temp @identity
189
202
 
190
- def uses_block?
191
- @uses_block
192
- end
203
+ @identity
204
+ end
193
205
 
194
- def catches_break!
195
- if @type == :iter && @parent
196
- @parent.catches_break!
197
- else
198
- @catches_break = true
206
+ def identity
207
+ @identity
199
208
  end
200
- end
201
209
 
202
- def catches_break?
203
- @catches_break
204
- end
210
+ def get_super_chain
211
+ chain, scope, defn, mid = [], self, 'null', 'null'
205
212
 
206
- def mid=(mid)
207
- @mid = mid
208
- end
213
+ while scope
214
+ if scope.type == :iter
215
+ chain << scope.identify!
216
+ scope = scope.parent if scope.parent
217
+
218
+ elsif scope.type == :def
219
+ defn = scope.identify!
220
+ mid = "'#{scope.mid}'"
221
+ break
222
+
223
+ else
224
+ break
225
+ end
226
+ end
227
+
228
+ [chain, defn, mid]
229
+ end
209
230
 
210
- # Gets the method id (as a jsid) of the current scope, which is assumed
211
- # to be a method (:def). If not, and this scope is a :iter, then the
212
- # parent scope will be checked. As a fallback, nil is returned. This is
213
- # used by super() to find out what method super() should be sent to.
214
- def mid
215
- if @type == :def
216
- @mid
217
- elsif @type == :iter && @parent
218
- @parent.mid
219
- else
220
- nil
231
+ def uses_block?
232
+ @uses_block
221
233
  end
222
234
  end
223
235
  end
224
-
225
- end; end
236
+ end
@@ -1,3 +1,3 @@
1
1
  module Opal
2
- VERSION = "0.3.19"
2
+ VERSION = "0.3.20"
3
3
  end
@@ -0,0 +1,21 @@
1
+ class DefineMethodByProcScope
2
+ in_scope = true
3
+ method_proc = proc { in_scope }
4
+
5
+ define_singleton_method(:proc_test, &method_proc)
6
+ end
7
+
8
+ describe "Kernel#define_singleton_method" do
9
+ it "defines a new singleton method for objects" do
10
+ s = Object.new
11
+ s.define_singleton_method(:test) { "world!" }
12
+ s.test.should == "world!"
13
+ lambda {
14
+ Object.new.test
15
+ }.should raise_error(NoMethodError)
16
+ end
17
+
18
+ it "maintains the Proc's scope" do
19
+ DefineMethodByProcScope.proc_test.should == true
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ describe "Time#at" do
2
+ describe "passed Numeric" do
3
+ it "returns a Time object representing the given number of Integer seconds since 1970-01-01 00:00:00 UTC" do
4
+ Time.at(1184027924).should be_kind_of(Time)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ describe "Time#day" do
2
+ it "returns the day of the month for a UTC Time" do
3
+ Time.new(1970, 1, 1).day.should == 1
4
+ end
5
+ end