Skip to content

Commit

Permalink
Allow registry to be created from grammar sources directly
Browse files Browse the repository at this point in the history
  • Loading branch information
nishtahir committed Oct 7, 2020
1 parent 1346524 commit 1c3851e
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 53 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"url": "https://github.com/PanAeon/vscode-tmgrammar-test/issues"
},
"scripts": {
"build": "tsc",
"build": "npx tsc",
"test": "mocha -r ts-node/register 'test/**/*.test.ts'",
"coverage": "npx nyc --reporter=html mocha -r ts-node/register 'test/**/*.test.ts'"
},
Expand Down Expand Up @@ -42,7 +42,7 @@
"istanbul": "^0.4.5",
"mocha": "^6.2.3",
"nyc": "^15.0.1",
"ts-node": "^8.10.0",
"ts-node": "^8.10.2",
"tslint": "^5.20.1",
"typescript": "^3.8.3"
},
Expand All @@ -53,4 +53,4 @@
"glob": "^7.1.6",
"vscode-textmate": "^4.1.1"
}
}
}
83 changes: 46 additions & 37 deletions src/unit/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import { GrammarTestCase, TestFailure } from './model';
import { parseGrammarTestCase } from './parsing';
//import { basename } from 'path';

export {parseGrammarTestCase, GrammarTestCase, TestFailure, missingScopes_}
export { parseGrammarTestCase, GrammarTestCase, TestFailure, missingScopes_ }


export async function runGrammarTestCase(registry: tm.Registry, testCase: GrammarTestCase): Promise<TestFailure[]> {
return registry.loadGrammar(testCase.metadata.scope).then((grammar: tm.IGrammar|null) => {
return registry.loadGrammar(testCase.metadata.scope).then((grammar: tm.IGrammar | null) => {

if (!grammar) {
throw new Error(`Could not load scope ${testCase.metadata.scope}`);
throw new Error(`Could not load scope ${testCase.metadata.scope}`);
}

const assertions = toMap((x) => x.sourceLineNumber, testCase.assertions)
Expand All @@ -24,14 +24,14 @@ export async function runGrammarTestCase(registry: tm.Registry, testCase: Gramma
let failures: TestFailure[] = []

testCase.source.forEach((line: string, n: number) => {
var {tokens, ruleStack:ruleStack1} = grammar.tokenizeLine(line, ruleStack);
var { tokens, ruleStack: ruleStack1 } = grammar.tokenizeLine(line, ruleStack);
ruleStack = ruleStack1;

if (assertions[n] !== undefined) {
let { testCaseLineNumber, scopeAssertions } = assertions[n];

scopeAssertions.forEach(({ from, to, scopes: requiredScopes, exclude:excludedScopes }) => {
const xs = tokens.filter((t) => from < t.endIndex && to > t.startIndex)
scopeAssertions.forEach(({ from, to, scopes: requiredScopes, exclude: excludedScopes }) => {
const xs = tokens.filter((t) => from < t.endIndex && to > t.startIndex)
if (xs.length === 0 && requiredScopes.length > 0) {
failures.push(<TestFailure>{
missing: requiredScopes,
Expand Down Expand Up @@ -68,62 +68,71 @@ export async function runGrammarTestCase(registry: tm.Registry, testCase: Gramma

}

export function createRegistryFromGrammars(grammars: Array<{ path: string, content: string }>): tm.Registry {
let grammarIndex: { [key: string]: tm.IRawGrammar } = {}

export function createRegistry(grammarPaths: string[]) : tm.Registry {
let grammars: { [key: string]: tm.IRawGrammar } = {}

for (let path of grammarPaths) {
let content = fs.readFileSync(path).toString()
let rawGrammar = tm.parseRawGrammar(content, path)
grammars[rawGrammar.scopeName] = rawGrammar;
}
for (const grammar of grammars) {
const { path, content } = grammar;
let rawGrammar = tm.parseRawGrammar(content, path);
grammarIndex[rawGrammar.scopeName] = rawGrammar;
}

return new tm.Registry(<tm.RegistryOptions>{
loadGrammar: function (scopeName) {
if (grammars[scopeName] !== undefined) {
return new Promise((c, e) => {
c(grammars[scopeName]);
});
} else {
console.warn("grammar not found for '" + scopeName + "'")
return new tm.Registry(<tm.RegistryOptions>{
loadGrammar: (scopeName) => {
if (grammarIndex[scopeName] !== undefined) {
return new Promise((fulfill, _) => {
fulfill(grammarIndex[scopeName]);
});
}
console.warn(`grammar not found for "${scopeName}"`)
return null;
}
return null;
}
});
});
}

export function createRegistry(grammarPaths: string[]): tm.Registry {
return createRegistryFromGrammars(
grammarPaths.map((path) => {
return {
path,
content: fs.readFileSync(path).toString()
}
})
);
}

// ------------------------------------------------------------ helper functions --------------------------------------


function missingScopes_(rs:string[], as: string[]):string[] {
let i = 0,j = 0;
while(i < as.length && j < rs.length) {
if (as[i] === rs[j]) {
i++;
j++;
} else {
i++
}
function missingScopes_(rs: string[], as: string[]): string[] {
let i = 0, j = 0;
while (i < as.length && j < rs.length) {
if (as[i] === rs[j]) {
i++;
j++;
} else {
i++
}
}

return j === rs.length ? [] : rs.slice(j);
}


function toMap<T>(f : (x:T) => number, xs: T[]): { [key: number]: T } {
function toMap<T>(f: (x: T) => number, xs: T[]): { [key: number]: T } {
return xs.reduce((m: { [key: number]: T }, x: T) => {
m[f(x)] = x;
return m;
}, {});
}

function arraysEqual<T>(a: T[], b:T[]) : boolean {
function arraysEqual<T>(a: T[], b: T[]): boolean {
if (a === b) { return true };
if (a === null || b === null) { return false };
if (a.length !== b.length) { return false };

for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) { return false };
if (a[i] !== b[i]) { return false };
}
return true;
}
Expand Down
17 changes: 8 additions & 9 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
"declaration": true, /* Generates corresponding '.d.ts' file. */
"declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./dist", /* Redirect output structure to the directory. */
"outDir": "./dist", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "incremental": true, /* Enable incremental compilation */
Expand All @@ -21,7 +21,7 @@
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
Expand All @@ -31,13 +31,13 @@
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */

/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */

/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
Expand All @@ -48,15 +48,14 @@
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */

/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */

/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
}
}
}
1 change: 0 additions & 1 deletion tslint.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

{
"rules": {
"no-unused-expression": true,
Expand Down

0 comments on commit 1c3851e

Please sign in to comment.