-
-
Notifications
You must be signed in to change notification settings - Fork 330
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1 parent
e273b2a
commit f3b11ec
Showing
23 changed files
with
484 additions
and
431 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
require 'opal/nodes/base' | ||
|
||
module Opal | ||
class Parser | ||
class CallNode < Node | ||
children :recvr, :meth, :arglist, :iter | ||
|
||
def compile | ||
if handled = compiler.handle_call(@sexp) | ||
push handled | ||
return | ||
end | ||
|
||
mid = compiler.mid_to_jsid meth.to_s | ||
|
||
compiler.method_calls << meth.to_sym | ||
|
||
# trying to access an lvar in irb mode | ||
if using_irb? | ||
with_temp do |tmp| | ||
lvar = meth.intern | ||
lvar = "#{lvar}$" if Parser::RESERVED.include?(lvar) | ||
call = s(:call, s(:self), meth.intern, s(:arglist)) | ||
push "((#{tmp} = $opal.irb_vars.#{lvar}) == null ? ", expr(call), " : #{tmp})" | ||
end | ||
|
||
return | ||
end | ||
|
||
case meth | ||
when :block_given? | ||
return push @compiler.js_block_given(@sexp, @level) | ||
when :__method__, :__callee__ | ||
if scope.def? | ||
return push(scope.mid.to_s.inspect) | ||
else | ||
return push("nil") | ||
end | ||
end | ||
|
||
splat = arglist[1..-1].any? { |a| a.first == :splat } | ||
|
||
if Sexp === arglist.last and arglist.last.type == :block_pass | ||
block = expr(arglist.pop) | ||
elsif iter | ||
block = expr(iter) | ||
end | ||
|
||
tmpfunc = scope.new_temp if block | ||
tmprecv = scope.new_temp if splat || tmpfunc | ||
|
||
recv_code = recv(recv_sexp) | ||
call_recv = s(:js_tmp, tmprecv || recv_code) | ||
|
||
if tmpfunc and !splat | ||
arglist.insert 1, call_recv | ||
end | ||
|
||
args = expr(arglist) | ||
|
||
if tmprecv | ||
push "(#{tmprecv} = ", recv_code, ")#{mid}" | ||
else | ||
push recv_code, mid | ||
end | ||
|
||
if tmpfunc | ||
unshift "(#{tmpfunc} = " | ||
push ", #{tmpfunc}._p = ", block, ", #{tmpfunc})" | ||
end | ||
|
||
if splat | ||
push ".apply(" | ||
push(tmprecv || recv_code) | ||
push ", ", args, ")" | ||
elsif tmpfunc | ||
push ".call(", args, ")" | ||
else | ||
push "(", args, ")" | ||
end | ||
|
||
scope.queue_temp tmpfunc if tmpfunc | ||
end | ||
|
||
def recv_sexp | ||
recvr || s(:self) | ||
end | ||
|
||
def using_irb? | ||
@compiler.irb_vars? and scope.top? and arglist == s(:arglist) and recvr.nil? and iter.nil? | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
require 'opal/nodes/class' | ||
|
||
module Opal | ||
class Parser | ||
# FIXME: needs rewrite | ||
class DefNode < BaseScopeNode | ||
children :recvr, :mid, :args, :stmts | ||
|
||
def compile | ||
jsid = compiler.mid_to_jsid mid.to_s | ||
params = nil | ||
scope_name = nil | ||
|
||
# opt args if last arg is sexp | ||
opt = args.pop if Sexp === args.last | ||
|
||
argc = args.length - 1 | ||
|
||
# block name (&block) | ||
if args.last.to_s.start_with? '&' | ||
block_name = args.pop.to_s[1..-1].to_sym | ||
argc -= 1 | ||
end | ||
|
||
# splat args *splat | ||
if args.last.to_s.start_with? '*' | ||
uses_splat = true | ||
if args.last == :* | ||
argc -= 1 | ||
else | ||
splat = args[-1].to_s[1..-1].to_sym | ||
args[-1] = splat | ||
argc -= 1 | ||
end | ||
end | ||
|
||
if compiler.arity_check? | ||
arity_code = arity_check(args, opt, uses_splat, block_name, mid) | ||
end | ||
|
||
in_scope(:def) do | ||
scope.mid = mid | ||
scope.defs = true if recvr | ||
|
||
if block_name | ||
scope.uses_block! | ||
scope.add_arg block_name | ||
end | ||
|
||
yielder = block_name || '$yield' | ||
scope.block_name = yielder | ||
|
||
params = process(args) | ||
stmt_code = stmt(stmts) | ||
|
||
add_temp 'self = this' | ||
|
||
line "#{splat} = $slice.call(arguments, #{argc});" if splat | ||
|
||
scope_name = scope.identity | ||
|
||
if scope.uses_block? | ||
add_temp "$iter = #{scope_name}._p" | ||
add_temp "#{yielder} = $iter || nil" | ||
end | ||
|
||
opt[1..-1].each do |o| | ||
next if o[2][2] == :undefined | ||
line "if (#{compiler.lvar_to_js o[1]} == null) {" | ||
line ' ', expr(o) | ||
line "}" | ||
end if opt | ||
|
||
if scope.uses_block? | ||
line "#{scope_name}._p = null;" | ||
end | ||
|
||
unshift "\n#{current_indent}", scope.to_vars | ||
line stmt_code | ||
|
||
unshift arity_code if arity_code | ||
|
||
unshift "var $zuper = $slice.call(arguments, 0);" if scope.uses_zuper | ||
|
||
if scope.catch_return | ||
unshift "try {\n" | ||
line "} catch ($returner) { if ($returner === $opal.returner) { return $returner.$v }" | ||
push " throw $returner; }" | ||
end | ||
end | ||
|
||
unshift ") {" | ||
unshift(params) | ||
unshift "function(" | ||
unshift "#{scope_name} = " if scope_name | ||
line "}" | ||
|
||
if recvr | ||
unshift '$opal.defs(', recv(recvr), ", '$#{mid}', " | ||
push ')' | ||
elsif scope.class? and %w(Object BasicObject).include?(scope.name) | ||
wrap "$opal.defn(self, '$#{mid}', ", ')' | ||
elsif scope.class_scope? | ||
scope.methods << "$#{mid}" | ||
unshift "#{scope.proto}#{jsid} = " | ||
elsif scope.iter? | ||
wrap "$opal.defn(self, '$#{mid}', ", ')' | ||
elsif scope.type == :sclass | ||
unshift "self._proto#{jsid} = " | ||
elsif scope.top? | ||
unshift "$opal.Object._proto#{jsid} = " | ||
else | ||
unshift "def#{jsid} = " | ||
end | ||
|
||
wrap '(', ', nil)' if expr? | ||
end | ||
|
||
# Returns code used in debug mode to check arity of method call | ||
def arity_check(args, opt, splat, block_name, mid) | ||
meth = mid.to_s.inspect | ||
|
||
arity = args.size - 1 | ||
arity -= (opt.size - 1) if opt | ||
arity -= 1 if splat | ||
arity = -arity - 1 if opt or splat | ||
|
||
# $arity will point to our received arguments count | ||
aritycode = "var $arity = arguments.length;" | ||
|
||
if arity < 0 # splat or opt args | ||
aritycode + "if ($arity < #{-(arity + 1)}) { $opal.ac($arity, #{arity}, this, #{meth}); }" | ||
else | ||
aritycode + "if ($arity !== #{arity}) { $opal.ac($arity, #{arity}, this, #{meth}); }" | ||
end | ||
end | ||
end | ||
|
||
# FIXME: needs rewrite | ||
class ArglistNode < Node | ||
def compile | ||
code, work = [], [] | ||
|
||
children.each do |current| | ||
splat = current.first == :splat | ||
arg = expr(current) | ||
|
||
if splat | ||
if work.empty? | ||
if code.empty? | ||
code << fragment("[].concat(") | ||
code << arg | ||
code << fragment(")") | ||
else | ||
code += ".concat(#{arg})" | ||
end | ||
else | ||
if code.empty? | ||
code << [fragment("["), work, fragment("]")] | ||
else | ||
code << [fragment(".concat(["), work, fragment("])")] | ||
end | ||
|
||
code << [fragment(".concat("), arg, fragment(")")] | ||
end | ||
|
||
work = [] | ||
else | ||
work << fragment(", ") unless work.empty? | ||
work << arg | ||
end | ||
end | ||
|
||
unless work.empty? | ||
join = work | ||
|
||
if code.empty? | ||
code = join | ||
else | ||
code << fragment(".concat(") << join << fragment(")") | ||
end | ||
end | ||
|
||
push(*code) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
require 'opal/nodes/class' | ||
|
||
module Opal | ||
class Parser | ||
# Generates code for an entire file, i.e. the base sexp | ||
class TopNode < BaseScopeNode | ||
def compile | ||
push version_comment | ||
|
||
line "(function($opal) {" | ||
|
||
in_scope(:top) do | ||
body_code = stmt(stmts) | ||
body_code = [body_code] unless body_code.is_a?(Array) | ||
|
||
add_temp 'self = $opal.top' | ||
add_temp '$scope = $opal' | ||
add_temp 'nil = $opal.nil' | ||
|
||
add_used_helpers | ||
line scope.to_vars | ||
|
||
compile_method_stubs | ||
compile_irb_vars | ||
|
||
line body_code | ||
end | ||
|
||
line "})(Opal);\n" | ||
end | ||
|
||
def stmts | ||
sexp = @sexp || s(:nil) | ||
scope = s(:scope, sexp) | ||
scope.line = sexp.line | ||
scope | ||
end | ||
|
||
def compile_irb_vars | ||
if compiler.irb_vars? | ||
line "if (!$opal.irb_vars) { $opal.irb_vars = {}; }" | ||
end | ||
end | ||
|
||
def add_used_helpers | ||
helpers = compiler.helpers.to_a | ||
helpers.to_a.each { |h| add_temp "$#{h} = $opal.#{h}" } | ||
end | ||
|
||
def compile_method_stubs | ||
if compiler.method_missing? | ||
calls = compiler.method_calls | ||
stubs = calls.to_a.map { |k| "'$#{k}'" }.join(', ') | ||
line "$opal.add_stubs([#{stubs}]);" | ||
end | ||
end | ||
|
||
def version_comment | ||
"/* Generated by Opal #{Opal::VERSION} */" | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters