@@ -16,7 +16,6 @@ with GNAT.Strings;
16
16
with GNATCOLL.JSON ; use GNATCOLL.JSON;
17
17
with GNATCOLL.Opt_Parse ;
18
18
with GNATCOLL.VFS ; use GNATCOLL.VFS;
19
- with Prettier_Ada.Documents.Builders ;
20
19
with Prettier_Ada.Documents.Json ;
21
20
22
21
with Langkit_Support.Errors ; use Langkit_Support.Errors;
@@ -106,6 +105,40 @@ package body Langkit_Support.Generic_API.Unparsing is
106
105
-- Decompose ``Node`` into a list of unparsing fragments and call
107
106
-- ``Process`` on each fragment.
108
107
108
+ -- ---------------------
109
+ -- Template symbols --
110
+ -- ---------------------
111
+
112
+ -- The following map type is used during templates parsing to validate the
113
+ -- names used as symbols in JSON templates, and to turn them into their
114
+ -- internal representation: ``Template_Symbol``.
115
+
116
+ type Symbol_Info is record
117
+ Source_Name : Unbounded_String;
118
+ -- Name for this symbol as found in the unparsing configuration
119
+
120
+ Template_Sym : Template_Symbol;
121
+ -- Unique identifier for this symbol
122
+
123
+ Has_Definition : Boolean;
124
+ -- Whether we have found one definition for this symbol
125
+ end record ;
126
+
127
+ package Symbol_Parsing_Maps is new Ada.Containers.Hashed_Maps
128
+ (Key_Type => Symbol_Type,
129
+ Element_Type => Symbol_Info,
130
+ Hash => Hash,
131
+ Equivalent_Keys => " =" );
132
+
133
+ function Lookup
134
+ (Source_Name : Unbounded_String;
135
+ Symbols : Symbol_Table;
136
+ Symbol_Map : in out Symbol_Parsing_Maps.Map)
137
+ return Symbol_Parsing_Maps.Reference_Type;
138
+ -- Return a reference to the entry in ``Symbol_Map`` corresponding to the
139
+ -- ```Source_Name`` symbol (converted to a ``Symbol_Type`` using
140
+ -- ``Symbols``). Create a map entry if it does not exist yet.
141
+
109
142
-- --------------------
110
143
-- Linear templates --
111
144
-- --------------------
@@ -360,6 +393,42 @@ package body Langkit_Support.Generic_API.Unparsing is
360
393
end case ;
361
394
end Iterate_On_Fragments ;
362
395
396
+ -- ----------
397
+ -- Lookup --
398
+ -- ----------
399
+
400
+ function Lookup
401
+ (Source_Name : Unbounded_String;
402
+ Symbols : Symbol_Table;
403
+ Symbol_Map : in out Symbol_Parsing_Maps.Map)
404
+ return Symbol_Parsing_Maps.Reference_Type
405
+ is
406
+ Symbol : constant Symbol_Type :=
407
+ Find (Symbols, To_Text (To_String (Source_Name)));
408
+ Position : Symbol_Parsing_Maps.Cursor := Symbol_Map.Find (Symbol);
409
+ Inserted : Boolean;
410
+ begin
411
+ if not Symbol_Parsing_Maps.Has_Element (Position) then
412
+
413
+ -- This is the first time we see this symbol in the current template:
414
+ -- create a new internal symbol for it. All internal symbols are
415
+ -- tracked as entries in ``Symbol_Map``, so we can use its length to
416
+ -- compute internal symbols that are unique for the current template.
417
+
418
+ declare
419
+ Info : constant Symbol_Info :=
420
+ (Source_Name => Source_Name,
421
+ Template_Sym => Template_Symbol (Symbol_Map.Length + 1 ),
422
+ Has_Definition => False);
423
+ begin
424
+ Symbol_Map.Insert (Symbol, Info, Position, Inserted);
425
+ pragma Assert (Inserted);
426
+ end ;
427
+ end if ;
428
+
429
+ return Symbol_Map.Reference (Position);
430
+ end Lookup ;
431
+
363
432
-- ---------
364
433
-- Image --
365
434
-- ---------
@@ -580,8 +649,9 @@ package body Langkit_Support.Generic_API.Unparsing is
580
649
-- ill-formed.
581
650
582
651
function Parse_Template_Helper
583
- (JSON : JSON_Value;
584
- Context : in out Template_Parsing_Context) return Document_Type;
652
+ (JSON : JSON_Value;
653
+ Context : in out Template_Parsing_Context;
654
+ Symbol_Map : in out Symbol_Parsing_Maps.Map) return Document_Type;
585
655
-- Helper for ``Parse_Template``. Implement the recursive part of
586
656
-- templates parsing: ``Parse_Template`` takes care of the post-parsing
587
657
-- validation.
@@ -674,9 +744,24 @@ package body Langkit_Support.Generic_API.Unparsing is
674
744
(JSON : JSON_Value;
675
745
Context : in out Template_Parsing_Context) return Template_Type
676
746
is
747
+ Symbol_Map : Symbol_Parsing_Maps.Map;
748
+ -- Mapping from name symbols found in the JSON (Symbol_Type) and
749
+ -- "ids" (Template_Symbol).
750
+
677
751
Root : constant Document_Type :=
678
- Parse_Template_Helper (JSON, Context);
752
+ Parse_Template_Helper (JSON, Context, Symbol_Map );
679
753
begin
754
+ -- Make sure that all symbols referenced in this template are also
755
+ -- defined in this template.
756
+
757
+ for Info of Symbol_Map loop
758
+ if not Info.Has_Definition then
759
+ Abort_Parsing
760
+ (Context,
761
+ " undefined symbol: " & To_String (Info.Source_Name));
762
+ end if ;
763
+ end loop ;
764
+
680
765
case Context.State.Kind is
681
766
when Initial =>
682
767
Abort_Parsing (Context, " recursion is missing" );
@@ -709,16 +794,18 @@ package body Langkit_Support.Generic_API.Unparsing is
709
794
-- -------------------------
710
795
711
796
function Parse_Template_Helper
712
- (JSON : JSON_Value;
713
- Context : in out Template_Parsing_Context) return Document_Type is
797
+ (JSON : JSON_Value;
798
+ Context : in out Template_Parsing_Context;
799
+ Symbol_Map : in out Symbol_Parsing_Maps.Map) return Document_Type is
714
800
begin
715
801
case JSON.Kind is
716
802
when JSON_Array_Type =>
717
803
declare
718
804
Items : Document_Vectors.Vector;
719
805
begin
720
806
for D of JSON_Array'(JSON.Get) loop
721
- Items.Append (Parse_Template_Helper (D, Context));
807
+ Items.Append
808
+ (Parse_Template_Helper (D, Context, Symbol_Map));
722
809
end loop ;
723
810
return Pool.Create_List (Items);
724
811
end ;
@@ -793,7 +880,7 @@ package body Langkit_Support.Generic_API.Unparsing is
793
880
return Pool.Create_Align
794
881
(Data,
795
882
Parse_Template_Helper
796
- (JSON.Get (" contents" ), Context));
883
+ (JSON.Get (" contents" ), Context, Symbol_Map ));
797
884
end ;
798
885
799
886
elsif Kind in
@@ -814,7 +901,9 @@ package body Langkit_Support.Generic_API.Unparsing is
814
901
then (Kind => Prettier.Inner_Root)
815
902
else raise Program_Error),
816
903
Contents => Parse_Template_Helper
817
- (JSON.Get (" contents" ), Context));
904
+ (JSON.Get (" contents" ),
905
+ Context,
906
+ Symbol_Map));
818
907
819
908
elsif Kind = " fill" then
820
909
declare
@@ -825,41 +914,75 @@ package body Langkit_Support.Generic_API.Unparsing is
825
914
(Context, " missing "" document"" key for fill" );
826
915
end if ;
827
916
Document :=
828
- Parse_Template_Helper (JSON.Get (" document" ), Context);
917
+ Parse_Template_Helper
918
+ (JSON.Get (" document" ), Context, Symbol_Map);
829
919
830
920
return Pool.Create_Fill (Document);
831
921
end ;
832
922
833
923
elsif Kind = " group" then
834
924
declare
835
- Document : Document_Type;
836
- Options : Prettier.Builders.Group_Options_Type :=
837
- Prettier.Builders.No_Group_Options;
838
-
839
- Should_Break : JSON_Value;
925
+ Document : Document_Type;
926
+ Should_Break : Boolean := False;
927
+ Id : Template_Symbol := No_Template_Symbol;
840
928
begin
841
929
if not JSON.Has_Field (" document" ) then
842
930
Abort_Parsing
843
931
(Context, " missing "" document"" key for group" );
844
932
end if ;
845
933
Document :=
846
- Parse_Template_Helper (JSON.Get (" document" ), Context);
934
+ Parse_Template_Helper
935
+ (JSON.Get (" document" ), Context, Symbol_Map);
847
936
848
937
if JSON.Has_Field (" shouldBreak" ) then
849
- Should_Break := JSON.Get (" shouldBreak" );
850
- if Should_Break.Kind /= JSON_Boolean_Type then
851
- Abort_Parsing
852
- (Context,
853
- " invalid group shouldBreak: "
854
- & Should_Break.Kind'Image);
855
- end if ;
856
- Options.Should_Break := Should_Break.Get;
938
+ declare
939
+ JSON_Should_Break : constant JSON_Value :=
940
+ JSON.Get (" shouldBreak" );
941
+ begin
942
+ if JSON_Should_Break.Kind /= JSON_Boolean_Type then
943
+ Abort_Parsing
944
+ (Context,
945
+ " invalid group shouldBreak: "
946
+ & JSON_Should_Break.Kind'Image);
947
+ end if ;
948
+ Should_Break := JSON_Should_Break.Get;
949
+ end ;
857
950
end if ;
858
951
859
- -- TODO??? (eng/libadalang/langkit#727) Handle the group
860
- -- id .
952
+ -- If a symbol is given to identify this group, create an
953
+ -- internal symbol for it .
861
954
862
- return Pool.Create_Group (Document, Options);
955
+ if JSON.Has_Field (" id" ) then
956
+ declare
957
+ JSON_Id : constant JSON_Value := JSON.Get (" id" );
958
+ begin
959
+ if JSON_Id.Kind /= JSON_String_Type then
960
+ Abort_Parsing
961
+ (Context,
962
+ " invalid group id: "
963
+ & JSON_Id.Kind'Image);
964
+ end if ;
965
+
966
+ declare
967
+ Info : Symbol_Info renames
968
+ Lookup (JSON_Id.Get, Symbols, Symbol_Map);
969
+ begin
970
+ -- Ensure that there is no conflicting symbol
971
+ -- definition in this template.
972
+
973
+ if Info.Has_Definition then
974
+ Abort_Parsing
975
+ (Context,
976
+ " duplicate group id: " & JSON_Id.Get);
977
+ else
978
+ Info.Has_Definition := True;
979
+ end if ;
980
+ Id := Info.Template_Sym;
981
+ end ;
982
+ end ;
983
+ end if ;
984
+
985
+ return Pool.Create_Group (Document, Should_Break, Id);
863
986
end ;
864
987
865
988
elsif Kind = " ifBreak" then
@@ -869,6 +992,8 @@ package body Langkit_Support.Generic_API.Unparsing is
869
992
870
993
Contents_Context : Template_Parsing_Context := Context;
871
994
Flat_Context : Template_Parsing_Context := Context;
995
+
996
+ Group_Id : Template_Symbol := No_Template_Symbol;
872
997
begin
873
998
if not JSON.Has_Field (" breakContents" ) then
874
999
Abort_Parsing
@@ -878,12 +1003,16 @@ package body Langkit_Support.Generic_API.Unparsing is
878
1003
879
1004
Contents :=
880
1005
Parse_Template_Helper
881
- (JSON.Get (" breakContents" ), Contents_Context);
1006
+ (JSON.Get (" breakContents" ),
1007
+ Contents_Context,
1008
+ Symbol_Map);
882
1009
883
1010
Flat_Contents :=
884
1011
(if JSON.Has_Field (" flatContents" )
885
1012
then Parse_Template_Helper
886
- (JSON.Get (" flatContents" ), Flat_Context)
1013
+ (JSON.Get (" flatContents" ),
1014
+ Flat_Context,
1015
+ Symbol_Map)
887
1016
else null );
888
1017
889
1018
-- Unify the parsing state for both branches and update
@@ -897,10 +1026,28 @@ package body Langkit_Support.Generic_API.Unparsing is
897
1026
end if ;
898
1027
Context.State := Contents_Context.State;
899
1028
900
- -- TODO??? (eng/libadalang/langkit#727) Handle the group
901
- -- id.
1029
+ -- If present, get the symbol for the given group id
1030
+
1031
+ if JSON.Has_Field (" groupId" ) then
1032
+ declare
1033
+ JSON_Id : constant JSON_Value :=
1034
+ JSON.Get (" groupId" );
1035
+ begin
1036
+ if JSON_Id.Kind /= JSON_String_Type then
1037
+ Abort_Parsing
1038
+ (Context,
1039
+ " invalid group id: "
1040
+ & JSON_Id.Kind'Image);
1041
+ end if ;
1042
+
1043
+ Group_Id :=
1044
+ Lookup (JSON_Id.Get, Symbols, Symbol_Map)
1045
+ .Template_Sym;
1046
+ end ;
1047
+ end if ;
902
1048
903
- return Pool.Create_If_Break (Contents, Flat_Contents);
1049
+ return Pool.Create_If_Break
1050
+ (Contents, Flat_Contents, Group_Id);
904
1051
end ;
905
1052
906
1053
elsif Kind = " indent" then
@@ -909,7 +1056,8 @@ package body Langkit_Support.Generic_API.Unparsing is
909
1056
(Context, " missing "" contents"" key for indent" );
910
1057
end if ;
911
1058
return Pool.Create_Indent
912
- (Parse_Template_Helper (JSON.Get (" contents" ), Context));
1059
+ (Parse_Template_Helper
1060
+ (JSON.Get (" contents" ), Context, Symbol_Map));
913
1061
914
1062
elsif Kind = " recurse_field" then
915
1063
declare
@@ -1473,7 +1621,8 @@ package body Langkit_Support.Generic_API.Unparsing is
1473
1621
return Pool.Create_Group
1474
1622
(Instantiate_Template_Helper
1475
1623
(Pool, Node, Template.Group_Document, Arguments),
1476
- Template.Group_Options,
1624
+ Template.Group_Should_Break,
1625
+ Template.Group_Id,
1477
1626
Node);
1478
1627
1479
1628
when Hard_Line =>
0 commit comments