diff --git a/src/core/CompileAssignArray.go b/src/core/CompileAssignArray.go index fff34ca..217e010 100644 --- a/src/core/CompileAssignArray.go +++ b/src/core/CompileAssignArray.go @@ -30,31 +30,31 @@ func (f *Function) CompileAssignArray(node *ast.Assign) error { Length: byte(1), } - index := left.Children[1] + indexExpr := left.Children[1] - if index.Token.IsNumeric() { - offset, err := f.ToNumber(index.Token) + if indexExpr.Token.IsNumeric() { + index, err := f.ToNumber(indexExpr.Token) if err != nil { return err } - memory.Offset = int8(offset) + memory.Offset = int8(index) } else { - typ, indexRegister, isTemporary, err := f.Evaluate(index) + index, isTemporary, err := f.Evaluate(indexExpr) if err != nil { return err } - if !types.Is(typ, types.AnyInt) { - return errors.New(&errors.TypeMismatch{Encountered: typ.Name(), Expected: types.AnyInt.Name()}, f.File, index.Token.Position) + if !types.Is(index.Type, types.AnyInt) { + return errors.New(&errors.TypeMismatch{Encountered: index.Type.Name(), Expected: types.AnyInt.Name()}, f.File, indexExpr.Token.Position) } - memory.OffsetRegister = indexRegister + memory.OffsetRegister = index.Register if isTemporary { - defer f.FreeRegister(indexRegister) + defer f.FreeRegister(index.Register) } } diff --git a/src/core/CompileAssignDivision.go b/src/core/CompileAssignDivision.go index cbca794..bf483eb 100644 --- a/src/core/CompileAssignDivision.go +++ b/src/core/CompileAssignDivision.go @@ -58,20 +58,24 @@ func (f *Function) CompileAssignDivision(expr *expression.Expression) error { defer f.UseVariable(remainderVariable) } - dividend := right.Children[0] - _, dividendRegister, isTemporary, err := f.Evaluate(dividend) + dividendExpr := right.Children[0] + dividend, isTemporary, err := f.Evaluate(dividendExpr) if err != nil { return err } + if !types.Is(dividend.Type, types.AnyInt) { + return errors.New(&errors.TypeMismatch{Encountered: dividend.Type.Name(), Expected: types.AnyInt.Name()}, f.File, dividendExpr.Token.Position) + } + divisor := right.Children[1] - err = f.Execute(right.Token, dividendRegister, divisor) + err = f.Execute(right.Token, dividend.Register, divisor) f.RegisterRegister(asm.MOVE, quotientVariable.Register, x86.RAX) f.RegisterRegister(asm.MOVE, remainderVariable.Register, x86.RDX) if isTemporary { - f.FreeRegister(dividendRegister) + f.FreeRegister(dividend.Register) } return err diff --git a/src/core/CompileFor.go b/src/core/CompileFor.go index 9f77413..d528dd7 100644 --- a/src/core/CompileFor.go +++ b/src/core/CompileFor.go @@ -4,8 +4,10 @@ import ( "git.urbach.dev/cli/q/src/asm" "git.urbach.dev/cli/q/src/ast" "git.urbach.dev/cli/q/src/cpu" + "git.urbach.dev/cli/q/src/errors" "git.urbach.dev/cli/q/src/expression" "git.urbach.dev/cli/q/src/token" + "git.urbach.dev/cli/q/src/types" ) // CompileFor compiles a for loop. @@ -66,18 +68,22 @@ func (f *Function) CompileFor(loop *ast.For) error { f.AddLabel(label) f.RegisterNumber(asm.COMPARE, counter, number) } else { - _, register, isTemporary, err := f.Evaluate(to) + value, isTemporary, err := f.Evaluate(to) if err != nil { return err } + if !types.Is(value.Type, types.AnyInt) { + return errors.New(&errors.TypeMismatch{Encountered: value.Type.Name(), Expected: types.AnyInt.Name()}, f.File, to.Token.Position) + } + if isTemporary { - defer f.FreeRegister(register) + defer f.FreeRegister(value.Register) } f.AddLabel(label) - f.RegisterRegister(asm.COMPARE, counter, register) + f.RegisterRegister(asm.COMPARE, counter, value.Register) } f.Jump(asm.JGE, labelEnd) diff --git a/src/core/CompileLen.go b/src/core/CompileLen.go index 4571c38..9eaeb40 100644 --- a/src/core/CompileLen.go +++ b/src/core/CompileLen.go @@ -13,21 +13,21 @@ var _len = Function{OutputTypes: []types.Type{types.AnyInt}} // CompileLen returns the length of a slice. func (f *Function) CompileLen(root *expression.Expression) error { - typ, register, isTemporary, err := f.Evaluate(root.Children[1]) + value, isTemporary, err := f.Evaluate(root.Children[1]) if err != nil { return err } - if !types.Is(typ, types.AnyArray) { - return errors.New(&errors.TypeMismatch{Encountered: typ.Name(), Expected: types.AnyArray.Name(), ParameterName: "array"}, f.File, root.Children[1].Token.Position) + if !types.Is(value.Type, types.AnyArray) { + return errors.New(&errors.TypeMismatch{Encountered: value.Type.Name(), Expected: types.AnyArray.Name(), ParameterName: "array"}, f.File, root.Children[1].Token.Position) } f.SaveRegister(f.CPU.Output[0]) - f.MemoryRegister(asm.LOAD, asm.Memory{Base: register, Offset: -8, OffsetRegister: math.MaxUint8, Length: 8}, f.CPU.Output[0]) + f.MemoryRegister(asm.LOAD, asm.Memory{Base: value.Register, Offset: -8, OffsetRegister: math.MaxUint8, Length: 8}, f.CPU.Output[0]) if isTemporary { - f.FreeRegister(register) + f.FreeRegister(value.Register) } return nil diff --git a/src/core/Evaluate.go b/src/core/Evaluate.go index 7189cf6..5f11a75 100644 --- a/src/core/Evaluate.go +++ b/src/core/Evaluate.go @@ -2,26 +2,24 @@ package core import ( "git.urbach.dev/cli/q/src/ast" - "git.urbach.dev/cli/q/src/cpu" "git.urbach.dev/cli/q/src/errors" "git.urbach.dev/cli/q/src/expression" "git.urbach.dev/cli/q/src/token" - "git.urbach.dev/cli/q/src/types" ) // Evaluate evaluates an expression and returns a register that contains the value of the expression. -func (f *Function) Evaluate(expr *expression.Expression) (types.Type, cpu.Register, bool, error) { +func (f *Function) Evaluate(expr *expression.Expression) (Value, bool, error) { if expr.Token.Kind == token.Identifier { name := expr.Token.Text(f.File.Bytes) variable := f.VariableByName(name) if variable == nil { - return nil, 0, false, errors.New(&errors.UnknownIdentifier{Name: name}, f.File, expr.Token.Position) + return Value{}, false, errors.New(&errors.UnknownIdentifier{Name: name}, f.File, expr.Token.Position) } if variable.Alive == 1 { f.UseVariable(variable) - return variable.Type, variable.Register, false, nil + return Value{variable.Type, variable.Register}, false, nil } } @@ -29,13 +27,13 @@ func (f *Function) Evaluate(expr *expression.Expression) (types.Type, cpu.Regist types, err := f.CompileCall(expr) if err != nil { - return nil, 0, false, err + return Value{}, false, err } - return types[0], f.CPU.Output[0], false, nil + return Value{types[0], f.CPU.Output[0]}, false, nil } tmp := f.NewRegister() typ, err := f.ExpressionToRegister(expr, tmp) - return typ, tmp, true, err + return Value{typ, tmp}, true, err } diff --git a/src/core/ExpressionToMemory.go b/src/core/ExpressionToMemory.go index 8886f6e..63ba85b 100644 --- a/src/core/ExpressionToMemory.go +++ b/src/core/ExpressionToMemory.go @@ -52,17 +52,17 @@ func (f *Function) ExpressionToMemory(node *expression.Expression, memory asm.Me } } - typ, register, isTemporary, err := f.Evaluate(node) + value, isTemporary, err := f.Evaluate(node) if err != nil { return nil, err } - f.MemoryRegister(asm.STORE, memory, register) + f.MemoryRegister(asm.STORE, memory, value.Register) if isTemporary { - f.FreeRegister(register) + f.FreeRegister(value.Register) } - return typ, err + return value.Type, err } diff --git a/src/core/Value.go b/src/core/Value.go new file mode 100644 index 0000000..28b9f81 --- /dev/null +++ b/src/core/Value.go @@ -0,0 +1,12 @@ +package core + +import ( + "git.urbach.dev/cli/q/src/cpu" + "git.urbach.dev/cli/q/src/types" +) + +// Value combines a register with its data type. +type Value struct { + Type types.Type + Register cpu.Register +} diff --git a/src/types/Is.go b/src/types/Is.go index 875df1a..4728d6a 100644 --- a/src/types/Is.go +++ b/src/types/Is.go @@ -27,8 +27,19 @@ func Is(a Type, b Type) bool { if a == AnyInt { switch b { - case Int64, Int32, Int16, Int8, UInt64, UInt32, UInt16, UInt8: + case Int64, Int32, Int16, Int8, UInt64, UInt32, UInt16, UInt8, AnyInt: return true + default: + return false + } + } + + if b == AnyInt { + switch a { + case Int64, Int32, Int16, Int8, UInt64, UInt32, UInt16, UInt8, AnyInt: + return true + default: + return false } }