Skip to content

Commit 53019eb

Browse files
committed
feat(parse)!: IParserTag return defaults to { ast, holes }
1 parent 4a82fd2 commit 53019eb

File tree

6 files changed

+63
-13
lines changed

6 files changed

+63
-13
lines changed

packages/parse/src/boot-peg.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,7 @@ pos = ${posSrc};`;
773773
/**
774774
* @template X
775775
* @param {ParserOptions} options
776-
* @returns {IPegTag<IParserTag<X>>}
776+
* @returns {IPegTag<IParserTag<X, any>>}
777777
*/
778778
const makeExtensionTag = (options = {}) => {
779779
/**

packages/parse/src/peg.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ interface ParserOptions {
3131
debug?: boolean;
3232
}
3333

34-
interface IParserTag<T = any, U = any> {
34+
interface IParserTag<T = any, U = { holes: any[]; ast: any }> {
3535
(template: TemplateStringsArray, ...args: T[]): U;
3636
options(opts: Partial<ParserOptions>): IParserTag<T, U>;
3737
parserCreator: PegParserCreator;

packages/parse/src/quasi-json.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const makeJSON = peg => {
1616
const { FAIL, HOLE, SKIP } = peg;
1717
return peg`
1818
# to be overridden or inherited
19-
start <- _WS assignExpr _EOF ${v => () => v};
19+
start <- _WS assignExpr _EOF ${ast => (...holes) => ({ ast, holes })};
2020
2121
# to be extended
2222
primaryExpr <- dataStructure;

packages/parse/src/quasi-justin.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
// See https://github.com/endojs/Jessie/blob/main/README.md
2323
// for documentation of the Jessie grammar.
2424

25-
// Justin is defined to be extended into the Chainmail grammar, to
26-
// provide its expression language in a JS-like style. Chainmail
27-
// expressions need to be pure and should be terminating.
25+
// Justin is also intended to be extended into the Chainmail grammar, to provide
26+
// its expression language in a JS-like style. Chainmail expressions need to be
27+
// pure and should be terminating.
2828

2929
/// <reference path="./peg.d.ts"/>
3030

@@ -70,7 +70,7 @@ const makeJustin = peg => {
7070
const { SKIP } = peg;
7171
return peg`
7272
# to be overridden or inherited
73-
start <- _WS assignExpr _EOF ${v => () => v};
73+
start <- _WS assignExpr _EOF ${ast => (...holes) => ({ ast, holes })};
7474
7575
# A.1 Lexical Grammar
7676
@@ -147,11 +147,14 @@ const makeJustin = peg => {
147147
/ "interface" / "private" / "public") _WSN;
148148
149149
# Quasiliterals aka template literals
150-
QUASI_CHAR <- "\\" . / ~"\`" .;
151-
QUASI_ALL <- "\`" < (~"\${" QUASI_CHAR)* > "\`" _WS;
152-
QUASI_HEAD <- "\`" < (~"\${" QUASI_CHAR)* > "\${" _WS;
153-
QUASI_MID <- "}" < (~"\${" QUASI_CHAR)* > "\${" _WS;
154-
QUASI_TAIL <- "}" < (~"\${" QUASI_CHAR)* > "\`" _WS;
150+
QCHAR <- "\\" . / ~QQUOTE .;
151+
QQUOTE <- "\`";
152+
QHOLE <- "\${";
153+
QHOLE_END <- "}";
154+
QUASI_ALL <- QQUOTE < (~QHOLE QCHAR)* > QQUOTE _WS;
155+
QUASI_HEAD <- QQUOTE < (~QHOLE QCHAR)* > QHOLE _WS;
156+
QUASI_MID <- QHOLE_END < (~QHOLE QCHAR)* > QHOLE _WS;
157+
QUASI_TAIL <- QHOLE_END < (~QHOLE QCHAR)* > QQUOTE _WS;
155158
156159
157160
# A.2 Expressions

packages/parse/test/parser-utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ const makeSerialParseWithTools = (testTag, assert) => {
153153
const dtag = doDebug ? testTag.options({ debug: true }) : testTag;
154154
const { result, tools } = dtag(tmpl);
155155
assert(result.status === 'fulfilled', 'parse failed');
156-
const parsed = result.value;
156+
const parsed = result.value.ast;
157157
currentTestTools = tools;
158158
if (doDump) {
159159
// tslint:disable-next-line:no-console

packages/parse/test/test-justin.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,53 @@ test('data', t => {
3535
t.deepEqual(parse('"\\f\\r\\n\\t\\b"'), ast(0, 'data', '\f\r\n\t\b'));
3636
});
3737

38+
test('holes', t => {
39+
const parseBLD = units => {
40+
const { testTag: testJustin } = makeParserUtils(justin, (val, message) =>
41+
t.assert(val, message),
42+
);
43+
const {
44+
result,
45+
tools: { ast, nest, hole },
46+
} = testJustin`make(BLD, ${units}, 'additional arg')`;
47+
assert(result.status === 'fulfilled', 'parse failed');
48+
const parsed = result.value;
49+
50+
t.deepEqual(
51+
parsed.ast,
52+
ast(
53+
nest(
54+
0,
55+
'call',
56+
nest(0, 'use', 'make'),
57+
nest(
58+
4,
59+
nest(5, 'use', 'BLD'),
60+
hole(0, 'exprHole', 0),
61+
nest(2, 'data', 'additional arg'),
62+
),
63+
),
64+
),
65+
);
66+
67+
t.assert(Array.isArray(parsed.holes));
68+
const expected = [units];
69+
t.is(parsed.holes.length, expected.length);
70+
expected.map((v, i) => t.is(parsed.holes[i], v, `hole ${i} is ${v}`));
71+
72+
return parsed;
73+
};
74+
75+
const p1 = parseBLD(BigInt(123));
76+
const p2 = parseBLD(BigInt(123));
77+
t.deepEqual(p1, p2);
78+
t.is(p1.ast, p2.ast);
79+
80+
const p3 = parseBLD(456);
81+
t.notDeepEqual(p2, p3);
82+
t.is(p1.ast, p3.ast);
83+
});
84+
3885
test('binops', t => {
3986
const { parse, ast } = makeParserUtils(justin, (val, message) =>
4087
t.assert(val, message),

0 commit comments

Comments
 (0)