Skip to content

Commit 0493e23

Browse files
committed
wasm: Handle dual package hazard, add JSON benchmark.
1 parent 367e96f commit 0493e23

6 files changed

Lines changed: 315 additions & 6 deletions

File tree

packages/lang-json/json.ohm

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
Based on jwmerrill's ohm-grammar-json:
3+
https://github.com/jwmerrill/ohm-grammar-json/blob/master/src/json.ohm
4+
5+
Original copyright and license follows:
6+
7+
ISC License (ISC)
8+
9+
Copyright (c) 2016, Jason Merrill <jason@squishythinking.com>
10+
11+
Permission to use, copy, modify, and/or distribute this software for any
12+
purpose with or without fee is hereby granted, provided that the above
13+
copyright notice and this permission notice appear in all copies.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18+
SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
21+
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22+
*/
23+
JSON {
24+
Start = Value
25+
26+
Value =
27+
Object
28+
| Array
29+
| String
30+
| Number
31+
| True
32+
| False
33+
| Null
34+
35+
Object =
36+
"{" "}" -- empty
37+
| "{" Pair ("," Pair)* "}" -- nonEmpty
38+
39+
Pair =
40+
String ":" Value
41+
42+
Array =
43+
"[" "]" -- empty
44+
| "[" Value ("," Value)* "]" -- nonEmpty
45+
46+
String (String) =
47+
stringLiteral
48+
49+
stringLiteral =
50+
"\"" doubleStringCharacter* "\""
51+
52+
doubleStringCharacter (character) =
53+
~("\"" | "\\") any -- nonEscaped
54+
| "\\" escapeSequence -- escaped
55+
56+
escapeSequence =
57+
"\"" -- doubleQuote
58+
| "\\" -- reverseSolidus
59+
| "/" -- solidus
60+
| "b" -- backspace
61+
| "f" -- formfeed
62+
| "n" -- newline
63+
| "r" -- carriageReturn
64+
| "t" -- horizontalTab
65+
| "u" fourHexDigits -- codePoint
66+
67+
fourHexDigits = hexDigit hexDigit hexDigit hexDigit
68+
69+
Number (Number) =
70+
numberLiteral
71+
72+
numberLiteral =
73+
decimal exponent -- withExponent
74+
| decimal -- withoutExponent
75+
76+
decimal =
77+
wholeNumber "." digit+ -- withFract
78+
| wholeNumber -- withoutFract
79+
80+
wholeNumber =
81+
"-" unsignedWholeNumber -- negative
82+
| unsignedWholeNumber -- nonNegative
83+
84+
unsignedWholeNumber =
85+
"0" -- zero
86+
| nonZeroDigit digit* -- nonZero
87+
88+
nonZeroDigit = "1".."9"
89+
90+
exponent =
91+
exponentMark ("+"|"-") digit+ -- signed
92+
| exponentMark digit+ -- unsigned
93+
94+
exponentMark = "e" | "E"
95+
96+
True = "true"
97+
False = "false"
98+
Null = "null"
99+
}

packages/lang-json/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "@ohm-js/lang-json",
3+
"private": true
4+
}

packages/wasm/Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ debug: clean
1515
OHM_DEBUG=1 make
1616

1717
.PHONY: bench
18-
bench: all build/es5.wasm build/liquid-html.wasm
18+
bench: all build/es5.wasm build/json.wasm build/liquid-html.wasm
1919
$(NODE) --expose-gc $(NODE_COMMON_FLAGS) scripts/bench.js
2020

2121
build/%.O3.wasm: build/%.wasm
@@ -40,6 +40,9 @@ build/ohmRuntime.wasm: runtime/ohmRuntime.ts
4040
build/es5.wasm: dist/index.js
4141
$(NODE) scripts/es5ToWasm.js build/es5.wasm
4242

43+
build/json.wasm: dist/index.js
44+
$(NODE) src/cli.js -o build/json.wasm ../lang-json/json.ohm
45+
4346
build/liquid-html.wasm: dist/index.js
4447
$(NODE) src/cli.js -g LiquidHTML -o build/liquid-html.wasm test/data/liquid-html.ohm
4548

packages/wasm/scripts/bench.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@ const inputs = {
1515
bookReview: readFileSync(join(datadir, 'book-review.liquid'), 'utf-8'),
1616
featuredProduct: readFileSync(join(datadir, 'featured-product.liquid'), 'utf-8'),
1717
footer: readFileSync(join(datadir, 'footer.liquid'), 'utf-8'),
18+
mockJSON: readFileSync(join(datadir, 'json-org-examples.json'), 'utf-8'),
1819
html5shiv: readFileSync(join(datadir, '_html5shiv-3.7.3.js'), 'utf-8'),
1920
underscore: readFileSync(join(datadir, '_underscore-1.8.3.js'), 'utf-8'),
2021
};
2122

2223
const liquid = ohm.grammars(readFileSync(join(datadir, 'liquid-html.ohm'), 'utf8'));
24+
const json = ohm.grammar(readFileSync(join(__dirname, '../../lang-json/json.ohm'), 'utf8'));
2325

