Simplified Evaluate function
This commit is contained in:
parent
9f78733d5d
commit
efb3089211
@ -41,7 +41,7 @@ func (f *Function) CompileAssignArray(node *ast.Assign) error {
|
|||||||
|
|
||||||
memory.Offset = int8(index)
|
memory.Offset = int8(index)
|
||||||
} else {
|
} else {
|
||||||
index, isTemporary, err := f.Evaluate(indexExpr)
|
index, err := f.Evaluate(indexExpr)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -52,10 +52,7 @@ func (f *Function) CompileAssignArray(node *ast.Assign) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
memory.OffsetRegister = index.Register
|
memory.OffsetRegister = index.Register
|
||||||
|
defer f.FreeRegister(index.Register)
|
||||||
if isTemporary {
|
|
||||||
defer f.FreeRegister(index.Register)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := f.ExpressionToMemory(right, memory)
|
_, err := f.ExpressionToMemory(right, memory)
|
||||||
|
@ -59,7 +59,7 @@ func (f *Function) CompileAssignDivision(expr *expression.Expression) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dividendExpr := right.Children[0]
|
dividendExpr := right.Children[0]
|
||||||
dividend, isTemporary, err := f.Evaluate(dividendExpr)
|
dividend, err := f.Evaluate(dividendExpr)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -73,10 +73,6 @@ func (f *Function) CompileAssignDivision(expr *expression.Expression) error {
|
|||||||
err = f.Execute(right.Token, dividend.Register, 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)
|
||||||
|
f.FreeRegister(dividend.Register)
|
||||||
if isTemporary {
|
|
||||||
f.FreeRegister(dividend.Register)
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ 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 {
|
||||||
value, isTemporary, err := f.Evaluate(to)
|
value, err := f.Evaluate(to)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -78,12 +78,9 @@ func (f *Function) CompileFor(loop *ast.For) error {
|
|||||||
return errors.New(&errors.TypeMismatch{Encountered: value.Type.Name(), Expected: types.AnyInt.Name()}, f.File, to.Token.Position)
|
return errors.New(&errors.TypeMismatch{Encountered: value.Type.Name(), Expected: types.AnyInt.Name()}, f.File, to.Token.Position)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isTemporary {
|
|
||||||
defer f.FreeRegister(value.Register)
|
|
||||||
}
|
|
||||||
|
|
||||||
f.AddLabel(label)
|
f.AddLabel(label)
|
||||||
f.RegisterRegister(asm.COMPARE, counter, value.Register)
|
f.RegisterRegister(asm.COMPARE, counter, value.Register)
|
||||||
|
defer f.FreeRegister(value.Register)
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Jump(asm.JGE, labelEnd)
|
f.Jump(asm.JGE, labelEnd)
|
||||||
|
@ -13,7 +13,7 @@ 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 {
|
||||||
value, isTemporary, err := f.Evaluate(root.Children[1])
|
value, err := f.Evaluate(root.Children[1])
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -25,10 +25,6 @@ func (f *Function) CompileLen(root *expression.Expression) error {
|
|||||||
|
|
||||||
f.SaveRegister(f.CPU.Output[0])
|
f.SaveRegister(f.CPU.Output[0])
|
||||||
f.MemoryRegister(asm.LOAD, asm.Memory{Base: value.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])
|
||||||
|
f.FreeRegister(value.Register)
|
||||||
if isTemporary {
|
|
||||||
f.FreeRegister(value.Register)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,11 @@ func (f *Function) Define(leaf *expression.Expression) (*scope.Variable, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
variable = &scope.Variable{
|
variable = &scope.Variable{
|
||||||
Name: name,
|
Name: name,
|
||||||
Register: f.NewRegister(),
|
Value: scope.Value{
|
||||||
Alive: uses,
|
Register: f.NewRegister(),
|
||||||
|
Alive: uses,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return variable, nil
|
return variable, nil
|
||||||
|
@ -4,22 +4,23 @@ import (
|
|||||||
"git.urbach.dev/cli/q/src/ast"
|
"git.urbach.dev/cli/q/src/ast"
|
||||||
"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/scope"
|
||||||
"git.urbach.dev/cli/q/src/token"
|
"git.urbach.dev/cli/q/src/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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) (Value, bool, error) {
|
func (f *Function) Evaluate(expr *expression.Expression) (scope.Value, 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 Value{}, false, errors.New(&errors.UnknownIdentifier{Name: name}, f.File, expr.Token.Position)
|
return scope.Value{}, 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 Value{variable.Type, variable.Register}, false, nil
|
return variable.Value, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,13 +28,26 @@ func (f *Function) Evaluate(expr *expression.Expression) (Value, bool, error) {
|
|||||||
types, err := f.CompileCall(expr)
|
types, err := f.CompileCall(expr)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Value{}, false, err
|
return scope.Value{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return Value{types[0], f.CPU.Output[0]}, false, nil
|
value := scope.Value{
|
||||||
|
Type: types[0],
|
||||||
|
Register: f.CPU.Output[0],
|
||||||
|
Alive: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp := f.NewRegister()
|
tmp := f.NewRegister()
|
||||||
typ, err := f.ExpressionToRegister(expr, tmp)
|
typ, err := f.ExpressionToRegister(expr, tmp)
|
||||||
return Value{typ, tmp}, true, err
|
|
||||||
|
value := scope.Value{
|
||||||
|
Type: typ,
|
||||||
|
Register: tmp,
|
||||||
|
Alive: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
return value, err
|
||||||
}
|
}
|
||||||
|
@ -52,17 +52,13 @@ func (f *Function) ExpressionToMemory(node *expression.Expression, memory asm.Me
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
value, isTemporary, err := f.Evaluate(node)
|
value, err := f.Evaluate(node)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
f.MemoryRegister(asm.STORE, memory, value.Register)
|
f.MemoryRegister(asm.STORE, memory, value.Register)
|
||||||
|
f.FreeRegister(value.Register)
|
||||||
if isTemporary {
|
|
||||||
f.FreeRegister(value.Register)
|
|
||||||
}
|
|
||||||
|
|
||||||
return value.Type, err
|
return value.Type, err
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,12 @@ func (f *Function) ResolveTypes() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
f.AddVariable(&scope.Variable{
|
f.AddVariable(&scope.Variable{
|
||||||
Name: param.name,
|
Name: param.name,
|
||||||
Type: param.typ,
|
Value: scope.Value{
|
||||||
Register: x86.InputRegisters[i],
|
Type: param.typ,
|
||||||
Alive: uses,
|
Register: x86.InputRegisters[i],
|
||||||
|
Alive: uses,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
@ -44,10 +44,12 @@ func (stack *Stack) PushScope(body ast.AST, buffer []byte) *Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.Variables = append(s.Variables, &Variable{
|
s.Variables = append(s.Variables, &Variable{
|
||||||
Name: v.Name,
|
Name: v.Name,
|
||||||
Register: v.Register,
|
Value: Value{
|
||||||
Alive: count,
|
Register: v.Register,
|
||||||
Type: v.Type,
|
Alive: count,
|
||||||
|
Type: v.Type,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
27
src/scope/Value.go
Normal file
27
src/scope/Value.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package scope
|
||||||
|
|
||||||
|
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
|
||||||
|
Alive uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAlive returns true if the Value is still alive.
|
||||||
|
func (v *Value) IsAlive() bool {
|
||||||
|
return v.Alive > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use reduces the lifetime counter by one.
|
||||||
|
func (v *Value) Use() {
|
||||||
|
if v.Alive == 0 {
|
||||||
|
panic("incorrect number of value use calls")
|
||||||
|
}
|
||||||
|
|
||||||
|
v.Alive--
|
||||||
|
}
|
@ -1,28 +1,7 @@
|
|||||||
package scope
|
package scope
|
||||||
|
|
||||||
import (
|
// Variable is a named value.
|
||||||
"git.urbach.dev/cli/q/src/cpu"
|
|
||||||
"git.urbach.dev/cli/q/src/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Variable represents a named register.
|
|
||||||
type Variable struct {
|
type Variable struct {
|
||||||
Type types.Type
|
Value
|
||||||
Name string
|
Name string
|
||||||
Alive uint8
|
|
||||||
Register cpu.Register
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAlive returns true if the variable is still alive.
|
|
||||||
func (v *Variable) IsAlive() bool {
|
|
||||||
return v.Alive > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use reduces the lifetime counter by one.
|
|
||||||
func (v *Variable) Use() {
|
|
||||||
if v.Alive == 0 {
|
|
||||||
panic("incorrect number of variable use calls")
|
|
||||||
}
|
|
||||||
|
|
||||||
v.Alive--
|
|
||||||
}
|
}
|
||||||
|
20
tests/programs/for.q
Normal file
20
tests/programs/for.q
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
main() {
|
||||||
|
total := 0
|
||||||
|
|
||||||
|
for 0..10 {
|
||||||
|
total += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
assert total == 10
|
||||||
|
|
||||||
|
for 0..total {
|
||||||
|
total -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
assert total == 5
|
||||||
|
|
||||||
|
for i := 0..10 {
|
||||||
|
assert i >= 0
|
||||||
|
assert i < 10
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +0,0 @@
|
|||||||
main() {
|
|
||||||
x := 0
|
|
||||||
|
|
||||||
for 0..5 {
|
|
||||||
x += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
assert x == 5
|
|
||||||
|
|
||||||
for i := 0..5 {
|
|
||||||
assert i >= 0
|
|
||||||
assert i < 5
|
|
||||||
}
|
|
||||||
}
|
|
@ -60,7 +60,7 @@ var programs = []struct {
|
|||||||
{"switch", 0},
|
{"switch", 0},
|
||||||
{"loop-infinite", 0},
|
{"loop-infinite", 0},
|
||||||
{"loop-lifetime", 0},
|
{"loop-lifetime", 0},
|
||||||
{"loop-for", 0},
|
{"for", 0},
|
||||||
{"memory-free", 0},
|
{"memory-free", 0},
|
||||||
{"out-of-memory", 0},
|
{"out-of-memory", 0},
|
||||||
{"index-static", 0},
|
{"index-static", 0},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user