Skip to content

Commit

Permalink
Keep track and initialize to nil used gvars
Browse files Browse the repository at this point in the history
fixes #489
  • Loading branch information
elia committed Mar 1, 2014
1 parent 8c56856 commit adc35ea
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 16 deletions.
4 changes: 4 additions & 0 deletions lib/opal/nodes/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ def add_ivar(name)
scope.add_scope_ivar name
end

def add_gvar(name)
scope.add_scope_gvar name
end

def add_temp(temp)
scope.add_scope_temp temp
end
Expand Down
33 changes: 21 additions & 12 deletions lib/opal/nodes/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,40 @@ module Nodes
module Helpers

# Reserved javascript keywords - we cannot create variables with the
# same name
RESERVED = %w[
arguments break case catch char class const continue debugger default
delete do else enum export extends false finally for function if import
in instanceof let native new return static switch super this throw try
true typeof var void while with undefined
]
# same name (ref: http://stackoverflow.com/a/9337272/601782)
ES51_RESERVED_WORD = /^(?:do|if|in|for|let|new|try|var|case|else|enum|eval|false|null|this|true|void|with|break|catch|class|const|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)$/

# ES3 reserved words that aren’t ES5.1 reserved words
ES3_RESERVED_WORD_EXCLUSIVE = /^(?:int|byte|char|goto|long|final|float|short|double|native|throws|boolean|abstract|volatile|transient|synchronized)$/

# Immutable properties of the global object
IMMUTABLE_PROPS = /^(?:NaN|Infinity|undefined)$/

# Doesn't take in account utf8
BASIC_IDENTIFIER_RULES = /^[$_a-z][$_a-z\d]*$/i


def property(name)
reserved?(name) ? "['#{name}']" : ".#{name}"
valid_name?(name) ? ".#{name}" : "[#{name.inspect}]"
end

def reserved?(name)
RESERVED.include? name
def valid_name?(name)
BASIC_IDENTIFIER_RULES =~ name and not(
ES51_RESERVED_WORD =~ name or
ES3_RESERVED_WORD_EXCLUSIVE =~ name or
IMMUTABLE_PROPS =~ name
)
end

def variable(name)
reserved?(name.to_s) ? "#{name}$" : name
valid_name?(name.to_s) ? name : "#{name}$"
end

# Converts a ruby lvar/arg name to a js identifier. Not all ruby names
# are valid in javascript. A $ suffix is added to non-valid names.
# varibales
def lvar_to_js(var)
var = "#{var}$" if RESERVED.include? var.to_s
var = "#{var}$" unless valid_name? var.to_s
var.to_sym
end

Expand Down
15 changes: 13 additions & 2 deletions lib/opal/nodes/scope.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class ScopeNode < Base

attr_reader :scope_name
attr_reader :ivars
attr_reader :gvars

attr_accessor :mid

Expand All @@ -37,6 +38,7 @@ def initialize(*)
@temps = []
@args = []
@ivars = []
@gvars = []
@parent = nil
@queue = []
@unique = 'a'
Expand Down Expand Up @@ -124,9 +126,14 @@ def to_vars
"if (self#{ivar} == null) self#{ivar} = nil;\n"
end

gv = gvars.map do |gvar|
"if ($gvars#{gvar} == null) $gvars#{gvar} = nil;\n"
end

indent = @compiler.parser_indent
res = vars.empty? ? '' : "var #{vars.join ', '};"
str = ivars.empty? ? res : "#{res}\n#{indent}#{iv.join indent}"
str = vars.empty? ? '' : "var #{vars.join ', '};\n"
str += "#{indent}#{iv.join indent}" unless ivars.empty?
str += "#{indent}#{gv.join indent}" unless gvars.empty?

if class? and !@proto_ivars.empty?
#raise "FIXME to_vars"
Expand Down Expand Up @@ -156,6 +163,10 @@ def add_scope_ivar(ivar)
end
end

def add_scope_gvar(gvar)
@gvars << gvar unless @gvars.include? gvar
end

def add_proto_ivar(ivar)
@proto_ivars << ivar unless @proto_ivars.include? ivar
end
Expand Down
7 changes: 5 additions & 2 deletions lib/opal/nodes/variables.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ def var_name

def compile
helper :gvars
push "$gvars[#{var_name.inspect}]"
name = property var_name
add_gvar name
push "$gvars#{name}"
end
end

Expand All @@ -103,7 +105,8 @@ def var_name

def compile
helper :gvars
push "$gvars[#{var_name.inspect}] = "
name = property var_name
push "$gvars#{name} = "
push expr(value)
end
end
Expand Down
1 change: 1 addition & 0 deletions spec/opal/filters/bugs/language.rb
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
fails "The defined? keyword for an expression with logical connectives returns nil for an expression with '!' and an unset global variable"
fails "The defined? keyword for an expression with logical connectives returns nil for an expression with 'not' and an unset class variable"
fails "The defined? keyword for an expression with logical connectives returns nil for an expression with '!' and an unset class variable"
fails "The defined? keyword for variables returns nil for a global variable that has been read but not assigned to"

fails "An ensure block inside a begin block is executed even when a symbol is thrown in it's corresponding begin block"
fails "An ensure block inside a method is executed even when a symbol is thrown in the method"
Expand Down

0 comments on commit adc35ea

Please sign in to comment.