diff --git a/asm/disassemble.go b/asm/disassemble.go index 358b60b..2b3a3b6 100644 --- a/asm/disassemble.go +++ b/asm/disassemble.go @@ -1,39 +1,91 @@ package asm import "fmt" +import "math" import "strings" import "github.com/firestuff/subcoding/vm" import "github.com/pkg/errors" -func Disassemble(prog *vm.Program) ([]byte, error) { +// 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 { - _, err := disassembleFunction(fnc) + dis, err := disassembleFunction(fnc) if err != nil { - return nil, errors.Wrapf(err, "At function index %d", f) + return "", errors.Wrapf(err, "At function index %d", f) } + + fncs = append(fncs, dis) } - return nil, nil + return fmt.Sprintf("functions:\n%s", strings.Join(fncs, "")), nil } -func disassembleFunction(fnc *vm.Function) ([]byte, error) { +func disassembleFunction(fnc *vm.Function) (string, error) { + instrs := []string{} + for i, instr := range fnc.Instructions { - _, err := disassembleInstruction(instr) + dis, err := disassembleInstruction(instr) if err != nil { - return nil, errors.Wrapf(err, "At instruction index %d", i) + return "", errors.Wrapf(err, "At instruction index %d", i) } + + instrs = append(instrs, dis) } - return nil, nil + return fmt.Sprintf("- - %s\n", strings.Join(instrs, "\n - ")), nil } -func disassembleInstruction(in *vm.Instruction) ([]byte, error) { +func disassembleInstruction(in *vm.Instruction) (string, error) { parts := []string{ nameByOpCode[in.OpCode], } + for i, t := range 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 []byte(encoded), nil + return encoded, nil +} + +func disassembleOperand(op *vm.Operand, t operandType) (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 u: + return fmt.Sprintf("%d", op.Value), nil + + case s: + return fmt.Sprintf("%+d", int64(op.Value)), nil + + case us: + // 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) + } } diff --git a/test/disasm_test.go b/test/disasm_test.go index c35d13d..95255e0 100644 --- a/test/disasm_test.go +++ b/test/disasm_test.go @@ -5,16 +5,27 @@ import "testing" import "github.com/firestuff/subcoding/asm" func TestRoundTrip(t *testing.T) { - prog, err := asm.AssembleString(` -functions: + src := `functions: - - [nop] -`) + - [mov, g0, 1] + - [add, f0, 5] + - [mov, g1, -5] + - [eq, 2, f0] + - [jmpt, -3] +- - [add, g0, -1] + - [cal, +5] +` + prog, err := asm.AssembleString(src) if err != nil { t.Fatal(err) } - _, err = asm.Disassemble(prog) + dis, err := asm.Disassemble(prog) if err != nil { t.Fatal(err) } + + if dis != src { + t.Fatalf("Disassembly mismatch: expected=%v actual=%v", src, dis) + } }