21
21
import java .util .Arrays ;
22
22
import java .util .List ;
23
23
import java .util .Map ;
24
+ import java .util .stream .Collectors ;
24
25
import software .amazon .awssdk .awscore .endpoints .AwsEndpointAttribute ;
25
26
import software .amazon .awssdk .awscore .endpoints .authscheme .SigV4AuthScheme ;
26
27
import software .amazon .awssdk .awscore .endpoints .authscheme .SigV4aAuthScheme ;
@@ -32,14 +33,17 @@ public class CodeGeneratorVisitor extends WalkRuleExpressionVisitor {
32
33
private final RuleRuntimeTypeMirror typeMirror ;
33
34
private final SymbolTable symbolTable ;
34
35
private final Map <String , KeyTypePair > knownEndpointAttributes ;
36
+ private final Map <String , ComputeScopeTree .Scope > ruleIdToScope ;
35
37
36
38
public CodeGeneratorVisitor (RuleRuntimeTypeMirror typeMirror ,
37
39
SymbolTable symbolTable ,
38
40
Map <String , KeyTypePair > knownEndpointAttributes ,
41
+ Map <String , ComputeScopeTree .Scope > ruleIdToScope ,
39
42
CodeBlock .Builder builder ) {
40
43
this .builder = builder ;
41
44
this .symbolTable = symbolTable ;
42
45
this .knownEndpointAttributes = knownEndpointAttributes ;
46
+ this .ruleIdToScope = ruleIdToScope ;
43
47
this .typeMirror = typeMirror ;
44
48
}
45
49
@@ -196,28 +200,14 @@ public Void visitRuleSetExpression(RuleSetExpression e) {
196
200
197
201
@ Override
198
202
public Void visitLetExpression (LetExpression expr ) {
199
- for (String key : expr .bindings ().keySet ()) {
200
- RuleType type = symbolTable .locals ().get (key );
201
- builder .addStatement ("$T $L = null" , type .javaType (), key );
202
- }
203
-
204
- int count = 0 ;
205
203
for (Map .Entry <String , RuleExpression > kvp : expr .bindings ().entrySet ()) {
206
204
String k = kvp .getKey ();
207
205
RuleExpression v = kvp .getValue ();
208
- builder . add ( "if (" );
209
- builder .add ("($ L = " , k );
206
+ RuleType type = symbolTable . locals (). get ( k );
207
+ builder .add ("$T $ L = " , type . javaType () , k );
210
208
v .accept (this );
211
- builder .add (") != null" );
212
-
213
- builder .beginControlFlow (")" );
214
- builder .addStatement ("locals = locals.toBuilder().$1L($1L).build()" , k );
215
-
216
- if (++count < expr .bindings ().size ()) {
217
- builder .nextControlFlow ("else" );
218
- builder .addStatement ("return RuleResult.carryOn()" );
219
- builder .endControlFlow ();
220
- }
209
+ builder .addStatement ("" );
210
+ builder .beginControlFlow ("if ($L != null)" , k );
221
211
}
222
212
return null ;
223
213
}
@@ -235,40 +225,101 @@ private void conditionsPreamble(RuleSetExpression expr) {
235
225
}
236
226
237
227
private void conditionsEpilogue (RuleSetExpression expr ) {
238
- int blocksToClose = expr .conditions ().size ();
239
- for (int idx = 0 ; idx < blocksToClose ; ++idx ) {
240
- builder .endControlFlow ();
228
+ for (RuleExpression condition : expr .conditions ()) {
229
+ if (condition .kind () == RuleExpression .RuleExpressionKind .LET ) {
230
+ LetExpression let = (LetExpression ) condition ;
231
+ for (int x = 0 ; x < let .bindings ().size (); x ++) {
232
+ builder .endControlFlow ();
233
+ }
234
+ } else {
235
+ builder .endControlFlow ();
236
+ }
241
237
}
242
- if (! expr . conditions (). isEmpty ( )) {
238
+ if (needsReturn ( expr )) {
243
239
builder .addStatement ("return $T.carryOn()" , typeMirror .rulesResult ().type ());
244
240
}
245
241
}
246
242
243
+ private boolean needsReturn (RuleSetExpression expr ) {
244
+ // If the expression can be inlined, then it doesn't live in
245
+ // its own method, no return at the end required
246
+ if (canBeInlined (expr )) {
247
+ return false ;
248
+ }
249
+ // If the expression has conditions all be be wrapped in
250
+ // if-blocks, thus at the end of the method we need to return
251
+ // carryOn()
252
+ if (!expr .conditions ().isEmpty ()) {
253
+ return true ;
254
+ }
255
+ // If the expression doesn't have any conditions, and doesn't
256
+ // have any children then we need to return carryOn(). This
257
+ // case SHOULD NOT happen but we assume below that there are
258
+ // children, thus adding the test here.
259
+ if (expr .children ().isEmpty ()) {
260
+ return true ;
261
+ }
262
+ // We have children, check the last one.
263
+ int size = expr .children ().size ();
264
+ RuleSetExpression child = expr .children ().get (size - 1 );
265
+ // If a tree then we don't need a return.
266
+ if (child .isTree ()) {
267
+ return false ;
268
+ }
269
+ // The child is not a tree, so it was inlined. Check if it
270
+ // does have any conditions, if it so, its body will be inside
271
+ // a block already so we need to return after it.
272
+ return !child .conditions ().isEmpty ();
273
+ }
274
+
247
275
private void codegenTreeBody (RuleSetExpression expr ) {
248
276
List <RuleSetExpression > children = expr .children ();
249
277
int size = children .size ();
278
+ boolean isFirst = true ;
250
279
for (int idx = 0 ; idx < size ; ++idx ) {
251
280
RuleSetExpression child = children .get (idx );
281
+ if (canBeInlined (child )) {
282
+ child .accept (this );
283
+ continue ;
284
+ }
252
285
boolean isLast = idx == size - 1 ;
253
286
if (isLast ) {
254
- builder .addStatement ("return $L(params, locals)" ,
255
- child .ruleId ());
287
+ builder .addStatement ("return $L($L)" ,
288
+ child .ruleId (),
289
+ callParams (child .ruleId ()));
256
290
continue ;
257
291
}
258
- boolean isFirst = idx == 0 ;
292
+
259
293
if (isFirst ) {
260
- builder .addStatement ("$T result = $L(params, locals)" ,
294
+ isFirst = false ;
295
+ builder .addStatement ("$T result = $L($L)" ,
261
296
typeMirror .rulesResult ().type (),
262
- child .ruleId ());
297
+ child .ruleId (),
298
+ callParams (child .ruleId ()));
263
299
} else {
264
- builder .addStatement ("result = $L(params, locals)" ,
265
- child .ruleId ());
300
+ builder .addStatement ("result = $L($L)" ,
301
+ child .ruleId (),
302
+ callParams (child .ruleId ()));
266
303
}
267
304
builder .beginControlFlow ("if (result.isResolved())" )
268
305
.addStatement ("return result" )
269
306
.endControlFlow ();
270
307
}
308
+ }
271
309
310
+ private boolean canBeInlined (RuleSetExpression child ) {
311
+ return !child .isTree ();
312
+ }
313
+
314
+ private String callParams (String ruleId ) {
315
+ ComputeScopeTree .Scope scope = ruleIdToScope .get (ruleId );
316
+ String args = scope .usesLocals ().stream ()
317
+ .filter (a -> !scope .defines ().contains (a ))
318
+ .collect (Collectors .joining (", " ));
319
+ if (args .isEmpty ()) {
320
+ return "params" ;
321
+ }
322
+ return "params, " + args ;
272
323
}
273
324
274
325
@ Override
@@ -381,7 +432,6 @@ private void addAttributeBlock(String k, RuleExpression v) {
381
432
builder .add (")" );
382
433
}
383
434
384
-
385
435
public CodeBlock .Builder builder () {
386
436
return builder ;
387
437
}
0 commit comments