-
-
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
9e04360
commit 05ed472
Showing
20 changed files
with
535 additions
and
488 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
require 'opal/nodes/array' | ||
|
||
module Opal | ||
module Nodes | ||
class ArrayNode < Base | ||
handle :array | ||
|
||
def compile | ||
return push('[]') if children.empty? | ||
|
||
code, work = [], [] | ||
|
||
children.each do |child| | ||
splat = child.type == :splat | ||
part = expr(child) | ||
|
||
if splat | ||
if work.empty? | ||
if code.empty? | ||
code << fragment("[].concat(") << part << fragment(")") | ||
else | ||
code << fragment(".concat(") << part << fragment(")") | ||
end | ||
else | ||
if code.empty? | ||
code << fragment("[") << work << fragment("]") | ||
else | ||
code << fragment(".concat([") << work << fragment("])") | ||
end | ||
|
||
code << fragment(".concat(") << part << fragment(")") | ||
end | ||
work = [] | ||
else | ||
work << fragment(", ") unless work.empty? | ||
work << part | ||
end | ||
end | ||
|
||
unless work.empty? | ||
join = [fragment("["), work, fragment("]")] | ||
|
||
if code.empty? | ||
code = join | ||
else | ||
code.push([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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
require 'opal/nodes/base' | ||
|
||
module Opal | ||
module Nodes | ||
class BaseScopeNode < Base | ||
def in_scope(type, &block) | ||
indent { compiler.in_scope(type, &block) } | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
require 'opal/nodes/base' | ||
|
||
module Opal | ||
module Nodes | ||
class DefinedNode < Base | ||
handle :defined | ||
|
||
children :value | ||
|
||
def compile | ||
type = value.type | ||
|
||
case type | ||
when :self, :nil, :false, :true | ||
push type.to_s.inspect | ||
when :lasgn, :iasgn, :gasgn, :cvdecl, :masgn, :op_asgn_or, :op_asgn_and | ||
push "'assignment'" | ||
when :paren, :not | ||
push expr(s(:defined, value[1])) | ||
when :lvar | ||
push "'local-variable'" | ||
else | ||
if respond_to? "compile_#{type}" | ||
__send__ "compile_#{type}" | ||
else | ||
push "'expression'" | ||
end | ||
end | ||
end | ||
|
||
def compile_call | ||
mid = mid_to_jsid value[2].to_s | ||
recv = value[1] ? expr(value[1]) : 'self' | ||
|
||
push '(', recv, "#{mid} || ", recv | ||
push "['$respond_to_missing?']('#{value[2].to_s}') ? 'method' : nil)" | ||
end | ||
|
||
def compile_ivar | ||
# FIXME: this check should be positive for ivars initialized as nil too. | ||
# Since currently all known ivars are inialized to nil in the constructor | ||
# we can't tell if it was the user that put nil and made the ivar #defined? | ||
# or not. | ||
with_temp do |tmp| | ||
name = value[1].to_s[1..-1] | ||
|
||
push "((#{tmp} = self['#{name}'], #{tmp} != null && #{tmp} !== nil) ? " | ||
push "'instance-variable' : nil)" | ||
end | ||
end | ||
|
||
def compile_super | ||
push expr(s(:defined_super, value)) | ||
end | ||
|
||
def compile_yield | ||
push compiler.js_block_given(@sexp, @level) | ||
wrap '((', ') != null ? "yield" : nil)' | ||
end | ||
|
||
def compile_xstr | ||
push expr(value) | ||
wrap '(typeof(', ') !== "undefined")' | ||
end | ||
alias compile_dxstr compile_xstr | ||
|
||
def compile_const | ||
push "($scope.#{value[1]} != null)" | ||
end | ||
|
||
def compile_colon2 | ||
# TODO: avoid try/catch, probably a #process_colon2 alternative that | ||
# does not raise errors is needed | ||
push "(function(){ try { return ((" | ||
push expr(value) | ||
push ") != null ? 'constant' : nil); } catch (err) { if (err._klass" | ||
push " === Opal.NameError) { return nil; } else { throw(err); }}; })()" | ||
end | ||
|
||
def compile_colon3 | ||
push "($opal.Object._scope.#{value[1]} == null ? nil : 'constant')" | ||
end | ||
|
||
def compile_cvar | ||
push "($opal.cvars['#{value[1]}'] != null ? 'class variable' : nil)" | ||
end | ||
|
||
def compile_gvar | ||
name = value[1].to_s[1..-1] | ||
|
||
if %w[~ !].include? name | ||
push "'global-variable'" | ||
elsif %w[` ' + &].include? name | ||
with_temp do |tmp| | ||
push "((#{tmp} = $gvars['~'], #{tmp} != null && #{tmp} !== nil) ? " | ||
push "'global-variable' : nil)" | ||
end | ||
else | ||
push "($gvars[#{name.inspect}] != null ? 'global-variable' : nil)" | ||
end | ||
end | ||
|
||
def compile_nth_ref | ||
with_temp do |tmp| | ||
push "((#{tmp} = $gvars['~'], #{tmp} != null && #{tmp} != nil) ? " | ||
push "'global-variable' : nil)" | ||
end | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
require 'opal/nodes/base' | ||
|
||
module Opal | ||
module Nodes | ||
class HashNode < Base | ||
handle :hash | ||
|
||
def keys_and_values | ||
keys, values = [], [] | ||
|
||
children.each_with_index do |obj, idx| | ||
if idx.even? | ||
keys << obj | ||
else | ||
values << obj | ||
end | ||
end | ||
|
||
[keys, values] | ||
end | ||
|
||
def simple_keys?(keys) | ||
keys.all? { |key| [:sym, :str].include? key.type } | ||
end | ||
|
||
def compile | ||
keys, values = keys_and_values | ||
|
||
if simple_keys? keys | ||
compile_hash2 keys, values | ||
else | ||
compile_hash | ||
end | ||
end | ||
|
||
def compile_hash | ||
helper :hash | ||
|
||
children.each_with_index do |child, idx| | ||
push ', ' unless idx == 0 | ||
push expr(child) | ||
end | ||
|
||
wrap '$hash(', ')' | ||
end | ||
|
||
def compile_hash2(keys, values) | ||
hash_obj, hash_keys = {}, [] | ||
helper :hash2 | ||
|
||
keys.size.times do |idx| | ||
key = keys[idx][1].to_s.inspect | ||
hash_keys << key unless hash_obj.include? key | ||
hash_obj[key] = expr(values[idx]) | ||
end | ||
|
||
hash_keys.each_with_index do |key, idx| | ||
push ', ' unless idx == 0 | ||
push "#{key}: " | ||
push hash_obj[key] | ||
end | ||
|
||
wrap "$hash2([#{hash_keys.join ', '}], {", "})" | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
require 'opal/nodes/class' | ||
require 'opal/nodes/base_scope' | ||
|
||
module Opal | ||
module Nodes | ||
|
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,62 @@ | ||
require 'opal/nodes/base' | ||
|
||
module Opal | ||
module Nodes | ||
class MassAssignNode < Base | ||
handle :masgn | ||
|
||
children :lhs, :rhs | ||
|
||
def compile | ||
tmp = scope.new_temp | ||
len = 0 # how many rhs items are we sure we have | ||
|
||
if rhs.type == :array | ||
len = rhs.size - 1 | ||
push "#{tmp} = ", expr(rhs) | ||
elsif rhs.type == :to_ary | ||
push "#{tmp} = $opal.to_ary(", expr(rhs[1]), ")" | ||
elsif rhs.type == :splat | ||
push "(#{tmp} = ", expr(rhs[1]), ")['$to_a'] ? (#{tmp} = #{tmp}['$to_a']())" | ||
push " : (#{tmp})._isArray ? #{tmp} : (#{tmp} = [#{tmp}])" | ||
else | ||
raise "unsupported mlhs type" | ||
end | ||
|
||
lhs.children.each_with_index do |child, idx| | ||
push ', ' | ||
|
||
if child.type == :splat | ||
if part = child[1] | ||
part = part.dup | ||
part << s(:js_tmp, "$slice.call(#{tmp}, #{idx})") | ||
push expr(part) | ||
end | ||
else | ||
if idx >= len | ||
assign = s(:js_tmp, "(#{tmp}[#{idx}] == null ? nil : #{tmp}[#{idx}])") | ||
else | ||
assign = s(:js_tmp, "#{tmp}[#{idx}]") | ||
end | ||
|
||
part = child.dup | ||
if child.type == :lasgn or child.type == :iasgn or child.type == :lvar | ||
part << assign | ||
elsif child.type == :call | ||
part[2] = "#{part[2]}=".to_sym | ||
part.last << assign | ||
elsif child.type == :attrasgn | ||
part.last << assign | ||
else | ||
raise "Bad lhs for masgn" | ||
end | ||
|
||
push expr(part) | ||
end | ||
end | ||
|
||
scope.queue_temp tmp | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
require 'opal/nodes/base_scope' | ||
|
||
module Opal | ||
module Nodes | ||
class ModuleNode < BaseScopeNode | ||
handle :module | ||
|
||
children :cid, :body | ||
|
||
def compile | ||
name, base = name_and_base | ||
helper :module | ||
|
||
push "(function($base) {" | ||
line " var self = $module($base, '#{name}');" | ||
|
||
in_scope(:module) do | ||
scope.name = name | ||
add_temp "#{scope.proto} = self._proto" | ||
add_temp '$scope = self._scope' | ||
|
||
body_code = stmt(body) | ||
empty_line | ||
|
||
line scope.to_vars | ||
line body_code | ||
line scope.to_donate_methods | ||
end | ||
|
||
line "})(", base, ")" | ||
end | ||
|
||
def name_and_base | ||
if Symbol === cid or String === cid | ||
[cid.to_s, 'self'] | ||
elsif cid.type == :colon2 | ||
[cid[2].to_s, expr(cid[1])] | ||
elsif cid.type == :colon3 | ||
[cid[1].to_s, '$opal.Object'] | ||
else | ||
raise "Bad receiver in module" | ||
end | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
require 'opal/nodes/base_scope' | ||
|
||
module Opal | ||
module Nodes | ||
class SingletonClassNode < BaseScopeNode | ||
handle :sclass | ||
|
||
children :object, :body | ||
|
||
def compile | ||
push "(function(self) {" | ||
|
||
in_scope(:sclass) do | ||
add_temp '$scope = self._scope' | ||
add_temp 'def = self._proto' | ||
|
||
line scope.to_vars | ||
line stmt(body) | ||
end | ||
|
||
line "})(", recv(object), ".$singleton_class())" | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -92,7 +92,6 @@ def compile | |
def has_splat? | ||
args.children.any? { |child| child.type == :splat } | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
require 'opal/nodes/class' | ||
require 'opal/nodes/base_scope' | ||
|
||
module Opal | ||
module Nodes | ||
|
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,65 @@ | ||
require 'opal/nodes/base' | ||
|
||
module Opal | ||
module Nodes | ||
class WhileNode < Base | ||
handle :while | ||
|
||
children :test, :body | ||
|
||
def compile | ||
with_temp do |redo_var| | ||
test_code = js_truthy(test) | ||
|
||
compiler.in_while do | ||
while_loop[:closure] = true if wrap_in_closure? | ||
while_loop[:redo_var] = redo_var | ||
|
||
body_code = stmt(body) | ||
|
||
if uses_redo? | ||
push "#{redo_var} = false; #{while_open}#{redo_var} || " | ||
push test_code | ||
push while_close | ||
else | ||
push while_open, test_code, while_close | ||
end | ||
|
||
push "#{redo_var} = false;" if uses_redo? | ||
line body_code, "}" | ||
end | ||
end | ||
|
||
wrap '(function() {', '; return nil; })()' if wrap_in_closure? | ||
end | ||
|
||
def while_open | ||
"while (" | ||
end | ||
|
||
def while_close | ||
") {" | ||
end | ||
|
||
def uses_redo? | ||
while_loop[:use_redo] | ||
end | ||
|
||
def wrap_in_closure? | ||
expr? or recv? | ||
end | ||
end | ||
|
||
class UntilNode < WhileNode | ||
handle :until | ||
|
||
def while_open | ||
"while (!(" | ||
end | ||
|
||
def while_close | ||
")) {" | ||
end | ||
end | ||
end | ||
end |