mirror of
https://github.com/duhanbalci/dexpr.git
synced 2026-07-02 00:29:15 +00:00
initial commit
This commit is contained in:
4313
editor/node_modules/@lezer/generator/dist/index.cjs
generated
vendored
Normal file
4313
editor/node_modules/@lezer/generator/dist/index.cjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
95
editor/node_modules/@lezer/generator/dist/index.d.cts
generated
vendored
Normal file
95
editor/node_modules/@lezer/generator/dist/index.d.cts
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
import { NodePropSource, NodeProp } from '@lezer/common';
|
||||
import { ExternalTokenizer, Stack, ContextTracker, LRParser } from '@lezer/lr';
|
||||
|
||||
type BuildOptions = {
|
||||
/**
|
||||
The name of the grammar file
|
||||
*/
|
||||
fileName?: string;
|
||||
/**
|
||||
A function that should be called with warnings. The default is
|
||||
to call `console.warn`.
|
||||
*/
|
||||
warn?: (message: string) => void;
|
||||
/**
|
||||
Whether to include term names in the output file. Defaults to
|
||||
false.
|
||||
*/
|
||||
includeNames?: boolean;
|
||||
/**
|
||||
Determines the module system used by the output file. Can be
|
||||
either `"cjs"` (CommonJS) or `"es"` (ES2015 module), defaults to
|
||||
`"es"`.
|
||||
*/
|
||||
moduleStyle?: string;
|
||||
/**
|
||||
Set this to true to output TypeScript code instead of plain
|
||||
JavaScript.
|
||||
*/
|
||||
typeScript?: boolean;
|
||||
/**
|
||||
The name of the export that holds the parser in the output file.
|
||||
Defaults to `"parser"`.
|
||||
*/
|
||||
exportName?: string;
|
||||
/**
|
||||
When calling `buildParser`, this can be used to provide
|
||||
placeholders for external tokenizers.
|
||||
*/
|
||||
externalTokenizer?: (name: string, terms: {
|
||||
[name: string]: number;
|
||||
}) => ExternalTokenizer;
|
||||
/**
|
||||
Used by `buildParser` to resolve external prop sources.
|
||||
*/
|
||||
externalPropSource?: (name: string) => NodePropSource;
|
||||
/**
|
||||
Provide placeholders for external specializers when using
|
||||
`buildParser`.
|
||||
*/
|
||||
externalSpecializer?: (name: string, terms: {
|
||||
[name: string]: number;
|
||||
}) => (value: string, stack: Stack) => number;
|
||||
/**
|
||||
If given, will be used to initialize external props in the parser
|
||||
returned by `buildParser`.
|
||||
*/
|
||||
externalProp?: (name: string) => NodeProp<any>;
|
||||
/**
|
||||
If given, will be used as context tracker in a parser built with
|
||||
`buildParser`.
|
||||
*/
|
||||
contextTracker?: ContextTracker<any> | ((terms: {
|
||||
[name: string]: number;
|
||||
}) => ContextTracker<any>);
|
||||
};
|
||||
/**
|
||||
Build an in-memory parser instance for a given grammar. This is
|
||||
mostly useful for testing. If your grammar uses external
|
||||
tokenizers, you'll have to provide the `externalTokenizer` option
|
||||
for the returned parser to be able to parse anything.
|
||||
*/
|
||||
declare function buildParser(text: string, options?: BuildOptions): LRParser;
|
||||
/**
|
||||
Build the code that represents the parser tables for a given
|
||||
grammar description. The `parser` property in the return value
|
||||
holds the main file that exports the `Parser` instance. The
|
||||
`terms` property holds a declaration file that defines constants
|
||||
for all of the named terms in grammar, holding their ids as value.
|
||||
This is useful when external code, such as a tokenizer, needs to
|
||||
be able to use these ids. It is recommended to run a tree-shaking
|
||||
bundler when importing this file, since you usually only need a
|
||||
handful of the many terms in your code.
|
||||
*/
|
||||
declare function buildParserFile(text: string, options?: BuildOptions): {
|
||||
parser: string;
|
||||
terms: string;
|
||||
};
|
||||
|
||||
/**
|
||||
The type of error raised when the parser generator finds an issue.
|
||||
*/
|
||||
declare class GenError extends Error {
|
||||
}
|
||||
|
||||
export { type BuildOptions, GenError, buildParser, buildParserFile };
|
||||
95
editor/node_modules/@lezer/generator/dist/index.d.ts
generated
vendored
Normal file
95
editor/node_modules/@lezer/generator/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
import { NodePropSource, NodeProp } from '@lezer/common';
|
||||
import { ExternalTokenizer, Stack, ContextTracker, LRParser } from '@lezer/lr';
|
||||
|
||||
type BuildOptions = {
|
||||
/**
|
||||
The name of the grammar file
|
||||
*/
|
||||
fileName?: string;
|
||||
/**
|
||||
A function that should be called with warnings. The default is
|
||||
to call `console.warn`.
|
||||
*/
|
||||
warn?: (message: string) => void;
|
||||
/**
|
||||
Whether to include term names in the output file. Defaults to
|
||||
false.
|
||||
*/
|
||||
includeNames?: boolean;
|
||||
/**
|
||||
Determines the module system used by the output file. Can be
|
||||
either `"cjs"` (CommonJS) or `"es"` (ES2015 module), defaults to
|
||||
`"es"`.
|
||||
*/
|
||||
moduleStyle?: string;
|
||||
/**
|
||||
Set this to true to output TypeScript code instead of plain
|
||||
JavaScript.
|
||||
*/
|
||||
typeScript?: boolean;
|
||||
/**
|
||||
The name of the export that holds the parser in the output file.
|
||||
Defaults to `"parser"`.
|
||||
*/
|
||||
exportName?: string;
|
||||
/**
|
||||
When calling `buildParser`, this can be used to provide
|
||||
placeholders for external tokenizers.
|
||||
*/
|
||||
externalTokenizer?: (name: string, terms: {
|
||||
[name: string]: number;
|
||||
}) => ExternalTokenizer;
|
||||
/**
|
||||
Used by `buildParser` to resolve external prop sources.
|
||||
*/
|
||||
externalPropSource?: (name: string) => NodePropSource;
|
||||
/**
|
||||
Provide placeholders for external specializers when using
|
||||
`buildParser`.
|
||||
*/
|
||||
externalSpecializer?: (name: string, terms: {
|
||||
[name: string]: number;
|
||||
}) => (value: string, stack: Stack) => number;
|
||||
/**
|
||||
If given, will be used to initialize external props in the parser
|
||||
returned by `buildParser`.
|
||||
*/
|
||||
externalProp?: (name: string) => NodeProp<any>;
|
||||
/**
|
||||
If given, will be used as context tracker in a parser built with
|
||||
`buildParser`.
|
||||
*/
|
||||
contextTracker?: ContextTracker<any> | ((terms: {
|
||||
[name: string]: number;
|
||||
}) => ContextTracker<any>);
|
||||
};
|
||||
/**
|
||||
Build an in-memory parser instance for a given grammar. This is
|
||||
mostly useful for testing. If your grammar uses external
|
||||
tokenizers, you'll have to provide the `externalTokenizer` option
|
||||
for the returned parser to be able to parse anything.
|
||||
*/
|
||||
declare function buildParser(text: string, options?: BuildOptions): LRParser;
|
||||
/**
|
||||
Build the code that represents the parser tables for a given
|
||||
grammar description. The `parser` property in the return value
|
||||
holds the main file that exports the `Parser` instance. The
|
||||
`terms` property holds a declaration file that defines constants
|
||||
for all of the named terms in grammar, holding their ids as value.
|
||||
This is useful when external code, such as a tokenizer, needs to
|
||||
be able to use these ids. It is recommended to run a tree-shaking
|
||||
bundler when importing this file, since you usually only need a
|
||||
handful of the many terms in your code.
|
||||
*/
|
||||
declare function buildParserFile(text: string, options?: BuildOptions): {
|
||||
parser: string;
|
||||
terms: string;
|
||||
};
|
||||
|
||||
/**
|
||||
The type of error raised when the parser generator finds an issue.
|
||||
*/
|
||||
declare class GenError extends Error {
|
||||
}
|
||||
|
||||
export { type BuildOptions, GenError, buildParser, buildParserFile };
|
||||
4309
editor/node_modules/@lezer/generator/dist/index.js
generated
vendored
Normal file
4309
editor/node_modules/@lezer/generator/dist/index.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
45
editor/node_modules/@lezer/generator/dist/rollup-plugin-lezer.cjs
generated
vendored
Normal file
45
editor/node_modules/@lezer/generator/dist/rollup-plugin-lezer.cjs
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var index_js = require('./index.cjs');
|
||||
|
||||
function lezer(config = {}) {
|
||||
let built = Object.create(null);
|
||||
|
||||
return {
|
||||
name: "rollup-plugin-lezer",
|
||||
|
||||
resolveId(source, importer) {
|
||||
let m = /^([^\0].*\.grammar)(\.terms)?$/.exec(source);
|
||||
if (!m) return null
|
||||
let id = path.resolve(importer ? path.dirname(importer) : process.cwd(), m[1]);
|
||||
return m[2] ? `\0${id}.terms` : id
|
||||
},
|
||||
|
||||
load(id) {
|
||||
let m = /^\0?(.*\.grammar)(\.terms)?$/.exec(id);
|
||||
if (!m) return null
|
||||
if (!m[2]) this.addWatchFile(id);
|
||||
let base = m[1];
|
||||
let build = built[base] || (built[base] = fs.promises.readFile(base, "utf8").then(code => index_js.buildParserFile(code, {
|
||||
fileName: base,
|
||||
moduleStyle: "es",
|
||||
exportName: config.exportName,
|
||||
warn: message => this.warn(message)
|
||||
})));
|
||||
return build.then(result => m[2] ? result.terms : result.parser)
|
||||
},
|
||||
|
||||
watchChange(id) {
|
||||
if (built[id]) built[id] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const rollup = lezer;
|
||||
|
||||
exports.lezer = lezer;
|
||||
exports.rollup = rollup;
|
||||
3
editor/node_modules/@lezer/generator/dist/rollup-plugin-lezer.d.cts
generated
vendored
Normal file
3
editor/node_modules/@lezer/generator/dist/rollup-plugin-lezer.d.cts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import {Plugin} from "rollup"
|
||||
|
||||
export function lezer(config?: {exportName?: string}): Plugin
|
||||
3
editor/node_modules/@lezer/generator/dist/rollup-plugin-lezer.d.ts
generated
vendored
Normal file
3
editor/node_modules/@lezer/generator/dist/rollup-plugin-lezer.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import {Plugin} from "rollup"
|
||||
|
||||
export function lezer(config?: {exportName?: string}): Plugin
|
||||
38
editor/node_modules/@lezer/generator/dist/rollup-plugin-lezer.js
generated
vendored
Normal file
38
editor/node_modules/@lezer/generator/dist/rollup-plugin-lezer.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
import {resolve, dirname} from "path"
|
||||
import {promises as fs} from "fs"
|
||||
import {buildParserFile} from "./index.js"
|
||||
|
||||
export function lezer(config = {}) {
|
||||
let built = Object.create(null)
|
||||
|
||||
return {
|
||||
name: "rollup-plugin-lezer",
|
||||
|
||||
resolveId(source, importer) {
|
||||
let m = /^([^\0].*\.grammar)(\.terms)?$/.exec(source)
|
||||
if (!m) return null
|
||||
let id = resolve(importer ? dirname(importer) : process.cwd(), m[1])
|
||||
return m[2] ? `\0${id}.terms` : id
|
||||
},
|
||||
|
||||
load(id) {
|
||||
let m = /^\0?(.*\.grammar)(\.terms)?$/.exec(id)
|
||||
if (!m) return null
|
||||
if (!m[2]) this.addWatchFile(id)
|
||||
let base = m[1]
|
||||
let build = built[base] || (built[base] = fs.readFile(base, "utf8").then(code => buildParserFile(code, {
|
||||
fileName: base,
|
||||
moduleStyle: "es",
|
||||
exportName: config.exportName,
|
||||
warn: message => this.warn(message)
|
||||
})))
|
||||
return build.then(result => m[2] ? result.terms : result.parser)
|
||||
},
|
||||
|
||||
watchChange(id) {
|
||||
if (built[id]) built[id] = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const rollup = lezer
|
||||
187
editor/node_modules/@lezer/generator/dist/test.cjs
generated
vendored
Normal file
187
editor/node_modules/@lezer/generator/dist/test.cjs
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
'use strict';
|
||||
|
||||
var common = require('@lezer/common');
|
||||
|
||||
const none = [];
|
||||
class TestSpec {
|
||||
constructor(name, props, children = none, wildcard = false) {
|
||||
this.name = name;
|
||||
this.props = props;
|
||||
this.children = children;
|
||||
this.wildcard = wildcard;
|
||||
}
|
||||
static parse(spec) {
|
||||
let pos = 0, tok = "sof", value = "";
|
||||
function err() {
|
||||
throw new SyntaxError("Invalid test spec: " + spec);
|
||||
}
|
||||
function next() {
|
||||
while (pos < spec.length && /\s/.test(spec.charAt(pos)))
|
||||
pos++;
|
||||
if (pos == spec.length)
|
||||
return tok = "eof";
|
||||
let next = spec.charAt(pos++);
|
||||
if (next == "(" && spec.slice(pos, pos + 4) == "...)") {
|
||||
pos += 4;
|
||||
return tok = "...";
|
||||
}
|
||||
if (/[\[\](),=]/.test(next))
|
||||
return tok = next;
|
||||
if (/[^()\[\],="\s]/.test(next)) {
|
||||
let name = /[^()\[\],="\s]*/.exec(spec.slice(pos - 1));
|
||||
value = name[0];
|
||||
pos += name[0].length - 1;
|
||||
return tok = "name";
|
||||
}
|
||||
if (next == '"') {
|
||||
let content = /^"((?:[^\\"]|\\.)*)"/.exec(spec.slice(pos - 1)) || err();
|
||||
value = JSON.parse(content[0]);
|
||||
pos += content[0].length - 1;
|
||||
return tok = "name";
|
||||
}
|
||||
return err();
|
||||
}
|
||||
next();
|
||||
function parseSeq() {
|
||||
let seq = [];
|
||||
while (tok != "eof" && tok != ")") {
|
||||
seq.push(parse());
|
||||
if (tok == ",")
|
||||
next();
|
||||
}
|
||||
return seq;
|
||||
}
|
||||
function parse() {
|
||||
let name = value, children = none, props = [], wildcard = false;
|
||||
if (tok != "name")
|
||||
err();
|
||||
next();
|
||||
if (tok == "[") {
|
||||
next();
|
||||
while (tok != "]") {
|
||||
if (tok != "name")
|
||||
err();
|
||||
let prop = common.NodeProp[value], val = "";
|
||||
if (!(prop instanceof common.NodeProp))
|
||||
err();
|
||||
next();
|
||||
if (tok == "=") {
|
||||
next();
|
||||
if (tok != "name")
|
||||
err();
|
||||
val = value;
|
||||
next();
|
||||
}
|
||||
props.push({ prop, value: prop.deserialize(val) });
|
||||
}
|
||||
next();
|
||||
}
|
||||
if (tok == "(") {
|
||||
next();
|
||||
children = parseSeq();
|
||||
// @ts-ignore TypeScript doesn't understand that `next` may have mutated `tok` (#9998)
|
||||
if (tok != ")")
|
||||
err();
|
||||
next();
|
||||
}
|
||||
else if (tok == "...") {
|
||||
wildcard = true;
|
||||
next();
|
||||
}
|
||||
return new TestSpec(name, props, children, wildcard);
|
||||
}
|
||||
let result = parseSeq();
|
||||
if (tok != "eof")
|
||||
err();
|
||||
return result;
|
||||
}
|
||||
matches(type) {
|
||||
if (type.name != this.name)
|
||||
return false;
|
||||
for (let { prop, value } of this.props)
|
||||
if ((value || type.prop(prop)) && JSON.stringify(type.prop(prop)) != JSON.stringify(value))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
function defaultIgnore(type) { return /\W/.test(type.name); }
|
||||
function testTree(tree, expect, mayIgnore = defaultIgnore) {
|
||||
let specs = TestSpec.parse(expect);
|
||||
let stack = [specs], pos = [0];
|
||||
tree.iterate({
|
||||
enter(n) {
|
||||
if (!n.name)
|
||||
return;
|
||||
let last = stack.length - 1, index = pos[last], seq = stack[last];
|
||||
let next = index < seq.length ? seq[index] : null;
|
||||
if (next && next.matches(n.type)) {
|
||||
if (next.wildcard) {
|
||||
pos[last]++;
|
||||
return false;
|
||||
}
|
||||
pos.push(0);
|
||||
stack.push(next.children);
|
||||
return undefined;
|
||||
}
|
||||
else if (mayIgnore(n.type)) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
let parent = last > 0 ? stack[last - 1][pos[last - 1]].name : "tree";
|
||||
let after = next ? next.name + (parent == "tree" ? "" : " in " + parent) : `end of ${parent}`;
|
||||
throw new Error(`Expected ${after}, got ${n.name} at ${n.to} \n${tree}`);
|
||||
}
|
||||
},
|
||||
leave(n) {
|
||||
if (!n.name)
|
||||
return;
|
||||
let last = stack.length - 1, index = pos[last], seq = stack[last];
|
||||
if (index < seq.length)
|
||||
throw new Error(`Unexpected end of ${n.name}. Expected ${seq.slice(index).map(s => s.name).join(", ")} at ${n.from}\n${tree}`);
|
||||
pos.pop();
|
||||
stack.pop();
|
||||
pos[last - 1]++;
|
||||
}
|
||||
});
|
||||
if (pos[0] != specs.length)
|
||||
throw new Error(`Unexpected end of tree. Expected ${stack[0].slice(pos[0]).map(s => s.name).join(", ")} at ${tree.length}\n${tree}`);
|
||||
}
|
||||
function toLineContext(file, index) {
|
||||
const endEol = file.indexOf('\n', index + 80);
|
||||
const endIndex = endEol === -1 ? file.length : endEol;
|
||||
return file.substring(index, endIndex).split(/\n/).map(str => ' | ' + str).join('\n');
|
||||
}
|
||||
function fileTests(file, fileName, mayIgnore = defaultIgnore) {
|
||||
let caseExpr = /\s*#[ \t]*(.*)(?:\r\n|\r|\n)([^]*?)==+>([^]*?)(?:$|(?:\r\n|\r|\n)+(?=#))/gy;
|
||||
let tests = [];
|
||||
let lastIndex = 0;
|
||||
for (;;) {
|
||||
let m = caseExpr.exec(file);
|
||||
if (!m)
|
||||
throw new Error(`Unexpected file format in ${fileName} around\n\n${toLineContext(file, lastIndex)}`);
|
||||
let text = m[2].trim(), expected = m[3].trim();
|
||||
let [, name, configStr] = /(.*?)(\{.*?\})?$/.exec(m[1]);
|
||||
let config = configStr ? JSON.parse(configStr) : null;
|
||||
let strict = !/⚠|\.\.\./.test(expected);
|
||||
tests.push({
|
||||
name,
|
||||
text,
|
||||
expected,
|
||||
configStr,
|
||||
config,
|
||||
strict,
|
||||
run(parser) {
|
||||
if (parser.configure && (strict || config))
|
||||
parser = parser.configure(Object.assign({ strict }, config));
|
||||
testTree(parser.parse(text), expected, mayIgnore);
|
||||
}
|
||||
});
|
||||
lastIndex = m.index + m[0].length;
|
||||
if (lastIndex == file.length)
|
||||
break;
|
||||
}
|
||||
return tests;
|
||||
}
|
||||
|
||||
exports.fileTests = fileTests;
|
||||
exports.testTree = testTree;
|
||||
15
editor/node_modules/@lezer/generator/dist/test.d.cts
generated
vendored
Normal file
15
editor/node_modules/@lezer/generator/dist/test.d.cts
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Tree, Parser, NodeType } from '@lezer/common';
|
||||
|
||||
declare function defaultIgnore(type: NodeType): boolean;
|
||||
declare function testTree(tree: Tree, expect: string, mayIgnore?: typeof defaultIgnore): void;
|
||||
declare function fileTests(file: string, fileName: string, mayIgnore?: typeof defaultIgnore): {
|
||||
name: string;
|
||||
text: string;
|
||||
expected: string;
|
||||
configStr: string;
|
||||
config: object;
|
||||
strict: boolean;
|
||||
run(parser: Parser): void;
|
||||
}[];
|
||||
|
||||
export { fileTests, testTree };
|
||||
15
editor/node_modules/@lezer/generator/dist/test.d.ts
generated
vendored
Normal file
15
editor/node_modules/@lezer/generator/dist/test.d.ts
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Tree, Parser, NodeType } from '@lezer/common';
|
||||
|
||||
declare function defaultIgnore(type: NodeType): boolean;
|
||||
declare function testTree(tree: Tree, expect: string, mayIgnore?: typeof defaultIgnore): void;
|
||||
declare function fileTests(file: string, fileName: string, mayIgnore?: typeof defaultIgnore): {
|
||||
name: string;
|
||||
text: string;
|
||||
expected: string;
|
||||
configStr: string;
|
||||
config: object;
|
||||
strict: boolean;
|
||||
run(parser: Parser): void;
|
||||
}[];
|
||||
|
||||
export { fileTests, testTree };
|
||||
184
editor/node_modules/@lezer/generator/dist/test.js
generated
vendored
Normal file
184
editor/node_modules/@lezer/generator/dist/test.js
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
import { NodeProp } from '@lezer/common';
|
||||
|
||||
const none = [];
|
||||
class TestSpec {
|
||||
constructor(name, props, children = none, wildcard = false) {
|
||||
this.name = name;
|
||||
this.props = props;
|
||||
this.children = children;
|
||||
this.wildcard = wildcard;
|
||||
}
|
||||
static parse(spec) {
|
||||
let pos = 0, tok = "sof", value = "";
|
||||
function err() {
|
||||
throw new SyntaxError("Invalid test spec: " + spec);
|
||||
}
|
||||
function next() {
|
||||
while (pos < spec.length && /\s/.test(spec.charAt(pos)))
|
||||
pos++;
|
||||
if (pos == spec.length)
|
||||
return tok = "eof";
|
||||
let next = spec.charAt(pos++);
|
||||
if (next == "(" && spec.slice(pos, pos + 4) == "...)") {
|
||||
pos += 4;
|
||||
return tok = "...";
|
||||
}
|
||||
if (/[\[\](),=]/.test(next))
|
||||
return tok = next;
|
||||
if (/[^()\[\],="\s]/.test(next)) {
|
||||
let name = /[^()\[\],="\s]*/.exec(spec.slice(pos - 1));
|
||||
value = name[0];
|
||||
pos += name[0].length - 1;
|
||||
return tok = "name";
|
||||
}
|
||||
if (next == '"') {
|
||||
let content = /^"((?:[^\\"]|\\.)*)"/.exec(spec.slice(pos - 1)) || err();
|
||||
value = JSON.parse(content[0]);
|
||||
pos += content[0].length - 1;
|
||||
return tok = "name";
|
||||
}
|
||||
return err();
|
||||
}
|
||||
next();
|
||||
function parseSeq() {
|
||||
let seq = [];
|
||||
while (tok != "eof" && tok != ")") {
|
||||
seq.push(parse());
|
||||
if (tok == ",")
|
||||
next();
|
||||
}
|
||||
return seq;
|
||||
}
|
||||
function parse() {
|
||||
let name = value, children = none, props = [], wildcard = false;
|
||||
if (tok != "name")
|
||||
err();
|
||||
next();
|
||||
if (tok == "[") {
|
||||
next();
|
||||
while (tok != "]") {
|
||||
if (tok != "name")
|
||||
err();
|
||||
let prop = NodeProp[value], val = "";
|
||||
if (!(prop instanceof NodeProp))
|
||||
err();
|
||||
next();
|
||||
if (tok == "=") {
|
||||
next();
|
||||
if (tok != "name")
|
||||
err();
|
||||
val = value;
|
||||
next();
|
||||
}
|
||||
props.push({ prop, value: prop.deserialize(val) });
|
||||
}
|
||||
next();
|
||||
}
|
||||
if (tok == "(") {
|
||||
next();
|
||||
children = parseSeq();
|
||||
// @ts-ignore TypeScript doesn't understand that `next` may have mutated `tok` (#9998)
|
||||
if (tok != ")")
|
||||
err();
|
||||
next();
|
||||
}
|
||||
else if (tok == "...") {
|
||||
wildcard = true;
|
||||
next();
|
||||
}
|
||||
return new TestSpec(name, props, children, wildcard);
|
||||
}
|
||||
let result = parseSeq();
|
||||
if (tok != "eof")
|
||||
err();
|
||||
return result;
|
||||
}
|
||||
matches(type) {
|
||||
if (type.name != this.name)
|
||||
return false;
|
||||
for (let { prop, value } of this.props)
|
||||
if ((value || type.prop(prop)) && JSON.stringify(type.prop(prop)) != JSON.stringify(value))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
function defaultIgnore(type) { return /\W/.test(type.name); }
|
||||
function testTree(tree, expect, mayIgnore = defaultIgnore) {
|
||||
let specs = TestSpec.parse(expect);
|
||||
let stack = [specs], pos = [0];
|
||||
tree.iterate({
|
||||
enter(n) {
|
||||
if (!n.name)
|
||||
return;
|
||||
let last = stack.length - 1, index = pos[last], seq = stack[last];
|
||||
let next = index < seq.length ? seq[index] : null;
|
||||
if (next && next.matches(n.type)) {
|
||||
if (next.wildcard) {
|
||||
pos[last]++;
|
||||
return false;
|
||||
}
|
||||
pos.push(0);
|
||||
stack.push(next.children);
|
||||
return undefined;
|
||||
}
|
||||
else if (mayIgnore(n.type)) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
let parent = last > 0 ? stack[last - 1][pos[last - 1]].name : "tree";
|
||||
let after = next ? next.name + (parent == "tree" ? "" : " in " + parent) : `end of ${parent}`;
|
||||
throw new Error(`Expected ${after}, got ${n.name} at ${n.to} \n${tree}`);
|
||||
}
|
||||
},
|
||||
leave(n) {
|
||||
if (!n.name)
|
||||
return;
|
||||
let last = stack.length - 1, index = pos[last], seq = stack[last];
|
||||
if (index < seq.length)
|
||||
throw new Error(`Unexpected end of ${n.name}. Expected ${seq.slice(index).map(s => s.name).join(", ")} at ${n.from}\n${tree}`);
|
||||
pos.pop();
|
||||
stack.pop();
|
||||
pos[last - 1]++;
|
||||
}
|
||||
});
|
||||
if (pos[0] != specs.length)
|
||||
throw new Error(`Unexpected end of tree. Expected ${stack[0].slice(pos[0]).map(s => s.name).join(", ")} at ${tree.length}\n${tree}`);
|
||||
}
|
||||
function toLineContext(file, index) {
|
||||
const endEol = file.indexOf('\n', index + 80);
|
||||
const endIndex = endEol === -1 ? file.length : endEol;
|
||||
return file.substring(index, endIndex).split(/\n/).map(str => ' | ' + str).join('\n');
|
||||
}
|
||||
function fileTests(file, fileName, mayIgnore = defaultIgnore) {
|
||||
let caseExpr = /\s*#[ \t]*(.*)(?:\r\n|\r|\n)([^]*?)==+>([^]*?)(?:$|(?:\r\n|\r|\n)+(?=#))/gy;
|
||||
let tests = [];
|
||||
let lastIndex = 0;
|
||||
for (;;) {
|
||||
let m = caseExpr.exec(file);
|
||||
if (!m)
|
||||
throw new Error(`Unexpected file format in ${fileName} around\n\n${toLineContext(file, lastIndex)}`);
|
||||
let text = m[2].trim(), expected = m[3].trim();
|
||||
let [, name, configStr] = /(.*?)(\{.*?\})?$/.exec(m[1]);
|
||||
let config = configStr ? JSON.parse(configStr) : null;
|
||||
let strict = !/⚠|\.\.\./.test(expected);
|
||||
tests.push({
|
||||
name,
|
||||
text,
|
||||
expected,
|
||||
configStr,
|
||||
config,
|
||||
strict,
|
||||
run(parser) {
|
||||
if (parser.configure && (strict || config))
|
||||
parser = parser.configure(Object.assign({ strict }, config));
|
||||
testTree(parser.parse(text), expected, mayIgnore);
|
||||
}
|
||||
});
|
||||
lastIndex = m.index + m[0].length;
|
||||
if (lastIndex == file.length)
|
||||
break;
|
||||
}
|
||||
return tests;
|
||||
}
|
||||
|
||||
export { fileTests, testTree };
|
||||
Reference in New Issue
Block a user