package generator import "github.com/llir/llvm/ir" import "github.com/llir/llvm/ir/value" import "git.tebibyte.media/sashakoshka/fspl/entity" type blockManager struct { generator *generator function *ir.Func block *ir.Block declarations map[*entity.Declaration] value.Value } // TODO make it a stackkkk func (this *generator) pushBlockManager (function *ir.Func) *blockManager { manager := new(blockManager) this.managerStack = append(this.managerStack, manager) manager.generator = this manager.function = function manager.newBlock() manager.declarations = make(map[*entity.Declaration] value.Value) 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 () *ir.Block { if this.block != nil && len(this.block.Insts) == 0 { return nil } previous := this.block this.block = this.function.NewBlock("") return previous } func (this *blockManager) variable (declaration *entity.Declaration) value.Value { return this.declarations[declaration] } func (this *blockManager) addDeclaration (declaration *entity.Declaration, initial value.Value) error { ty, err := this.generator.generateType(declaration.Type()) if err != nil { return err } location := this.block.NewAlloca(ty) this.declarations[declaration] = location if initial != nil { this.block.NewStore(initial, location) } 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.Params[index]) 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.Params[0]) return true } for index, argument := range scope.Signature.Arguments { if argument.Name == declaration.Name { this.addDeclaration ( declaration, this.function.Params[index + 1]) 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 }