Generate switch statements
This commit is contained in:
parent
5dda7b2186
commit
650289f03e
|
@ -92,6 +92,13 @@ testUnit (test,
|
|||
0,
|
||||
)}
|
||||
|
||||
func TestSwitchExitCode (test *testing.T) {
|
||||
testUnit (test,
|
||||
"/test-data/data/switch-exit-code", nil,
|
||||
"", "",
|
||||
4,
|
||||
)}
|
||||
|
||||
func TestReturnAssign (test *testing.T) {
|
||||
dependencies := []string {
|
||||
compileDependency(test, "io"),
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
'624d4557-5291-4ad7-9283-7c200b9c2942'
|
||||
'4f3d6ccb-c233-4648-abd2-72e3f9a82efd'
|
||||
+ 'io'
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
'433ed4ee-be14-4d0f-baef-a13919ec3b6c'
|
|
@ -0,0 +1,10 @@
|
|||
[main]: I32 'main' = {
|
||||
x:I32 = 1
|
||||
[switch x]
|
||||
}
|
||||
|
||||
[switch x:I32]:I32 = switch x
|
||||
| 0 5
|
||||
| 1 4
|
||||
| 2 3
|
||||
* 0
|
|
@ -426,6 +426,59 @@ U: (| Int F64 UInt)
|
|||
`)
|
||||
}
|
||||
|
||||
|
||||
func TestSwitchReturn (test *testing.T) {
|
||||
testString (test,
|
||||
`%"AAAAAAAAAAAAAAAAAAAAAA==::Bool" = type i1
|
||||
define %"AAAAAAAAAAAAAAAAAAAAAA==::Bool" @"0zNZN147MN2wzMAQ6NS2dQ==::is5"(i64 %x) {
|
||||
0:
|
||||
%1 = alloca i64
|
||||
store i64 %x, ptr %1
|
||||
%2 = load i64, ptr %1
|
||||
switch i64 %2, label %3 [
|
||||
i64 5, label %4
|
||||
]
|
||||
3:
|
||||
ret i1 false
|
||||
4:
|
||||
ret i1 true
|
||||
}
|
||||
`,
|
||||
`
|
||||
[is5 x:Int]:Bool = {
|
||||
switch x | 5 [return true]
|
||||
false
|
||||
}
|
||||
`)
|
||||
}
|
||||
|
||||
func TestSwitchReturnValueUsed (test *testing.T) {
|
||||
testString (test,
|
||||
`%"AAAAAAAAAAAAAAAAAAAAAA==::Bool" = type i1
|
||||
define %"AAAAAAAAAAAAAAAAAAAAAA==::Bool" @"0zNZN147MN2wzMAQ6NS2dQ==::is5"(i64 %x) {
|
||||
0:
|
||||
%1 = alloca i64
|
||||
store i64 %x, ptr %1
|
||||
%2 = load i64, ptr %1
|
||||
switch i64 %2, label %6 [
|
||||
i64 5, label %5
|
||||
]
|
||||
3:
|
||||
%4 = phi i1 [ false, %6 ]
|
||||
ret i1 %4
|
||||
5:
|
||||
ret i1 true
|
||||
6:
|
||||
br label %3
|
||||
}
|
||||
`,
|
||||
`
|
||||
[is5 x:Int]:Bool = switch x
|
||||
| 5 [return true]
|
||||
* false
|
||||
`)
|
||||
}
|
||||
|
||||
func TestIfElseReturnValueUsed (test *testing.T) {
|
||||
testString (test,
|
||||
`%"AAAAAAAAAAAAAAAAAAAAAA==::Bool" = type i1
|
||||
|
|
|
@ -95,6 +95,8 @@ func (this *generator) generateExpressionAny (expression entity.Expression) (reg
|
|||
return this.generateIfElse(expression, resultModeAny)
|
||||
case *entity.Match:
|
||||
return this.generateMatch(expression, resultModeAny)
|
||||
case *entity.Switch:
|
||||
return this.generateSwitch(expression, resultModeAny)
|
||||
case *entity.Loop:
|
||||
return this.generateLoop(expression, resultModeAny)
|
||||
case *entity.For:
|
||||
|
@ -160,6 +162,9 @@ func (this *generator) generateExpressionVal (expression entity.Expression) (llv
|
|||
case *entity.Match:
|
||||
val, _, err := this.generateMatch(expression, resultModeVal)
|
||||
return val, err
|
||||
case *entity.Switch:
|
||||
val, _, err := this.generateSwitch(expression, resultModeVal)
|
||||
return val, err
|
||||
case *entity.Loop:
|
||||
val, _, err := this.generateLoop(expression, resultModeVal)
|
||||
return val, err
|
||||
|
@ -235,6 +240,9 @@ func (this *generator) generateExpressionLoc (expression entity.Expression) (llv
|
|||
case *entity.Match:
|
||||
loc, _, err := this.generateMatch(expression, resultModeLoc)
|
||||
return loc, err
|
||||
case *entity.Switch:
|
||||
loc, _, err := this.generateSwitch(expression, resultModeLoc)
|
||||
return loc, err
|
||||
case *entity.Loop:
|
||||
loc, _, err := this.generateLoop(expression, resultModeLoc)
|
||||
return loc, err
|
||||
|
|
|
@ -214,6 +214,88 @@ func (this *generator) generateMatch (match *entity.Match, mode resultMode) (llv
|
|||
}
|
||||
}
|
||||
|
||||
func (this *generator) generateSwitch (match *entity.Switch, mode resultMode) (llvm.Value, bool, error) {
|
||||
irValue, err := this.generateExpressionVal(match.Value)
|
||||
if err != nil { return nil, false, err }
|
||||
irValueType, err := this.generateType(match.Value.Type())
|
||||
if err != nil { return nil, false, err }
|
||||
|
||||
previousBlock := this.blockManager.Block
|
||||
exitBlock := this.blockManager.newBlock()
|
||||
|
||||
irCases := make([]*llvm.Case, len(match.Cases))
|
||||
irIncomings := []*llvm.Incoming { }
|
||||
loc := false
|
||||
first := true
|
||||
|
||||
generateCaseExpression := func (expression entity.Expression) error {
|
||||
thisMode := mode
|
||||
if !first && mode != resultModeAny {
|
||||
if loc { thisMode = resultModeLoc
|
||||
} else { thisMode = resultModeVal }
|
||||
}
|
||||
result, thisLoc, err := this.generateExpression(expression, thisMode)
|
||||
if err != nil { return err }
|
||||
if first { loc = thisLoc }
|
||||
if !this.blockManager.Terminated() {
|
||||
if expression != nil {
|
||||
irIncomings = append(irIncomings, &llvm.Incoming {
|
||||
X: result,
|
||||
Predecessor: this.blockManager.Block,
|
||||
})
|
||||
}
|
||||
this.blockManager.NewBr(exitBlock)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// generate value cases
|
||||
for index, cas := range match.Cases {
|
||||
caseBlock := this.blockManager.newBlock()
|
||||
key := match.CaseOrder[index]
|
||||
irCases[index] = &llvm.Case {
|
||||
X: llvm.NewConstInt (
|
||||
llvm.ReduceToBase(irValueType).(*llvm.TypeInt),
|
||||
key),
|
||||
Target: caseBlock,
|
||||
}
|
||||
err = generateCaseExpression(cas.Expression)
|
||||
if err != nil { return nil, false, err }
|
||||
}
|
||||
|
||||
// generate default case
|
||||
var defaultBlock llvm.Value
|
||||
if match.Default != nil {
|
||||
defaultBlock = this.blockManager.newBlock()
|
||||
err = generateCaseExpression(match.Default.Expression)
|
||||
if err != nil { return nil, false, err }
|
||||
}
|
||||
|
||||
// create switch branch
|
||||
this.blockManager.Block = previousBlock
|
||||
if defaultBlock == nil {
|
||||
this.blockManager.NewSwitch(irValue, exitBlock, irCases...)
|
||||
} else {
|
||||
this.blockManager.NewSwitch(irValue, defaultBlock, irCases...)
|
||||
}
|
||||
|
||||
// discard/obtain results
|
||||
this.blockManager.Block = exitBlock
|
||||
if mode == resultModeAny {
|
||||
return nil, false, nil
|
||||
} else {
|
||||
irType, err := this.generateType(match.Type())
|
||||
if err != nil { return nil, false, err }
|
||||
if defaultBlock == nil {
|
||||
irIncomings = append(irIncomings, &llvm.Incoming {
|
||||
X: llvm.NewConstZeroInitializer(irType),
|
||||
Predecessor: previousBlock,
|
||||
})
|
||||
}
|
||||
return this.blockManager.NewPhi(irIncomings...), loc, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (this *generator) generateLoop (loop *entity.Loop, mode resultMode) (llvm.Value, bool, error) {
|
||||
irResultType, err := this.generateType(loop.Type())
|
||||
if err != nil { return nil, false, err }
|
||||
|
|
Loading…
Reference in New Issue