Class: Y2R::AST::YCP::Call

Inherits:
Node
  • Object
show all
Defined in:
lib/y2r/ast/ycp.rb

Instance Method Summary collapse

Methods inherited from Node

#always_returns?, #compile_as_copy_if_needed, #compile_statements, #compile_statements_inside_block, #compile_statements_with_whitespace, #creates_local_scope?, #needs_copy?, #never_nil?, #optimize_last_statement, #optimize_next, #optimize_return, #remove_duplicate_imports, transfers_comments

Instance Method Details

#compile(context) ⇒ Object



921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
# File 'lib/y2r/ast/ycp.rb', line 921

def compile(context)
  call = case category
    when :function
      if !ns && context.locals.include?(name)
        Ruby::MethodCall.new(
          :receiver => RubyVar.for(nil, name, context, :in_code),
          :name     => "call",
          :args     => args.map { |a| a.compile(context) },
          :block    => nil,
          :parens   => true
        )
      else
        # In the XML, all module function calls are qualified (e.g.
        # "M::i"). This includes call to functions defined in this
        # module. The problem is that in generated Ruby code, the module
        # namespace may not exist yet (e.g. when the function is called
        # at module toplvel in YCP), so we have to omit it (which is OK,
        # because then the call will be invoked on |self|, whish is
        # always our module).
        fixed_ns = ns == context.module_name ? nil : ns
        receiver = if fixed_ns
          Ruby::Variable.new(:name => fixed_ns)
        else
          nil
        end

        Ruby::MethodCall.new(
          :receiver => receiver,
          :name     => name,
          :args     => args.map { |a| a.compile(context) },
          :block    => nil,
          :parens   => true
        )
      end
    when :variable # function reference stored in variable
      Ruby::MethodCall.new(
        :receiver => RubyVar.for(ns, name, context, :in_code),
        :name     => "call",
        :args     => args.map { |a| a.compile(context) },
        :block    => nil,
        :parens   => true
      )
    else
      raise "Unknown call category: #{category.inspect}."
  end

  reference_args_with_types = args.zip(type.arg_types).select do |arg, type|
    type.reference?
  end

  if !reference_args_with_types.empty?
    setters = reference_args_with_types.map do |arg, type|
      arg.compile_as_setter(context)
    end
    getters = reference_args_with_types.map do |arg, type|
      arg.compile_as_getter(context)
    end

    case result
      when :used
        result_var = Ruby::Variable.new(
          :name => RubyVar.escape_local("#{name}_result")
        )

        Ruby::Expressions.new(
          :expressions => [
            *setters,
            Ruby::Assignment.new(:lhs => result_var, :rhs => call),
            *getters,
            result_var
          ]
        )

      when :unused
        Ruby::Statements.new(
          :statements => [
            *setters,
            call,
            *getters,
          ]
        )

      else
        raise "Unknown call result usage flag: #{result.inspect}."
    end

  else
    call
  end
end