# encoding: utf-8 # frozen_string_literal: true module Carbon module Compiler module Visitor class Generation # Statement generation. module Statements Generation.on Node::Statement::Return => :visit_statement_return def visit_statement_return(node, context) if node.value value = accept(node.value, context) assert_type_equal(value.type, context.function.type, location: node.location) context.build { |b| b.ret(value) } else assert_type_equal(Carbon::Void, context.function.type, location: node.location) context.build(&:ret_void) end end Generation.on Node::Statement::Let => :visit_statement_let def visit_statement_let(node, context) name = node.name.value value = accept(node.value, context) if node.value assert_type_equal(value.type, node.type, location: node.value.location) if node.value assert_nolocal(name, context) context.build do |b| context[name] = b.alloca(node.type).as(node.type) value = value || b.null(node.type).as(node.type) b.store(value, context[name]) end end Generation.on Node::Statement::While => :visit_statement_while def visit_statement_while(node, context) loop, merge = context.new("while-loop"), context.new("while-merge") cond = accept(node.condition, context) assert_type_boolean(cond.type, location: node.condition.location) check = context.build.icmp(:ne, cond, 0) context.build.cond(check, loop, merge) context.swap(loop) accept(node.body, context) cond = accept(node.condition, context) check = context.build.icmp(:ne, cond, 0) context.build.cond(check, loop, merge) context.swap(merge) end Generation.on Node::Statement::For => :visit_statement_for def visit_statement_for(node, context) loop, merge = context.new("for-loop"), context.new("for-merge") accept(node.initial, context) cond = accept(node.condition, context) assert_type_boolean(cond.type, location: node.condition.location) check = context.build.icmp(:ne, cond, 0) context.build.cond(check, loop, merge) context.swap(loop) accept(node.body, context) accept(node.increment, context) cond = accept(node.condition, context) check = context.build.icmp(:ne, cond, 0) context.build.cond(check, loop, merge) context.swap(merge) end Generation.on Node::Statement::If => :visit_statement_if def visit_statement_if(node, context) cond = accept(node.condition, context) assert_type_boolean(cond.type, location: node.condition.location) check = context.build.icmp(:ne, cond, 0) iftrue, iffalse, ifmerge = context.new("if-true"), context.new("if-false"), context.new("if-merge") context.build.cond(check, iftrue, iffalse) context.swap(iftrue) accept(node.body, context) context.build.br(ifmerge) context.swap(iffalse) statement_if_false_merge(node, context, merge) context.swap(ifmerge) end Generation.on Node::Statement::ElsIf => :visit_statement_elsif def visit_statement_elsif(node, context, merge) cond = accept(node.condition) assert_type_boolean(cond.type, location: node.condition.location) check = context.build.icmp(:ne, cond, 0) ifetrue = context.new("if-else-true") ifefalse = context.new("if-else-false") context.build.cond(check, ifetrue, ifefalse) context.swap(ifetrue) accept(node.body, context) context.build.br(merge) context.swap(ifefalse) statement_if_false_merge(node, context, merge) context.swap(merge) end Generation.on Node::Statement::Else => :visit_statement_else def visit_statement_else(node, context, merge) accept(node.body, context) context.build.br(merge) context.swap(merge) end private def statement_if_false_merge(node, context, merge) if node.follow accept(node.follow, context, merge) else context.build.br(merge) end end end end end end end