# encoding: utf-8 # frozen_string_literal: true module Carbon module Compiler module Visitor class Generation module Expressions module Assignment Generation.on Node::Expression::Assignment => :visit_expression_assignment def visit_expression_assignment(node, context) case node.left when Node::Expression::Call::Access assign_access(node, context) when Node::Expression::Call::Attribute assign_attribute(node, context) when Node::Name assign_name(node, context) else fail # not possible end end private def assign_access(node, context) access = node.left base = accept(access.expression, context) params = [*access.parameters, node.right] .map { |p| accept(p, context) } ptypes = params.map(&:type) name = base.type.call("[]=", [base.type, *ptypes], access.generics) func, gens = context.find(name) context.build.call(name, base, *params).as(func.return.sub(gens)) end def assign_attribute(node, context) attribute = node.left base = accept(attribute.expression, context) bitem = context.index.fetch(base.type).first if bitem.is_a?(Carbon::Concrete::Item::Struct) && attribute.expression.is_a?(Node::Name) assign_attribute_struct(attribute, base, node, context) else assign_attribute_other(attribute, base, node, context) end end def assign_attribute_struct(attribute, base, node, context) params = [accept(node.right, context)] ptypes = params.map(&:type) name = base.type.call("#{attribute.name.value}=", [base.type.to_pointer, *ptypes], attribute.generics) func, gens = context.find(name) do return assign_attribute_other(attribute, base, node, context) end address = context.current.fetch(attribute.expression.value) context.build do |b| b.call(name, address, *params).as(func.return.sub(gens)) end end def assign_attribute_other(attribute, base, node, context) params = [accept(node.right, context)] ptypes = params.map(&:type) name = base.type.call("#{attribute.name.value}=", [base.type, *ptypes], attribute.generics) func, gens = context.find(name) context.build.call(name, base, *params).as(func.return.sub(gens)) end def assign_name(node, context) if context.current.key?(node.left.value) assign_local(node, context) else assign_function(node, context) end end def assign_function(node, context) value = accept(node.right, context) name = @name.call(node.left.value, [@name, value.type]) thisp = context.current.fetch("self") this = context.build.load(thisp).as(@name) func, gens = context.find(name) context.build.call(name, this, value).as(func.return.sub(gens)) end def assign_local(node, context) local = context.current.fetch(node.left.value) value = accept(node.right, context) assert_type_equal(value.type, local.type, location: node.right.location) context.build.store(value, local) context.build.load(local).as(local.type) end end end end end end end