Permalink
Browse files

Rewrite compile_or to deal properly with shortcut logic, and in proce…

…ss do slight refactor to split out common functionality also used by compile_if and compile_while
  • Loading branch information...
vidarh committed Sep 23, 2014
1 parent 960f1b0 commit c288585bff3a717128f970b921923d5f9b49ee2c
Showing with 54 additions and 38 deletions.
  1. +54 −36 compiler.rb
  2. +0 −2 globalscope.rb
View
@@ -51,7 +51,6 @@ def initialize emitter = Emitter.new
@global_constants << :false
@global_constants << :true
@global_constants << :nil
@global_constants << :__left
@classes = {}
@vtableoffsets = VTableOffsets.new
@trace = false
@@ -304,28 +303,33 @@ def compile_defm(scope, name, args, body)
return Value.new([:addr, clean_method_name(fname)])
end
def compile_jmp_on_false(scope, r, target)
if r && r.type == :object
@e.save_result(r)
@e.cmpl(@e.result_value, "nil")
@e.je(target)
@e.cmpl(@e.result_value, "false")
@e.je(target)
else
@e.jmp_on_false(target, r)
end
end
# Compiles an if expression.
# Takes the current (outer) scope and two expressions representing
# the if and else arm.
# If no else arm is given, it defaults to nil.
def compile_if(scope, cond, if_arm, else_arm = nil)
@e.comment("if: #{cond.inspect}")
res = compile_eval_arg(scope, cond)
l_else_arm = @e.get_local + "_else"
l_end_if_arm = @e.get_local + "_endif"
if res && res.type == :object
@e.save_result(res)
@e.cmpl(@e.result_value, "nil")
@e.je(l_else_arm)
@e.cmpl(@e.result_value, "false")
@e.je(l_else_arm)
else
@e.jmp_on_false(l_else_arm, res)
end
compile_jmp_on_false(scope, res, l_else_arm)
@e.comment("then: #{if_arm.inspect}")
ifret = compile_eval_arg(scope, if_arm)
l_end_if_arm = @e.get_local + "_endif"
@e.jmp(l_end_if_arm) if else_arm
@e.comment("else: #{else_arm.inspect}")
@e.local(l_else_arm)
@@ -336,16 +340,7 @@ def compile_if(scope, cond, if_arm, else_arm = nil)
# in the if vs. else arm, so we need to assume all bets are off.
@e.evict_all
# We only return a specific type if there's either only an "if"
# expression, or both the "if" and "else" expressions have the
# same type.
#
type = nil
if ifret && (!elseret || ifret.type == elseret.type)
type = ifret.type
end
return Value.new([:subexpr], type)
combine_types(ifret, elseret)
end
def compile_return(scope, arg = nil)
@@ -369,11 +364,44 @@ def compile_and scope, left, right
compile_if(scope, left, right)
end
def combine_types(left, right)
type = nil
if left && (!right || left.type == right.type)
type = left.type
end
return Value.new([:subexpr],type)
end
# Changes to make #compile_if comply with real-life requirements
# makes it hard to use it to implement 'or' without introducing a
# temporarily variable. First we did that using a global, as a
# hack. This does things more "properly" as a first stage to
# either refactoring out the commonalities with compile_if or
# create a "lower level" more generic method to handle conditions
#
# (for "or" we really only need a way to explicitly say that
# the return value of the condition should be left untouched
# if the "true" / if-then part of the the if condition should remain
#
def compile_or scope, left, right
@e.comment("compile_or: #{left.inspect} || #{right.inspect}")
# FIXME: Eek. need to make sure variables are assigned for these. Turn it into a rewrite?
compile_eval_arg(scope,[:assign, :__left, left])
compile_if(scope, :__left, :__left, right)
ret = compile_eval_arg(scope,left)
l_or = @e.get_local + "_or"
compile_jmp_on_false(scope, ret, l_or)
l_end_or = @e.get_local + "_end_or"
@e.jmp(l_end_or)
@e.comment(".. or:")
@e.local(l_or)
or_ret = compile_eval_arg(scope,right)
@e.local(l_end_or)
@e.evict_all
combine_types(ret,or_ret)
end
# Compiles the ternary if form (cond ? then : else)
@@ -788,17 +816,7 @@ def compile_index(scope, arr, index)
def compile_while(scope, cond, body)
@e.loop do |br|
var = compile_eval_arg(scope, cond)
if var && var.type == :object
@e.save_result(var)
@e.cmpl(@e.result_value, "nil")
@e.je(br)
@e.cmpl(@e.result_value, "false")
@e.je(br)
else
@e.jmp_on_false(br, var)
end
# @e.jmp_on_false(br)
compile_jmp_on_false(scope, var, br)
compile_exp(scope, body)
end
return Value.new([:subexpr])
View
@@ -16,8 +16,6 @@ def initialize(offsets)
@globals[:false] = true
@globals[:true] = true
@globals[:nil] = true
@globals[:__left] = true
end
def add_constant(c,v = true)

0 comments on commit c288585

Please sign in to comment.