diff --git a/lib/coffee_script/grammar.y b/lib/coffee_script/grammar.y index 799f04d4..0817762f 100644 --- a/lib/coffee_script/grammar.y +++ b/lib/coffee_script/grammar.y @@ -38,7 +38,7 @@ prechigh right WHEN LEADING_WHEN IN OF BY right THROW FOR NEW SUPER left EXTENDS - left ASSIGN '||=' '&&=' + left ASSIGN '||=' '&&=' '?=' right RETURN right '=>' '==>' UNLESS IF ELSE WHILE preclow @@ -187,6 +187,7 @@ rule | Expression '%=' Expression { result = OpNode.new(val[1], val[0], val[2]) } | Expression '||=' Expression { result = OpNode.new(val[1], val[0], val[2]) } | Expression '&&=' Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression '?=' Expression { result = OpNode.new(val[1], val[0], val[2]) } | Expression INSTANCEOF Expression { result = OpNode.new(val[1], val[0], val[2]) } | Expression IN Expression { result = OpNode.new(val[1], val[0], val[2]) } diff --git a/lib/coffee_script/lexer.rb b/lib/coffee_script/lexer.rb index 1d0cb83d..dad8b3d7 100644 --- a/lib/coffee_script/lexer.rb +++ b/lib/coffee_script/lexer.rb @@ -25,7 +25,7 @@ module CoffeeScript STRING = /\A(""|''|"(.*?)([^\\]|\\\\)"|'(.*?)([^\\]|\\\\)')/m HEREDOC = /\A("{6}|'{6}|"{3}\n?(.*?)\n?(\s*)"{3}|'{3}\n?(.*?)\n?(\s*)'{3})/m JS = /\A(``|`(.*?)([^\\]|\\\\)`)/m - OPERATOR = /\A([+\*&|\/\-%=<>:!]+)/ + OPERATOR = /\A([+\*&|\/\-%=<>:!?]+)/ WHITESPACE = /\A([ \t]+)/ COMMENT = /\A(((\n?[ \t]*)?#.*$)+)/ CODE = /\A(=?=>)/ diff --git a/lib/coffee_script/nodes.rb b/lib/coffee_script/nodes.rb index e0db94ff..525e1af6 100644 --- a/lib/coffee_script/nodes.rb +++ b/lib/coffee_script/nodes.rb @@ -556,7 +556,7 @@ module CoffeeScript :not => '!' } CHAINABLE = [:<, :>, :>=, :<=, :===, :'!==='] - CONDITIONALS = [:'||=', :'&&='] + CONDITIONALS = [:'||=', :'&&=', :'?='] PREFIX_OPERATORS = [:typeof, :delete] def initialize(operator, first, second=nil, flip=false) @@ -593,7 +593,9 @@ module CoffeeScript def compile_conditional(o) first, second = @first.compile(o), @second.compile(o) + o[:scope].find(first) if @first.unwrap.is_a?(Value) sym = @operator[0..1] + return "#{first} = (typeof #{first} !== \"undefined\" && #{first} !== null) ? #{first} : #{second}" if @operator == '?=' "#{first} = #{first} #{sym} #{second}" end diff --git a/test/fixtures/execution/test_operations.coffee b/test/fixtures/execution/test_operations.coffee index 56f57b6c..0b996da6 100644 --- a/test/fixtures/execution/test_operations.coffee +++ b/test/fixtures/execution/test_operations.coffee @@ -16,3 +16,13 @@ i: 0 func: => i++ print(1 > func() < 1) + + +# The conditional assignment based on existence. + +a: 5 +a: null +a ?= 10 +b ?= 10 + +print(a is 10 and b is 10) \ No newline at end of file