# encoding: utf-8 # frozen_string_literal: true module Carbon module Compiler module Visitor class Generation # Building functions and function bodies. module Function Generation.on Node::Definition::Function => :visit_function def visit_function(node) params = node.parameters.map { |p| function_parameter_type(p) } full = @name.call(node.name, params, node.generics) @index.define(function: full) do |function| function[:return] = node.type function_definition(function, node) end end Generation.on Node::Definition::Function::Body => :visit_function_body def visit_function_body(node, context) context.push node.children.each { |c| accept(c, context) } context.pop end private def function_definition(function, node) return unless node.body function_definition_intern(function, node) end def function_definition_intern(function, node) function[:definition] = proc do |index| definition = Tacky::Function.new(function[:parameters]) context = Context.new(definition, index, node).tap(&:push) function_definition_intern_parameters(definition, node, context) accept(node.body, context) definition end end def function_definition_intern_parameters(defn, node, context) defn.params.each_with_index do |param, i| fparam = node.parameters[i] next if fparam.name.value == "_" param.name = "#{fparam.name.value}.p" context.build do |b| value = b.alloca(fparam.type).as(fparam.type) context[fparam] = value b.set(param, context[fparam]) end end end def function_parameter_type(param) return @name if param.name.value.to_s == "self" param.type end end end end end end