Skip to content

Commit d92083d

Browse files
committed
chore: Update benchmarks and add the json-6 parser
1 parent d421cdf commit d92083d

File tree

8 files changed

+161
-104
lines changed

8 files changed

+161
-104
lines changed

benchmarks/README.md

+24-24
Original file line numberDiff line numberDiff line change
@@ -25,30 +25,30 @@ If you modify some grammars, you have to regenerate parsers before running the t
2525
## Performance
2626

2727
❯ node parse
28-
Parsing JSON data 4868 characters long using:
29-
the built-in parser x 51,485 ops/sec ±7.66% (58 runs sampled)
30-
the pure chevrotain parser x 6,445 ops/sec ±9.27% (52 runs sampled)
31-
the extended chevrotain parser x 6,802 ops/sec ±8.64% (63 runs sampled)
32-
the standard jsonlint parser x 56,024 ops/sec ±8.26% (66 runs sampled)
33-
the extended jsonlint parser x 5,664 ops/sec ±9.85% (64 runs sampled)
34-
the tokenising jsonlint parser x 5,086 ops/sec ±8.54% (65 runs sampled)
35-
the pure hand-built parser x 9,260 ops/sec ±8.53% (67 runs sampled)
36-
the extended hand-built parser x 8,965 ops/sec ±8.46% (66 runs sampled)
37-
the AST parser x 6,226 ops/sec ±7.87% (85 runs sampled)
38-
the Myna parser x 1,784 ops/sec ±7.12% (81 runs sampled)
39-
the pure jju parser x 5,047 ops/sec ±8.06% (72 runs sampled)
40-
the extended jju parser x 4,966 ops/sec ±7.73% (73 runs sampled)
41-
the tokenisable jju parser x 4,287 ops/sec ±8.43% (65 runs sampled)
42-
the tokenising jju parser x 3,378 ops/sec ±8.30% (65 runs sampled)
43-
the comments-enabled parser x 4,101 ops/sec ±9.01% (65 runs sampled)
44-
the pure pegjs parser x 1,628 ops/sec ±8.18% (59 runs sampled)
45-
the extended pegjs parser x 1,611 ops/sec ±9.66% (63 runs sampled)
46-
the pure jison parser x 1,283 ops/sec ±9.04% (57 runs sampled)
47-
the extended jison parser x 1,186 ops/sec ±8.65% (58 runs sampled)
48-
the JSON5 parser x 953 ops/sec ±8.71% (68 runs sampled)
49-
the Nearley parser x 663 ops/sec ±8.44% (59 runs sampled)
50-
The fastest one was the standard jsonlint parser.
51-
28+
Parsing JSON data 4797 characters long using:
29+
the built-in parser x 78,856 ops/sec ±0.50% (92 runs sampled)
30+
the pure chevrotain parser x 9,815 ops/sec ±1.29% (90 runs sampled)
31+
the extended chevrotain parser x 9,512 ops/sec ±0.90% (92 runs sampled)
32+
the standard jsonlint parser x 78,998 ops/sec ±0.48% (95 runs sampled)
33+
the extended jsonlint parser x 7,923 ops/sec ±0.51% (93 runs sampled)
34+
the tokenising jsonlint parser x 6,281 ops/sec ±0.71% (91 runs sampled)
35+
the pure hand-built parser x 13,529 ops/sec ±0.62% (92 runs sampled)
36+
the extended hand-built parser x 13,475 ops/sec ±0.81% (92 runs sampled)
37+
the AST parser x 9,201 ops/sec ±0.74% (91 runs sampled)
38+
the Myna parser x 3,089 ops/sec ±0.54% (94 runs sampled)
39+
the pure jju parser x 8,596 ops/sec ±0.98% (92 runs sampled)
40+
the extended jju parser x 6,966 ops/sec ±0.59% (89 runs sampled)
41+
the tokenisable jju parser x 6,091 ops/sec ±0.84% (89 runs sampled)
42+
the tokenising jju parser x 4,651 ops/sec ±0.54% (92 runs sampled)
43+
the comments-enabled parser x 5,632 ops/sec ±0.65% (92 runs sampled)
44+
the pure pegjs parser x 2,413 ops/sec ±0.69% (92 runs sampled)
45+
the extended pegjs parser x 2,124 ops/sec ±0.66% (92 runs sampled)
46+
the pure jison parser x 1,722 ops/sec ±1.16% (88 runs sampled)
47+
the extended jison parser x 1,619 ops/sec ±0.65% (91 runs sampled)
48+
the JSON5 parser x 1,283 ops/sec ±0.43% (91 runs sampled)
49+
the JSON6 parser x 7,922 ops/sec ±1.78% (92 runs sampled)
50+
the Nearley parser x 944 ops/sec ±0.51% (92 runs sampled)
51+
The fastest one were the standard jsonlint parser and the built-in parser.
5252

