opal 0.3.19 → 0.3.20

Sign up to get free protection for your applications and to get access to all the features.
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