Skip to content

Commit d8b3e13

Browse files
committed
Fix parsing of string literals with a leading combining character.
Closes #25.
1 parent 4b5bff1 commit d8b3e13

File tree

4 files changed

+26
-10
lines changed

4 files changed

+26
-10
lines changed

lib/JSON/Tiny/Actions.pm

+13-1
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,21 @@ method arraylist($/) {
2424
}
2525

2626
method string($/) {
27-
make +@$<str> == 1
27+
my $str = +@$<str> == 1
2828
?? $<str>[0].made
2929
!! $<str>>>.made.join;
30+
31+
# see https://github.com/moritz/json/issues/25
32+
# when a combining character comes after an opening quote,
33+
# it doesn't become part of the quoted string, because
34+
# it's stuffed into the same grapheme as the quote.
35+
# so we need to extract those combining character(s)
36+
# from the match of the opening quote, and stuff it into the string.
37+
if $0.Str ne '"' {
38+
my @chars := $0.Str.NFC;
39+
$str = @chars[1..*].chrs ~ $str;
40+
}
41+
make $str
3042
}
3143
method value:sym<number>($/) { make +$/.Str }
3244
method value:sym<string>($/) { make $<string>.made }

lib/JSON/Tiny/Grammar.pm

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ token value:sym<array> { <array> };
2323
token value:sym<string> { <string> }
2424

2525
token string {
26-
\" ~ \" [ <str> | \\ <str=.str_escape> ]*
26+
# see https://github.com/moritz/json/issues/25
27+
(:ignoremark '"') ~ \" [ <str> | \\ <str=.str_escape> ]*
2728
}
2829

2930
token str {

t/01-parse.t

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ my @t =
1616
' [ ] ',
1717
# https://github.com/moritz/json/issues/24
1818
qq/["\x[85]"]/,
19+
# https://github.com/moritz/json/issues/25
20+
qq/["̥̞ͫͩ̉̎͊ỏ̟͙̞̻̻̹̹r̵̨͇̫̦̺̮̼ͭ,̷̧̬̲͈̤̤̅̉͛ͫ͠ ̣͕̝̳̗̲̩̣͗̋͘e̼ͩ̔̿̾̋̾͘a̸̙͙͔̜͙̳̻͊ͯͪͤͬ͊͆͠c̦̃̓̈̾͗́͝͝ḩ͉͓̦̯̞̆ ̵͇͍ͪ̀́w̷ͩ͗̃͒͏̲̼̯̕i̞̫̜̮̣̰͎̅̂͋̀ͅń̢̨̪̭̠̼͕͎̐́͆̅ͅd̰̤̝͎̹͕ͩ̃̏̃̍͊̔ȏ̶̼̺̪̾ͨ̈̄ͤ̄̚̕w̙̻̱̙̺͎͚̙ͧͪ̊̒̕͝ ̴̼̰̱͈̠ͤ̋̏̇͛&̠̺̟̞͎̳̻̙̽̓́̔̇ͩ͛ͧ̚ ̡̡̫̻͐̌̐̌ͬͦ̂͞"]/,
1921
# stolen from JSON::XS, 18_json_checker.t, and adapted a bit
2022
Q<<[
2123
"JSON Test Pattern pass1",

t/03-unicode.t

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
use v6;
2-
use JSON::Tiny::Grammar;
3-
use JSON::Tiny::Actions;
2+
use JSON::Tiny;
43
use Test;
54

6-
75
my @t =
86
'{ "a" : "b\u00E5" }' => { 'a' => '' },
9-
'[ "\u2685" ]' => [ '' ];
7+
'[ "\u2685" ]' => [ '' ],
8+
# issue #25
9+
qq{"x\c[ZERO WIDTH JOINER]a"} => "x\c[ZERO WIDTH JOINER]a",
10+
qq{"\c[ZERO WIDTH JOINER]"} => "\c[ZERO WIDTH JOINER]",
11+
;
1012

1113
plan (+@t);
1214
for @t -> $p {
13-
my $a = JSON::Tiny::Actions.new();
14-
my $o = JSON::Tiny::Grammar.parse($p.key, :actions($a));
15-
is-deeply $o.made, $p.value, "Correct data structure for «{$p.key}»"
16-
or say "# Got: {$o.made.perl}\n# Expected: {$p.value.perl}";
15+
my $got = from-json($p.key);
16+
is-deeply $got, $p.value, "Correct data structure for «{$p.key}»"
17+
or say "# Got: $got.perl()\n# Expected: {$p.value.perl}";
1718
}

0 commit comments

Comments
 (0)