Typed operands
This commit is contained in:
@@ -61,12 +61,13 @@ func assembleInstruction(in instruction) (*vm.Instruction, error) {
|
|||||||
instr.OpCode = opCode
|
instr.OpCode = opCode
|
||||||
|
|
||||||
operands := in[1:]
|
operands := in[1:]
|
||||||
if len(operands) != operandsByOpCode[instr.OpCode] {
|
pattern := operandsByOpCode[instr.OpCode]
|
||||||
return nil, fmt.Errorf("Incorrect number of operands: expected %d, found %d\n", operandsByOpCode[instr.OpCode], len(operands))
|
if len(operands) != len(pattern) {
|
||||||
|
return nil, fmt.Errorf("Incorrect number of operands: expected %d, found %d\n", len(pattern), len(operands))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(operands) >= 1 {
|
if len(operands) >= 1 {
|
||||||
op1, err := assembleOperand(operands[0])
|
op1, err := assembleOperand(operands[0], pattern[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "In first operand")
|
return nil, errors.Wrapf(err, "In first operand")
|
||||||
}
|
}
|
||||||
@@ -75,7 +76,7 @@ func assembleInstruction(in instruction) (*vm.Instruction, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(operands) >= 2 {
|
if len(operands) >= 2 {
|
||||||
op2, err := assembleOperand(operands[1])
|
op2, err := assembleOperand(operands[1], pattern[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "In second operand")
|
return nil, errors.Wrapf(err, "In second operand")
|
||||||
}
|
}
|
||||||
@@ -86,7 +87,7 @@ func assembleInstruction(in instruction) (*vm.Instruction, error) {
|
|||||||
return instr, nil
|
return instr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func assembleOperand(op string) (vm.Operand, error) {
|
func assembleOperand(op string, t operandType) (vm.Operand, error) {
|
||||||
op = strings.ToLower(op)
|
op = strings.ToLower(op)
|
||||||
ret := vm.Operand{}
|
ret := vm.Operand{}
|
||||||
numStr := ""
|
numStr := ""
|
||||||
@@ -100,25 +101,31 @@ func assembleOperand(op string) (vm.Operand, error) {
|
|||||||
ret.Type = vm.GlobalMemoryIndex
|
ret.Type = vm.GlobalMemoryIndex
|
||||||
numStr = strings.TrimPrefix(op, "g")
|
numStr = strings.TrimPrefix(op, "g")
|
||||||
|
|
||||||
default:
|
case t == s || t == u || t == us:
|
||||||
ret.Type = vm.Literal
|
ret.Type = vm.Literal
|
||||||
numStr = op
|
numStr = op
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ret, fmt.Errorf("Invalid operand value type: %s", op)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(numStr, "+") || strings.HasPrefix(numStr, "-"):
|
case t == s || (t == us && (strings.HasPrefix(numStr, "+") || strings.HasPrefix(numStr, "-"))):
|
||||||
num, err := strconv.ParseInt(numStr, 10, 64)
|
num, err := strconv.ParseInt(numStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ret, errors.Wrapf(err, "While parsing operand value %s", numStr)
|
return ret, errors.Wrapf(err, "While parsing operand value %s", numStr)
|
||||||
}
|
}
|
||||||
ret.Value = uint64(num)
|
ret.Value = uint64(num)
|
||||||
|
|
||||||
default:
|
case t == u || t == us || t == r:
|
||||||
num, err := strconv.ParseUint(numStr, 10, 64)
|
num, err := strconv.ParseUint(numStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ret, errors.Wrapf(err, "While parsing operand value %s", numStr)
|
return ret, errors.Wrapf(err, "While parsing operand value %s", numStr)
|
||||||
}
|
}
|
||||||
ret.Value = num
|
ret.Value = num
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ret, fmt.Errorf("Invalid operand value: %s", numStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
|||||||
@@ -50,29 +50,38 @@ var opCodeByName = map[string]vm.OpCodeType{
|
|||||||
"jmpf": vm.OpJmpF,
|
"jmpf": vm.OpJmpF,
|
||||||
}
|
}
|
||||||
|
|
||||||
var operandsByOpCode = map[vm.OpCodeType]int{
|
type operandType int
|
||||||
vm.OpNop: 0,
|
|
||||||
vm.OpCal: 1,
|
|
||||||
vm.OpRet: 0,
|
|
||||||
|
|
||||||
vm.OpMov: 2,
|
const (
|
||||||
vm.OpAdd: 2,
|
u operandType = 0
|
||||||
vm.OpSub: 2,
|
s = 1
|
||||||
vm.OpMul: 2,
|
us = 2
|
||||||
vm.OpDivU: 2,
|
r = 3
|
||||||
vm.OpDivS: 2,
|
)
|
||||||
|
|
||||||
vm.OpEq: 2,
|
var operandsByOpCode = map[vm.OpCodeType][]operandType{
|
||||||
vm.OpLTU: 2,
|
vm.OpNop: []operandType{},
|
||||||
vm.OpLTS: 2,
|
vm.OpCal: []operandType{s},
|
||||||
vm.OpGTU: 2,
|
vm.OpRet: []operandType{},
|
||||||
vm.OpGTS: 2,
|
|
||||||
vm.OpLTEU: 2,
|
|
||||||
vm.OpLTES: 2,
|
|
||||||
vm.OpGTEU: 2,
|
|
||||||
vm.OpGTES: 2,
|
|
||||||
|
|
||||||
vm.OpJmp: 1,
|
vm.OpMov: []operandType{r, us},
|
||||||
vm.OpJmpT: 1,
|
vm.OpAdd: []operandType{r, us},
|
||||||
vm.OpJmpF: 1,
|
vm.OpSub: []operandType{r, us},
|
||||||
|
vm.OpMul: []operandType{r, us},
|
||||||
|
vm.OpDivU: []operandType{r, u},
|
||||||
|
vm.OpDivS: []operandType{r, s},
|
||||||
|
|
||||||
|
vm.OpEq: []operandType{us, us},
|
||||||
|
vm.OpLTU: []operandType{u, u},
|
||||||
|
vm.OpLTS: []operandType{s, s},
|
||||||
|
vm.OpGTU: []operandType{u, u},
|
||||||
|
vm.OpGTS: []operandType{s, s},
|
||||||
|
vm.OpLTEU: []operandType{u, u},
|
||||||
|
vm.OpLTES: []operandType{s, s},
|
||||||
|
vm.OpGTEU: []operandType{u, u},
|
||||||
|
vm.OpGTES: []operandType{s, s},
|
||||||
|
|
||||||
|
vm.OpJmp: []operandType{s},
|
||||||
|
vm.OpJmpT: []operandType{s},
|
||||||
|
vm.OpJmpF: []operandType{s},
|
||||||
}
|
}
|
||||||
|
|||||||
35
test/asm_test.go
Normal file
35
test/asm_test.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
import "github.com/firestuff/subcoding/asm"
|
||||||
|
|
||||||
|
func TestTooManyOperands(t *testing.T) {
|
||||||
|
_, err := asm.AssembleString(`
|
||||||
|
functions:
|
||||||
|
- - [nop, 0]
|
||||||
|
`)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Lack of error when passing operand to nop")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTooFewOperands(t *testing.T) {
|
||||||
|
_, err := asm.AssembleString(`
|
||||||
|
functions:
|
||||||
|
- - [mov, g0]
|
||||||
|
`)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Lack of error when passing only one operand to mov")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIncorrectSigned(t *testing.T) {
|
||||||
|
_, err := asm.AssembleString(`
|
||||||
|
functions:
|
||||||
|
- - [ltu, 0, -1]
|
||||||
|
`)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Lack of error when passing signed value to ltu")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user