Simplified variable usage

This commit is contained in:
Eduard Urbach 2024-07-22 19:10:14 +02:00
parent 504111734f
commit c027208369
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
8 changed files with 45 additions and 44 deletions

View File

@ -20,7 +20,7 @@ func (f *Function) Compare(comparison *expression.Expression) error {
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, left.Token.Position)
}
defer f.useVariable(variable)
defer f.UseVariable(variable)
return f.Execute(comparison.Token, variable.Register, right)
}

View File

@ -21,7 +21,7 @@ func (f *Function) CompileAssign(node *ast.Assign) error {
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, left.Token.Position)
}
defer f.useVariable(variable)
defer f.UseVariable(variable)
return f.Execute(operator, variable.Register, right)
}
@ -33,7 +33,7 @@ func (f *Function) CompileAssign(node *ast.Assign) error {
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, left.Children[0].Token.Position)
}
defer f.useVariable(variable)
defer f.UseVariable(variable)
index := left.Children[1]
offset, _, err := f.Number(index.Token)

View File

@ -17,7 +17,7 @@ func (f *Function) ExecuteLeaf(operation token.Token, register cpu.Register, ope
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, operand.Position)
}
defer f.useVariable(variable)
defer f.UseVariable(variable)
return f.ExecuteRegisterRegister(operation, register, variable.Register)
case token.Number, token.Rune:

View File

@ -21,7 +21,7 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error {
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, t.Position)
}
f.useVariable(variable)
f.UseVariable(variable)
f.RegisterRegister(asm.MOVE, register, variable.Register)
return nil

View File

@ -1,36 +0,0 @@
package core
import (
"git.akyoto.dev/cli/q/src/build/config"
"git.akyoto.dev/cli/q/src/build/scope"
)
func (f *Function) useVariable(variable *scope.Variable) {
for i, scope := range f.Scopes {
if scope.InLoop && variable.Scope != scope {
continue
}
local := scope.VariableByName(variable.Name)
if local == nil {
continue
}
local.Alive--
if local.Alive < 0 {
panic("incorrect number of variable use calls")
}
if local.Alive == 0 {
if config.Comments {
f.Comment("%s (%s) died in scope %d", local.Name, local.Register, i)
}
scope.Free(local.Register)
} else if config.Comments {
f.Comment("%s (%s) used in scope %d", local.Name, local.Register, i)
}
}
}

View File

@ -7,13 +7,14 @@ import (
// Scope represents an independent code block.
type Scope struct {
Variables []*Variable
Depth uint8
InLoop bool
cpu.State
}
// AddVariable adds a new variable to the current scope.
func (s *Scope) AddVariable(variable *Variable) {
variable.Scope = s
variable.Depth = s.Depth
s.Variables = append(s.Variables, variable)
s.Use(variable.Register)
}

View File

@ -40,6 +40,7 @@ func (stack *Stack) PushScope(body ast.AST, buffer []byte) *Scope {
Name: v.Name,
Register: v.Register,
Alive: count,
Depth: uint8(len(stack.Scopes)),
})
}
}
@ -47,3 +48,24 @@ func (stack *Stack) PushScope(body ast.AST, buffer []byte) *Scope {
stack.Scopes = append(stack.Scopes, s)
return s
}
// UseVariable reduces the lifetime of the variable in all scopes.
func (stack *Stack) UseVariable(variable *Variable) {
for depth, scope := range stack.Scopes {
if scope.InLoop && variable.Depth != uint8(depth) {
continue
}
local := scope.VariableByName(variable.Name)
if local == nil {
continue
}
local.Use()
if !local.IsAlive() {
scope.Free(local.Register)
}
}
}

View File

@ -6,8 +6,22 @@ import (
// Variable represents a named register.
type Variable struct {
Scope *Scope
Name string
Register cpu.Register
Alive int
Depth 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() {
v.Alive--
if v.Alive < 0 {
panic("incorrect number of variable use calls")
}
}