Skip to content

Instantly share code, notes, and snippets.

@lizmat
Created September 19, 2018 21:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lizmat/0454f034b9336673cea4fb31927ca164 to your computer and use it in GitHub Desktop.
Save lizmat/0454f034b9336673cea4fb31927ca164 to your computer and use it in GitHub Desktop.
A faster JSON parser, with limited capabilities
my $meta = "META6.json".IO.slurp;
my $old = Rakudo::Internals::JSON.new.from-json($meta);
use Test;
use MONKEY;
augment class Rakudo::Internals::JSON {
sub parse(\item,\iterator) {
item.starts-with('{')
?? parse-hash(iterator)
!! item.starts-with('[')
?? parse-array(iterator)
!! item.starts-with('"')
?? parse-string(item,iterator)
!! die
}
sub parse-hash(\iterator) {
my %hash;
nqp::until(
nqp::eqaddr((my \item := iterator.pull-one),IterationEnd),
nqp::if(
item eq '}' || item eq '},',
(return %hash), # done
nqp::stmts(
nqp::if(
item.starts-with('"'),
(my $key = parse-string(item,iterator)),
die
),
nqp::if(
iterator.pull-one ne ':',
die,
%hash.push: $key, parse(iterator.pull-one,iterator)
)
)
)
);
die # should return with valid otherwise
}
sub parse-array(\iterator) {
my @array;
nqp::until(
nqp::eqaddr((my \item = iterator.pull-one),IterationEnd),
nqp::if(
item eq ']' || item eq '],',
(return @array),
@array.push: parse(item,iterator)
)
);
die # should return with valid otherwise
}
sub parse-string(\item, \iterator) {
nqp::if(
item.ends-with('"'),
item.substr(1,*-1),
nqp::if(
item.ends-with('",'),
item.substr(1,*-2),
nqp::stmts(
(my str @parts = item.substr(1)),
nqp::until(
nqp::eqaddr((my \part = iterator.pull-one),IterationEnd),
nqp::if(
part.ends-with('"'),
nqp::stmts(
@parts.push(part.substr(0,*-1)),
return @parts.join(" ")
),
nqp::if(
part.ends-with('",'),
nqp::stmts(
@parts.push(part.substr(0,*-2)),
return @parts.join(" ")
),
@parts.push(part)
)
)
),
die # should return with valid otherwise
)
)
)
}
method quick-from-json($text) {
CATCH { return Nil }
my \iterator = $text.words.iterator;
parse(iterator.pull-one, iterator)
}
}
my $new = Rakudo::Internals::JSON.new.quick-from-json($meta);
is-deeply $new, $old;
my \then = now;
Rakudo::Internals::JSON.new.quick-from-json($meta) for ^1000;
say now - then;
@ugexe
Copy link

ugexe commented Sep 19, 2018

any type of fallback will essentially make the speed improvement non-existent in the case of zef because it has to parse entire ecosystems worth of data (not pick/choose individual META6.json) where there will almost certainly be at least one case of $some-non-happy-path-content

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment