2023-11-21 20:04:22 +00:00
|
|
|
package generator
|
|
|
|
|
2023-11-26 09:02:22 +00:00
|
|
|
import "fmt"
|
|
|
|
import "errors"
|
2023-11-23 01:37:37 +00:00
|
|
|
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 {
|
2023-11-23 01:37:37 +00:00
|
|
|
*llvm.Block
|
2023-11-21 20:04:22 +00:00
|
|
|
generator *generator
|
2023-11-23 01:37:37 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2023-11-23 01:37:37 +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()
|
2023-11-23 01:37:37 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2023-11-23 01:37:37 +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,
|
2023-11-23 01:37:37 +00:00
|
|
|
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,
|
2023-11-23 01:37:37 +00:00
|
|
|
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,
|
2023-11-23 01:37:37 +00:00
|
|
|
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
|
|
|
|
}
|