5353
[performance]: ./results/performance.md
5454
[quality of error reporting]: ./results/errorReportingQuality.md

benchmarks/fail.js

+27
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const { parse: jjuParse } = require('./jju/pure')
66
const { parse: pegjsParse } = require('./pegjs/pure')
77
const jisonParser = require('./jison/pure').parser
88
const JSON5 = require('json5')
9+
const JSON6 = require('json-6')
910
const { parse: parseWithComments } = require('comment-json')
1011

1112
const inputSources = [
@@ -231,6 +232,31 @@ function parseJSON5 () {
231232
}
232233
}
233234

235+
function improveJSON6Error (error) {
236+
let { message } = error
237+
message = message.replaceAll('\n', ' ')
238+
let [, lineNumber, columnNumber] = / \[(\d+):(\d+)\]$/.exec(message)
239+
--columnNumber
240+
const cursor = `line ${lineNumber}, column ${columnNumber}`
241+
const offset = getOffset(lineNumber, columnNumber)
242+
const position = showPosition({ offset })
243+
message = message
244+
.replace(/ \[\d+:\d+\]$/, '')
245+
.replace(/ \(near '.+'\)$/, '')
246+
.replace(/ unexpected at \d+$/, '')
247+
message = message.charAt(0).toUpperCase() + message.substr(1)
248+
error.message = `Parse error on ${cursor}:\n${position}\n${message}`
249+
throw error
250+
}
251+
252+
function parseJSON6 () {
253+
try {
254+
JSON6.parse(inputSource)
255+
} catch (error) {
256+
improveJSON6Error(error)
257+
}
258+
}
259+
234260
for (const test of inputSources) {
235261
inputSource = test
236262
const formattedTest = test
@@ -246,6 +272,7 @@ for (const test of inputSources) {
246272
.add('the pegjs parser', parsePegjs)
247273
.add('the jison parser', parseJison)
248274
.add('the JSON5 parser', parseJSON5)
275+
.add('the JSON6 parser', parseJSON6)
249276
.start()
250277
console.log()
251278
}

benchmarks/package.json

+5-4
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
},
77
"devDependencies": {
88
"benchmark": "2.1.4",
9-
"chevrotain": "10.1.2",
10-
"comment-json": "4.2.2",
9+
"chevrotain": "10.4.2",
10+
"comment-json": "4.2.3",
1111
"jison": "0.4.18",
12+
"json-6": "1.1.4",
1213
"json-to-ast": "2.1.0",
13-
"json5": "2.2.1",
14-
"moo": "0.5.1",
14+
"json5": "2.2.3",
15+
"moo": "0.5.2",
1516
"myna-parser": "2.5.1",
1617
"nearley": "2.20.1",
1718
"pegjs": "0.10.0"

benchmarks/parse.js

+6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const handbuiltParse = require('./hand-built/pure')
1515
const handbuiltExtendedParse = require('./hand-built/pure')
1616
const astParse = require('json-to-ast')
1717
const JSON5 = require('json5')
18+
const JSON6 = require('json-6')
1819
const { parse: parseWithComments } = require('comment-json')
1920
const { parse: parseThis, tokenize: tokenizeThis } = require('..')
2021
const myna = require('myna-parser')
@@ -108,6 +109,10 @@ function parseJSON5 () {
108109
JSON5.parse(input)
109110
}
110111

112+
function parseJSON6 () {
113+
JSON6.parse(input)
114+
}
115+
111116
function parseAST () {
112117
astParse(input, {
113118
loc: true
@@ -139,5 +144,6 @@ createSuite(`Parsing JSON data ${input.length} characters long using`)
139144
.add('the pure jison parser', parsePureJison)
140145
.add('the extended jison parser', parseExtendedJison)
141146
.add('the JSON5 parser', parseJSON5)
147+
.add('the JSON6 parser', parseJSON6)
142148
.add('the Nearley parser', parseNearley)
143149
.start()

benchmarks/pnpm-lock.yaml

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

benchmarks/results/errorReportingQuality.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,13 @@ Jison appears to return different line number of the error occurrence. If there
503503

504504
### [JSON5]
505505

506-
A short and technical message. Structured information about the error contains only the line and column, bot not the offset.
506+
A short and technical message. Structured information about the error contains only the line and column, but not the offset.
507+
508+
The context information can be added using the line and column of the error.
509+
510+
### [JSON6]
511+
512+
A short and technical message. Extra information about the error is appended to the error message. It contains the offset, the line and column, and an excerpt of the invalid input.
507513

508514
The context information can be added using the line and column of the error.
509515

@@ -517,4 +523,5 @@ The context information can be added using the line and column of the error.
517523
[PEG.JS]: http://pegjs.org/
518524
[Jison]: http://zaach.github.io/jison/
519525
[JSON5]: https://json5.org/
526+
[JSON6]: https://github.com/d3x0r/JSON6#readme
520527
[original JSONLint]: https://github.com/zaach/jison

benchmarks/results/evaluation.md

+3-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ The best parser is likely to be chosen specifically for the particular usage sce
88
Universal Parser
99
----------------
1010

11-
The most understandable messages are reported by [JJU] and [PEG.js]. The performance of the latter is not on par with the fastest parsers, but other parsers generated from a grammar specification are even slower.
11+
The most understandable messages are reported by [JJU] and [PEG.js]. The performance of the latter is not on par with the fastest parsers, but other parsers generated from a grammar specification are even slower. [JSON6] contains the extended information, but appended to the error message, which can make it longer and not so easy to read.
1212

1313
Validate Standard JSON As Fast As Possible
1414
------------------------------------------
@@ -18,7 +18,7 @@ The [built-in] native JSON parser (`JSON.parse`) offers by far the best performa
1818
Validate Non-Standard JSON
1919
--------------------------
2020

21-
Depending on extra features required, [Chevrotain] and [JJU] offer the best quality/performance ratio. Chevrotain tries harder to explain, what was wrong, which is often quite counterproductive. JJU explains the problems well-enough with a single sentence, even ended by a full-stop. Chevrotain packs additional features like recovery and reporting all errors instead of just the first one. This extra feature might make it a winner for a flexibly configurable scenario. However, the Chevrotain parser needs significantly more code, than all the others.
21+
Depending on extra features required, [Chevrotain], [JJU] and [JSON6] offer the best quality/performance ratio. Chevrotain tries harder to explain, what was wrong, which is often quite counterproductive. JJU explains the problems well-enough with a single sentence, even ended by a full-stop. Chevrotain packs additional features like recovery and reporting all errors instead of just the first one. This extra feature might make it a winner for a flexibly configurable scenario. However, the Chevrotain parser needs significantly more code, than all the others. JSON6 supports many extensions to JSON/JSON5 standards.
2222

2323
[tested with a JSON grammar]: https://sap.github.io/chevrotain/performance/
2424
[performance]: ./performance.md
@@ -27,5 +27,4 @@ Depending on extra features required, [Chevrotain] and [JJU] offer the best qual
2727
[Chevrotain]: https://github.com/SAP/chevrotain
2828
[JJU]: http://rlidwka.github.io/jju/
2929
[PEG.JS]: http://pegjs.org/
30-
[Jison]: http://zaach.github.io/jison/
31-
[JSON5]: https://json5.org/
30+
[JSON6]: https://github.com/d3x0r/JSON6#readme

0 commit comments

Comments
 (0)