the existential operator can now be used infix as well

This commit is contained in:
Jeremy Ashkenas
2010-01-16 23:03:54 -05:00
parent 52539ae7d2
commit f6c8e81ea6
4 changed files with 36 additions and 18 deletions

View File

@@ -179,6 +179,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 AND Expression { result = OpNode.new(val[1], val[0], val[2]) } | Expression AND Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression OR Expression { result = OpNode.new(val[1], val[0], val[2]) } | Expression OR 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 '+=' Expression { result = OpNode.new(val[1], val[0], val[2]) } | Expression '+=' Expression { result = OpNode.new(val[1], val[0], val[2]) }

View File

@@ -556,7 +556,7 @@ module CoffeeScript
:not => '!' :not => '!'
} }
CHAINABLE = [:<, :>, :>=, :<=, :===, :'!==='] CHAINABLE = [:<, :>, :>=, :<=, :===, :'!===']
CONDITIONALS = [:'||=', :'&&=', :'?='] ASSIGNMENT = [:'||=', :'&&=', :'?=']
PREFIX_OPERATORS = [:typeof, :delete] PREFIX_OPERATORS = [:typeof, :delete]
def initialize(operator, first, second=nil, flip=false) def initialize(operator, first, second=nil, flip=false)
@@ -574,8 +574,9 @@ module CoffeeScript
def compile_node(o) def compile_node(o)
return write(compile_chain(o)) if chainable? && @first.unwrap.is_a?(OpNode) && @first.unwrap.chainable? return write(compile_chain(o)) if chainable? && @first.unwrap.is_a?(OpNode) && @first.unwrap.chainable?
return write(compile_conditional(o)) if CONDITIONALS.include?(@operator.to_sym) return write(compile_assignment(o)) if ASSIGNMENT.include?(@operator.to_sym)
return write(compile_unary(o)) if unary? return write(compile_unary(o)) if unary?
return write(compile_existence(o)) if @operator == '?'
write("#{@first.compile(o)} #{@operator} #{@second.compile(o)}") write("#{@first.compile(o)} #{@operator} #{@second.compile(o)}")
end end
@@ -588,17 +589,22 @@ module CoffeeScript
@first.second = ParentheticalNode.new(AssignNode.new(temp, shared)) @first.second = ParentheticalNode.new(AssignNode.new(temp, shared))
shared = temp shared = temp
end end
write("(#{@first.compile(o)}) && (#{shared.compile(o)} #{@operator} #{@second.compile(o)})") "(#{@first.compile(o)}) && (#{shared.compile(o)} #{@operator} #{@second.compile(o)})"
end end
def compile_conditional(o) def compile_assignment(o)
first, second = @first.compile(o), @second.compile(o) first, second = @first.compile(o), @second.compile(o)
o[:scope].find(first) if @first.unwrap.is_a?(Value) o[:scope].find(first) if @first.unwrap.is_a?(Value)
sym = @operator[0..1] sym = @operator[0..1]
return "#{first} = (#{first} !== undefined && #{first} !== null) ? #{first} : #{second}" if @operator == '?=' return "#{first} = #{ExistenceNode.compile_test(first)} ? #{first} : #{second}" if @operator == '?='
"#{first} = #{first} #{sym} #{second}" "#{first} = #{first} #{sym} #{second}"
end end
def compile_existence(o)
first, second = @first.compile(o), @second.compile(o)
"#{ExistenceNode.compile_test(first)} ? #{first} : #{second}"
end
def compile_unary(o) def compile_unary(o)
space = PREFIX_OPERATORS.include?(@operator.to_sym) ? ' ' : '' space = PREFIX_OPERATORS.include?(@operator.to_sym) ? ' ' : ''
parts = [@operator.to_s, space, @first.compile(o)] parts = [@operator.to_s, space, @first.compile(o)]
@@ -890,13 +896,16 @@ module CoffeeScript
class ExistenceNode < Node class ExistenceNode < Node
children :expression children :expression
def self.compile_test(variable)
"(typeof #{variable} !== \"undefined\" && #{variable} !== null)"
end
def initialize(expression) def initialize(expression)
@expression = expression @expression = expression
end end
def compile_node(o) def compile_node(o)
val = @expression.compile(o) write(ExistenceNode.compile_test(@expression.compile(o)))
write("(typeof #{val} !== \"undefined\" && #{val} !== null)")
end end
end end

View File

@@ -2,4 +2,22 @@ print(if my_special_variable? then false else true)
my_special_variable: false my_special_variable: false
print(if my_special_variable? then true else false) print(if my_special_variable? then true else false)
# Existential assignment.
a: 5
a: null
a ?= 10
b ?= 10
print(a is 10 and b is 10)
# The existential operator.
z: null
x: z ? "EX"
print(z is null and x is "EX")

View File

@@ -16,13 +16,3 @@ i: 0
func: => i++ func: => i++
print(1 > func() < 1) 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)