1212import java .util .List ;
1313import java .util .Objects ;
1414import java .util .Optional ;
15+ import java .util .Queue ;
1516import java .util .stream .Stream ;
1617
1718import org .antlr .v4 .runtime .tree .TerminalNode ;
2627import dev .vepo .jsonata .functions .ArrayIndexJSONataFunction ;
2728import dev .vepo .jsonata .functions .ArrayQueryJSONataFunction ;
2829import dev .vepo .jsonata .functions .ArrayRangeJSONataFunction ;
30+ import dev .vepo .jsonata .functions .BockContext ;
2931import dev .vepo .jsonata .functions .BooleanExpressionJSONataFunction ;
3032import dev .vepo .jsonata .functions .BooleanOperator ;
3133import dev .vepo .jsonata .functions .BuiltInSortJSONataFunction ;
4345import dev .vepo .jsonata .functions .ObjectBuilderJSONataFunction ;
4446import dev .vepo .jsonata .functions .ObjectMapperJSONataFunction ;
4547import dev .vepo .jsonata .functions .StringConcatJSONataFunction ;
48+ import dev .vepo .jsonata .functions .UserDefinedFunctionJSONataFunction ;
4649import dev .vepo .jsonata .functions .WildcardJSONataFunction ;
4750import dev .vepo .jsonata .functions .generated .JSONataGrammarBaseListener ;
4851import dev .vepo .jsonata .functions .generated .JSONataGrammarParser .AlgebraicExpressionContext ;
4952import dev .vepo .jsonata .functions .generated .JSONataGrammarParser .AllDescendantSearchContext ;
5053import dev .vepo .jsonata .functions .generated .JSONataGrammarParser .ArrayConstructorContext ;
5154import dev .vepo .jsonata .functions .generated .JSONataGrammarParser .ArrayIndexQueryContext ;
5255import dev .vepo .jsonata .functions .generated .JSONataGrammarParser .ArrayQueryContext ;
56+ import dev .vepo .jsonata .functions .generated .JSONataGrammarParser .BlockExpressionContext ;
5357import dev .vepo .jsonata .functions .generated .JSONataGrammarParser .BooleanCompareContext ;
5458import dev .vepo .jsonata .functions .generated .JSONataGrammarParser .BooleanExpressionContext ;
5559import dev .vepo .jsonata .functions .generated .JSONataGrammarParser .BooleanValueContext ;
7377import dev .vepo .jsonata .functions .generated .JSONataGrammarParser .RootPathContext ;
7478import dev .vepo .jsonata .functions .generated .JSONataGrammarParser .StringValueContext ;
7579import dev .vepo .jsonata .functions .generated .JSONataGrammarParser .ToArrayContext ;
80+ import dev .vepo .jsonata .functions .generated .JSONataGrammarParser .VariableAssignmentContext ;
81+ import dev .vepo .jsonata .functions .generated .JSONataGrammarParser .VariableUsageContext ;
7682
7783public class JSONataGrammarListener extends JSONataGrammarBaseListener {
78- private static final Logger logger = LoggerFactory .getLogger (JSONataGrammarListener .class );
79-
8084 public enum BuiltInFunction {
8185 SORT ("$sort" ),
8286 SUM ("$sum" );
8387
84- public static BuiltInFunction get (String name ) {
88+ public static Optional < BuiltInFunction > get (String name ) {
8589 return Stream .of (values ())
8690 .filter (n -> n .name .compareToIgnoreCase (name ) == 0 )
87- .findAny ()
88- .orElseThrow (() -> new JSONataException (String .format ("Unknown function!!! function=%s" , name )));
91+ .findAny ();
8992 }
9093
9194 private String name ;
@@ -95,6 +98,8 @@ public static BuiltInFunction get(String name) {
9598 }
9699 }
97100
101+ private static final Logger logger = LoggerFactory .getLogger (JSONataGrammarListener .class );
102+
98103 private static String fieldName2Text (TerminalNode ctx ) {
99104 if (!ctx .getText ().startsWith ("`" )) {
100105 return ctx .getText ();
@@ -113,12 +118,13 @@ private static String sanitise(String str) {
113118 }
114119
115120 private final Deque <JSONataFunction > expressions ;
116-
117121 private final Deque <DeclaredFunction > functionsDeclared ;
122+ private final Queue <BockContext > blocks ;
118123
119124 public JSONataGrammarListener () {
120125 this .expressions = new LinkedList <>();
121126 this .functionsDeclared = new LinkedList <>();
127+ this .blocks = new LinkedList <>();
122128 }
123129
124130 @ Override
@@ -131,15 +137,28 @@ public void exitFunctionDeclarationBuilder(FunctionDeclarationBuilderContext ctx
131137 this .expressions .removeLast ()));
132138 }
133139
140+ private List <JSONataFunction > previous (int size ) {
141+ var fns = new ArrayList <JSONataFunction >(size );
142+ for (int i = 0 ; i < size ; ++i ) {
143+ fns .addFirst (expressions .removeLast ());
144+ }
145+ return fns ;
146+ }
147+
134148 @ Override
135149 public void exitFunctionCall (FunctionCallContext ctx ) {
136150 logger .atInfo ().setMessage ("Function call! {}" ).addArgument (ctx ::getText ).log ();
137- var valueProvider = expressions .removeLast ();
138151 Optional <DeclaredFunction > maybeFn = functionsDeclared .isEmpty () ? Optional .empty () : Optional .of (functionsDeclared .removeLast ());
139- expressions .offer (switch (BuiltInFunction .get (ctx .functionStatement ().IDENTIFIER ().getText ())) {
140- case SORT -> new BuiltInSortJSONataFunction (valueProvider , maybeFn );
141- case SUM -> new BuiltInSumJSONataFunction (valueProvider );
142- });
152+ var fnName = ctx .functionStatement ().IDENTIFIER ().getText ();
153+ expressions .offer (BuiltInFunction .get (fnName )
154+ .map (fn -> switch (fn ) {
155+ case SORT -> new BuiltInSortJSONataFunction (expressions .removeLast (), maybeFn );
156+ case SUM -> new BuiltInSumJSONataFunction (expressions .removeLast ());
157+ })
158+ .orElseGet (() -> this .blocks .peek ().function (fnName )
159+ .map (fn -> new UserDefinedFunctionJSONataFunction (previous (fn .parameterNames ().size ()),
160+ fn ))
161+ .orElseThrow (() -> new JSONataException ("Function not found: " + fnName ))));
143162 }
144163
145164 @ Override
@@ -151,7 +170,13 @@ public void exitRootPath(RootPathContext ctx) {
151170 @ Override
152171 public void exitIdentifier (IdentifierContext ctx ) {
153172 logger .atInfo ().setMessage ("Identifier! {}" ).addArgument (ctx ::getText ).log ();
154- expressions .offer (new FieldMapJSONataFunction (fieldName2Text (ctx .IDENTIFIER ())));
173+ if (blocks .isEmpty ()) {
174+ expressions .offer (new FieldMapJSONataFunction (fieldName2Text (ctx .IDENTIFIER ())));
175+ } else {
176+ expressions .offer (Objects .requireNonNull (this .blocks .peek (), "Variable should only be defined in blocks!" )
177+ .variable (ctx .IDENTIFIER ().getText ())
178+ .orElseGet (() -> new FieldMapJSONataFunction (fieldName2Text (ctx .IDENTIFIER ()))));
179+ }
155180 }
156181
157182 @ Override
@@ -330,6 +355,42 @@ public void exitObjectConstructor(ObjectConstructorContext ctx) {
330355 expressions .offer (new JoinJSONataFunction (previousFunction , new ObjectBuilderJSONataFunction (fieldList )));
331356 }
332357
358+ @ Override
359+ public void exitObjectBuilder (ObjectBuilderContext ctx ) {
360+ logger .atInfo ().setMessage ("Object builder! {}" ).addArgument (ctx ::getText ).log ();
361+ expressions .offer (new ObjectBuilderJSONataFunction (objectFields (ctx .fieldList ())));
362+ }
363+
364+ @ Override
365+ public void enterBlockExpression (BlockExpressionContext ctx ) {
366+ logger .atInfo ().setMessage ("Block expression! {}" ).addArgument (ctx ::getText ).log ();
367+ this .blocks .offer (new BockContext ());
368+ }
369+
370+ @ Override
371+ public void exitVariableUsage (VariableUsageContext ctx ) {
372+ logger .atInfo ().setMessage ("Variable usage! {}" ).addArgument (ctx ::getText ).log ();
373+ expressions .offer (Objects .requireNonNull (this .blocks .peek (), "Variable should only be defined in blocks!" )
374+ .variable (ctx .IDENTIFIER ().getText ())
375+ .orElseThrow (() -> new JSONataException ("Variable not found: " + ctx .IDENTIFIER ().getText ())));
376+ }
377+
378+ @ Override
379+ public void exitVariableAssignment (VariableAssignmentContext ctx ) {
380+ logger .atInfo ().setMessage ("Variable assignment! {}" ).addArgument (ctx ::getText ).log ();
381+ if (Objects .nonNull (ctx .expression ())) {
382+ Objects .requireNonNull (this .blocks .peek (), "Variable should only be defined in blocks!" )
383+ .defineVariable (ctx .IDENTIFIER ().getText (), expressions .removeLast ());
384+ } else {
385+ Objects .requireNonNull (this .blocks .peek (), "Variable should only be defined in blocks!" )
386+ .defineFunction (ctx .IDENTIFIER ().getText (), functionsDeclared .removeLast ());
387+ }
388+ }
389+
390+ public List <JSONataFunction > getExpressions () {
391+ return expressions .stream ().toList ();
392+ }
393+
333394 private List <FieldContent > objectFields (FieldListContext ctx ) {
334395 var expresisonCounter = ctx .expression ().size ();
335396 var fieldBuilder = new ArrayList <FieldContent >(expresisonCounter );
@@ -340,14 +401,4 @@ private List<FieldContent> objectFields(FieldListContext ctx) {
340401 }
341402 return fieldBuilder ;
342403 }
343-
344- @ Override
345- public void exitObjectBuilder (ObjectBuilderContext ctx ) {
346- logger .atInfo ().setMessage ("Object builder! {}" ).addArgument (ctx ::getText ).log ();
347- expressions .offer (new ObjectBuilderJSONataFunction (objectFields (ctx .fieldList ())));
348- }
349-
350- public List <JSONataFunction > getExpressions () {
351- return expressions .stream ().toList ();
352- }
353404}
0 commit comments