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)
|
||||
} else {
|
||||
index, isTemporary, err := f.Evaluate(indexExpr)
|
||||
index, err := f.Evaluate(indexExpr)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@ -52,11 +52,8 @@ func (f *Function) CompileAssignArray(node *ast.Assign) error {
|
||||
}
|
||||
|
||||
memory.OffsetRegister = index.Register
|
||||
|
||||
if isTemporary {
|
||||
defer f.FreeRegister(index.Register)
|
||||
}
|
||||
}
|
||||
|
||||
_, err := f.ExpressionToMemory(right, memory)
|
||||
return err
|
||||
|
@ -59,7 +59,7 @@ func (f *Function) CompileAssignDivision(expr *expression.Expression) error {
|
||||
}
|
||||
|
||||
dividendExpr := right.Children[0]
|
||||
dividend, isTemporary, err := f.Evaluate(dividendExpr)
|
||||
dividend, err := f.Evaluate(dividendExpr)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@ -73,10 +73,6 @@ func (f *Function) CompileAssignDivision(expr *expression.Expression) error {
|
||||
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(dividend.Register)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ func (f *Function) CompileFor(loop *ast.For) error {
|
||||
f.AddLabel(label)
|
||||
f.RegisterNumber(asm.COMPARE, counter, number)
|
||||
} else {
|
||||
value, isTemporary, err := f.Evaluate(to)
|
||||
value, err := f.Evaluate(to)
|
||||
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
if isTemporary {
|
||||
defer f.FreeRegister(value.Register)
|
||||
}
|
||||
|
||||
f.AddLabel(label)
|
||||
f.RegisterRegister(asm.COMPARE, counter, value.Register)
|
||||
defer f.FreeRegister(value.Register)
|
||||
}
|
||||
|
||||
f.Jump(asm.JGE, labelEnd)
|
||||
|
@ -13,7 +13,7 @@ var _len = Function{OutputTypes: []types.Type{types.AnyInt}}
|
||||
|
||||
// CompileLen returns the length of a slice.
|
||||
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 {
|
||||
return err
|
||||
@ -25,10 +25,6 @@ func (f *Function) CompileLen(root *expression.Expression) error {
|
||||
|
||||
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])
|
||||
|
||||
if isTemporary {
|
||||
f.FreeRegister(value.Register)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -24,8 +24,10 @@ func (f *Function) Define(leaf *expression.Expression) (*scope.Variable, error)
|
||||
|
||||
variable = &scope.Variable{
|
||||
Name: name,
|
||||
Value: scope.Value{
|
||||
Register: f.NewRegister(),
|
||||
Alive: uses,
|
||||
},
|
||||
}
|
||||
|
||||
return variable, nil
|
||||
|
@ -4,22 +4,23 @@ import (
|
||||
"git.urbach.dev/cli/q/src/ast"
|
||||
"git.urbach.dev/cli/q/src/errors"
|
||||
"git.urbach.dev/cli/q/src/expression"
|
||||
"git.urbach.dev/cli/q/src/scope"
|
||||
"git.urbach.dev/cli/q/src/token"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
name := expr.Token.Text(f.File.Bytes)
|
||||
variable := f.VariableByName(name)
|
||||
|
||||
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 {
|
||||
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)
|
||||
|
||||
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()
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
f.MemoryRegister(asm.STORE, memory, value.Register)
|
||||
|
||||
if isTemporary {
|
||||
f.FreeRegister(value.Register)
|
||||
}
|
||||
|
||||
return value.Type, err
|
||||
}
|
||||
|
@ -31,9 +31,11 @@ func (f *Function) ResolveTypes() error {
|
||||
|
||||
f.AddVariable(&scope.Variable{
|
||||
Name: param.name,
|
||||
Value: scope.Value{
|
||||
Type: param.typ,
|
||||
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
|
||||
}
|
@ -45,9 +45,11 @@ func (stack *Stack) PushScope(body ast.AST, buffer []byte) *Scope {
|
||||
|
||||
s.Variables = append(s.Variables, &Variable{
|
||||
Name: v.Name,
|
||||
Value: Value{
|
||||
Register: v.Register,
|
||||
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
|
||||
|
||||
import (
|
||||
"git.urbach.dev/cli/q/src/cpu"
|
||||
"git.urbach.dev/cli/q/src/types"
|
||||
)
|
||||
|
||||
// Variable represents a named register.
|
||||
// Variable is a named value.
|
||||
type Variable struct {
|
||||
Type types.Type
|
||||
Value
|
||||
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},
|
||||
{"loop-infinite", 0},
|
||||
{"loop-lifetime", 0},
|
||||
{"loop-for", 0},
|
||||
{"for", 0},
|
||||
{"memory-free", 0},
|
||||
{"out-of-memory", 0},
|
||||
{"index-static", 0},
|
||||
|
Loading…
x
Reference in New Issue
Block a user