Skip to content

Commit 0a30293

Browse files
committedOct 24, 2013
Move require() and auotload() resolve logic into DependencyResolver class
1 parent 515efb9 commit 0a30293

File tree

7 files changed

+153
-125
lines changed

7 files changed

+153
-125
lines changed
 

‎Rakefile

+7-7
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,22 @@ require 'opal-sprockets'
2929
# We can't do this at runtime, so we hijack the method (and make sure we only
3030
# do this at the top level). We figure out which file we are including, and
3131
# add it to our require list
32-
class Opal::Compiler
33-
alias_method :mspec_handle_call, :handle_call
32+
class Opal::Nodes::CallNode
33+
alias_method :mspec_handle_special, :handle_special
3434

35-
def handle_call(sexp)
36-
if sexp[2] == :language_version and @scope.top?
37-
lang_type = sexp[3][2][1]
35+
def handle_special
36+
if meth == :language_version and scope.top?
37+
lang_type = arglist[2][1]
3838
target = "rubyspec/language/versions/#{lang_type}_1.9"
3939

4040
if File.exist?(target)
41-
@requires << target
41+
compiler.requires << target
4242
end
4343

4444
return fragment("nil")
4545
end
4646

47-
mspec_handle_call sexp
47+
mspec_handle_special
4848
end
4949
end
5050

‎doc/home.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Opal
2+
3+
[Method Missing](method_missing.md)
4+

‎lib/opal/compiler.rb

+1-65
Original file line numberDiff line numberDiff line change
@@ -212,75 +212,11 @@ def handlers
212212
@handlers ||= Opal::Nodes::Base.handlers
213213
end
214214

215-
# Handle "special" method calls, e.g. require(). Subclasses can override
216-
# this method. If this method returns nil, then the method will continue
217-
# to be generated by CallNode.
218-
def handle_call(sexp)
219-
case sexp[2]
220-
when :require
221-
return handle_require(sexp[3][1])
222-
when :autoload
223-
if @scope.class_scope?
224-
return handle_require(sexp[3][2])
225-
end
226-
else
227-
nil
228-
end
229-
end
230-
231215
# An array of requires used in this file
232216
def requires
233217
@requires ||= []
234218
end
235219

236-
def handle_require(sexp)
237-
str = handle_require_sexp sexp
238-
requires << str unless str.nil?
239-
fragment("", sexp)
240-
end
241-
242-
def handle_require_sexp(sexp)
243-
type = sexp.shift
244-
245-
if type == :str
246-
return sexp[0]
247-
elsif type == :call
248-
recv, meth, args = sexp
249-
parts = args[1..-1].map { |s| handle_require_sexp s }
250-
251-
if recv == [:const, :File]
252-
if meth == :expand_path
253-
return handle_expand_path(*parts)
254-
elsif meth == :join
255-
return handle_expand_path parts.join("/")
256-
elsif meth == :dirname
257-
return handle_expand_path parts[0].split("/")[0...-1].join("/")
258-
end
259-
end
260-
end
261-
262-
case dynamic_require_severity
263-
when :error
264-
error "Cannot handle dynamic require"
265-
when :warning
266-
warning "Cannot handle dynamic require"
267-
end
268-
end
269-
270-
def handle_expand_path(path, base = '')
271-
"#{base}/#{path}".split("/").inject([]) do |p, part|
272-
if part == ''
273-
# we had '//', so ignore
274-
elsif part == '..'
275-
p.pop
276-
else
277-
p << part
278-
end
279-
280-
p
281-
end.join "/"
282-
end
283-
284220
# The last sexps in method bodies, for example, need to be returned
285221
# in the compiled javascript. Due to syntax differences between
286222
# javascript any ruby, some sexps need to be handled specially. For
@@ -357,7 +293,7 @@ def returns(sexp)
357293
end
358294
end
359295

360-
def js_block_given(sexp, level)
296+
def handle_block_given_call(sexp)
361297
@scope.uses_block!
362298
if @scope.block_name
363299
fragment("(#{@scope.block_name} !== nil)", sexp)

‎lib/opal/nodes.rb

+1
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@
2222
require 'opal/nodes/array'
2323
require 'opal/nodes/defined'
2424
require 'opal/nodes/masgn'
25+
require 'opal/nodes/arglist'

‎lib/opal/nodes/arglist.rb

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
require 'opal/nodes/base'
2+
3+
module Opal
4+
module Nodes
5+
# FIXME: needs rewrite
6+
class ArglistNode < Base
7+
handle :arglist
8+
9+
def compile
10+
code, work = [], []
11+
12+
children.each do |current|
13+
splat = current.first == :splat
14+
arg = expr(current)
15+
16+
if splat
17+
if work.empty?
18+
if code.empty?
19+
code << fragment("[].concat(")
20+
code << arg
21+
code << fragment(")")
22+
else
23+
code += ".concat(#{arg})"
24+
end
25+
else
26+
if code.empty?
27+
code << [fragment("["), work, fragment("]")]
28+
else
29+
code << [fragment(".concat(["), work, fragment("])")]
30+
end
31+
32+
code << [fragment(".concat("), arg, fragment(")")]
33+
end
34+
35+
work = []
36+
else
37+
work << fragment(", ") unless work.empty?
38+
work << arg
39+
end
40+
end
41+
42+
unless work.empty?
43+
join = work
44+
45+
if code.empty?
46+
code = join
47+
else
48+
code << fragment(".concat(") << join << fragment(")")
49+
end
50+
end
51+
52+
push(*code)
53+
end
54+
end
55+
end
56+
end

