fspl/generator/blockmanager.go

201 lines
6.1 KiB
Go
Raw Normal View History

2023-11-21 20:04:22 +00:00
package generator
import "git.tebibyte.media/sashakoshka/fspl/llvm"
2023-11-21 20:04:22 +00:00
import "git.tebibyte.media/sashakoshka/fspl/entity"
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-21 20:04:22 +00:00
}
func (this *generator) pushBlockManager (function *llvm.Function) *blockManager {
2023-11-21 20:04:22 +00:00
manager := new(blockManager)
this.managerStack = append(this.managerStack, manager)
manager.generator = this
manager.function = function
manager.newBlock()
manager.declarations = make(map[*entity.Declaration] llvm.Value)
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[0]
} else {
this.blockManager = nil
}
}
func (this *blockManager) newBlock () *llvm.Block {
if this.Block != nil && len(this.Block.Instructions) == 0 { return nil }
2023-11-21 20:04:22 +00:00
previous := this.Block
this.Block = this.function.NewBlock("")
2023-11-21 20:04:22 +00:00
return previous
}
func (this *blockManager) variable (declaration *entity.Declaration) llvm.Value {
2023-11-21 20:04:22 +00:00
return this.declarations[declaration]
}
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 }
location := this.Block.NewAlloca(ty)
2023-11-21 20:04:22 +00:00
this.declarations[declaration] = location
if initial != nil {
this.Block.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}
switch expression.(type) {
case *entity.Call:
expression := expression.(*entity.Call)
for _, argument := range expression.Arguments {
if !overStatements(argument, callback) { return false }
}
case *entity.MethodCall:
expression := expression.(*entity.MethodCall)
for _, argument := range expression.Arguments {
if !overStatements(argument, callback) { return false }
}
case *entity.Subscript:
expression := expression.(*entity.Subscript)
if !overStatements(expression.Slice, callback) { return false }
if !overStatements(expression.Offset, callback) { return false }
case *entity.Slice:
expression := expression.(*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:
expression := expression.(*entity.Dereference)
if !overStatements(expression.Pointer, callback) { return false }
case *entity.Reference:
expression := expression.(*entity.Reference)
if !overStatements(expression.Value, callback) { return false }
case *entity.ValueCast:
expression := expression.(*entity.ValueCast)
if !overStatements(expression.Value, callback) { return false }
case *entity.BitCast:
expression := expression.(*entity.BitCast)
if !overStatements(expression.Value, callback) { return false }
case *entity.Operation:
expression := expression.(*entity.Operation)
for _, argument := range expression.Arguments {
if !overStatements(argument, callback) { return false }
}
case *entity.Block:
expression := expression.(*entity.Block)
for _, step := range expression.Steps {
if !overStatements(step, callback) { return false }
}
case *entity.IfElse:
expression := expression.(*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:
expression := expression.(*entity.Loop)
if !overStatements(expression.Body, callback) { return false }
case *entity.Break:
expression := expression.(*entity.Break)
if !overStatements(expression.Value, callback) { return false }
case *entity.Return:
expression := expression.(*entity.Return)
if !overStatements(expression.Value, callback) { return false }
case *entity.LiteralArray:
expression := expression.(*entity.LiteralArray)
for _, element := range expression.Elements {
if !overStatements(element, callback) { return false}
}
case *entity.LiteralStruct:
expression := expression.(*entity.LiteralStruct)
for _, member := range expression.Members {
if !overStatements(member.Value, callback) { return false}
}
}
return true
}