@@ -591,15 +591,26 @@ package body Langkit_Support.Generic_API.Unparsing is
591
591
-- Return the expected name for the given Member in the given Node
592
592
593
593
type Template_Parsing_State_Kind is
594
- (Initial, Recurse_Found, For_Recurse_Field);
594
+ (Simple_Recurse, Recurse_Field);
595
+ -- There are two kinds of templates we expect to find in unparsing
596
+ -- configurations:
597
+ --
598
+ -- * Simple_Recurse templates, that cannot contain "text" nodes and
599
+ -- whose linearization must yield a single "recurse" node.
600
+ --
601
+ -- * Recurse_Field templates, whose linearization must yield the
602
+ -- sequence of "text"/"recurse_field" that is expected for a node.
603
+
595
604
type Template_Parsing_State
596
- (Kind : Template_Parsing_State_Kind := Initial )
605
+ (Kind : Template_Parsing_State_Kind := Simple_Recurse )
597
606
is record
598
607
case Kind is
599
- when Initial | Recurse_Found =>
600
- null ;
608
+ when Simple_Recurse =>
609
+ Recurse_Found : Boolean;
610
+ -- Whether template parsing has found the "recurse" node
611
+ -- expected for the current branch.
601
612
602
- when For_Recurse_Field =>
613
+ when Recurse_Field =>
603
614
Linear_Template : Linear_Template_Vectors.Vector;
604
615
-- Sequence of tokens/fields that the parsed template is
605
616
-- supposed to yield once instantiated/formatted.
@@ -610,8 +621,6 @@ package body Langkit_Support.Generic_API.Unparsing is
610
621
end case ;
611
622
end record ;
612
623
613
- Initial_State : constant Template_Parsing_State := (Kind => Initial);
614
-
615
624
type Template_Parsing_Context_Kind is
616
625
(Node_Template, Field_Template, Sep_Template);
617
626
-- Indicate which kind of template we are parsing:
@@ -641,6 +650,21 @@ package body Langkit_Support.Generic_API.Unparsing is
641
650
end case ;
642
651
end record ;
643
652
653
+ function Template_Kind
654
+ (JSON : JSON_Value) return Template_Parsing_State_Kind;
655
+ -- Determine the plausible kind for the given JSON-encoded template.
656
+ -- Note that this is just a heuristic: if will return the right kind for
657
+ -- a well-formed template, but will return an approximation for an
658
+ -- ill-formed template.
659
+
660
+ function Initial_State_For
661
+ (Node : Type_Ref;
662
+ JSON : JSON_Value;
663
+ Context : Template_Parsing_Context) return Template_Parsing_State;
664
+ -- Return an inital template parsing state for the "node" template of
665
+ -- ``Node``, to create from ``JSON``. Raise an Invalid_Input exception
666
+ -- if the initial state found is invalid in this context.
667
+
644
668
function Parse_Template
645
669
(JSON : JSON_Value;
646
670
Context : in out Template_Parsing_Context) return Template_Type;
@@ -736,6 +760,126 @@ package body Langkit_Support.Generic_API.Unparsing is
736
760
end if ;
737
761
end To_Struct_Member_Index ;
738
762
763
+ -- -----------------
764
+ -- Template_Kind --
765
+ -- -----------------
766
+
767
+ function Template_Kind
768
+ (JSON : JSON_Value) return Template_Parsing_State_Kind
769
+ is
770
+ Result : Template_Parsing_State_Kind := Simple_Recurse;
771
+ Abort_Recursion : exception ;
772
+
773
+ function Kind_Matches
774
+ (JSON : JSON_Value; Kind : String) return Boolean;
775
+ -- Assuming that JSON is an object, return whether it has a "kind"
776
+ -- field equal to Kind.
777
+
778
+ procedure Process (JSON : JSON_Value);
779
+ procedure Process_Map_Item (Name : String; JSON : JSON_Value);
780
+
781
+ -- ----------------
782
+ -- Kind_Matches --
783
+ -- ----------------
784
+
785
+ function Kind_Matches
786
+ (JSON : JSON_Value; Kind : String) return Boolean
787
+ is
788
+ begin
789
+ return JSON.Has_Field (" kind" )
790
+ and then JSON.Get (" kind" ).Kind = JSON_String_Type
791
+ and then String'(JSON.Get (" kind" )) = Kind;
792
+ end Kind_Matches ;
793
+
794
+ -- -----------
795
+ -- Process --
796
+ -- -----------
797
+
798
+ procedure Process (JSON : JSON_Value) is
799
+ begin
800
+ case JSON.Kind is
801
+ when JSON_Object_Type =>
802
+
803
+ -- As soon as we find a "text" template node or a
804
+ -- "recurse_field" one, we know this is a "recurse_field"
805
+ -- template.
806
+
807
+ if Kind_Matches (JSON, " text" )
808
+ or else Kind_Matches (JSON, " recurse_field" )
809
+ then
810
+ Result := Recurse_Field;
811
+ raise Abort_Recursion;
812
+ end if ;
813
+
814
+ JSON.Map_JSON_Object (Process_Map_Item'Access );
815
+
816
+ when JSON_Array_Type =>
817
+ for Item of JSON_Array'(JSON.Get) loop
818
+ Process (Item);
819
+ end loop ;
820
+
821
+ when others =>
822
+ null ;
823
+ end case ;
824
+ end Process ;
825
+
826
+ -- --------------------
827
+ -- Process_Map_Item --
828
+ -- --------------------
829
+
830
+ procedure Process_Map_Item (Name : String; JSON : JSON_Value) is
831
+ pragma Unreferenced (Name);
832
+ begin
833
+ Process (JSON);
834
+ end Process_Map_Item ;
835
+
836
+ begin
837
+ Process (JSON);
838
+ return Result;
839
+ exception
840
+ when Abort_Recursion =>
841
+ return Result;
842
+ end Template_Kind ;
843
+
844
+ -- ---------------------
845
+ -- Initial_State_For --
846
+ -- ---------------------
847
+
848
+ function Initial_State_For
849
+ (Node : Type_Ref;
850
+ JSON : JSON_Value;
851
+ Context : Template_Parsing_Context) return Template_Parsing_State is
852
+ begin
853
+ return Result : Template_Parsing_State (Template_Kind (JSON)) do
854
+ case Result.Kind is
855
+ when Simple_Recurse =>
856
+ Result.Recurse_Found := False;
857
+
858
+ when Recurse_Field =>
859
+ -- Ensure that "recurse_field" templates are valid for this
860
+ -- node.
861
+
862
+ if Is_Abstract (Node) then
863
+ Abort_Parsing
864
+ (Context,
865
+ " text/recurse_field are valid for concrete nodes"
866
+ & " only" );
867
+ elsif Is_Token_Node (Node) then
868
+ Abort_Parsing
869
+ (Context,
870
+ " text/recurse_field are not valid for token nodes" );
871
+ elsif Is_List_Node (Node) then
872
+ Abort_Parsing
873
+ (Context,
874
+ " text/recurse_field are not valid for list nodes" );
875
+ end if ;
876
+
877
+ Result.Linear_Template := Linear_Template (Node);
878
+ Result.Linear_Position := 1 ;
879
+ end case ;
880
+ end return ;
881
+ end Initial_State_For ;
882
+
739
883
-- ------------------
740
884
-- Parse_Template --
741
885
-- ------------------
@@ -763,13 +907,14 @@ package body Langkit_Support.Generic_API.Unparsing is
763
907
end loop ;
764
908
765
909
case Context.State.Kind is
766
- when Initial =>
767
- Abort_Parsing (Context, " recursion is missing" );
768
-
769
- when Recurse_Found =>
770
- return (Kind => With_Recurse, Root => Root);
910
+ when Simple_Recurse =>
911
+ if Context.State.Recurse_Found then
912
+ return (Kind => With_Recurse, Root => Root);
913
+ else
914
+ Abort_Parsing (Context, " recursion is missing" );
915
+ end if ;
771
916
772
- when For_Recurse_Field =>
917
+ when Recurse_Field =>
773
918
774
919
-- Make sure that the template covers all items in the linear
775
920
-- template.
@@ -1207,15 +1352,18 @@ package body Langkit_Support.Generic_API.Unparsing is
1207
1352
procedure Process_Recurse (Context : in out Template_Parsing_Context) is
1208
1353
begin
1209
1354
case Context.State.Kind is
1210
- when Initial =>
1211
- Context.State := (Kind => Recurse_Found);
1212
- when Recurse_Found =>
1213
- Abort_Parsing (Context, " too many recursions" );
1214
- when For_Recurse_Field =>
1355
+ when Simple_Recurse =>
1356
+ if Context.State.Recurse_Found then
1357
+ Abort_Parsing (Context, " too many recursions" );
1358
+ else
1359
+ Context.State.Recurse_Found := True;
1360
+ end if ;
1361
+
1362
+ when Recurse_Field =>
1215
1363
Abort_Parsing
1216
1364
(Context,
1217
1365
" using "" recurse"" /"" recurse_flatten"" in the same template"
1218
- & " as "" recurse_field"" /tokens is invalid" );
1366
+ & " as "" recurse_field"" /"" text "" is invalid" );
1219
1367
end case ;
1220
1368
end Process_Recurse ;
1221
1369
@@ -1230,50 +1378,16 @@ package body Langkit_Support.Generic_API.Unparsing is
1230
1378
function What return String
1231
1379
is (case Item.Kind is
1232
1380
when Token_Item => " text" ,
1233
- when Field_Item => " "" recurse_field"" " );
1381
+ when Field_Item => " recurse_field" );
1234
1382
begin
1235
- -- Ensure that the node that the context for which this template is
1236
- -- parsed supports tokens/"recurse_field" templates .
1383
+ -- Ensure that it is valid to have a "recurse_field" node in this
1384
+ -- template .
1237
1385
1238
- if Context.Kind /= Node_Template then
1239
- Abort_Parsing
1240
- (Context,
1241
- What & " is valid in "" node"" templates only" );
1242
- elsif Is_Abstract (Context.Node) then
1243
- Abort_Parsing
1244
- (Context,
1245
- What & " is valid for concrete nodes only" );
1246
- elsif Is_Token_Node (Context.Node) then
1247
- Abort_Parsing
1248
- (Context,
1249
- What & " is not valid for token nodes" );
1250
- elsif Is_List_Node (Context.Node) then
1386
+ if Context.State.Kind /= Recurse_Field then
1251
1387
Abort_Parsing
1252
- (Context,
1253
- What & " is not valid for list nodes" );
1388
+ (Context, What & " cannot appear in a "" recurse"" template" );
1254
1389
end if ;
1255
1390
1256
- -- Ensure that this template does not already has a "recurse"
1257
- -- template, and that we have a linear template for validation.
1258
-
1259
- case Context.State.Kind is
1260
- when Initial =>
1261
- Context.State :=
1262
- (Kind => For_Recurse_Field,
1263
- Linear_Template => Linear_Template
1264
- (Context.Node),
1265
- Linear_Position => 1 );
1266
-
1267
- when Recurse_Found =>
1268
- Abort_Parsing
1269
- (Context,
1270
- " "" recurse"" /"" recurse_flatten"" and " & What
1271
- & " cannot appear in the same template" );
1272
-
1273
- when For_Recurse_Field =>
1274
- null ;
1275
- end case ;
1276
-
1277
1391
-- Now validate this new item: it must match what the linear template
1278
1392
-- expects next.
1279
1393
@@ -1363,7 +1477,7 @@ package body Langkit_Support.Generic_API.Unparsing is
1363
1477
To_Struct_Member_Index (Name, Node);
1364
1478
Context : Template_Parsing_Context :=
1365
1479
(Kind => Field_Template,
1366
- State => Initial_State ,
1480
+ State => (Simple_Recurse, Recurse_Found => False) ,
1367
1481
Node => Node,
1368
1482
Field => From_Index (Language, Member));
1369
1483
begin
@@ -1441,21 +1555,29 @@ package body Langkit_Support.Generic_API.Unparsing is
1441
1555
procedure Process (Name : String; Value : JSON_Value) is
1442
1556
Key : constant Type_Index := To_Type_Index (Name);
1443
1557
Node : constant Type_Ref := From_Index (Language, Key);
1444
- Context : Template_Parsing_Context :=
1445
- (Kind => Node_Template,
1446
- Node => Node,
1447
- State => Initial_State);
1448
1558
Config : constant Node_Config_Access := new Node_Config_Record'
1449
1559
(Node_Template => No_Template,
1450
1560
Field_Configs => <>,
1451
1561
List_Sep => No_Template);
1452
1562
begin
1453
1563
Result.Node_Configs.Insert (Key, Config);
1454
1564
1455
- Config.Node_Template :=
1456
- (if Value.Has_Field (" node" )
1457
- then Parse_Template (Value.Get (" node" ), Context)
1458
- else Pool.Create_Recurse);
1565
+ if Value.Has_Field (" node" ) then
1566
+ declare
1567
+ JSON_Template : constant JSON_Value := Value.Get (" node" );
1568
+ Context : Template_Parsing_Context :=
1569
+ (Kind => Node_Template,
1570
+ Node => Node,
1571
+ State => <>);
1572
+ begin
1573
+ Context.State :=
1574
+ Initial_State_For (Node, JSON_Template, Context);
1575
+ Config.Node_Template :=
1576
+ Parse_Template (JSON_Template, Context);
1577
+ end ;
1578
+ else
1579
+ Config.Node_Template := Pool.Create_Recurse;
1580
+ end if ;
1459
1581
1460
1582
if Value.Has_Field (" fields" ) then
1461
1583
Load_Field_Configs
@@ -1472,7 +1594,8 @@ package body Langkit_Support.Generic_API.Unparsing is
1472
1594
Context : Template_Parsing_Context :=
1473
1595
(Kind => Sep_Template,
1474
1596
Node => Node,
1475
- State => Initial_State);
1597
+ State => (Kind => Simple_Recurse,
1598
+ Recurse_Found => False));
1476
1599
begin
1477
1600
Config.List_Sep :=
1478
1601
Parse_Template (Value.Get (" sep" ), Context);
0 commit comments