Skip to content

Commit e59a378

Browse files
author
markw65
committed
fixes and coverage
1 parent ef0a1d0 commit e59a378

File tree

4 files changed

+87
-22
lines changed

4 files changed

+87
-22
lines changed

lib/compiler/passes/generate-js.js

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ function wrapInSourceNode(prefix, chunk, location, suffix, name) {
9090
*
9191
* @typedef {PEG.SourceBuildOptions<PEG.SourceOutputs>} SourceBuildOptions
9292
* @typedef {object} ExtraOptions
93-
* @property {undefined} [dependencies]
94-
* @property {undefined} [exportVar]
93+
* @property {PEG.Dependencies} [dependencies]
94+
* @property {string} [exportVar]
9595
* @typedef {SourceBuildOptions & ExtraOptions} Options
9696
*/
9797
/**
@@ -101,12 +101,13 @@ function wrapInSourceNode(prefix, chunk, location, suffix, name) {
101101
* @param {Options} options
102102
*/
103103
function generateJS(ast, options) {
104-
if (!ast.literals || !ast.locations) {
104+
if (!ast.literals || !ast.locations || !ast.classes
105+
|| !ast.expectations || !ast.functions) {
105106
throw new Error(
106107
"generateJS: generate bytecode was not called."
107108
);
108109
}
109-
const { literals, locations } = ast;
110+
const { literals, locations, classes, expectations, functions } = ast;
110111
if (!options.allowedStartRules) {
111112
throw new Error(
112113
"generateJS: options.allowedStartRules was not set."
@@ -191,7 +192,7 @@ function generateJS(ast, options) {
191192
}
192193
if (code instanceof SourceNode) {
193194
inSourceNode++;
194-
code.children = (helper(code.children));
195+
code.children = helper(code.children);
195196
inSourceNode--;
196197
return code;
197198
}
@@ -232,7 +233,7 @@ function generateJS(ast, options) {
232233
return "\"" + stringEscape(literal) + "\"";
233234
}
234235

235-
/** @param {PEG.ast.CharacterRange} cls */
236+
/** @param {PEG.ast.GrammarCharacterClass} cls */
236237
function buildRegexp(cls) {
237238
return "/^["
238239
+ (cls.inverted ? "^" : "")
@@ -244,7 +245,7 @@ function generateJS(ast, options) {
244245
+ "]/" + (cls.ignoreCase ? "i" : "");
245246
}
246247

247-
/** @param {PEG.ast.Expectation} e */
248+
/** @param {PEG.ast.GrammarExpectation} e */
248249
function buildExpectation(e) {
249250
switch (e.type) {
250251
case "rule": {
@@ -289,14 +290,14 @@ function generateJS(ast, options) {
289290

290291
return new SourceNode(
291292
null, null, options.grammarSource, [
292-
(ast.literals || []).map(
293+
literals.map(
293294
(c, i) => " var " + l(i) + " = " + buildLiteral(c) + ";"
294-
).concat("", (ast.classes || []).map(
295+
).concat("", classes.map(
295296
(c, i) => " var " + r(i) + " = " + buildRegexp(c) + ";"
296-
)).concat("", (ast.expectations || []).map(
297+
)).concat("", expectations.map(
297298
(c, i) => " var " + e(i) + " = " + buildExpectation(c) + ";"
298299
)).concat("").join("\n"),
299-
...(ast.functions || []).map(buildFunc),
300+
...functions.map(buildFunc),
300301
]
301302
);
302303
}
@@ -409,10 +410,8 @@ function generateJS(ast, options) {
409410
function generateRuleFunction(rule) {
410411
/** @type {SourceArray} */
411412
const parts = [];
412-
if (!rule.bytecode) {
413-
return parts;
414-
}
415-
const stack = new Stack(rule.name, "s", "var", rule.bytecode);
413+
const bytecode = /** @type {number[]} */(rule.bytecode);
414+
const stack = new Stack(rule.name, "s", "var", bytecode);
416415

417416
/** @param {number[]} bc */
418417
function compile(bc) {
@@ -798,7 +797,7 @@ function generateJS(ast, options) {
798797
return parts;
799798
}
800799

801-
const code = compile(rule.bytecode);
800+
const code = compile(bytecode);
802801

803802
parts.push(wrapInSourceNode(
804803
"function ",

lib/peg.d.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,17 @@ declare namespace ast {
5555
* Type of the classes field on a Grammar node. Not quite the same as
5656
* CharacterClass (`parts` was renamed to `value`).
5757
*/
58-
interface CharacterRange {
58+
interface GrammarCharacterClass {
5959
value: (string[] | string)[];
6060
inverted: boolean;
6161
ignoreCase: boolean;
6262
}
6363

64-
type Expectation =
64+
type GrammarExpectation =
6565
| { type: "any" }
6666
| { type: "literal"; value: string; ignoreCase: boolean }
6767
| { type: "rule"; value: string }
68-
| CharacterRange & { type: "class" }
68+
| GrammarCharacterClass & { type: "class" }
6969
;
7070

7171
/** The main Peggy AST class returned by the parser. */
@@ -88,8 +88,8 @@ declare namespace ast {
8888
* bytecodes to refer back to via index.
8989
*/
9090
literals?: string[];
91-
classes?: CharacterRange[];
92-
expectations?: Expectation[];
91+
classes?: GrammarCharacterClass[];
92+
expectations?: GrammarExpectation[];
9393
functions?: FunctionConst[];
9494
locations?: LocationRange[];
9595
}

test/types/peg.test-d.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ describe("peg.d.ts", () => {
176176
it("creates an AST", () => {
177177
const grammar = peggy.parser.parse(src);
178178
expectType<peggy.ast.Grammar>(grammar);
179-
180179
const visited: { [typ: string]: number } = {};
181180
function add(typ: string): void {
182181
if (!visited[typ]) {
@@ -197,6 +196,17 @@ describe("peg.d.ts", () => {
197196
);
198197
expectType<peggy.ast.Initializer | undefined>(node.initializer);
199198
expectType<peggy.ast.Rule[]>(node.rules);
199+
expectType<string[] | undefined>(node.literals);
200+
expectType<peggy.ast.GrammarCharacterClass[] | undefined>(node.classes);
201+
expectType<peggy.ast.GrammarExpectation[] | undefined>(
202+
node.expectations
203+
);
204+
expectType<peggy.ast.FunctionConst[] | undefined>(
205+
node.functions
206+
);
207+
expectType<peggy.LocationRange[] | undefined>(
208+
node.locations
209+
);
200210

201211
if (node.topLevelInitializer) {
202212
visit(node.topLevelInitializer);
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// @ts-check
2+
"use strict";
3+
4+
const chai = require("chai");
5+
const pass = require("../../../../lib/compiler/passes/generate-js");
6+
7+
const { expect } = chai;
8+
/**
9+
* @typedef {import("../../../../lib/peg")} PEG
10+
*/
11+
12+
describe("compiler pass |generateJS|", () => {
13+
describe("coverage", () => {
14+
/** @type {PEG.ast.Grammar} */
15+
const ast = {
16+
type: "grammar",
17+
rules: [],
18+
location: {
19+
source: "",
20+
start: { line:1, column:1, offset:0 },
21+
end: { line:1, column:1, offset:0 },
22+
},
23+
};
24+
const options
25+
= /** @type {PEG.SourceBuildOptions<PEG.SourceOutputs>} */({});
26+
it("throws unless various grammar fields are set", () => {
27+
expect(
28+
() => pass(ast, options)
29+
).to.throw(Error, "generateJS: generate bytecode was not called.");
30+
ast.literals = [];
31+
expect(
32+
() => pass({ ...ast, literals:[] }, options)
33+
).to.throw(Error, "generateJS: generate bytecode was not called.");
34+
ast.locations = [];
35+
expect(
36+
() => pass({ ...ast, literals:[] }, options)
37+
).to.throw(Error, "generateJS: generate bytecode was not called.");
38+
ast.classes = [];
39+
expect(
40+
() => pass({ ...ast, literals:[] }, options)
41+
).to.throw(Error, "generateJS: generate bytecode was not called.");
42+
ast.expectations = [];
43+
expect(
44+
() => pass({ ...ast, literals:[] }, options)
45+
).to.throw(Error, "generateJS: generate bytecode was not called.");
46+
ast.functions = [];
47+
expect(
48+
() => pass(ast, options)
49+
).to.throw(Error, "generateJS: options.allowedStartRules was not set.");
50+
options.allowedStartRules = ["start"];
51+
expect(
52+
() => pass(ast, options)
53+
).to.not.throw();
54+
});
55+
});
56+
});

0 commit comments

Comments
 (0)