Simplified file structure
This commit is contained in:
parent
cacee7260a
commit
a466281307
219 changed files with 453 additions and 457 deletions
30
src/scope/Scope.go
Normal file
30
src/scope/Scope.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package scope
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/cpu"
|
||||
)
|
||||
|
||||
// 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) {
|
||||
s.Variables = append(s.Variables, variable)
|
||||
s.Use(variable.Register)
|
||||
}
|
||||
|
||||
// VariableByName returns the variable with the given name or `nil` if it doesn't exist.
|
||||
func (s *Scope) VariableByName(name string) *Variable {
|
||||
for _, v := range s.Variables {
|
||||
if v.Name == name {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
94
src/scope/Stack.go
Normal file
94
src/scope/Stack.go
Normal file
|
@ -0,0 +1,94 @@
|
|||
package scope
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/ast"
|
||||
"git.akyoto.dev/cli/q/src/cpu"
|
||||
"git.akyoto.dev/cli/q/src/token"
|
||||
)
|
||||
|
||||
// Stack is a stack of scopes.
|
||||
type Stack struct {
|
||||
Scopes []*Scope
|
||||
}
|
||||
|
||||
// AddVariable adds a new variable to the current scope.
|
||||
func (stack *Stack) AddVariable(variable *Variable) {
|
||||
stack.CurrentScope().AddVariable(variable)
|
||||
}
|
||||
|
||||
// CurrentScope returns the current scope.
|
||||
func (stack *Stack) CurrentScope() *Scope {
|
||||
return stack.Scopes[len(stack.Scopes)-1]
|
||||
}
|
||||
|
||||
// PopScope removes the scope at the top of the stack.
|
||||
func (stack *Stack) PopScope() {
|
||||
stack.Scopes = stack.Scopes[:len(stack.Scopes)-1]
|
||||
}
|
||||
|
||||
// PushScope pushes a new scope to the top of the stack.
|
||||
func (stack *Stack) PushScope(body ast.AST, buffer []byte) *Scope {
|
||||
s := &Scope{}
|
||||
|
||||
if len(stack.Scopes) > 0 {
|
||||
lastScope := stack.Scopes[len(stack.Scopes)-1]
|
||||
s.State = lastScope.State
|
||||
s.Variables = make([]*Variable, 0, len(lastScope.Variables))
|
||||
s.InLoop = lastScope.InLoop
|
||||
|
||||
for _, v := range lastScope.Variables {
|
||||
count := ast.Count(body, buffer, token.Identifier, v.Name)
|
||||
|
||||
if count == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
s.Variables = append(s.Variables, &Variable{
|
||||
Name: v.Name,
|
||||
Register: v.Register,
|
||||
Alive: count,
|
||||
Type: v.Type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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 _, scope := range stack.Scopes {
|
||||
if scope.InLoop {
|
||||
continue
|
||||
}
|
||||
|
||||
local := scope.VariableByName(variable.Name)
|
||||
|
||||
if local == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
local.Use()
|
||||
|
||||
if !local.IsAlive() {
|
||||
scope.Free(local.Register)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VariableByName returns the variable with the given name or `nil` if it doesn't exist.
|
||||
func (stack *Stack) VariableByName(name string) *Variable {
|
||||
return stack.CurrentScope().VariableByName(name)
|
||||
}
|
||||
|
||||
// VariableByRegister returns the variable that occupies the given register or `nil` if none occupy the register.
|
||||
func (stack *Stack) VariableByRegister(register cpu.Register) *Variable {
|
||||
for _, v := range stack.CurrentScope().Variables {
|
||||
if v.Register == register {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
28
src/scope/Variable.go
Normal file
28
src/scope/Variable.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package scope
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/cpu"
|
||||
"git.akyoto.dev/cli/q/src/types"
|
||||
)
|
||||
|
||||
// Variable represents a named register.
|
||||
type Variable struct {
|
||||
Name string
|
||||
Type types.Type
|
||||
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--
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue