Skip to content

Commit a6ea466

Browse files
committed
chore: Add the Nearley parser to the performance comparison
1 parent fe36d55 commit a6ea466

File tree

6 files changed

+163
-1
lines changed

6 files changed

+163
-1
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
.nyc_output
33
benchmarks/jison/*.js
44
benchmarks/pegjs/*.js
5+
benchmarks/nearley/*.js
56
coverage
67
node_modules
78
lib/jsonlint*.js

benchmarks/nearley/pure.ne

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# http://www.json.org/
2+
# http://www.asciitable.com/
3+
@{%
4+
5+
const moo = require('moo')
6+
7+
let lexer = moo.compile({
8+
space: {match: /\s+/, lineBreaks: true},
9+
number: /-?(?:[0-9]|[1-9][0-9]+)(?:\.[0-9]+)?(?:[eE][-+]?[0-9]+)?\b/,
10+
string: /"(?:\\["bfnrt\/\\]|\\u[a-fA-F0-9]{4}|[^"\\])*"/,
11+
'{': '{',
12+
'}': '}',
13+
'[': '[',
14+
']': ']',
15+
',': ',',
16+
':': ':',
17+
true: 'true',
18+
false: 'false',
19+
null: 'null',
20+
})
21+
22+
%}
23+
24+
@lexer lexer
25+
26+
json -> _ (object | array) _ {% function(d) { return d[1][0]; } %}
27+
28+
object -> "{" _ "}" {% function(d) { return {}; } %}
29+
| "{" _ pair (_ "," _ pair):* _ "}" {% extractObject %}
30+
31+
array -> "[" _ "]" {% function(d) { return []; } %}
32+
| "[" _ value (_ "," _ value):* _ "]" {% extractArray %}
33+
34+
value ->
35+
object {% id %}
36+
| array {% id %}
37+
| number {% id %}
38+
| string {% id %}
39+
| "true" {% function(d) { return true; } %}
40+
| "false" {% function(d) { return false; } %}
41+
| "null" {% function(d) { return null; } %}
42+
43+
number -> %number {% function(d) { return parseFloat(d[0].value) } %}
44+
45+
string -> %string {% function(d) { return JSON.parse(d[0].value) } %}
46+
47+
pair -> key _ ":" _ value {% function(d) { return [d[0], d[4]]; } %}
48+
49+
key -> string {% id %}
50+
51+
_ -> null | %space {% function(d) { return null; } %}
52+
53+
@{%
54+
55+
function extractPair(kv, output) {
56+
if(kv[0]) { output[kv[0]] = kv[1]; }
57+
}
58+
59+
function extractObject(d) {
60+
let output = {};
61+
62+
extractPair(d[2], output);
63+
64+
for (let i in d[3]) {
65+
extractPair(d[3][i][3], output);
66+
}
67+
68+
return output;
69+
}
70+
71+
function extractArray(d) {
72+
let output = [d[2]];
73+
74+
for (let i in d[3]) {
75+
output.push(d[3][i][3]);
76+
}
77+
78+
return output;
79+
}
80+
81+
%}

benchmarks/package-lock.json

+67
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

benchmarks/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "jsonlint-benchmarks",
33
"private": true,
44
"scripts": {
5-
"prepare": "jison -o jison/pure.js jison/pure.y jison/pure.l && jison -o jison/extended.js jison/extended.y jison/extended.l && pegjs pegjs/pure.pegjs && pegjs pegjs/extended.pegjs"
5+
"prepare": "jison -o jison/pure.js jison/pure.y jison/pure.l && jison -o jison/extended.js jison/extended.y jison/extended.l && pegjs pegjs/pure.pegjs && pegjs pegjs/extended.pegjs && nearleyc nearley/purel.ne -o nearley/purel.js"
66
},
77
"devDependencies": {
88
"benchmark": "2.1.4",
@@ -11,7 +11,9 @@
1111
"jison": "0.4.18",
1212
"json-to-ast": "2.1.0",
1313
"json5": "2.1.1",
14+
"moo": "0.5.1",
1415
"myna-parser": "2.5.1",
16+
"nearley": "2.19.0",
1517
"pegjs": "0.10.0"
1618
}
1719
}

benchmarks/parse.js

+10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ const { parse: parseThis, tokenize: tokenizeThis } = require('..')
2020
const myna = require('myna-parser')
2121
require('./myna/pure')(myna)
2222
const mynaParse = myna.parsers.json
23+
const { Parser: NearleyParser, Grammar: NearleyGrammar } = require('nearley')
24+
const nearleyJsonGrammar = require('./nearley/pure')
25+
const nearleyParser = new NearleyParser(NearleyGrammar.fromCompiled(nearleyJsonGrammar));
26+
const nearleyOrigin = nearleyParser.save()
2327

2428
const pkg = require('../package')
2529
const input = JSON.stringify(pkg, undefined, 2)
@@ -79,6 +83,11 @@ function parseCurrentTokenising () {
7983
tokenizeThis(input, { mode: 'json5' })
8084
}
8185

86+
function parseNearley () {
87+
nearleyParser.restore(nearleyOrigin)
88+
nearleyParser.feed(input)
89+
}
90+
8291
function parsePurePegjs () {
8392
pegjsParse(input)
8493
}
@@ -130,4 +139,5 @@ createSuite(`Parsing JSON data ${input.length} characters long using`)
130139
.add('the pure jison parser', parsePureJison)
131140
.add('the extended jison parser', parseExtendedJison)
132141
.add('the JSON5 parser', parseJSON5)
142+
.add('the Nearley parser', parseNearley)
133143
.start()

benchmarks/results/performance.md

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ This is a result of the [benchmark] run by `npm run benchmarks`. The numbers sho
4848
the pure jison parser x 2,460 ops/sec ±0.49% (89 runs sampled)
4949
the extended jison parser x 2,195 ops/sec ±0.63% (88 runs sampled)
5050
the JSON5 parser x 1,660 ops/sec ±0.84% (90 runs sampled)
51+
the Nearley parser x 1,408 ops/sec ±1.14% (85 runs sampled)
5152
The fastest one was the built-in parser,the standard jsonlint parser.
5253

5354
I looked further at capabilities and licenses of the parsers.

0 commit comments

Comments
 (0)