Simplified variable usage
This commit is contained in:
parent
504111734f
commit
c027208369
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user