2121import java .util .Arrays ;
2222import java .util .List ;
2323import java .util .Map ;
24+ import java .util .stream .Collectors ;
2425import software .amazon .awssdk .awscore .endpoints .AwsEndpointAttribute ;
2526import software .amazon .awssdk .awscore .endpoints .authscheme .SigV4AuthScheme ;
2627import software .amazon .awssdk .awscore .endpoints .authscheme .SigV4aAuthScheme ;
@@ -32,14 +33,17 @@ public class CodeGeneratorVisitor extends WalkRuleExpressionVisitor {
3233 private final RuleRuntimeTypeMirror typeMirror ;
3334 private final SymbolTable symbolTable ;
3435 private final Map <String , KeyTypePair > knownEndpointAttributes ;
36+ private final Map <String , ComputeScopeTree .Scope > ruleIdToScope ;
3537
3638 public CodeGeneratorVisitor (RuleRuntimeTypeMirror typeMirror ,
3739 SymbolTable symbolTable ,
3840 Map <String , KeyTypePair > knownEndpointAttributes ,
41+ Map <String , ComputeScopeTree .Scope > ruleIdToScope ,
3942 CodeBlock .Builder builder ) {
4043 this .builder = builder ;
4144 this .symbolTable = symbolTable ;
4245 this .knownEndpointAttributes = knownEndpointAttributes ;
46+ this .ruleIdToScope = ruleIdToScope ;
4347 this .typeMirror = typeMirror ;
4448 }
4549
@@ -196,28 +200,14 @@ public Void visitRuleSetExpression(RuleSetExpression e) {
196200
197201 @ Override
198202 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 ;
205203 for (Map .Entry <String , RuleExpression > kvp : expr .bindings ().entrySet ()) {
206204 String k = kvp .getKey ();
207205 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 );
210208 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 );
221211 }
222212 return null ;
223213 }
@@ -235,40 +225,101 @@ private void conditionsPreamble(RuleSetExpression expr) {
235225 }
236226
237227 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+ }
241237 }
242- if (! expr . conditions (). isEmpty ( )) {
238+ if (needsReturn ( expr )) {
243239 builder .addStatement ("return $T.carryOn()" , typeMirror .rulesResult ().type ());
244240 }
245241 }
246242
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+
247275 private void codegenTreeBody (RuleSetExpression expr ) {
248276 List <RuleSetExpression > children = expr .children ();
249277 int size = children .size ();
278+ boolean isFirst = true ;
250279 for (int idx = 0 ; idx < size ; ++idx ) {
251280 RuleSetExpression child = children .get (idx );
281+ if (canBeInlined (child )) {
282+ child .accept (this );
283+ continue ;
284+ }
252285 boolean isLast = idx == size - 1 ;
253286 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 ()));
256290 continue ;
257291 }
258- boolean isFirst = idx == 0 ;
292+
259293 if (isFirst ) {
260- builder .addStatement ("$T result = $L(params, locals)" ,
294+ isFirst = false ;
295+ builder .addStatement ("$T result = $L($L)" ,
261296 typeMirror .rulesResult ().type (),
262- child .ruleId ());
297+ child .ruleId (),
298+ callParams (child .ruleId ()));
263299 } else {
264- builder .addStatement ("result = $L(params, locals)" ,
265- child .ruleId ());
300+ builder .addStatement ("result = $L($L)" ,
301+ child .ruleId (),
302+ callParams (child .ruleId ()));
266303 }
267304 builder .beginControlFlow ("if (result.isResolved())" )
268305 .addStatement ("return result" )
269306 .endControlFlow ();
270307 }
308+ }
271309
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 ;
272323 }
273324
274325 @ Override
@@ -381,7 +432,6 @@ private void addAttributeBlock(String k, RuleExpression v) {
381432 builder .add (")" );
382433 }
383434
384-
385435 public CodeBlock .Builder builder () {
386436 return builder ;
387437 }
0 commit comments