1414
1515package dev .cel .common .ast ;
1616
17- import static com .google .common .collect .ImmutableList .toImmutableList ;
18-
1917import com .google .common .base .Preconditions ;
2018import com .google .common .collect .ImmutableList ;
2119import dev .cel .common .CelAbstractSyntaxTree ;
2220import dev .cel .common .annotations .Internal ;
23- import dev .cel .common .navigation .CelNavigableExpr ;
21+ import dev .cel .common .ast .CelExpr .CelCall ;
22+ import dev .cel .common .ast .CelExpr .CelIdent ;
23+ import dev .cel .common .ast .CelExpr .ExprKind .Kind ;
2424import java .util .Optional ;
2525
2626/**
@@ -61,27 +61,17 @@ public CelExpr expr() {
6161 * @throws IllegalArgumentException if the block is malformed or its indices are invalid.
6262 */
6363 public static Optional <CelBlock > extract (CelAbstractSyntaxTree ast ) {
64- CelNavigableExpr celNavigableExpr = CelNavigableExpr .fromExpr (ast .getExpr ());
65-
66- ImmutableList <CelExpr > allCelBlocks =
67- celNavigableExpr
68- .allNodes ()
69- .map (CelNavigableExpr ::expr )
70- .filter (expr -> expr .callOrDefault ().function ().equals (FUNCTION_NAME ))
71- .collect (toImmutableList ());
72- if (allCelBlocks .isEmpty ()) {
64+ CelExpr root = ast .getExpr ();
65+ if (!isBlockCall (root )) {
66+ new BlockValidator (root ).validate (root , 0 );
7367 return Optional .empty ();
7468 }
7569
76- Preconditions .checkArgument (
77- allCelBlocks .size () == 1 ,
78- "Expected 1 cel.block function to be present but found %s" ,
79- allCelBlocks .size ());
80- Preconditions .checkArgument (
81- celNavigableExpr .expr ().equals (allCelBlocks .get (0 )),
82- "Expected cel.block to be present at root" );
70+ return Optional .of (fromExpr (root ));
71+ }
8372
84- return Optional .of (fromExpr (allCelBlocks .get (0 )));
73+ private static boolean isBlockCall (CelExpr expr ) {
74+ return expr .getKind ().equals (Kind .CALL ) && expr .call ().function ().equals (FUNCTION_NAME );
8575 }
8676
8777 /**
@@ -100,45 +90,71 @@ private static CelBlock fromExpr(CelExpr expr) {
10090 Preconditions .checkArgument (
10191 expr .call ().args ().get (0 ).exprKind ().getKind () == CelExpr .ExprKind .Kind .LIST ,
10292 "Expected first argument of cel.@block to be a list" );
93+ Preconditions .checkArgument (
94+ !expr .call ().target ().isPresent (), "Expected cel.@block to be a global call" );
10395
10496 CelBlock block = new CelBlock (expr );
97+ BlockValidator validator = new BlockValidator (expr );
10598
10699 // Assert correctness on block indices used in subexpressions
107100 ImmutableList <CelExpr > subexprs = block .indices ();
108101 for (int i = 0 ; i < subexprs .size (); i ++) {
109- verifyBlockIndex (subexprs .get (i ), i , expr );
102+ validator . validate (subexprs .get (i ), i );
110103 }
111104
112105 // Assert correctness on block indices used in block result
113- CelExpr blockResult = block .result ();
114- verifyBlockIndex (blockResult , subexprs .size (), expr );
115- boolean resultHasAtLeastOneBlockIndex =
116- CelNavigableExpr .fromExpr (blockResult )
117- .allNodes ()
118- .map (CelNavigableExpr ::expr )
119- .anyMatch (e -> e .identOrDefault ().name ().startsWith (INDEX_PREFIX ));
120106 Preconditions .checkArgument (
121- resultHasAtLeastOneBlockIndex ,
107+ validator . validate ( block . result (), subexprs . size ()) ,
122108 "Expected at least one reference of index in cel.block result" );
123109
124110 return block ;
125111 }
126112
127- private static void verifyBlockIndex (CelExpr celExpr , int maxIndexValue , CelExpr rootBlock ) {
128- boolean areAllIndicesValid =
129- CelNavigableExpr .fromExpr (celExpr )
130- .allNodes ()
131- .map (CelNavigableExpr ::expr )
132- .filter (expr -> expr .identOrDefault ().name ().startsWith (INDEX_PREFIX ))
133- .map (CelExpr ::ident )
134- .allMatch (
135- blockIdent ->
136- Integer .parseInt (blockIdent .name ().substring (INDEX_PREFIX .length ()))
137- < maxIndexValue );
138- Preconditions .checkArgument (
139- areAllIndicesValid ,
140- "Illegal block index found. The index value must be less than %s. Expr: %s" ,
141- maxIndexValue ,
142- rootBlock );
113+ private static final class BlockValidator extends CelExprVisitor {
114+ private final CelExpr root ;
115+ private int maxIndexValue ;
116+ private boolean hasBlockIndex ;
117+
118+ private boolean validate (CelExpr expr , int maxIndexValue ) {
119+ this .maxIndexValue = maxIndexValue ;
120+ this .hasBlockIndex = false ;
121+ visit (expr );
122+ return hasBlockIndex ;
123+ }
124+
125+ @ Override
126+ public void visit (CelExpr expr ) {
127+ if (!expr .getKind ().equals (Kind .NOT_SET )) {
128+ super .visit (expr );
129+ }
130+ }
131+
132+ @ Override
133+ protected void visit (CelExpr expr , CelCall call ) {
134+ if (call .function ().equals (FUNCTION_NAME )) {
135+ throw new IllegalArgumentException (
136+ isBlockCall (root )
137+ ? "Expected 1 cel.block function to be present but found 2"
138+ : "Expected cel.block to be present at root" );
139+ }
140+ super .visit (expr , call );
141+ }
142+
143+ @ Override
144+ protected void visit (CelExpr expr , CelIdent ident ) {
145+ if (ident .name ().startsWith (INDEX_PREFIX )) {
146+ hasBlockIndex = true ;
147+ int indexValue = Integer .parseInt (ident .name ().substring (INDEX_PREFIX .length ()));
148+ Preconditions .checkArgument (
149+ indexValue >= 0 && indexValue < maxIndexValue ,
150+ "Illegal block index found. The index value must be less than %s. Expr: %s" ,
151+ maxIndexValue ,
152+ root );
153+ }
154+ }
155+
156+ private BlockValidator (CelExpr root ) {
157+ this .root = root ;
158+ }
143159 }
144160}
0 commit comments