10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
namespace goose::builtins
{
void SetupWhileStmt( Env& e )
{
auto handleWhile = []( Parser& p, uint32_t locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
if( p.isInParenExpr() || !p.cfg() )
{
dm.emitSyntaxErrorMessage( locationId, "the while statement is not allowed here.", 0 );
return false;
}
auto pPrecBB = p.cfg()->currentBB();
if( !pPrecBB || pPrecBB->terminator() )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
locationId, "unreachable code.", 0 );
p.cfg()->poison();
}
// Create a scope for the entire while, so that any var declared
// inside of the condition is alive and visible throughout the while.
Scope s( p );
auto np = p.makeNestedParser();
if( !np.parseExpression( precedence::IfStmt ) )
{
dm.emitSyntaxErrorMessage( locationId, "expected an expression following the while statement.", 0 );
return false;
}
auto condVal = np.popValue();
if( !condVal )
{
dm.emitSyntaxErrorMessage( locationId, "expected an expression following the while statement.", 0 );
return false;
}
const auto& context = p.resolver()->context();
auto converted = ConvertValueToType( context, *condVal, GetValueType< bool >() );
if( holds_alternative< ValUnifyError >( converted ) )
{
switch( get< ValUnifyError >( converted ) )
{
// If the condition is invalid, bail out and mark the current
// diagnostics context as bust to avoid spamming cascading errors.
case ValUnifyError::NoSolution:
dm.emitSyntaxErrorMessage( condVal->locationId(), "the while condition can't be converted to a bool." );
break;
case ValUnifyError::Ambiguous:
dm.emitSyntaxErrorMessage( condVal->locationId(), "ambiguous while condition bool conversion." );
break;
}
return false;
}
if( get< Value >( converted ).isPoison() )
p.cfg()->poison();
// The condition may have emitted additional basic blocks, so get the current block again.
pPrecBB = p.cfg()->currentBB();
auto pHeaderBB = p.cfg()->createBB();
// Set the loop header's location to a span including the while keyword and the condition
pHeaderBB->setLocationId( Location::CreateSpanningLocation( locationId, condVal->locationId() ) );
Parser::BreakableScopeGuard bsg( p );
Parser::ContinuableScopeGuard csg( p );
auto pBodyBB = ParseSubStatement( p, precedence::IfStmt );
if( !pBodyBB )
{
dm.emitSyntaxErrorMessage( p.resolver()->getCurrentLocation(), "expected a statement after the while condition.", 0 );
return false;
}
if( !pPrecBB )
return true;
// Retrieve the final block of the loop body, if any
if( auto pBodySuccBB = p.cfg()->currentBB(); pBodySuccBB && !pBodySuccBB->terminator() )
{
// Jump from the end of the body BB back to the loop header
pBodySuccBB->setTerminator( llr::Branch( pHeaderBB ) );
}
// Jump unconditionally from the pred block to the loop header.
pPrecBB->setTerminator( llr::Branch( pHeaderBB ) );
auto pSuccBB = p.cfg()->createBB();
auto breakLevel = p.breakableScopeLevels();
auto continueLevel = p.continuableScopeLevels();
// Go through all basic blocks, find all break and continue terminators
// for our scope level and replace them with branches respectively to
// the successor BB or to the loop header BB.
p.cfg()->forEachBB( [&]( auto&& bb )
{
const auto& t = bb->terminator();
if( !t )
return;
if( const auto* pBreak = get_if< llr::Break >( &t->content() ) )
{
|
>
|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
namespace goose::builtins
{
void SetupWhileStmt( Env& e )
{
auto handleWhile = []( Parser& p, uint32_t locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
const auto& cb = p.context().codeBuilder();
if( p.isInParenExpr() || !cb )
{
dm.emitSyntaxErrorMessage( locationId, "the while statement is not allowed here.", 0 );
return false;
}
const auto& cfg = cb->cfg();
auto pPrecBB = cfg->currentBB();
if( !pPrecBB || pPrecBB->terminator() )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
locationId, "unreachable code.", 0 );
cfg->poison();
}
// Create a scope for the entire while, so that any var declared
// inside of the condition is alive and visible throughout the while.
Scope s( p );
auto np = p.makeNestedParser();
if( !np.parseExpression( precedence::IfStmt ) )
{
dm.emitSyntaxErrorMessage( locationId, "expected an expression following the while statement.", 0 );
return false;
}
auto condVal = np.popValue();
if( !condVal )
{
dm.emitSyntaxErrorMessage( locationId, "expected an expression following the while statement.", 0 );
return false;
}
const auto& context = p.context();
auto converted = ConvertValueToType( context, *condVal, GetValueType< bool >() );
if( holds_alternative< ValUnifyError >( converted ) )
{
switch( get< ValUnifyError >( converted ) )
{
// If the condition is invalid, bail out and mark the current
// diagnostics context as bust to avoid spamming cascading errors.
case ValUnifyError::NoSolution:
dm.emitSyntaxErrorMessage( condVal->locationId(), "the while condition can't be converted to a bool." );
break;
case ValUnifyError::Ambiguous:
dm.emitSyntaxErrorMessage( condVal->locationId(), "ambiguous while condition bool conversion." );
break;
}
return false;
}
if( get< Value >( converted ).isPoison() )
cb->poison();
// The condition may have emitted additional basic blocks, so get the current block again.
pPrecBB = cfg->currentBB();
auto pHeaderBB = cfg->createBB();
// Set the loop header's location to a span including the while keyword and the condition
pHeaderBB->setLocationId( Location::CreateSpanningLocation( locationId, condVal->locationId() ) );
CodeBuilder::BreakableScopeGuard bsg( cb );
CodeBuilder::ContinuableScopeGuard csg( cb );
auto pBodyBB = ParseSubStatement( p, precedence::IfStmt );
if( !pBodyBB )
{
dm.emitSyntaxErrorMessage( p.resolver()->currentLocation(), "expected a statement after the while condition.", 0 );
return false;
}
if( !pPrecBB )
return true;
// Retrieve the final block of the loop body, if any
if( auto pBodySuccBB = cfg->currentBB(); pBodySuccBB && !pBodySuccBB->terminator() )
{
// Jump from the end of the body BB back to the loop header
pBodySuccBB->setTerminator( llr::Branch( pHeaderBB ) );
}
// Jump unconditionally from the pred block to the loop header.
pPrecBB->setTerminator( llr::Branch( pHeaderBB ) );
auto pSuccBB = cfg->createBB();
auto breakLevel = cb->breakableScopeLevels();
auto continueLevel = cb->continuableScopeLevels();
// Go through all basic blocks, find all break and continue terminators
// for our scope level and replace them with branches respectively to
// the successor BB or to the loop header BB.
cfg->forEachBB( [&]( auto&& bb )
{
const auto& t = bb->terminator();
if( !t )
return;
if( const auto* pBreak = get_if< llr::Break >( &t->content() ) )
{
|
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
} );
// Emit the conditional branch that will either run an iteration of the loop or exit to the succ bb.
pHeaderBB->setTerminator( llr::CondBranch(
get< Value >( converted ),
pBodyBB, pSuccBB ) );
p.cfg()->setCurrentBB( pSuccBB );
return true;
};
Rule r( handleWhile );
auto ruleVal = ToValue( move( r ) );
auto ruleTerm = ValueToIRExpr( ruleVal );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( while ) ), ANYTERM( _ ), ruleTerm );
}
}
|
|
|
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
} );
// Emit the conditional branch that will either run an iteration of the loop or exit to the succ bb.
pHeaderBB->setTerminator( llr::CondBranch(
get< Value >( converted ),
pBodyBB, pSuccBB ) );
cfg->setCurrentBB( pSuccBB );
return true;
};
Rule r( handleWhile );
auto ruleVal = ToValue( move( r ) );
auto ruleTerm = ValueToIRExpr( ruleVal );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( while ) ), ANYTERM( _ ), ruleTerm );
}
}
|