diff --git a/src/build/arch/x64/Move.go b/src/build/arch/x64/Move.go index 82f5869..cac1d09 100644 --- a/src/build/arch/x64/Move.go +++ b/src/build/arch/x64/Move.go @@ -4,13 +4,14 @@ import ( "encoding/binary" "git.akyoto.dev/cli/q/src/build/cpu" + "git.akyoto.dev/cli/q/src/build/sizeof" ) // MoveRegisterNumber moves an integer into the given register. func MoveRegisterNumber(code []byte, destination cpu.Register, number int) []byte { w := byte(0) - if SizeOf(int64(number)) == 8 { + if sizeof.Signed(int64(number)) == 8 { w = 1 } diff --git a/src/build/arch/x64/SizeOf_test.go b/src/build/arch/x64/SizeOf_test.go deleted file mode 100644 index eb84a59..0000000 --- a/src/build/arch/x64/SizeOf_test.go +++ /dev/null @@ -1,21 +0,0 @@ -package x64_test - -import ( - "math" - "testing" - - "git.akyoto.dev/cli/q/src/build/arch/x64" - "git.akyoto.dev/go/assert" -) - -func TestSizeOf(t *testing.T) { - assert.Equal(t, x64.SizeOf(0), 1) - assert.Equal(t, x64.SizeOf(math.MinInt8), 1) - assert.Equal(t, x64.SizeOf(math.MaxInt8), 1) - assert.Equal(t, x64.SizeOf(math.MinInt16), 2) - assert.Equal(t, x64.SizeOf(math.MaxInt16), 2) - assert.Equal(t, x64.SizeOf(math.MinInt32), 4) - assert.Equal(t, x64.SizeOf(math.MaxInt32), 4) - assert.Equal(t, x64.SizeOf(math.MinInt64), 8) - assert.Equal(t, x64.SizeOf(math.MaxInt64), 8) -} diff --git a/src/build/arch/x64/encodeNum.go b/src/build/arch/x64/encodeNum.go index 2053dfb..a9a3313 100644 --- a/src/build/arch/x64/encodeNum.go +++ b/src/build/arch/x64/encodeNum.go @@ -4,11 +4,12 @@ import ( "encoding/binary" "git.akyoto.dev/cli/q/src/build/cpu" + "git.akyoto.dev/cli/q/src/build/sizeof" ) // encodeNum encodes an instruction with up to two registers and a number parameter. func encodeNum(code []byte, mod AddressMode, reg cpu.Register, rm cpu.Register, number int, opCode8 byte, opCode32 byte) []byte { - if SizeOf(int64(number)) == 1 { + if sizeof.Signed(int64(number)) == 1 { code = encode(code, mod, reg, rm, 8, opCode8) return append(code, byte(number)) } diff --git a/src/build/asm/Finalize.go b/src/build/asm/Finalize.go index e38a83f..7094fe2 100644 --- a/src/build/asm/Finalize.go +++ b/src/build/asm/Finalize.go @@ -7,6 +7,7 @@ import ( "git.akyoto.dev/cli/q/src/build/arch/x64" "git.akyoto.dev/cli/q/src/build/config" "git.akyoto.dev/cli/q/src/build/elf" + "git.akyoto.dev/cli/q/src/build/sizeof" ) // Finalize generates the final machine code. @@ -242,7 +243,7 @@ restart: for i, pointer := range pointers { address := pointer.Resolve() - if x64.SizeOf(int64(address)) > int(pointer.Size) { + if sizeof.Signed(int64(address)) > int(pointer.Size) { left := code[:pointer.Position-Address(pointer.OpSize)] right := code[pointer.Position+Address(pointer.Size):] size := pointer.Size + pointer.OpSize diff --git a/src/build/core/CompileAssignArray.go b/src/build/core/CompileAssignArray.go index f519ea0..167d3e3 100644 --- a/src/build/core/CompileAssignArray.go +++ b/src/build/core/CompileAssignArray.go @@ -21,7 +21,7 @@ func (f *Function) CompileAssignArray(node *ast.Assign) error { defer f.UseVariable(variable) index := left.Children[1] - offset, _, err := f.Number(index.Token) + offset, err := f.Number(index.Token) if err != nil { return err diff --git a/src/build/core/ExecuteLeaf.go b/src/build/core/ExecuteLeaf.go index 6dd7645..fe78ef6 100644 --- a/src/build/core/ExecuteLeaf.go +++ b/src/build/core/ExecuteLeaf.go @@ -21,7 +21,7 @@ func (f *Function) ExecuteLeaf(operation token.Token, register cpu.Register, ope return f.ExecuteRegisterRegister(operation, register, variable.Register) case token.Number, token.Rune: - number, _, err := f.Number(operand) + number, err := f.Number(operand) if err != nil { return err diff --git a/src/build/core/ExpressionToMemory.go b/src/build/core/ExpressionToMemory.go index af7ec37..d876c7b 100644 --- a/src/build/core/ExpressionToMemory.go +++ b/src/build/core/ExpressionToMemory.go @@ -4,18 +4,21 @@ import ( "git.akyoto.dev/cli/q/src/build/asm" "git.akyoto.dev/cli/q/src/build/errors" "git.akyoto.dev/cli/q/src/build/expression" + "git.akyoto.dev/cli/q/src/build/sizeof" "git.akyoto.dev/cli/q/src/build/token" ) // ExpressionToMemory puts the result of an expression into the specified memory address. func (f *Function) ExpressionToMemory(node *expression.Expression, memory asm.Memory) error { if node.IsLeaf() && (node.Token.Kind == token.Number || node.Token.Kind == token.Rune) { - number, size, err := f.Number(node.Token) + number, err := f.Number(node.Token) if err != nil { return err } + size := byte(sizeof.Signed(int64(number))) + if size != memory.Length { return errors.New(&errors.NumberExceedsBounds{Number: number, ExpectedSize: memory.Length, Size: size}, f.File, node.Token.Position) } diff --git a/src/build/core/Number.go b/src/build/core/Number.go index 2cc05a1..f6c14cd 100644 --- a/src/build/core/Number.go +++ b/src/build/core/Number.go @@ -10,45 +10,45 @@ import ( ) // Number tries to convert the token into a numeric value. -func (f *Function) Number(t token.Token) (int, byte, error) { +func (f *Function) Number(t token.Token) (int, error) { switch t.Kind { case token.Number: digits := t.Text(f.File.Bytes) if strings.HasPrefix(digits, "0x") { number, err := strconv.ParseInt(digits[2:], 16, 64) - return int(number), 8, err + return int(number), err } if strings.HasPrefix(digits, "0o") { number, err := strconv.ParseInt(digits[2:], 8, 64) - return int(number), 8, err + return int(number), err } if strings.HasPrefix(digits, "0b") { number, err := strconv.ParseInt(digits[2:], 2, 64) - return int(number), 8, err + return int(number), err } number, err := strconv.Atoi(digits) - return number, 8, err + return number, err case token.Rune: r := t.Bytes(f.File.Bytes) r = r[1 : len(r)-1] if len(r) == 0 { - return 0, 0, errors.New(errors.InvalidRune, f.File, t.Position+1) + return 0, errors.New(errors.InvalidRune, f.File, t.Position+1) } number, size := utf8.DecodeRune(r) if len(r) > size { - return 0, 0, errors.New(errors.InvalidRune, f.File, t.Position+1) + return 0, errors.New(errors.InvalidRune, f.File, t.Position+1) } - return int(number), byte(size), nil + return int(number), nil } - return 0, 0, errors.New(errors.InvalidNumber, f.File, t.Position) + return 0, errors.New(errors.InvalidNumber, f.File, t.Position) } diff --git a/src/build/core/TokenToRegister.go b/src/build/core/TokenToRegister.go index 50e2b77..e95d87d 100644 --- a/src/build/core/TokenToRegister.go +++ b/src/build/core/TokenToRegister.go @@ -26,7 +26,7 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error { return nil case token.Number, token.Rune: - number, _, err := f.Number(t) + number, err := f.Number(t) if err != nil { return err diff --git a/src/build/arch/x64/SizeOf.go b/src/build/sizeof/Signed.go similarity index 67% rename from src/build/arch/x64/SizeOf.go rename to src/build/sizeof/Signed.go index 6c7293a..a0fee4a 100644 --- a/src/build/arch/x64/SizeOf.go +++ b/src/build/sizeof/Signed.go @@ -1,9 +1,9 @@ -package x64 +package sizeof import "math" -// SizeOf tells you how many bytes are needed to encode this number. -func SizeOf(number int64) int { +// Signed tells you how many bytes are needed to encode this signed number. +func Signed(number int64) int { switch { case number >= math.MinInt8 && number <= math.MaxInt8: return 1 diff --git a/src/build/sizeof/Signed_test.go b/src/build/sizeof/Signed_test.go new file mode 100644 index 0000000..6ddc15f --- /dev/null +++ b/src/build/sizeof/Signed_test.go @@ -0,0 +1,21 @@ +package sizeof_test + +import ( + "math" + "testing" + + "git.akyoto.dev/cli/q/src/build/sizeof" + "git.akyoto.dev/go/assert" +) + +func TestSigned(t *testing.T) { + assert.Equal(t, sizeof.Signed(0), 1) + assert.Equal(t, sizeof.Signed(math.MinInt8), 1) + assert.Equal(t, sizeof.Signed(math.MaxInt8), 1) + assert.Equal(t, sizeof.Signed(math.MinInt16), 2) + assert.Equal(t, sizeof.Signed(math.MaxInt16), 2) + assert.Equal(t, sizeof.Signed(math.MinInt32), 4) + assert.Equal(t, sizeof.Signed(math.MaxInt32), 4) + assert.Equal(t, sizeof.Signed(math.MinInt64), 8) + assert.Equal(t, sizeof.Signed(math.MaxInt64), 8) +} diff --git a/src/build/sizeof/Unsigned.go b/src/build/sizeof/Unsigned.go new file mode 100644 index 0000000..949b77a --- /dev/null +++ b/src/build/sizeof/Unsigned.go @@ -0,0 +1,20 @@ +package sizeof + +import "math" + +// Unsigned tells you how many bytes are needed to encode this unsigned number. +func Unsigned(number uint64) int { + switch { + case number <= math.MaxUint8: + return 1 + + case number <= math.MaxUint16: + return 2 + + case number <= math.MaxUint32: + return 4 + + default: + return 8 + } +} diff --git a/src/build/sizeof/Unsigned_test.go b/src/build/sizeof/Unsigned_test.go new file mode 100644 index 0000000..e9a5dc8 --- /dev/null +++ b/src/build/sizeof/Unsigned_test.go @@ -0,0 +1,17 @@ +package sizeof_test + +import ( + "math" + "testing" + + "git.akyoto.dev/cli/q/src/build/sizeof" + "git.akyoto.dev/go/assert" +) + +func TestUnsigned(t *testing.T) { + assert.Equal(t, sizeof.Unsigned(0), 1) + assert.Equal(t, sizeof.Unsigned(math.MaxUint8), 1) + assert.Equal(t, sizeof.Unsigned(math.MaxUint16), 2) + assert.Equal(t, sizeof.Unsigned(math.MaxUint32), 4) + assert.Equal(t, sizeof.Unsigned(math.MaxUint64), 8) +}