Skip to content

Commit 7ea84bf

Browse files
committed
Merge branch 'mr/pmderodat/unparsing-if-empty' into 'master'
Unparsing: introduce the ifEmpty template Closes #760 See merge request eng/libadalang/langkit!1013
2 parents a810056 + 5879a2e commit 7ea84bf

13 files changed

+308
-2
lines changed

langkit/support/langkit_support-generic_api-unparsing.adb

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,53 @@ package body Langkit_Support.Generic_API.Unparsing is
13511351
(Contents, Flat_Contents, Group_Id);
13521352
end;
13531353

1354+
elsif Kind = "ifEmpty" then
1355+
if Context.Kind /= Field_Template then
1356+
Abort_Parsing
1357+
(Context,
1358+
"""ifEmpty"" is valid only in field templates");
1359+
end if;
1360+
1361+
declare
1362+
Then_Contents : Document_Type;
1363+
Else_Contents : Document_Type;
1364+
1365+
Then_Context : Template_Parsing_Context := Context;
1366+
Else_Context : Template_Parsing_Context := Context;
1367+
begin
1368+
if not JSON.Has_Field ("then") then
1369+
Abort_Parsing
1370+
(Context,
1371+
"missing ""then"" key for ifEmpty");
1372+
end if;
1373+
Then_Contents :=
1374+
Parse_Template_Helper
1375+
(JSON.Get ("then"), Then_Context, Symbol_Map);
1376+
1377+
if not JSON.Has_Field ("else") then
1378+
Abort_Parsing
1379+
(Context,
1380+
"missing ""else"" key for ifEmpty");
1381+
end if;
1382+
Else_Contents :=
1383+
Parse_Template_Helper
1384+
(JSON.Get ("else"), Else_Context, Symbol_Map);
1385+
1386+
-- Unify the parsing state for both branches and update
1387+
-- Context accordingly.
1388+
1389+
if Then_Context.State /= Else_Context.State then
1390+
Abort_Parsing
1391+
(Context,
1392+
"ifEmpty alternatives have inconsistent recurse"
1393+
& " structure");
1394+
end if;
1395+
Context.State := Else_Context.State;
1396+
1397+
return Pool.Create_If_Empty
1398+
(Then_Contents, Else_Contents);
1399+
end;
1400+
13541401
elsif Kind = "indent" then
13551402
if not JSON.Has_Field ("contents") then
13561403
Abort_Parsing
@@ -1926,6 +1973,19 @@ package body Langkit_Support.Generic_API.Unparsing is
19261973
(Pool, Node, Template.If_Break_Flat_Contents, Arguments),
19271974
Template.If_Break_Group_Id);
19281975

1976+
when If_Empty =>
1977+
declare
1978+
Child : constant Lk_Node :=
1979+
Arguments.With_Recurse_Doc.Node;
1980+
Subtemplate : constant Document_Type :=
1981+
(if Child.Is_List_Node and then Child.Children_Count = 0
1982+
then Template.If_Empty_Then
1983+
else Template.If_Empty_Else);
1984+
begin
1985+
return Instantiate_Template_Helper
1986+
(Pool, Node, Subtemplate, Arguments);
1987+
end;
1988+
19291989
when Indent =>
19301990
return Pool.Create_Indent
19311991
(Instantiate_Template_Helper

langkit/support/langkit_support-generic_api-unparsing.ads

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,16 @@ package Langkit_Support.Generic_API.Unparsing is
189189
-- "groupId": <symbol>
190190
-- }
191191
--
192+
-- * The "ifEmpty" template is valid only inside a fields configuration.
193+
-- It yields its "then" alternative if the field is an empty list, and
194+
-- its "else" alternative otherwise::
195+
--
196+
-- {
197+
-- "kind": "ifEmpty",
198+
-- "then": <sub-template>,
199+
-- "else": <sub-template>
200+
-- }
201+
--
192202
-- * The "indent" template yields an "indent" Prettier document::
193203
--
194204
-- {"kind": "indent", "contents": <sub-template>}

langkit/support/langkit_support-prettier_utils.adb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ package body Langkit_Support.Prettier_Utils is
142142
(Group_Id => To_Prettier_Symbol
143143
(Symbol_Map, Document.If_Break_Group_Id)));
144144

145+
when If_Empty =>
146+
raise Program_Error with "uninstantiated template";
147+
145148
when Indent =>
146149
return Indent (Recurse (Document.Indent_Document));
147150

@@ -368,6 +371,25 @@ package body Langkit_Support.Prettier_Utils is
368371
end return;
369372
end Create_If_Break;
370373

374+
---------------------
375+
-- Create_If_Empty --
376+
---------------------
377+
378+
function Create_If_Empty
379+
(Self : in out Document_Pool;
380+
Then_Contents : Document_Type;
381+
Else_Contents : Document_Type) return Document_Type is
382+
begin
383+
return Result : constant Document_Type :=
384+
new Document_Record'
385+
(Kind => If_Empty,
386+
If_Empty_Then => Then_Contents,
387+
If_Empty_Else => Else_Contents)
388+
do
389+
Self.Register (Result);
390+
end return;
391+
end Create_If_Empty;
392+
371393
-------------------
372394
-- Create_Indent --
373395
-------------------
@@ -688,6 +710,9 @@ package body Langkit_Support.Prettier_Utils is
688710
Last_Spacing := Spacing_Kind'Min (LS_Break, LS_Flat);
689711
end;
690712

713+
when If_Empty =>
714+
raise Program_Error;
715+
691716
when Indent =>
692717

693718
-- Indent does not emit any spacing before processing its inner
@@ -861,6 +886,11 @@ package body Langkit_Support.Prettier_Utils is
861886
Process (Document.If_Break_Contents, Prefix & List_Indent);
862887
Process (Document.If_Break_Flat_Contents, Prefix & List_Indent);
863888

889+
when If_Empty =>
890+
Put_Line ("ifEmpty:");
891+
Process (Document.If_Empty_Then, Prefix & List_Indent);
892+
Process (Document.If_Empty_Else, Prefix & List_Indent);
893+
864894
when Indent =>
865895
Put_Line ("indent:");
866896
Process (Document.Indent_Document, Prefix & Simple_Indent);

langkit/support/langkit_support-prettier_utils.ads

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ private package Langkit_Support.Prettier_Utils is
6363
Hard_Line,
6464
Hard_Line_Without_Break_Parent,
6565
If_Break,
66+
If_Empty,
6667
Indent,
6768
Line,
6869
List,
@@ -102,6 +103,10 @@ private package Langkit_Support.Prettier_Utils is
102103
If_Break_Flat_Contents : Document_Type;
103104
If_Break_Group_Id : Template_Symbol;
104105

106+
when If_Empty =>
107+
If_Empty_Then : Document_Type;
108+
If_Empty_Else : Document_Type;
109+
105110
when Indent =>
106111
Indent_Document : Document_Type;
107112

@@ -234,6 +239,12 @@ private package Langkit_Support.Prettier_Utils is
234239
return Document_Type;
235240
-- Return an ``If_Break`` node
236241

242+
function Create_If_Empty
243+
(Self : in out Document_Pool;
244+
Then_Contents : Document_Type;
245+
Else_Contents : Document_Type) return Document_Type;
246+
-- Return an ``If_Empty`` node
247+
237248
function Create_Indent
238249
(Self : in out Document_Pool;
239250
Document : Document_Type) return Document_Type;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"node_configs": {
3+
"FunDecl": {
4+
"fields": {
5+
"f_args": {
6+
"kind": "ifEmpty",
7+
"then": ["softline", "recurse"],
8+
"else": [
9+
{
10+
"kind": "indent",
11+
"contents": ["hardline", "recurse"]
12+
},
13+
"hardline"
14+
]
15+
}
16+
}
17+
}
18+
}
19+
}
20+

testsuite/tests/ada_api/unparsing/commands.adb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ begin
158158
Check ("cmd_hardline.json");
159159
Check ("cmd_hardlinewithoutbreakparent.json");
160160
Check ("cmd_ifbreak.json");
161+
Check ("cmd_ifempty.json", "def f(): Int {i;}");
162+
Check ("cmd_ifempty.json", "def f(i: Int): Int {i;}");
161163
Check ("cmd_indent.json");
162164
Check ("cmd_line.json");
163165
Check ("cmd_list.json");

testsuite/tests/ada_api/unparsing/expected_concrete_syntax.lkt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ grammar foo_grammar {
1313
fun_decl <- FunDecl(
1414
"def"
1515
name
16-
?pick("("
17-
list+(param_spec, ",")
16+
pick("("
17+
list*(param_spec, ",")
1818
")") ":" type_ref "{" list*(stmt) "}"
1919
)
2020
stmt <- Stmt(expr ";")

testsuite/tests/ada_api/unparsing/invalid_config.adb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ begin
6363
Check ("invalid_ifbreak.json");
6464
Check ("invalid_ifbreak2.json");
6565
Check ("invalid_ifbreak3.json");
66+
Check ("invalid_ifempty.json");
67+
Check ("invalid_ifempty2.json");
68+
Check ("invalid_ifempty3.json");
6669
Check ("invalid_indent.json");
6770
Check ("invalid_markasroot.json");
6871
Check ("invalid_innerroot.json");
@@ -91,6 +94,7 @@ begin
9194
Check ("recurse_whitespace.json");
9295
Check ("recurse_indent_too_few.json");
9396
Check ("recurse_indent_too_many.json");
97+
Check ("recurse_if_empty.json");
9498
New_Line;
9599

96100
Put_Line ("Done.");
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"node_configs": {
3+
"VarDecl": {
4+
"fields": {
5+
"f_name": {
6+
"kind": "ifEmpty",
7+
"then": "recurse"
8+
}
9+
}
10+
}
11+
}
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"node_configs": {
3+
"VarDecl": {
4+
"fields": {
5+
"f_name": {
6+
"kind": "ifEmpty",
7+
"else": "recurse"
8+
}
9+
}
10+
}
11+
}
12+
}

0 commit comments

Comments
 (0)