Added Value type

This commit is contained in:
Eduard Urbach 2025-02-27 14:16:25 +01:00
parent ae6530aadb
commit 9f78733d5d
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
8 changed files with 65 additions and 34 deletions

View File

@ -30,31 +30,31 @@ func (f *Function) CompileAssignArray(node *ast.Assign) error {
Length: byte(1), Length: byte(1),
} }
index := left.Children[1] indexExpr := left.Children[1]
if index.Token.IsNumeric() { if indexExpr.Token.IsNumeric() {
offset, err := f.ToNumber(index.Token) index, err := f.ToNumber(indexExpr.Token)
if err != nil { if err != nil {
return err return err
} }
memory.Offset = int8(offset) memory.Offset = int8(index)
} else { } else {
typ, indexRegister, isTemporary, err := f.Evaluate(index) index, isTemporary, err := f.Evaluate(indexExpr)
if err != nil { if err != nil {
return err return err
} }
if !types.Is(typ, types.AnyInt) { if !types.Is(index.Type, types.AnyInt) {
return errors.New(&errors.TypeMismatch{Encountered: typ.Name(), Expected: types.AnyInt.Name()}, f.File, index.Token.Position) 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 { if isTemporary {
defer f.FreeRegister(indexRegister) defer f.FreeRegister(index.Register)
} }
} }

View File

@ -58,20 +58,24 @@ func (f *Function) CompileAssignDivision(expr *expression.Expression) error {
defer f.UseVariable(remainderVariable) defer f.UseVariable(remainderVariable)
} }
dividend := right.Children[0] dividendExpr := right.Children[0]
_, dividendRegister, isTemporary, err := f.Evaluate(dividend) dividend, isTemporary, err := f.Evaluate(dividendExpr)
if err != nil { if err != nil {
return err 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] 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, quotientVariable.Register, x86.RAX)
f.RegisterRegister(asm.MOVE, remainderVariable.Register, x86.RDX) f.RegisterRegister(asm.MOVE, remainderVariable.Register, x86.RDX)
if isTemporary { if isTemporary {
f.FreeRegister(dividendRegister) f.FreeRegister(dividend.Register)
} }
return err return err

View File

@ -4,8 +4,10 @@ import (
"git.urbach.dev/cli/q/src/asm" "git.urbach.dev/cli/q/src/asm"
"git.urbach.dev/cli/q/src/ast" "git.urbach.dev/cli/q/src/ast"
"git.urbach.dev/cli/q/src/cpu" "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/expression"
"git.urbach.dev/cli/q/src/token" "git.urbach.dev/cli/q/src/token"
"git.urbach.dev/cli/q/src/types"
) )
// CompileFor compiles a for loop. // CompileFor compiles a for loop.
@ -66,18 +68,22 @@ func (f *Function) CompileFor(loop *ast.For) error {
f.AddLabel(label) f.AddLabel(label)
f.RegisterNumber(asm.COMPARE, counter, number) f.RegisterNumber(asm.COMPARE, counter, number)
} else { } else {
_, register, isTemporary, err := f.Evaluate(to) value, isTemporary, err := f.Evaluate(to)
if err != nil { if err != nil {
return err 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 { if isTemporary {
defer f.FreeRegister(register) defer f.FreeRegister(value.Register)
} }
f.AddLabel(label) f.AddLabel(label)
f.RegisterRegister(asm.COMPARE, counter, register) f.RegisterRegister(asm.COMPARE, counter, value.Register)
} }
f.Jump(asm.JGE, labelEnd) f.Jump(asm.JGE, labelEnd)

View File

@ -13,21 +13,21 @@ var _len = Function{OutputTypes: []types.Type{types.AnyInt}}
// CompileLen returns the length of a slice. // CompileLen returns the length of a slice.
func (f *Function) CompileLen(root *expression.Expression) error { 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 { if err != nil {
return err return err
} }
if !types.Is(typ, types.AnyArray) { if !types.Is(value.Type, types.AnyArray) {
return errors.New(&errors.TypeMismatch{Encountered: typ.Name(), Expected: types.AnyArray.Name(), ParameterName: "array"}, f.File, root.Children[1].Token.Position) 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.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 { if isTemporary {
f.FreeRegister(register) f.FreeRegister(value.Register)
} }
return nil return nil

View File

@ -2,26 +2,24 @@ package core
import ( import (
"git.urbach.dev/cli/q/src/ast" "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/errors"
"git.urbach.dev/cli/q/src/expression" "git.urbach.dev/cli/q/src/expression"
"git.urbach.dev/cli/q/src/token" "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. // 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 { if expr.Token.Kind == token.Identifier {
name := expr.Token.Text(f.File.Bytes) name := expr.Token.Text(f.File.Bytes)
variable := f.VariableByName(name) variable := f.VariableByName(name)
if variable == nil { 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 { if variable.Alive == 1 {
f.UseVariable(variable) 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) types, err := f.CompileCall(expr)
if err != nil { 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() tmp := f.NewRegister()
typ, err := f.ExpressionToRegister(expr, tmp) typ, err := f.ExpressionToRegister(expr, tmp)
return typ, tmp, true, err return Value{typ, tmp}, true, err
} }

View File

@ -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 { if err != nil {
return nil, err return nil, err
} }
f.MemoryRegister(asm.STORE, memory, register) f.MemoryRegister(asm.STORE, memory, value.Register)
if isTemporary { if isTemporary {
f.FreeRegister(register) f.FreeRegister(value.Register)
} }
return typ, err return value.Type, err
} }

12
src/core/Value.go Normal file
View File

@ -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
}

View File

@ -27,8 +27,19 @@ func Is(a Type, b Type) bool {
if a == AnyInt { if a == AnyInt {
switch b { switch b {
case Int64, Int32, Int16, Int8, UInt64, UInt32, UInt16, UInt8: case Int64, Int32, Int16, Int8, UInt64, UInt32, UInt16, UInt8, AnyInt:
return true 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
} }
} }