Skip to content

Commit bf2d7d2

Browse files
[Fix] Apply the GrammarNormalizer to grammars generated from stags. (#429)
This PR applies `GrammarNormalizer` to grammars generated from stags to improve the efficiency at runtime. --------- Signed-off-by: Yuchuan <[email protected]>
1 parent f43b36b commit bf2d7d2

File tree

3 files changed

+59
-69
lines changed

3 files changed

+59
-69
lines changed

cpp/structural_tag.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1020,7 +1020,7 @@ Result<Grammar, StructuralTagError> StructuralTagToGrammar(const std::string& st
10201020
if (result.IsErr()) {
10211021
return ResultErr(std::move(result).UnwrapErr());
10221022
}
1023-
return ResultOk(std::move(result).Unwrap());
1023+
return ResultOk(GrammarNormalizer::Apply(std::move(result).Unwrap()));
10241024
}
10251025

10261026
} // namespace xgrammar

tests/python/test_grammar_matcher_structural_tag.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,22 @@ class Schema(BaseModel):
4242
basic_integer ::= (("0") | (basic_integer_1 [1-9] [0-9]*))
4343
basic_string ::= (("\"" basic_string_sub)) (=(root_part_0 [ \n\t]* "}"))
4444
root_part_0 ::= (([ \n\t]* "," [ \n\t]* "\"arg2\"" [ \n\t]* ":" [ \n\t]* basic_integer)) (=([ \n\t]* "}"))
45-
root ::= (("{" [ \n\t]* "\"arg1\"" [ \n\t]* ":" [ \n\t]* basic_string root_part_0 [ \n\t]* "}"))
45+
root ::= (("{" [ \n\t]* "\"arg1\"" [ \n\t]* ":" [ \n\t]* basic_string root_part_0 [ \n\t]* "}")) (=("</function>"))
4646
basic_integer_1 ::= ("" | ("-")) (=([1-9] [0-9]*))
4747
basic_escape_1 ::= (([\"\\/bfnrt]) | ("u" [A-Fa-f0-9] [A-Fa-f0-9] [A-Fa-f0-9] [A-Fa-f0-9])) (=(basic_string_sub_1))
4848
basic_string_sub_1 ::= (("\"") | ([^\0-\x1f\"\\\r\n] basic_string_sub_1) | ("\\" basic_escape_1 basic_string_sub_1)) (=([ \n\t]* [,}\]:]))
4949
basic_integer_2 ::= (("0") | (basic_integer_1_1 [1-9] [0-9]*))
5050
basic_string_1 ::= (("\"" basic_string_sub_1)) (=(root_part_0_1 [ \n\t]* "}"))
5151
root_part_0_1 ::= (([ \n\t]* "," [ \n\t]* "\"arg2\"" [ \n\t]* ":" [ \n\t]* basic_integer_2)) (=([ \n\t]* "}"))
52-
root_1 ::= (("{" [ \n\t]* "\"arg1\"" [ \n\t]* ":" [ \n\t]* basic_string_1 root_part_0_1 [ \n\t]* "}"))
52+
root_1 ::= (("{" [ \n\t]* "\"arg1\"" [ \n\t]* ":" [ \n\t]* basic_string_1 root_part_0_1 [ \n\t]* "}")) (=("</function>"))
5353
basic_integer_1_1 ::= ("" | ("-")) (=([1-9] [0-9]*))
5454
basic_escape_2 ::= (([\"\\/bfnrt]) | ("u" [A-Fa-f0-9] [A-Fa-f0-9] [A-Fa-f0-9] [A-Fa-f0-9])) (=(basic_string_sub_2))
5555
basic_string_sub_2 ::= (("\"") | ([^\0-\x1f\"\\\r\n] basic_string_sub_2) | ("\\" basic_escape_2 basic_string_sub_2)) (=([ \n\t]* [,}\]:]))
5656
basic_number ::= ((basic_number_7 basic_number_3 basic_number_6)) (=(root_part_0_2 [ \n\t]* "}"))
5757
basic_string_2 ::= (("\"" basic_string_sub_2))
5858
root_prop_1 ::= (("[" [ \n\t]* basic_string_2 root_prop_1_1 [ \n\t]* "]") | ("[" [ \n\t]* "]"))
5959
root_part_0_2 ::= (([ \n\t]* "," [ \n\t]* "\"arg4\"" [ \n\t]* ":" [ \n\t]* root_prop_1)) (=([ \n\t]* "}"))
60-
root_2 ::= (("{" [ \n\t]* "\"arg3\"" [ \n\t]* ":" [ \n\t]* basic_number root_part_0_2 [ \n\t]* "}"))
60+
root_2 ::= (("{" [ \n\t]* "\"arg3\"" [ \n\t]* ":" [ \n\t]* basic_number root_part_0_2 [ \n\t]* "}")) (=("</function>"))
6161
basic_number_1 ::= ("" | ("-")) (=([1-9] [0-9]*))
6262
basic_number_2 ::= (([0-9] basic_number_2) | ([0-9]))
6363
basic_number_3 ::= ("" | ("." basic_number_2)) (=(basic_number_6))
@@ -98,7 +98,6 @@ class Schema2(BaseModel):
9898
triggers = ["<function=f", "<function=g"]
9999

100100
grammar = xgr.Grammar.from_structural_tag(tags, triggers)
101-
102101
assert str(grammar) == expected_grammar_test_structural_tag
103102

104103
accepted_inputs = [

tests/python/test_structural_tag_converter.py

Lines changed: 55 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,7 @@ def check_stag_with_instance(
7272
const_string_stag_grammar = [
7373
(
7474
{"type": "const_string", "value": "Hello!"},
75-
r"""const_string ::= (("Hello!"))
76-
root ::= ((const_string))
75+
r"""root ::= (("Hello!"))
7776
""",
7877
)
7978
]
@@ -178,8 +177,7 @@ def test_qwen_parameter_xml_format(
178177
{"type": "json_schema", "json_schema": {"type": "number"}},
179178
],
180179
},
181-
r"""const_string ::= (("Hello!"))
182-
basic_number ::= ((basic_number_7 basic_number_3 basic_number_6))
180+
r"""basic_number ::= ((basic_number_7 basic_number_3 basic_number_6))
183181
root ::= ((basic_number))
184182
basic_number_1 ::= ("" | ("-")) (=([1-9] [0-9]*))
185183
basic_number_2 ::= (([0-9] basic_number_2) | ([0-9]))
@@ -188,7 +186,7 @@ def test_qwen_parameter_xml_format(
188186
basic_number_5 ::= (([0-9] basic_number_5) | ([0-9]))
189187
basic_number_6 ::= ("" | ([eE] basic_number_4 basic_number_5))
190188
basic_number_7 ::= (("0") | (basic_number_1 [1-9] [0-9]*)) (=(basic_number_3 basic_number_6))
191-
sequence ::= ((const_string root))
189+
sequence ::= (("Hello!" root))
192190
root_1 ::= ((sequence))
193191
""",
194192
)
@@ -222,8 +220,7 @@ def test_sequence_format(
222220
{"type": "json_schema", "json_schema": {"type": "number"}},
223221
],
224222
},
225-
r"""const_string ::= (("Hello!"))
226-
basic_number ::= ((basic_number_7 basic_number_3 basic_number_6))
223+
r"""basic_number ::= ((basic_number_7 basic_number_3 basic_number_6))
227224
root ::= ((basic_number))
228225
basic_number_1 ::= ("" | ("-")) (=([1-9] [0-9]*))
229226
basic_number_2 ::= (([0-9] basic_number_2) | ([0-9]))
@@ -232,7 +229,7 @@ def test_sequence_format(
232229
basic_number_5 ::= (([0-9] basic_number_5) | ([0-9]))
233230
basic_number_6 ::= ("" | ([eE] basic_number_4 basic_number_5))
234231
basic_number_7 ::= (("0") | (basic_number_1 [1-9] [0-9]*)) (=(basic_number_3 basic_number_6))
235-
or ::= ((const_string) | (root))
232+
or ::= (("Hello!") | (root))
236233
root_1 ::= ((or))
237234
""",
238235
)
@@ -266,7 +263,7 @@ def test_or_format(
266263
"end": "END",
267264
},
268265
r"""basic_number ::= ((basic_number_7 basic_number_3 basic_number_6))
269-
root ::= ((basic_number))
266+
root ::= ((basic_number)) (=("END"))
270267
basic_number_1 ::= ("" | ("-")) (=([1-9] [0-9]*))
271268
basic_number_2 ::= (([0-9] basic_number_2) | ([0-9]))
272269
basic_number_3 ::= ("" | ("." basic_number_2)) (=(basic_number_6))
@@ -334,8 +331,7 @@ def test_any_text_format(
334331
any_text_only_stag_grammar = [
335332
(
336333
{"type": "any_text"},
337-
r"""any_text ::= (([\0-\U0010ffff]*))
338-
root ::= ((any_text))
334+
r"""root ::= (([\0-\U0010ffff]*))
339335
""",
340336
)
341337
]
@@ -370,8 +366,8 @@ def _get_triggered_tag_format(at_least_one: bool, stop_after_first: bool):
370366
(
371367
0,
372368
_get_triggered_tag_format(at_least_one=False, stop_after_first=False),
373-
r"""const_string ::= (("L1"))
374-
const_string_1 ::= (("L2"))
369+
r"""const_string ::= (("L1")) (=("A"))
370+
const_string_1 ::= (("L2")) (=("A"))
375371
triggered_tags_group ::= (("1" const_string "A") | ("2" const_string_1 "A"))
376372
triggered_tags ::= TagDispatch(
377373
("A", triggered_tags_group),
@@ -388,7 +384,7 @@ def _get_triggered_tag_format(at_least_one: bool, stop_after_first: bool):
388384
r"""const_string ::= (("L1"))
389385
const_string_1 ::= (("L2"))
390386
triggered_tags_group ::= (("1" const_string "A") | ("2" const_string_1 "A"))
391-
triggered_tags_first ::= (("A1" const_string "A") | ("A2" const_string_1 "A"))
387+
triggered_tags_first ::= (("A1" const_string "A") | ("A2" const_string_1 "A")) (=(triggered_tags_sub))
392388
triggered_tags_sub ::= TagDispatch(
393389
("A", triggered_tags_group),
394390
stop_eos=true,
@@ -402,8 +398,8 @@ def _get_triggered_tag_format(at_least_one: bool, stop_after_first: bool):
402398
(
403399
2,
404400
_get_triggered_tag_format(at_least_one=False, stop_after_first=True),
405-
r"""const_string ::= (("L1"))
406-
const_string_1 ::= (("L2"))
401+
r"""const_string ::= (("L1")) (=("A"))
402+
const_string_1 ::= (("L2")) (=("A"))
407403
triggered_tags_group ::= (("1" const_string "A") | ("2" const_string_1 "A"))
408404
triggered_tags ::= TagDispatch(
409405
("A", triggered_tags_group),
@@ -417,8 +413,8 @@ def _get_triggered_tag_format(at_least_one: bool, stop_after_first: bool):
417413
(
418414
3,
419415
_get_triggered_tag_format(at_least_one=True, stop_after_first=True),
420-
r"""const_string ::= (("L1"))
421-
const_string_1 ::= (("L2"))
416+
r"""const_string ::= (("L1")) (=("A"))
417+
const_string_1 ::= (("L2")) (=("A"))
422418
triggered_tags ::= (("A1" const_string "A") | ("A2" const_string_1 "A"))
423419
root ::= ((triggered_tags))
424420
""",
@@ -466,8 +462,7 @@ def test_triggered_tag_format(
466462
}
467463
],
468464
},
469-
r"""const_string ::= (("[TEXT]"))
470-
triggered_tags_group ::= (("" const_string "<end>"))
465+
r"""triggered_tags_group ::= (("[TEXT]" "<end>"))
471466
triggered_tags ::= TagDispatch(
472467
("<start>", triggered_tags_group),
473468
stop_eos=true,
@@ -527,8 +522,8 @@ def _get_triggered_tag_with_outside_tag(at_least_one: bool, stop_after_first: bo
527522
(
528523
0,
529524
_get_triggered_tag_with_outside_tag(at_least_one=False, stop_after_first=False),
530-
r"""const_string ::= (("L1"))
531-
const_string_1 ::= (("L2"))
525+
r"""const_string ::= (("L1")) (=("A"))
526+
const_string_1 ::= (("L2")) (=("A"))
532527
triggered_tags_group ::= (("1" const_string "A") | ("2" const_string_1 "A"))
533528
triggered_tags ::= TagDispatch(
534529
("A", triggered_tags_group),
@@ -546,7 +541,7 @@ def _get_triggered_tag_with_outside_tag(at_least_one: bool, stop_after_first: bo
546541
r"""const_string ::= (("L1"))
547542
const_string_1 ::= (("L2"))
548543
triggered_tags_group ::= (("1" const_string "A") | ("2" const_string_1 "A"))
549-
triggered_tags_first ::= (("A1" const_string "A") | ("A2" const_string_1 "A"))
544+
triggered_tags_first ::= (("A1" const_string "A") | ("A2" const_string_1 "A")) (=(triggered_tags_sub))
550545
triggered_tags_sub ::= TagDispatch(
551546
("A", triggered_tags_group),
552547
stop_eos=false,
@@ -561,8 +556,8 @@ def _get_triggered_tag_with_outside_tag(at_least_one: bool, stop_after_first: bo
561556
(
562557
2,
563558
_get_triggered_tag_with_outside_tag(at_least_one=False, stop_after_first=True),
564-
r"""const_string ::= (("L1"))
565-
const_string_1 ::= (("L2"))
559+
r"""const_string ::= (("L1")) (=("A"))
560+
const_string_1 ::= (("L2")) (=("A"))
566561
triggered_tags_group ::= (("1" const_string "A") | ("2" const_string_1 "A"))
567562
triggered_tags ::= TagDispatch(
568563
("A", triggered_tags_group),
@@ -577,9 +572,9 @@ def _get_triggered_tag_with_outside_tag(at_least_one: bool, stop_after_first: bo
577572
(
578573
3,
579574
_get_triggered_tag_with_outside_tag(at_least_one=True, stop_after_first=True),
580-
r"""const_string ::= (("L1"))
581-
const_string_1 ::= (("L2"))
582-
triggered_tags_sub ::= (("A1" const_string "A") | ("A2" const_string_1 "A"))
575+
r"""const_string ::= (("L1")) (=("A"))
576+
const_string_1 ::= (("L2")) (=("A"))
577+
triggered_tags_sub ::= (("A1" const_string "A") | ("A2" const_string_1 "A")) (=("end"))
583578
triggered_tags ::= ((triggered_tags_sub "end"))
584579
tag ::= (("begin" triggered_tags))
585580
root ::= ((tag))
@@ -632,47 +627,47 @@ def _get_tags_with_separator_format(at_least_one: bool, stop_after_first: bool):
632627
(
633628
0,
634629
_get_tags_with_separator_format(at_least_one=False, stop_after_first=False),
635-
r"""const_string ::= (("L1"))
630+
r"""const_string ::= (("L1")) (=("A"))
636631
tag ::= (("A1" const_string "A"))
637-
const_string_1 ::= (("L2"))
632+
const_string_1 ::= (("L2")) (=("A"))
638633
tag_1 ::= (("A2" const_string_1 "A"))
639634
tags_with_separator_tags ::= ((tag) | (tag_1))
640-
tags_with_separator_sub ::= (("AA" tags_with_separator_tags tags_with_separator_sub) | "")
641-
tags_with_separator ::= ((tags_with_separator_tags tags_with_separator_sub) | "")
635+
tags_with_separator_sub ::= ("" | ("AA" tags_with_separator_tags tags_with_separator_sub))
636+
tags_with_separator ::= ("" | (tags_with_separator_tags tags_with_separator_sub))
642637
root ::= ((tags_with_separator))
643638
""",
644639
),
645640
(
646641
1,
647642
_get_tags_with_separator_format(at_least_one=True, stop_after_first=False),
648-
r"""const_string ::= (("L1"))
643+
r"""const_string ::= (("L1")) (=("A"))
649644
tag ::= (("A1" const_string "A"))
650-
const_string_1 ::= (("L2"))
645+
const_string_1 ::= (("L2")) (=("A"))
651646
tag_1 ::= (("A2" const_string_1 "A"))
652647
tags_with_separator_tags ::= ((tag) | (tag_1))
653-
tags_with_separator_sub ::= (("AA" tags_with_separator_tags tags_with_separator_sub) | "")
648+
tags_with_separator_sub ::= ("" | ("AA" tags_with_separator_tags tags_with_separator_sub))
654649
tags_with_separator ::= ((tags_with_separator_tags tags_with_separator_sub))
655650
root ::= ((tags_with_separator))
656651
""",
657652
),
658653
(
659654
2,
660655
_get_tags_with_separator_format(at_least_one=False, stop_after_first=True),
661-
r"""const_string ::= (("L1"))
656+
r"""const_string ::= (("L1")) (=("A"))
662657
tag ::= (("A1" const_string "A"))
663-
const_string_1 ::= (("L2"))
658+
const_string_1 ::= (("L2")) (=("A"))
664659
tag_1 ::= (("A2" const_string_1 "A"))
665660
tags_with_separator_tags ::= ((tag) | (tag_1))
666-
tags_with_separator ::= ((tags_with_separator_tags) | "")
661+
tags_with_separator ::= ("" | (tags_with_separator_tags))
667662
root ::= ((tags_with_separator))
668663
""",
669664
),
670665
(
671666
3,
672667
_get_tags_with_separator_format(at_least_one=True, stop_after_first=True),
673-
r"""const_string ::= (("L1"))
668+
r"""const_string ::= (("L1")) (=("A"))
674669
tag ::= (("A1" const_string "A"))
675-
const_string_1 ::= (("L2"))
670+
const_string_1 ::= (("L2")) (=("A"))
676671
tag_1 ::= (("A2" const_string_1 "A"))
677672
tags_with_separator_tags ::= ((tag) | (tag_1))
678673
tags_with_separator ::= ((tags_with_separator_tags))
@@ -729,9 +724,9 @@ def _get_tags_with_separator_format_with_outside_tag(at_least_one: bool, stop_af
729724
_get_tags_with_separator_format_with_outside_tag(
730725
at_least_one=False, stop_after_first=False
731726
),
732-
r"""const_string ::= (("L1"))
727+
r"""const_string ::= (("L1")) (=("A"))
733728
tag ::= (("A1" const_string "A"))
734-
const_string_1 ::= (("L2"))
729+
const_string_1 ::= (("L2")) (=("A"))
735730
tag_1 ::= (("A2" const_string_1 "A"))
736731
tags_with_separator_tags ::= ((tag) | (tag_1))
737732
tags_with_separator_sub ::= (("AA" tags_with_separator_tags tags_with_separator_sub) | ("end"))
@@ -743,9 +738,9 @@ def _get_tags_with_separator_format_with_outside_tag(at_least_one: bool, stop_af
743738
(
744739
1,
745740
_get_tags_with_separator_format_with_outside_tag(at_least_one=True, stop_after_first=False),
746-
r"""const_string ::= (("L1"))
741+
r"""const_string ::= (("L1")) (=("A"))
747742
tag ::= (("A1" const_string "A"))
748-
const_string_1 ::= (("L2"))
743+
const_string_1 ::= (("L2")) (=("A"))
749744
tag_1 ::= (("A2" const_string_1 "A"))
750745
tags_with_separator_tags ::= ((tag) | (tag_1))
751746
tags_with_separator_sub ::= (("AA" tags_with_separator_tags tags_with_separator_sub) | ("end"))
@@ -757,11 +752,11 @@ def _get_tags_with_separator_format_with_outside_tag(at_least_one: bool, stop_af
757752
(
758753
2,
759754
_get_tags_with_separator_format_with_outside_tag(at_least_one=False, stop_after_first=True),
760-
r"""const_string ::= (("L1"))
755+
r"""const_string ::= (("L1")) (=("A"))
761756
tag ::= (("A1" const_string "A"))
762-
const_string_1 ::= (("L2"))
757+
const_string_1 ::= (("L2")) (=("A"))
763758
tag_1 ::= (("A2" const_string_1 "A"))
764-
tags_with_separator_tags ::= ((tag) | (tag_1))
759+
tags_with_separator_tags ::= ((tag) | (tag_1)) (=("end"))
765760
tags_with_separator ::= ((tags_with_separator_tags "end") | ("end"))
766761
tag_2 ::= (("begin" tags_with_separator))
767762
root ::= ((tag_2))
@@ -770,11 +765,11 @@ def _get_tags_with_separator_format_with_outside_tag(at_least_one: bool, stop_af
770765
(
771766
3,
772767
_get_tags_with_separator_format_with_outside_tag(at_least_one=True, stop_after_first=True),
773-
r"""const_string ::= (("L1"))
768+
r"""const_string ::= (("L1")) (=("A"))
774769
tag ::= (("A1" const_string "A"))
775-
const_string_1 ::= (("L2"))
770+
const_string_1 ::= (("L2")) (=("A"))
776771
tag_1 ::= (("A2" const_string_1 "A"))
777-
tags_with_separator_tags ::= ((tag) | (tag_1))
772+
tags_with_separator_tags ::= ((tag) | (tag_1)) (=("end"))
778773
tags_with_separator ::= ((tags_with_separator_tags "end"))
779774
tag_2 ::= (("begin" tags_with_separator))
780775
root ::= ((tag_2))
@@ -1049,13 +1044,12 @@ def test_compound_format(
10491044
},
10501045
"end": "<end>",
10511046
},
1052-
r"""const_string ::= (("[TEXT]"))
1053-
any_text ::= TagDispatch(
1047+
r"""any_text ::= TagDispatch(
10541048
stop_eos=false,
10551049
stop_str=("<end>"),
10561050
loop_after_dispatch=false
10571051
)
1058-
sequence ::= ((const_string any_text))
1052+
sequence ::= (("[TEXT]" any_text))
10591053
tag ::= (("<start>" sequence))
10601054
root ::= ((tag))
10611055
""",
@@ -1105,22 +1099,21 @@ def test_compound_format(
11051099
stop_str=("<end2>"),
11061100
loop_after_dispatch=false
11071101
)
1108-
triggered_tags_group ::= ((">" any_text ""))
1109-
triggered_tags_first ::= (("<start2>" any_text ""))
1102+
triggered_tags_group ::= ((">" any_text))
1103+
triggered_tags_first ::= (("<start2>" any_text)) (=(triggered_tags_sub))
11101104
triggered_tags_sub ::= TagDispatch(
11111105
("<start2", triggered_tags_group),
11121106
stop_eos=false,
11131107
stop_str=("<end>"),
11141108
loop_after_dispatch=true
11151109
)
11161110
triggered_tags ::= ((triggered_tags_first triggered_tags_sub))
1117-
const_string ::= (("[TEXT2]"))
11181111
any_text_1 ::= TagDispatch(
11191112
stop_eos=false,
11201113
stop_str=("<end>"),
11211114
loop_after_dispatch=false
11221115
)
1123-
sequence ::= ((const_string any_text_1))
1116+
sequence ::= (("[TEXT2]" any_text_1))
11241117
any_text_2 ::= TagDispatch(
11251118
stop_eos=false,
11261119
stop_str=("<end3>"),
@@ -1192,30 +1185,28 @@ def test_compound_format(
11921185
stop_str=("<end2>"),
11931186
loop_after_dispatch=false
11941187
)
1195-
triggered_tags_group ::= ((">" any_text ""))
1196-
triggered_tags_first ::= (("<start2>" any_text ""))
1188+
triggered_tags_group ::= ((">" any_text))
1189+
triggered_tags_first ::= (("<start2>" any_text)) (=(triggered_tags_sub))
11971190
triggered_tags_sub ::= TagDispatch(
11981191
("<start2", triggered_tags_group),
11991192
stop_eos=true,
12001193
stop_str=(),
12011194
loop_after_dispatch=true
12021195
)
12031196
triggered_tags ::= ((triggered_tags_first triggered_tags_sub))
1204-
const_string ::= (("[TEXT]"))
12051197
any_text_1 ::= (([\0-\U0010ffff]*))
1206-
sequence ::= ((const_string any_text_1))
1198+
sequence ::= (("[TEXT]" any_text_1))
12071199
any_text_2 ::= TagDispatch(
12081200
stop_eos=false,
12091201
stop_str=("<end3>"),
12101202
loop_after_dispatch=false
12111203
)
12121204
tag ::= (("<start3>" any_text_2))
12131205
tags_with_separator_tags ::= ((tag))
1214-
tags_with_separator_sub ::= (("<sep>" tags_with_separator_tags tags_with_separator_sub) | "")
1206+
tags_with_separator_sub ::= ("" | ("<sep>" tags_with_separator_tags tags_with_separator_sub))
12151207
tags_with_separator ::= ((tags_with_separator_tags tags_with_separator_sub))
1216-
const_string_1 ::= (("[TEXT2]"))
12171208
any_text_3 ::= (([\0-\U0010ffff]*))
1218-
sequence_1 ::= ((const_string_1 any_text_3))
1209+
sequence_1 ::= (("[TEXT2]" any_text_3))
12191210
or ::= ((tags_with_separator) | (sequence_1))
12201211
or_1 ::= ((triggered_tags) | (sequence) | (or))
12211212
root ::= ((or_1))

0 commit comments

Comments
 (0)