Added Value type
This commit is contained in:
parent
ae6530aadb
commit
9f78733d5d
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
12
src/core/Value.go
Normal 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
|
||||||
|
}
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user