import type { BinaryOp, UnaryOp } from "../ast" import type { Loc } from "./loc" export type Operand = Loc | number export type AbsInsnCopy = { type: "copy", dest: Loc, source: Operand, } export type AbsInsnGoto = { type: "goto", dest: string, } export type AbsInsnLabel = { type: "label", dest: string, } type UnaryInsn = { type: "unary", dest: Loc, op: Op, source: Operand, } // NOTE: We convert binary -> unary when going SSA3 -> SSA2 export type AbsInsn2Unary = UnaryInsn // Abstract instruction in two-address form export type AbsInsn2 = AbsInsnCopy | AbsInsnLabel | AbsInsnGoto | AbsInsn2Unary type CopyFn = (dest: Loc, source: Operand) => A type StringFn = (name: string) => A type UnaryFn = (dest: Loc, op: Op, source: Operand) => A type UnaryFn2 = UnaryFn export const insnReduce2 = ( copy: CopyFn, label: StringFn, goto: StringFn, unary: UnaryFn2, insn: AbsInsn2 ): A => { switch (insn.type) { case 'copy': return copy(insn.dest, insn.source) case 'label': return label(insn.dest) case 'goto': return goto(insn.dest) case 'unary': return unary(insn.dest, insn.op, insn.source) } } export type AbsInsn3Unary = UnaryInsn export type AbsInsnBinary = { type: "binary", dest: Loc, source: Operand, op: BinaryOp, source1: Operand } // Abstract instruction in three-address form export type AbsInsn3 = AbsInsnCopy | AbsInsnLabel | AbsInsnGoto | AbsInsn3Unary | AbsInsnBinary export const CopyInsn = (dest: Loc, source: Operand): AbsInsnCopy => ({ type: 'copy', dest, source, }) export const UnaryInsn = (dest: Loc, op: Op, source: Operand): UnaryInsn => ({ type: 'unary', dest, op, source, }) export const BinaryInsn = (dest: Loc, source: Operand, op: BinaryOp, source1: Operand): AbsInsnBinary => ({ type: 'binary', dest, source, op, source1, }) export const LabelInsn = (dest: string): AbsInsnLabel => ({ type: 'label', dest, }) export const GotoInsn = (dest: string): AbsInsnGoto => ({ type: 'goto', dest, })