q/src/build/core/Scope.go

66 lines
1.3 KiB
Go

package core
import (
"git.akyoto.dev/cli/q/src/build/ast"
"git.akyoto.dev/cli/q/src/build/config"
"git.akyoto.dev/cli/q/src/build/cpu"
"git.akyoto.dev/cli/q/src/build/token"
)
// Scope represents an independent code block.
type Scope struct {
variables map[string]*Variable
inLoop bool
cpu.State
}
// Scope returns the current scope.
func (s *state) Scope() *Scope {
return s.scopes[len(s.scopes)-1]
}
// pushScope pushes a new scope to the top of the stack.
func (f *Function) pushScope(body ast.AST) *Scope {
scope := &Scope{}
if len(f.scopes) > 0 {
lastScope := f.scopes[len(f.scopes)-1]
scope.State = lastScope.State
scope.variables = make(map[string]*Variable, len(lastScope.variables))
scope.inLoop = lastScope.inLoop
for k, v := range lastScope.variables {
count := ast.Count(body, token.Identifier, v.Name)
if count == 0 {
continue
}
scope.variables[k] = &Variable{
Name: v.Name,
Register: v.Register,
Alive: count,
}
}
} else {
scope.variables = map[string]*Variable{}
}
f.scopes = append(f.scopes, scope)
if config.Comments {
f.Comment("scope %d start", len(f.scopes))
}
return scope
}
// popScope removes the scope at the top of the stack.
func (f *Function) popScope() {
if config.Comments {
f.Comment("scope %d end", len(f.scopes))
}
f.scopes = f.scopes[:len(f.scopes)-1]
}