Skip to content

Commit

Permalink
Fix source compiler evaluation order
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryan Brown committed Mar 17, 2010
1 parent 83940c0 commit 054bb99
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 22 deletions.
55 changes: 41 additions & 14 deletions lib/duby/jvm/source_compiler.rb
Expand Up @@ -198,13 +198,24 @@ def this
end

def local_assign(scope, name, type, expression, value)
simple = value.expr?(self)
value = value.precompile(self)
name = scoped_local_name(name, scope)
if method.local?(name)
@method.print @lvalue if expression
if expression
if simple
@method.print '('
else
@method.print @lvalue
end
end
@method.print "#{name} = "
value.compile(self, true)
@method.puts ';'
if simple && expression
@method.print ')'
else
@method.puts ';'
end
else
@method.declare_local(type, name) do
value.compile(self, true)
Expand Down Expand Up @@ -370,12 +381,24 @@ def operator(target, op, params, expression)
end
end

def compile_args(call)
call.parameters.map do |param|
param.precompile(self)
def precompile_nodes(nodes)
if nodes.all? {|n| n.expr?(self)}
nodes
else
nodes.map do |node|
tempval = node.precompile(self)
if tempval == node && !node.kind_of?(Duby::AST::Literal)
tempval = node.temp(self)
end
tempval
end
end
end

def compile_args(call)
precompile_nodes(call.parameters)
end

def self_type
type = AST::type(@class.name.tr('/', '.'))
type = type.meta if @static
Expand Down Expand Up @@ -538,7 +561,15 @@ def method_call(target, call, params, expression)
end

def temp(expression, value=nil)
assign(@method.tmp(expression.inferred_type), value || expression)
value ||= expression
type = value.inferred_type
if value.expr?(self)
@method.tmp(type) do
value.compile(self, true)
end
else
assign(@method.tmp(type), value)
end
end

def empty_array(type, size)
Expand Down Expand Up @@ -579,14 +610,10 @@ def array(node, expression)
end
end

def build_string(nodes, expression)
def build_string(orig_nodes, expression)
if expression
simple = true
nodes = nodes.map do |node|
simple &&= node.expr?(self)
node.precompile(self)
end
log "nodes: #{nodes.inspect}"
nodes = precompile_nodes(orig_nodes)
simple = nodes.equal?(orig_nodes)
if !simple
@method.print(lvalue)
end
Expand All @@ -602,7 +629,7 @@ def build_string(nodes, expression)
end
@method.puts ';' unless simple
else
nodes.each {|n| n.compile(self, false)}
orig_nodes.each {|n| n.compile(self, false)}
end
end

Expand Down
4 changes: 2 additions & 2 deletions lib/duby/jvm/source_generator/builder.rb
Expand Up @@ -355,9 +355,9 @@ def local?(name)
!!@locals[name]
end

def tmp(type)
def tmp(type, &block)
@temps += 1
declare_local(type, "temp$#{@temps}")
declare_local(type, "temp$#{@temps}", &block)
end

def label
Expand Down
6 changes: 0 additions & 6 deletions lib/duby/jvm/source_generator/precompile.rb
Expand Up @@ -177,10 +177,4 @@ def expr?(compiler)
false
end
end

class LocalAssignment
def expr?(compiler)
false
end
end
end
22 changes: 22 additions & 0 deletions test/test_jvm_compiler.rb
Expand Up @@ -2078,6 +2078,28 @@ def self.b
end
end

def test_evaluation_order
cls, = compile(<<-EOF)
def call(a:int, b:int, c:int)
print "\#{a}, \#{b}, \#{c}"
end
def test_call(a:int)
call(a, if a < 10;a+=1;a;else;a;end, a)
end
def test_string(a:int)
"\#{a}, \#{if a < 10;a += 1;a;else;a;end}, \#{a}"
end
EOF

assert_output("1, 2, 2") do
cls.test_call(1)
end

assert_equal("2, 3, 3", cls.test_string(2))
end

# TODO: need a writable field somewhere...
# def test_field_write
# cls, = compile(<<-EOF)
Expand Down

0 comments on commit 054bb99

Please sign in to comment.