‎lib/opal/nodes/call.rb

+83-52
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class CallNode < Base
88
children :recvr, :meth, :arglist, :iter
99

1010
def compile
11-
if handled = compiler.handle_call(@sexp)
11+
if handled = self.handle_special
1212
push handled
1313
return
1414
end
@@ -28,17 +28,6 @@ def compile
2828
return
2929
end
3030

31-
case meth
32-
when :block_given?
33-
return push @compiler.js_block_given(@sexp, @level)
34-
when :__method__, :__callee__
35-
if scope.def?
36-
return push(scope.mid.to_s.inspect)
37-
else
38-
return push("nil")
39-
end
40-
end
41-
4231
splat = arglist[1..-1].any? { |a| a.first == :splat }
4332

4433
if Sexp === arglist.last and arglist.last.type == :block_pass
@@ -90,56 +79,98 @@ def recv_sexp
9079
def using_irb?
9180
@compiler.irb? and scope.top? and arglist == s(:arglist) and recvr.nil? and iter.nil?
9281
end
93-
end
9482

95-
# FIXME: needs rewrite
96-
class ArglistNode < Base
97-
handle :arglist
83+
# Handle "special" method calls, e.g. require(). Subclasses can override
84+
# this method. If this method returns nil, then the method will continue
85+
# to be generated by CallNode.
86+
def handle_special
87+
case meth
88+
when :require then handle_require
89+
when :autoload then handle_autoload
90+
when :block_given? then handle_block_given
91+
when :__method__, :__callee__ then handle_callee
92+
end
93+
end
9894

99-
def compile
100-
code, work = [], []
101-
102-
children.each do |current|
103-
splat = current.first == :splat
104-
arg = expr(current)
105-
106-
if splat
107-
if work.empty?
108-
if code.empty?
109-
code << fragment("[].concat(")
110-
code << arg
111-
code << fragment(")")
112-
else
113-
code += ".concat(#{arg})"
114-
end
115-
else
116-
if code.empty?
117-
code << [fragment("["), work, fragment("]")]
118-
else
119-
code << [fragment(".concat(["), work, fragment("])")]
120-
end
95+
def handle_require
96+
str = DependencyResolver.new(compiler, arglist[1]).resolve
97+
compiler.requires << str unless str.nil?
98+
fragment ''
99+
end
121100

122-
code << [fragment(".concat("), arg, fragment(")")]
123-
end
101+
def handle_autoload
102+
if scope.class_scope?
103+
str = DependencyResolver.new(compiler, arglist[2]).resolve
104+
compiler.requires << str unless str.nil?
105+
fragment ''
106+
end
107+
end
124108

125-
work = []
126-
else
127-
work << fragment(", ") unless work.empty?
128-
work << arg
129-
end
109+
def handle_block_given
110+
compiler.handle_block_given_call @sexp
111+
end
112+
113+
def handle_callee
114+
if scope.def?
115+
fragment scope.mid.to_s.inspect
116+
else
117+
fragment 'nil'
118+
end
119+
end
120+
121+
class DependencyResolver
122+
def initialize(compiler, sexp)
123+
@compiler = compiler
124+
@sexp = sexp
130125
end
131126

132-
unless work.empty?
133-
join = work
127+
def resolve
128+
handle_part @sexp
129+
end
130+
131+
def handle_part(sexp)
132+
type = sexp.type
133+
134+
if type == :str
135+
return sexp[1]
136+
elsif type == :call
137+
_, recv, meth, args = sexp
138+
139+
parts = args[1..-1].map { |s| handle_part s }
134140

135-
if code.empty?
136-
code = join
137-
else
138-
code << fragment(".concat(") << join << fragment(")")
141+
if recv == [:const, :File]
142+
if meth == :expand_path
143+
return expand_path(*parts)
144+
elsif meth == :join
145+
return expand_path parts.join('/')
146+
elsif meth == :dirname
147+
return expand_path parts[0].split('/')[0...-1].join('/')
148+
end
149+
end
150+
end
151+
152+
msg = "Cannot handle dynamic require"
153+
case @compiler.dynamic_require_severity
154+
when :error
155+
@compiler.error msg
156+
when :warning
157+
@compiler.warning msg
139158
end
140159
end
141160

142-
push(*code)
161+
def expand_path(path, base = '')
162+
"#{base}/#{path}".split("/").inject([]) do |p, part|
163+
if part == ''
164+
# we had '//', so ignore
165+
elsif part == '..'
166+
p.pop
167+
else
168+
p << part
169+
end
170+
171+
p
172+
end.join "/"
173+
end
143174
end
144175
end
145176
end

‎lib/opal/nodes/defined.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def compile_super
5454
end
5555

5656
def compile_yield
57-
push compiler.js_block_given(@sexp, @level)
57+
push compiler.handle_block_given_call(@sexp)
5858
wrap '((', ') != null ? "yield" : nil)'
5959
end
6060

0 commit comments

Comments
 (0)
Please sign in to comment.