Skip to content

Commit e2f68bb

Browse files
committed
Introduce the "is_comment" trivia annotation
This new annotation will allow unparsers to determine which trivia should be preserve during unparsing (no trivia is preserve right now).
1 parent e670f4d commit e2f68bb

File tree

11 files changed

+77
-17
lines changed

11 files changed

+77
-17
lines changed

langkit/lexer/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ def c_name(self) -> str:
240240
prefixed_name = get_context().lang_name + self.base_name
241241
return prefixed_name.upper
242242

243+
@property
244+
def is_comment(self) -> bool:
245+
return isinstance(self, WithTrivia) and self._is_comment
246+
243247
def __repr__(self) -> str:
244248
assert self.name is not None
245249
return '<{} {}>'.format(type(self).__name__,
@@ -271,6 +275,19 @@ class MyToken(LexerToken):
271275
"""
272276
is_trivia: bool = True
273277

278+
def __init__(
279+
self,
280+
start_ignore_layout: bool = False,
281+
end_ignore_layout: bool = False,
282+
comment: bool = False,
283+
):
284+
"""
285+
:param comment: Whether unparsing must treat this token as a comment,
286+
i.e. a trivia to preserve in unparsed sources.
287+
"""
288+
super().__init__(start_ignore_layout, end_ignore_layout)
289+
self._is_comment = comment
290+
274291

275292
class WithSymbol(TokenAction):
276293
"""

langkit/lkt_lowering.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -846,27 +846,37 @@ def interpret(
846846
scope: Scope,
847847
) -> Any:
848848
check_source_language(not args, 'No positional argument allowed')
849+
result: dict[str, Any] = {}
849850

850851
try:
851852
expr = kwargs.pop('start_ignore_layout')
852853
except KeyError:
853-
start_ignore_layout = False
854+
result["start_ignore_layout"] = False
854855
else:
855-
start_ignore_layout = parse_static_bool(ctx, expr)
856+
result["start_ignore_layout"] = parse_static_bool(ctx, expr)
856857

857858
try:
858859
expr = kwargs.pop('end_ignore_layout')
859860
except KeyError:
860-
end_ignore_layout = False
861+
result["end_ignore_layout"] = False
861862
else:
862-
end_ignore_layout = parse_static_bool(ctx, expr)
863+
result["end_ignore_layout"] = parse_static_bool(ctx, expr)
864+
865+
# The "comment" argument is valid for trivia tokens only
866+
if self.name == "trivia":
867+
try:
868+
expr = kwargs.pop("comment")
869+
except KeyError:
870+
result["comment"] = False
871+
else:
872+
result["comment"] = parse_static_bool(ctx, expr)
863873

864874
check_source_language(
865875
not kwargs,
866876
'Invalid arguments: {}'.format(', '.join(sorted(kwargs)))
867877
)
868878

869-
return (start_ignore_layout, end_ignore_layout)
879+
return result
870880

871881

872882
class WithLexerAnnotationSpec(AnnotationSpec):
@@ -1452,15 +1462,17 @@ def process_token_rule(
14521462
# Gather token action info from the annotations. If absent,
14531463
# fallback to WithText.
14541464
token_cons = None
1455-
start_ignore_layout = False
1456-
end_ignore_layout = False
1465+
cons_kwargs = {
1466+
"start_ignore_layout": False,
1467+
"end_ignore_layout": False,
1468+
}
14571469
if rule_annot.ignore:
14581470
token_cons = ignore_constructor
14591471
for name in ('text', 'trivia', 'symbol'):
14601472
annot = getattr(rule_annot, name)
14611473
if not annot:
14621474
continue
1463-
start_ignore_layout, end_ignore_layout = annot
1475+
cons_kwargs.update(annot)
14641476

14651477
check_source_language(token_cons is None,
14661478
'At most one token action allowed')
@@ -1486,7 +1498,7 @@ def process_token_rule(
14861498
check_source_language(token_name not in tokens,
14871499
'Duplicate token name')
14881500

1489-
token = token_cons(start_ignore_layout, end_ignore_layout)
1501+
token = token_cons(**cons_kwargs)
14901502
if token_name is not None:
14911503
tokens[token_name] = token
14921504
if isinstance(token, TokenAction):

langkit/support/langkit_support-generic_api.adb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,16 @@ package body Langkit_Support.Generic_API is
148148
return Create_Name (Kind.Id.Token_Kinds (Kind.Index).Name.all);
149149
end Token_Kind_Name;
150150

151+
----------------
152+
-- Is_Comment --
153+
----------------
154+
155+
function Is_Comment (Kind : Token_Kind_Ref) return Boolean is
156+
begin
157+
Check_Token_Kind (Kind);
158+
return Kind.Id.Token_Kinds (Kind.Index).Is_Comment;
159+
end Is_Comment;
160+
151161
--------------
152162
-- To_Index --
153163
--------------

langkit/support/langkit_support-generic_api.ads

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@ package Langkit_Support.Generic_API is
120120
-- Return the name for the given token kind. Raise a
121121
-- ``Precondition_Failure`` exception if ``Kind`` is ``No_Token_Kind_Ref``.
122122

123+
function Is_Comment (Kind : Token_Kind_Ref) return Boolean;
124+
-- Return whether unparsing must treat the given token kind as a comment,
125+
-- i.e. a trivia to preserve in unparsed sources. Raise a
126+
-- ``Precondition_Failure`` exception if ``Kind`` is ``No_Token_Kind_Ref``.
127+
123128
type Any_Token_Kind_Index is new Natural;
124129
subtype Token_Kind_Index is
125130
Any_Token_Kind_Index range 1 .. Any_Token_Kind_Index'Last;

langkit/support/langkit_support-internal.ads

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ package Langkit_Support.Internal is
2626
-- Descriptors for token kinds
2727

2828
type Token_Kind_Descriptor is record
29-
Name : Text_Access;
30-
Family : Token_Family_Index;
29+
Name : Text_Access;
30+
Family : Token_Family_Index;
31+
Is_Comment : Boolean;
3132
end record;
3233
type Token_Kind_Descriptor_Array is
3334
array (Token_Kind_Index range <>) of Token_Kind_Descriptor;

langkit/templates/pkg_generic_impl_spec_ada.mako

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,9 @@ private package ${ada_lib_name}.Generic_Impl is
8080
family = ctx.lexer.tokens.token_to_family[token]
8181
lines += [
8282
f"{G.token_kind_index(token)} =>",
83-
f" (Name => {name}'Access,",
84-
f" Family => {G.token_family_index(family)})",
83+
f" (Name => {name}'Access,",
84+
f" Family => {G.token_family_index(family)},",
85+
f" Is_Comment => {token.is_comment})",
8586
]
8687
%>
8788
${name} : aliased constant Text_Type :=

testsuite/python_support/lexer_example.lkt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ lexer foo_lexer {
4545

4646
family comments {
4747
@unparse_newline_after
48-
@trivia()
48+
@trivia(comment=true)
4949
comment <- p"#(.?)+"
5050
}
5151

testsuite/tests/ada_api/generic_api/analysis.adb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,11 @@ begin
7373
Family_Name : constant Text_Type :=
7474
Format_Name (Token_Family_Name (Family), Camel_With_Underscores);
7575
begin
76-
Put_Line
77-
(" " & Image (Kind_Name) & " (" & Image (Family_Name) & ")");
76+
Put (" " & Image (Kind_Name) & " (" & Image (Family_Name));
77+
if Is_Comment (Kind) then
78+
Put (", is_comment");
79+
end if;
80+
Put_Line (")");
7881
end;
7982
end loop;
8083
New_Line;

testsuite/tests/ada_api/generic_api/test.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Token kinds:
4343
Number (Alphanumericals)
4444
Identifier (Alphanumericals)
4545
String (Default_Family)
46-
Comment (Comments)
46+
Comment (Comments, is_comment)
4747

4848
Token families:
4949
Alphanumericals

testsuite/tests/grammar/invalid_lexers/test.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ token_action_5.lkt:4:5: error: At most one token action allowed
169169
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
170170

171171

172+
== token_action_6.lkt ==
173+
token_action_6.lkt:4:5: error: Invalid arguments: comment
174+
4 | @text(comment=false) example <- "example"
175+
| ^^^^^^^^^^^^^^^^^^^^
176+
177+
172178
== token_matcher.lkt ==
173179
token_matcher.lkt:4:16: error: Invalid lexing expression
174180
4 | example <- /

0 commit comments

Comments
 (0)