2426
let liquidHtmlMatcher;
2527
let es5Matcher;
28+
let jsonMatcher;
2629

2730
function checkOk(val) {
2831
if (!val) {
@@ -91,6 +94,17 @@ group('LiquidHTML: footer.liquid', () => {
9194
});
9295
});
9396

97+
group('JSON', () => {
98+
summary(() => {
99+
bench('Wasm', () => {
100+
matchWithInput(jsonMatcher, inputs.mockJSON);
101+
});
102+
bench('JS', () => {
103+
json.match(inputs.mockJSON);
104+
});
105+
});
106+
});
107+
94108
(async () => {
95109
// Note: we are deliberately creating one instance of the matcher that's
96110
// reused. This takes advantage of JIT tier-up, and approximates usage
@@ -103,6 +117,10 @@ group('LiquidHTML: footer.liquid', () => {
103117
es5,
104118
readFileSync(join(__dirname, '../build/es5.wasm')),
105119
);
120+
jsonMatcher = await wasmMatcherForGrammar(
121+
json,
122+
readFileSync(join(__dirname, '../build/json.wasm')),
123+
);
106124

107125
await run();
108126
})();

packages/wasm/src/index.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* global process */
22

33
import * as w from '@wasmgroundup/emit';
4-
import {pexprs, ohmGrammar} from 'ohm-js';
4+
import * as ohm from 'ohm-js';
55
// import wabt from 'wabt';
66

77
import * as ir from './ir.ts';
@@ -21,6 +21,7 @@ const IMPLICIT_SPACE_SKIPPING = true;
2121
const EMIT_GENERALIZED_RULES = true;
2222

2323
const {instr} = w;
24+
const {pexprs} = ohm;
2425

2526
const isNonNull = x => x != null;
2627

@@ -659,10 +660,19 @@ Assembler.STACK_FRAME_SIZE_BYTES = 8;
659660
export class Compiler {
660661
constructor(grammar) {
661662
assert(grammar && 'superGrammar' in grammar, 'Not a valid grammar: ' + grammar);
662-
assert(
663-
grammar instanceof ohmGrammar.constructor,
664-
'Grammar smells fishy. Do you have multiple instances of ohm-js?',
665-
);
663+
664+
// Detect the so-called "dual package hazard". Since we use the identity
665+
// of the pexpr constructors when compiling the grammar, it gets confusing
666+
// if there are multiple copies of Ohm.
667+
if (!(grammar instanceof ohm.ohmGrammar.constructor)) {
668+
// If we have the source, recover by instantiating the grammar anew.
669+
// Fail otherwise.
670+
assert(
671+
!!grammar.source,
672+
'Grammar smells fishy. Do you have multiple instances of ohm-js?',
673+
);
674+
grammar = ohm.grammar(grammar.source.contents);
675+
}
666676

667677
this.grammar = grammar;
668678

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
[
2+
{
3+
"glossary": {
4+
"title": "example glossary",
5+
"GlossDiv": {
6+
"title": "S",
7+
"GlossList": {
8+
"GlossEntry": {
9+
"ID": "SGML",
10+
"SortAs": "SGML",
11+
"GlossTerm": "Standard Generalized Markup Language",
12+
"Acronym": "SGML",
13+
"Abbrev": "ISO 8879:1986",
14+
"GlossDef": {
15+
"para": "A meta-markup language, used to create markup languages such as DocBook.",
16+
"GlossSeeAlso": ["GML", "XML"]
17+
},
18+
"GlossSee": "markup"
19+
}
20+
}
21+
}
22+
}
23+
},
24+
{"menu": {
25+
"id": "file",
26+
"value": "File",
27+
"popup": {
28+
"menuitem": [
29+
{"value": "New", "onclick": "CreateNewDoc()"},
30+
{"value": "Open", "onclick": "OpenDoc()"},
31+
{"value": "Close", "onclick": "CloseDoc()"}
32+
]
33+
}
34+
}},
35+
{"widget": {
36+
"debug": "on",
37+
"window": {
38+
"title": "Sample Konfabulator Widget",
39+
"name": "main_window",
40+
"width": 500,
41+
"height": 500
42+
},
43+
"image": {
44+
"src": "Images/Sun.png",
45+
"name": "sun1",
46+
"hOffset": 250,
47+
"vOffset": 250,
48+
"alignment": "center"
49+
},
50+
"text": {
51+
"data": "Click Here",
52+
"size": 36,
53+
"style": "bold",
54+
"name": "text1",
55+
"hOffset": 250,
56+
"vOffset": 100,
57+
"alignment": "center",
58+
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
59+
}
60+
}},
61+
{"web-app": {
62+
"servlet": [
63+
{
64+
"servlet-name": "cofaxCDS",
65+
"servlet-class": "org.cofax.cds.CDSServlet",
66+
"init-param": {
67+
"configGlossary:installationAt": "Philadelphia, PA",
68+
"configGlossary:adminEmail": "ksm@pobox.com",
69+
"configGlossary:poweredBy": "Cofax",
70+
"configGlossary:poweredByIcon": "/images/cofax.gif",
71+
"configGlossary:staticPath": "/content/static",
72+
"templateProcessorClass": "org.cofax.WysiwygTemplate",
73+
"templateLoaderClass": "org.cofax.FilesTemplateLoader",
74+
"templatePath": "templates",
75+
"templateOverridePath": "",
76+
"defaultListTemplate": "listTemplate.htm",
77+
"defaultFileTemplate": "articleTemplate.htm",
78+
"useJSP": false,
79+
"jspListTemplate": "listTemplate.jsp",
80+
"jspFileTemplate": "articleTemplate.jsp",
81+
"cachePackageTagsTrack": 200,
82+
"cachePackageTagsStore": 200,
83+
"cachePackageTagsRefresh": 60,
84+
"cacheTemplatesTrack": 100,
85+
"cacheTemplatesStore": 50,
86+
"cacheTemplatesRefresh": 15,
87+
"cachePagesTrack": 200,
88+
"cachePagesStore": 100,
89+
"cachePagesRefresh": 10,
90+
"cachePagesDirtyRead": 10,
91+
"searchEngineListTemplate": "forSearchEnginesList.htm",
92+
"searchEngineFileTemplate": "forSearchEngines.htm",
93+
"searchEngineRobotsDb": "WEB-INF/robots.db",
94+
"useDataStore": true,
95+
"dataStoreClass": "org.cofax.SqlDataStore",
96+
"redirectionClass": "org.cofax.SqlRedirection",
97+
"dataStoreName": "cofax",
98+
"dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
99+
"dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
100+
"dataStoreUser": "sa",
101+
"dataStorePassword": "dataStoreTestQuery",
102+
"dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
103+
"dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
104+
"dataStoreInitConns": 10,
105+
"dataStoreMaxConns": 100,
106+
"dataStoreConnUsageLimit": 100,
107+
"dataStoreLogLevel": "debug",
108+
"maxUrlLength": 500}},
109+
{
110+
"servlet-name": "cofaxEmail",
111+
"servlet-class": "org.cofax.cds.EmailServlet",
112+
"init-param": {
113+
"mailHost": "mail1",
114+
"mailHostOverride": "mail2"}},
115+
{
116+
"servlet-name": "cofaxAdmin",
117+
"servlet-class": "org.cofax.cds.AdminServlet"},
118+
119+
{
120+
"servlet-name": "fileServlet",
121+
"servlet-class": "org.cofax.cds.FileServlet"},
122+
{
123+
"servlet-name": "cofaxTools",
124+
"servlet-class": "org.cofax.cms.CofaxToolsServlet",
125+
"init-param": {
126+
"templatePath": "toolstemplates/",
127+
"log": 1,
128+
"logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
129+
"logMaxSize": "",
130+
"dataLog": 1,
131+
"dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
132+
"dataLogMaxSize": "",
133+
"removePageCache": "/content/admin/remove?cache=pages&id=",
134+
"removeTemplateCache": "/content/admin/remove?cache=templates&id=",
135+
"fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
136+
"lookInContext": 1,
137+
"adminGroupID": 4,
138+
"betaServer": true}}],
139+
"servlet-mapping": {
140+
"cofaxCDS": "/",
141+
"cofaxEmail": "/cofaxutil/aemail/*",
142+
"cofaxAdmin": "/admin/*",
143+
"fileServlet": "/static/*",
144+
"cofaxTools": "/tools/*"},
145+
146+
"taglib": {
147+
"taglib-uri": "cofax.tld",
148+
"taglib-location": "/WEB-INF/tlds/cofax.tld"}}},
149+
{"menu": {
150+
"header": "SVG Viewer",
151+
"items": [
152+
{"id": "Open"},
153+
{"id": "OpenNew", "label": "Open New"},
154+
null,
155+
{"id": "ZoomIn", "label": "Zoom In"},
156+
{"id": "ZoomOut", "label": "Zoom Out"},
157+
{"id": "OriginalView", "label": "Original View"},
158+
null,
159+
{"id": "Quality"},
160+
{"id": "Pause"},
161+
{"id": "Mute"},
162+
null,
163+
{"id": "Find", "label": "Find..."},
164+
{"id": "FindAgain", "label": "Find Again"},
165+
{"id": "Copy"},
166+
{"id": "CopyAgain", "label": "Copy Again"},
167+
{"id": "CopySVG", "label": "Copy SVG"},
168+
{"id": "ViewSVG", "label": "View SVG"},
169+
{"id": "ViewSource", "label": "View Source"},
170+
{"id": "SaveAs", "label": "Save As"},
171+
null,
172+
{"id": "Help"},
173+
{"id": "About", "label": "About Adobe CVG Viewer..."}
174+
]
175+
}}]

0 commit comments

Comments
 (0)