Refactored code structure
This commit is contained in:
parent
9e52e2dd1c
commit
fd6e874b44
54 changed files with 583 additions and 450 deletions
|
@ -1,126 +0,0 @@
|
|||
package build
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/build/ast"
|
||||
"git.akyoto.dev/cli/q/src/build/config"
|
||||
"git.akyoto.dev/cli/q/src/build/expression"
|
||||
"git.akyoto.dev/cli/q/src/build/token"
|
||||
"git.akyoto.dev/cli/q/src/errors"
|
||||
)
|
||||
|
||||
// CompileVariableDefinition compiles a variable definition.
|
||||
func (f *Function) CompileVariableDefinition(node *ast.Define) error {
|
||||
name := node.Name.Text()
|
||||
|
||||
if f.identifierExists(name) {
|
||||
return errors.New(&errors.VariableAlreadyExists{Name: name}, f.File, node.Name.Position)
|
||||
}
|
||||
|
||||
uses := countIdentifier(f.Body, name) - 1
|
||||
|
||||
if uses == 0 {
|
||||
return errors.New(&errors.UnusedVariable{Name: name}, f.File, node.Name.Position)
|
||||
}
|
||||
|
||||
value := node.Value
|
||||
|
||||
err := value.EachLeaf(func(leaf *expression.Expression) error {
|
||||
if leaf.Token.Kind == token.Identifier && !f.identifierExists(leaf.Token.Text()) {
|
||||
return errors.New(&errors.UnknownIdentifier{Name: leaf.Token.Text()}, f.File, leaf.Token.Position)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if uses == 1 {
|
||||
f.definitions[name] = &Definition{
|
||||
Name: name,
|
||||
Value: value,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return f.storeVariableInRegister(name, value, uses)
|
||||
}
|
||||
|
||||
func (f *Function) addVariable(variable *Variable) {
|
||||
if config.Verbose {
|
||||
f.Logf("%s occupies %s (alive: %d)", variable.Name, variable.Register, variable.Alive)
|
||||
}
|
||||
|
||||
f.variables[variable.Name] = variable
|
||||
f.cpu.Use(variable.Register)
|
||||
}
|
||||
|
||||
func (f *Function) useVariable(variable *Variable) {
|
||||
variable.Alive--
|
||||
|
||||
if config.Verbose {
|
||||
f.Logf("%s occupying %s was used (alive: %d)", variable.Name, variable.Register, variable.Alive)
|
||||
}
|
||||
|
||||
if variable.Alive < 0 {
|
||||
panic("incorrect number of variable use calls")
|
||||
}
|
||||
|
||||
if variable.Alive == 0 {
|
||||
if config.Verbose {
|
||||
f.Logf("%s is no longer used, free register: %s", variable.Name, variable.Register)
|
||||
}
|
||||
|
||||
f.cpu.Free(variable.Register)
|
||||
}
|
||||
}
|
||||
|
||||
// identifierExists returns true if the identifier has been defined.
|
||||
func (f *Function) identifierExists(name string) bool {
|
||||
_, exists := f.variables[name]
|
||||
|
||||
if exists {
|
||||
return true
|
||||
}
|
||||
|
||||
_, exists = f.definitions[name]
|
||||
|
||||
if exists {
|
||||
return true
|
||||
}
|
||||
|
||||
_, exists = f.functions[name]
|
||||
return exists
|
||||
}
|
||||
|
||||
func (f *Function) storeVariableInRegister(name string, value *expression.Expression, uses int) error {
|
||||
reg, exists := f.cpu.FindFree(f.cpu.General)
|
||||
|
||||
if !exists {
|
||||
panic("no free registers")
|
||||
}
|
||||
|
||||
err := f.ExpressionToRegister(value, reg)
|
||||
|
||||
f.addVariable(&Variable{
|
||||
Name: name,
|
||||
Register: reg,
|
||||
Alive: uses,
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func countIdentifier(tokens token.List, name string) int {
|
||||
count := 0
|
||||
|
||||
for _, t := range tokens {
|
||||
if t.Kind == token.Identifier && t.Text() == name {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue