fspl/generator/blockmanager.go

233 lines
6.6 KiB
Go
Raw Normal View History

2023-11-21 20:04:22 +00:00
package generator
2023-11-26 09:02:22 +00:00
import "fmt"
import "errors"
import "git.tebibyte.media/sashakoshka/fspl/llvm"
2023-11-21 20:04:22 +00:00
import "git.tebibyte.media/sashakoshka/fspl/entity"
2023-11-26 09:02:22 +00:00
type loopEntry struct {
value llvm.Value
stub *llvm.Block
wantLocation bool
}
2023-11-21 20:04:22 +00:00
type blockManager struct {
*llvm.Block
2023-11-21 20:04:22 +00:00
generator *generator
function *llvm.Function
declarations map[*entity.Declaration] llvm.Value
2023-11-26 09:02:22 +00:00
loops []*loopEntry
2023-11-21 20:04:22 +00:00
}
func (this *blockManager) String () string {
return fmt.Sprint(this.function.Name())
}
func (this *generator) pushBlockManager (function *llvm.Function) *blockManager {
2023-11-21 20:04:22 +00:00
manager := new(blockManager)
manager.generator = this
manager.function = function
manager.newBlock()
manager.declarations = make(map[*entity.Declaration] llvm.Value)
this.managerStack = append(this.managerStack, manager)
this.blockManager = manager
2023-11-21 20:04:22 +00:00
return manager
}
func (this *generator) popBlockManager () {
this.managerStack = this.managerStack[:len(this.managerStack) - 1]
if len(this.managerStack) > 0 {
this.blockManager = this.managerStack[len(this.managerStack) - 1]
2023-11-21 20:04:22 +00:00
} else {
this.blockManager = nil
}
}
2023-11-26 09:02:22 +00:00
func (this *blockManager) pushLoop (wantLocation bool) *loopEntry {
entry := &loopEntry { wantLocation: wantLocation }
this.loops = append(this.loops, entry)
return entry
}
func (this *blockManager) popLoop () {
this.loops = this.loops[:len(this.loops) - 1]
}
func (this *blockManager) topLoop () *loopEntry {
return this.loops[len(this.loops) - 1]
}
func (this *blockManager) newAllocaFront (element llvm.Type) llvm.Value {
alloca := llvm.NewAlloca(element)
firstBlock := this.function.Blocks[0]
if firstBlock.Terminated() {
lastIndex := len(firstBlock.Instructions) - 1
firstBlock.Instructions = append (
firstBlock.Instructions,
firstBlock.Instructions[lastIndex])
firstBlock.Instructions[lastIndex] = alloca
} else {
firstBlock.AddInstruction(alloca)
}
return alloca
}
2023-11-21 20:04:22 +00:00
2023-11-26 09:02:22 +00:00
func (this *blockManager) newBlock () *llvm.Block {
this.Block = this.function.NewBlock()
return this.Block
2023-11-21 20:04:22 +00:00
}
2023-11-26 09:02:22 +00:00
func (this *blockManager) variable (declaration *entity.Declaration) (llvm.Value, error) {
value, ok := this.declarations[declaration]
if !ok {
return nil, errors.New(fmt.Sprintf("declaration of %v does not exist", declaration.Name))
}
return value, nil
2023-11-21 20:04:22 +00:00
}
func (this *blockManager) addDeclaration (declaration *entity.Declaration, initial llvm.Value) error {
2023-11-21 20:04:22 +00:00
ty, err := this.generator.generateType(declaration.Type())
if err != nil { return err }
2023-11-26 09:02:22 +00:00
location := this.newAllocaFront(ty)
2023-11-21 20:04:22 +00:00
this.declarations[declaration] = location
if initial != nil {
2023-11-26 09:02:22 +00:00
this.NewStore(initial, location)
2023-11-21 20:04:22 +00:00
}
return nil
}
func (this *blockManager) addDeclarationsInFunction (scope entity.Scoped) error {
var err error
add := func (expression entity.Statement) bool {
if expression, ok := expression.(entity.Scoped); ok {
err = this.addDeclarationsDirectlyIn(expression)
}
return err == nil
}
switch scope.(type) {
case *entity.Function:
scope := scope.(*entity.Function)
scope.OverVariables(func (declaration *entity.Declaration) bool {
for index, argument := range scope.Signature.Arguments {
if argument.Name == declaration.Name {
this.addDeclaration (
declaration,
this.function.Parameters[index])
2023-11-21 20:04:22 +00:00
return true
}
}
this.addDeclaration(declaration, nil)
return true
})
if scope.Body == nil { break }
overStatements(scope.Body, add)
case *entity.Method:
scope := scope.(*entity.Method)
scope.OverVariables(func (declaration *entity.Declaration) bool {
if declaration.Name == "this" {
this.addDeclaration (
declaration,
this.function.Parameters[0])
2023-11-21 20:04:22 +00:00
return true
}
for index, argument := range scope.Signature.Arguments {
if argument.Name == declaration.Name {
this.addDeclaration (
declaration,
this.function.Parameters[index + 1])
2023-11-21 20:04:22 +00:00
return true
}
}
this.addDeclaration(declaration, nil)
return true
})
if scope.Body == nil { break }
overStatements(scope.Body, add)
}
return err
}
func (this *blockManager) addDeclarationsDirectlyIn (scope entity.Scoped) error {
var err error
scope.OverVariables(func (declaration *entity.Declaration) bool {
err = this.addDeclaration(declaration, nil)
return err == nil
})
return err
}
// if ya nasty
func overStatements (
expression entity.Statement,
callback func(entity.Statement) bool,
) bool {
if expression == nil { return true }
if !callback(expression) { return false}
2023-11-30 07:13:47 +00:00
switch expression := expression.(type) {
2023-11-21 20:04:22 +00:00
case *entity.Call:
for _, argument := range expression.Arguments {
if !overStatements(argument, callback) { return false }
}
case *entity.MethodCall:
for _, argument := range expression.Arguments {
if !overStatements(argument, callback) { return false }
}
case *entity.Subscript:
if !overStatements(expression.Slice, callback) { return false }
if !overStatements(expression.Offset, callback) { return false }
case *entity.Slice:
if !overStatements(expression.Slice, callback) { return false }
if !overStatements(expression.Start, callback) { return false }
if !overStatements(expression.End, callback) { return false }
case *entity.Dereference:
if !overStatements(expression.Pointer, callback) { return false }
case *entity.Reference:
if !overStatements(expression.Value, callback) { return false }
2023-11-30 07:13:47 +00:00
case *entity.Length:
if !overStatements(expression.Slice, callback) { return false }
2023-11-21 20:04:22 +00:00
case *entity.ValueCast:
if !overStatements(expression.Value, callback) { return false }
case *entity.BitCast:
if !overStatements(expression.Value, callback) { return false }
case *entity.Operation:
for _, argument := range expression.Arguments {
if !overStatements(argument, callback) { return false }
}
case *entity.Block:
for _, step := range expression.Steps {
if !overStatements(step, callback) { return false }
}
case *entity.IfElse:
if !overStatements(expression.Condition, callback) { return false }
if !overStatements(expression.True, callback) { return false }
if !overStatements(expression.False, callback) { return false }
case *entity.Loop:
if !overStatements(expression.Body, callback) { return false }
case *entity.Break:
if !overStatements(expression.Value, callback) { return false }
case *entity.Return:
if !overStatements(expression.Value, callback) { return false }
case *entity.LiteralArray:
for _, element := range expression.Elements {
if !overStatements(element, callback) { return false}
}
case *entity.LiteralStruct:
for _, member := range expression.Members {
if !overStatements(member.Value, callback) { return false}
}
}
return true
}