118 lines
3.5 KiB
Go
118 lines
3.5 KiB
Go
package generator
|
|
|
|
// import "fmt"
|
|
import "git.tebibyte.media/fspl/fspl/llvm"
|
|
import "git.tebibyte.media/fspl/fspl/entity"
|
|
// import "git.tebibyte.media/fspl/fspl/analyzer"
|
|
|
|
func (this *generator) generateBlock (block *entity.Block, mode resultMode) (llvm.Value, bool, error) {
|
|
if len(block.Steps) == 0 { return nil, false, nil }
|
|
|
|
lastIndex := len(block.Steps) - 1
|
|
for _, step := range block.Steps[:lastIndex] {
|
|
_, _, err := this.generateExpressionAny(step)
|
|
if err != nil { return nil, false, err }
|
|
}
|
|
|
|
return this.generateExpression(block.Steps[lastIndex], mode)
|
|
}
|
|
|
|
func (this *generator) generateBreak (brk *entity.Break) (llvm.Value, error) {
|
|
loopEntry := this.blockManager.topLoop()
|
|
if brk.Value != nil {
|
|
value, loc, err := this.generateExpression(brk.Value, loopEntry.mode)
|
|
if err != nil { return nil, err }
|
|
loopEntry.value = value
|
|
loopEntry.loc = loc
|
|
}
|
|
|
|
loopEntry.stub = this.blockManager.Block
|
|
return nil, nil
|
|
}
|
|
|
|
func (this *generator) generateReturn (ret *entity.Return) (llvm.Value, error) {
|
|
if ret.Value == nil {
|
|
this.blockManager.NewRet(nil)
|
|
} else {
|
|
value, err := this.generateExpressionVal(ret.Value)
|
|
if err != nil { return nil, err }
|
|
this.blockManager.NewRet(value)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (this *generator) generateIfElse (ifelse *entity.IfElse, mode resultMode) (llvm.Value, bool, error) {
|
|
condition, err := this.generateExpressionVal(ifelse.Condition)
|
|
if err != nil { return nil, false, err }
|
|
previous := this.blockManager.Block
|
|
|
|
var trueBlock, falseBlock *llvm.Block
|
|
var tru, fals llvm.Value
|
|
var loc bool
|
|
|
|
trueBlock = this.blockManager.newBlock()
|
|
exitBlock := this.blockManager.newBlock()
|
|
this.blockManager.Block = trueBlock
|
|
|
|
tru, loc, err = this.generateExpression(ifelse.True, mode)
|
|
if err != nil { return nil, false, err }
|
|
if !this.blockManager.Terminated() { this.blockManager.NewBr(exitBlock) }
|
|
|
|
if ifelse.False == nil {
|
|
// there is no false case
|
|
previous.NewCondBr(condition, trueBlock, exitBlock)
|
|
this.blockManager.Block = exitBlock
|
|
return nil, loc, nil
|
|
} else {
|
|
// there is a false case
|
|
falseBlock = this.blockManager.newBlock()
|
|
fals, _, err = this.generateExpression(ifelse.False, mode)
|
|
if err != nil { return nil, false, err }
|
|
if !this.blockManager.Terminated() { this.blockManager.NewBr(exitBlock) }
|
|
|
|
if mode == resultModeAny {
|
|
// discard results of statements
|
|
previous.NewCondBr(condition, trueBlock, falseBlock)
|
|
this.blockManager.Block = exitBlock
|
|
return nil, false, nil
|
|
} else {
|
|
// obtain results of statements
|
|
// set up phi to capture results
|
|
trueIncoming := &llvm.Incoming {
|
|
X: tru,
|
|
Predecessor: trueBlock,
|
|
}
|
|
falseIncoming := &llvm.Incoming {
|
|
X: fals,
|
|
Predecessor: falseBlock,
|
|
}
|
|
|
|
previous.NewCondBr(condition, trueBlock, falseBlock)
|
|
this.blockManager.Block = exitBlock
|
|
return this.blockManager.NewPhi(trueIncoming, falseIncoming), loc, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
func (this *generator) generateLoop (loop *entity.Loop, mode resultMode) (llvm.Value, bool, error) {
|
|
previous := this.blockManager.Block
|
|
body := this.blockManager.newBlock()
|
|
previous.NewBr(body)
|
|
|
|
loopEntry := this.blockManager.pushLoop(mode)
|
|
defer this.blockManager.popLoop()
|
|
|
|
_, _, err := this.generateExpressionAny(loop.Body)
|
|
if err != nil { return nil, false, err }
|
|
|
|
this.blockManager.NewBr(body)
|
|
exit := this.blockManager.newBlock()
|
|
|
|
if loopEntry.stub != nil {
|
|
loopEntry.stub.SetTerminator(&llvm.TerminatorBr {
|
|
Target: exit,
|
|
})
|
|
}
|
|
return loopEntry.value, loopEntry.loc, nil
|
|
}
|