From efb3089211a7f7e54e005943443efb310c2c824a Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Thu, 27 Feb 2025 15:30:44 +0100 Subject: [PATCH] Simplified Evaluate function --- src/core/CompileAssignArray.go | 7 ++----- src/core/CompileAssignDivision.go | 8 ++------ src/core/CompileFor.go | 7 ++----- src/core/CompileLen.go | 8 ++------ src/core/Define.go | 8 +++++--- src/core/Evaluate.go | 26 ++++++++++++++++++++------ src/core/ExpressionToMemory.go | 8 ++------ src/core/ResolveTypes.go | 10 ++++++---- src/core/Value.go | 12 ------------ src/scope/Stack.go | 10 ++++++---- src/scope/Value.go | 27 +++++++++++++++++++++++++++ src/scope/Variable.go | 27 +++------------------------ tests/programs/for.q | 20 ++++++++++++++++++++ tests/programs/loop-for.q | 14 -------------- tests/programs_test.go | 2 +- 15 files changed, 98 insertions(+), 96 deletions(-) delete mode 100644 src/core/Value.go create mode 100644 src/scope/Value.go create mode 100644 tests/programs/for.q delete mode 100644 tests/programs/loop-for.q diff --git a/src/core/CompileAssignArray.go b/src/core/CompileAssignArray.go index 217e010..ab379e4 100644 --- a/src/core/CompileAssignArray.go +++ b/src/core/CompileAssignArray.go @@ -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,10 +52,7 @@ func (f *Function) CompileAssignArray(node *ast.Assign) error { } memory.OffsetRegister = index.Register - - if isTemporary { - defer f.FreeRegister(index.Register) - } + defer f.FreeRegister(index.Register) } _, err := f.ExpressionToMemory(right, memory) diff --git a/src/core/CompileAssignDivision.go b/src/core/CompileAssignDivision.go index bf483eb..619e19b 100644 --- a/src/core/CompileAssignDivision.go +++ b/src/core/CompileAssignDivision.go @@ -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) - } - + f.FreeRegister(dividend.Register) return err } diff --git a/src/core/CompileFor.go b/src/core/CompileFor.go index d528dd7..98a63d9 100644 --- a/src/core/CompileFor.go +++ b/src/core/CompileFor.go @@ -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) diff --git a/src/core/CompileLen.go b/src/core/CompileLen.go index 9eaeb40..076bcc1 100644 --- a/src/core/CompileLen.go +++ b/src/core/CompileLen.go @@ -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) - } - + f.FreeRegister(value.Register) return nil } diff --git a/src/core/Define.go b/src/core/Define.go index eacd340..d56208d 100644 --- a/src/core/Define.go +++ b/src/core/Define.go @@ -23,9 +23,11 @@ func (f *Function) Define(leaf *expression.Expression) (*scope.Variable, error) } variable = &scope.Variable{ - Name: name, - Register: f.NewRegister(), - Alive: uses, + Name: name, + Value: scope.Value{ + Register: f.NewRegister(), + Alive: uses, + }, } return variable, nil diff --git a/src/core/Evaluate.go b/src/core/Evaluate.go index 5f11a75..44adb18 100644 --- a/src/core/Evaluate.go +++ b/src/core/Evaluate.go @@ -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 } diff --git a/src/core/ExpressionToMemory.go b/src/core/ExpressionToMemory.go index 63ba85b..d807371 100644 --- a/src/core/ExpressionToMemory.go +++ b/src/core/ExpressionToMemory.go @@ -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) - } - + f.FreeRegister(value.Register) return value.Type, err } diff --git a/src/core/ResolveTypes.go b/src/core/ResolveTypes.go index 42382fb..cf17430 100644 --- a/src/core/ResolveTypes.go +++ b/src/core/ResolveTypes.go @@ -30,10 +30,12 @@ func (f *Function) ResolveTypes() error { } f.AddVariable(&scope.Variable{ - Name: param.name, - Type: param.typ, - Register: x86.InputRegisters[i], - Alive: uses, + Name: param.name, + Value: scope.Value{ + Type: param.typ, + Register: x86.InputRegisters[i], + Alive: uses, + }, }) } diff --git a/src/core/Value.go b/src/core/Value.go deleted file mode 100644 index 28b9f81..0000000 --- a/src/core/Value.go +++ /dev/null @@ -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 -} diff --git a/src/scope/Stack.go b/src/scope/Stack.go index 16a2e62..5037f45 100644 --- a/src/scope/Stack.go +++ b/src/scope/Stack.go @@ -44,10 +44,12 @@ func (stack *Stack) PushScope(body ast.AST, buffer []byte) *Scope { } s.Variables = append(s.Variables, &Variable{ - Name: v.Name, - Register: v.Register, - Alive: count, - Type: v.Type, + Name: v.Name, + Value: Value{ + Register: v.Register, + Alive: count, + Type: v.Type, + }, }) } } diff --git a/src/scope/Value.go b/src/scope/Value.go new file mode 100644 index 0000000..93a3774 --- /dev/null +++ b/src/scope/Value.go @@ -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-- +} diff --git a/src/scope/Variable.go b/src/scope/Variable.go index 79962f6..4a387ae 100644 --- a/src/scope/Variable.go +++ b/src/scope/Variable.go @@ -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 - 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-- + Value + Name string } diff --git a/tests/programs/for.q b/tests/programs/for.q new file mode 100644 index 0000000..e41e08f --- /dev/null +++ b/tests/programs/for.q @@ -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 + } +} \ No newline at end of file diff --git a/tests/programs/loop-for.q b/tests/programs/loop-for.q deleted file mode 100644 index cc85bac..0000000 --- a/tests/programs/loop-for.q +++ /dev/null @@ -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 - } -} \ No newline at end of file diff --git a/tests/programs_test.go b/tests/programs_test.go index 2f15d5f..3979fc9 100644 --- a/tests/programs_test.go +++ b/tests/programs_test.go @@ -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},