Class: Duby::AST::If

Inherits:
Node show all
Defined in:
lib/duby/ast/flow.rb,
lib/duby/compiler.rb,
lib/duby/jvm/source_generator/precompile.rb

Instance Attribute Summary collapse

Attributes inherited from Node

#children, #inferred_type, #newline, #parent, #position

Instance Method Summary collapse

Methods inherited from Node

#[], #each, #inspect, #line_number, #log, #precompile, #resolve_if, #resolved!, #resolved?, #simple_name, #temp, #to_s

Constructor Details

#initialize(parent, line_number, &block) ⇒ If

Returns a new instance of If.



33
34
35
36
# File 'lib/duby/ast/flow.rb', line 33

def initialize(parent, line_number, &block)
  super(parent, line_number, &block)
  @condition, @body, @else = children
end

Instance Attribute Details

#bodyObject

Returns the value of attribute body.



31
32
33
# File 'lib/duby/ast/flow.rb', line 31

def body
  @body
end

#conditionObject

Returns the value of attribute condition.



31
32
33
# File 'lib/duby/ast/flow.rb', line 31

def condition
  @condition
end

#elseObject

Returns the value of attribute else.



31
32
33
# File 'lib/duby/ast/flow.rb', line 31

def else
  @else
end

Instance Method Details

#compile(compiler, expression) ⇒ Object



124
125
126
127
# File 'lib/duby/compiler.rb', line 124

def compile(compiler, expression)
  compiler.line(line_number)
  compiler.branch(self, expression)
end

#expr?(compiler) ⇒ Boolean

Returns:



50
51
52
53
54
55
# File 'lib/duby/jvm/source_generator/precompile.rb', line 50

def expr?(compiler)
  return false unless condition.predicate.expr?(compiler)
  return false unless body.nil? || body.expr?(compiler)
  return false unless self.else.nil? || self.else.expr?(compiler)
  true
end

#infer(typer) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/duby/ast/flow.rb', line 38

def infer(typer)
  unless resolved?
    condition_type = typer.infer(condition)
    unless condition_type
      typer.defer(condition)
    end

    # condition type is unrelated to body types, so we proceed with bodies
    then_type = typer.infer(body) if body

    if !then_type
      # attempt to determine else branch
      if self.else
        else_type = typer.infer(self.else)

        if !else_type
          # we have neither type, defer until later
          typer.defer(self)
        else
          # we have else but not then, defer only then and use else type for now
          @inferred_type = else_type
          typer.defer(self)
        end
      else
        # no then type could be inferred and no else body, defer for now
        typer.defer(self)
      end
    else
      if self.else
        else_type = typer.infer(self.else)

        if !else_type
          # we determined a then type, so we use that and defer the else body
          @inferred_type = then_type
          typer.defer(self)
        else
          # both then and else inferred, ensure they're compatible
          if then_type.compatible?(else_type)
            # types are compatible...if condition is resolved, we're done
            @inferred_type = then_type.narrow(else_type)
            resolved! if condition_type
          else
            raise Typer::InferenceError.new("if statement with incompatible result types")
          end
        end
      else
        # only then and type inferred, we're 100% resolved
        @inferred_type = then_type
        resolved! if condition_type
      end
    end
  end

  @inferred_type
end