Skip to content

Commit

Permalink
Showing 3 changed files with 64 additions and 54 deletions.
56 changes: 35 additions & 21 deletions lib/opal/parser.rb
Original file line number Diff line number Diff line change
@@ -328,6 +328,14 @@ def in_while
result
end

def in_case
return unless block_given?
old = @case_stmt
@case_stmt = {}
yield
@case_stmt = old
end

# Returns true if the parser is curently handling a while sexp,
# false otherwise.
#
@@ -1941,27 +1949,32 @@ def process_break(sexp, level)

# s(:case, expr, when1, when2, ..)
def process_case(exp, level)
pre = []
code = []
@scope.add_local "$case"
expr = process exp.shift, :expr
pre, code = [], []

# are we inside a statement_closure
returnable = level != :stmt
done_else = false

pre << fragment("$case = ", exp) << expr << fragment(";", exp)
in_case do
if cond = exp.shift
@case_stmt[:cond] = true
@scope.add_local "$case"
expr = process cond, :expr
pre << f("$case = ", exp) << expr << f(";", exp)
end

until exp.empty?
wen = exp.shift
if wen and wen.first == :when
returns(wen) if returnable
wen = process(wen, :stmt)
code << fragment("else ", exp) unless code.empty?
code << wen
elsif wen # s(:else)
done_else = true
wen = returns(wen) if returnable
code << fragment("else {", exp) << process(wen, :stmt) << fragment("}", exp)
until exp.empty?
wen = exp.shift
if wen and wen.first == :when
returns(wen) if returnable
wen = process(wen, :stmt)
code << fragment("else ", exp) unless code.empty?
code << wen
elsif wen # s(:else)
done_else = true
wen = returns(wen) if returnable
code << fragment("else {", exp) << process(wen, :stmt) << fragment("}", exp)
end
end
end

@@ -1984,7 +1997,6 @@ def process_case(exp, level)
def process_when(exp, level)
arg = exp.shift[1..-1]
body = exp.shift || s(:nil)
#body = process body, level if body
body = process body, level

test = []
@@ -2001,10 +2013,12 @@ def process_when(exp, level)

test << splt
else
call = s(:call, a, :===, s(:arglist, s(:js_tmp, "$case")))
call = process call, :expr

test << call
if @case_stmt[:cond]
call = s(:call, a, :===, s(:arglist, s(:js_tmp, "$case")))
test << process(call, :expr)
else
test << js_truthy(a)
end
end
end

4 changes: 0 additions & 4 deletions spec/filters/bugs/case.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
opal_filter "case" do
fails "The 'case'-construct lets you define a method after the case statement"
fails "The 'case'-construct with no target expression evaluates the body of the first clause when at least one of its condition expressions is true"
fails "The 'case'-construct with no target expression evaluates the body of the first when clause that is not false/nil"
fails "The 'case'-construct with no target expression evaluates the body of the else clause if all when clauses are false/nil"
fails "The 'case'-construct with no target expression evaluates multiple conditional expressions as a boolean disjunction"
fails "The 'case'-construct with no target expression evaluates true as only 'true' when true is the first clause"
end
58 changes: 29 additions & 29 deletions spec/rubyspec/language/case_spec.rb
Original file line number Diff line number Diff line change
@@ -245,44 +245,44 @@ def bar; @calls << :bar; end

describe "The 'case'-construct with no target expression" do
it "evaluates the body of the first clause when at least one of its condition expressions is true" do
# case
# when true, false; 'foo'
# end.should == 'foo'
case
when true, false; 'foo'
end.should == 'foo'
end

it "evaluates the body of the first when clause that is not false/nil" do
# case
# when false; 'foo'
# when 2; 'bar'
# when 1 == 1; 'baz'
# end.should == 'bar'

# case
# when false; 'foo'
# when nil; 'foo'
# when 1 == 1; 'bar'
# end.should == 'bar'
case
when false; 'foo'
when 2; 'bar'
when 1 == 1; 'baz'
end.should == 'bar'

case
when false; 'foo'
when nil; 'foo'
when 1 == 1; 'bar'
end.should == 'bar'
end

it "evaluates the body of the else clause if all when clauses are false/nil" do
# case
# when false; 'foo'
# when nil; 'foo'
# when 1 == 2; 'bar'
# else 'baz'
# end.should == 'baz'
case
when false; 'foo'
when nil; 'foo'
when 1 == 2; 'bar'
else 'baz'
end.should == 'baz'
end

it "evaluates multiple conditional expressions as a boolean disjunction" do
# case
# when true, false; 'foo'
# else 'bar'
# end.should == 'foo'

# case
# when false, true; 'foo'
# else 'bar'
# end.should == 'foo'
case
when true, false; 'foo'
else 'bar'
end.should == 'foo'

case
when false, true; 'foo'
else 'bar'
end.should == 'foo'
end

it "evaluates true as only 'true' when true is the first clause" do

0 comments on commit b7355f6

Please sign in to comment.