package asm import "fmt" import "math" import "strings" import "github.com/firestuff/subcoding/vm" import "github.com/pkg/errors" // Lots of manual yaml assembly because the yaml package is missing features (flow in nested arrays) func Disassemble(prog *vm.Program) (string, error) { fncs := []string{} for f, fnc := range prog.Functions { dis, err := disassembleFunction(fnc) if err != nil { return "", errors.Wrapf(err, "At function index %d", f) } fncs = append(fncs, dis) } return fmt.Sprintf(`global_memory_size: %d function_memory_size: %d functions: %s`, prog.GlobalMemorySize, prog.FunctionMemorySize, strings.Join(fncs, ""), ), nil } func disassembleFunction(fnc *vm.Function) (string, error) { instrs := []string{} for i, instr := range fnc.Instructions { dis, err := disassembleInstruction(instr) if err != nil { return "", errors.Wrapf(err, "At instruction index %d", i) } instrs = append(instrs, dis) } return fmt.Sprintf("- - %s\n", strings.Join(instrs, "\n - ")), nil } func disassembleInstruction(in *vm.Instruction) (string, error) { parts := []string{ nameByOpCode[in.OpCode], } for i, t := range vm.OperandsByOpCode[in.OpCode] { op, err := disassembleOperand(in.Operands[i], t) if err != nil { return "", err } parts = append(parts, op) } encoded := fmt.Sprintf("[%s]", strings.Join(parts, ", ")) return encoded, nil } func disassembleOperand(op *vm.Operand, t vm.OperandNumericType) (string, error) { switch op.Type { case vm.GlobalMemoryIndex: return fmt.Sprintf("g%d", op.Value), nil case vm.FunctionMemoryIndex: return fmt.Sprintf("f%d", op.Value), nil case vm.Literal: switch t { case vm.OperandUnsigned: return fmt.Sprintf("%d", op.Value), nil case vm.OperandSigned: return fmt.Sprintf("%+d", int64(op.Value)), nil case vm.OperandSignedOrUnsigned: // Take our best guess if op.Value > math.MaxInt64 { return fmt.Sprintf("%+d", int64(op.Value)), nil } else { return fmt.Sprintf("%d", op.Value), nil } default: return "", fmt.Errorf("Invalid operand assembler type: %d", t) } default: return "", fmt.Errorf("Invalid operand type: %d", op.Type) } }