Skip to content

Commit daf0ffb

Browse files
authored
Merge pull request #13 from devanshj/master
feat: fetch grammar from upstream
2 parents 542cfbb + 63be1ee commit daf0ffb

File tree

12 files changed

+531
-1890
lines changed

12 files changed

+531
-1890
lines changed

.gitignore

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
node_modules
22
dist
3-
src/parser/JavaParser.ts
4-
src/parser/JavaParserListener.ts
5-
src/parser/JavaParserVisitor.ts
6-
src/parser/JavaLexer.ts
7-
src/parser/JavaContexts.ts
8-
src/parser/*.interp
3+
src/parser/*
4+
!src/parser/.gitkeep

build.ts

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import { promises as fs } from 'fs';
2+
import rimraf from 'rimraf';
3+
import fetch from 'node-fetch';
4+
import path from 'path';
5+
import { exec } from 'child_process';
6+
import { once } from 'events';
7+
import { EOL } from 'os';
8+
import { promisify } from 'util';
9+
10+
const files = [
11+
'JavaParser.g4',
12+
'JavaLexer.g4'
13+
];
14+
15+
const main = async () => {
16+
let isStale = await withLog(
17+
'Checking if head is stale... ',
18+
getIsStale(),
19+
isStale => isStale ? 'Stale' : 'Up-to date'
20+
)
21+
if (!isStale && !process.argv.includes('--force')) {
22+
console.log('Exiting, use --force to build anyway');
23+
return;
24+
}
25+
let files = await withLog('Fetching files from upstream... ', getFiles());
26+
await withLog('Writing files... ', writeFiles(files));
27+
await withLog('Updating head.json... ', updateHead());
28+
await withLog('Generating parser...\n', writeParser());
29+
await withLog('Generating contexts... ', writeParserContexts());
30+
await withLog('Compiling typescript files... ', writeJavascript());
31+
console.log('Build successful!');
32+
}
33+
34+
const getIsStale = async () => {
35+
let [head, upstreamHead] = await Promise.all([getHead(), getUpstreamHead()]);
36+
return files.some(file => head[file] !== upstreamHead[file]);
37+
}
38+
39+
const getHead = async () =>
40+
JSON.parse(
41+
await fs.readFile(path.join(__dirname, 'src/head.json'), 'utf-8')
42+
) as { [file: string]: string };
43+
44+
let upstreamHeadCache: { [file: string]: string } | undefined;
45+
const getUpstreamHead = async () => {
46+
if (upstreamHeadCache) return upstreamHeadCache;
47+
48+
let upstreamHead = mergeAll(
49+
await Promise.all(
50+
files.map(async file => {
51+
let res = await fetch(`https://api.github.com/repos/antlr/grammars-v4/commits?path=java/java/${file}`);
52+
let commits = await res.json();
53+
return { [file]: commits[0].sha as string };
54+
})
55+
)
56+
)
57+
upstreamHeadCache = upstreamHead;
58+
return upstreamHead;
59+
}
60+
61+
const getFiles = async () =>
62+
mergeAll(await Promise.all(
63+
files.map(async file => {
64+
let res = await fetch(`https://raw.githubusercontent.com/antlr/grammars-v4/master/java/java/${file}`)
65+
let data = await res.text();
66+
return { [file]: data };
67+
})
68+
))
69+
70+
const writeFiles = (files: { [file: string]: string }) =>
71+
Promise.all(
72+
Object.entries(files)
73+
.map(([file, data]) =>
74+
fs.writeFile(path.join(__dirname, 'src/parser/', file), data)
75+
)
76+
)
77+
78+
const updateHead = async () =>
79+
fs.writeFile(
80+
path.join(__dirname, 'src/head.json'),
81+
JSON.stringify(await getUpstreamHead(), null, ' ')
82+
)
83+
84+
const writeParser = () =>
85+
execCommand(`${prependBinDir('antlr4ts')} -visitor -o src/parser -Xexact-output-dir src/parser/JavaLexer.g4 src/parser/JavaParser.g4`)
86+
87+
const writeParserContexts = async () => {
88+
let listenerSource = await fs.readFile(path.join(__dirname, '/src/parser/JavaParserListener.ts'), 'utf-8');
89+
90+
let exportList =
91+
listenerSource
92+
.split(EOL)
93+
.map((l) => {
94+
let matches = l.match(/import\s*\{\s*(.*Context)\s*\}.*/);
95+
if (matches === null) return null;
96+
return matches[1];
97+
})
98+
.filter((c) => c !== null)
99+
.reduce((list, context) => list + ` ${context},${EOL}`, '');
100+
101+
await fs.writeFile(
102+
path.join(__dirname, '/src/parser/JavaContexts.ts'),
103+
`export {${EOL}${exportList}} from './JavaParser';`
104+
);
105+
}
106+
107+
const writeJavascript = async () => {
108+
await promisify(rimraf)(path.join(__dirname, "/dist"))
109+
await execCommand(prependBinDir('tsc'))
110+
}
111+
112+
const withLog = async <T>(
113+
label: string,
114+
promise: Promise<T>,
115+
fulfilMessage: ((value: T) => string) = () => 'Done'
116+
) => {
117+
process.stdout.write(label);
118+
try {
119+
let value = await promise;
120+
process.stdout.write(fulfilMessage(value) + '\n')
121+
return value;
122+
} catch (error) {
123+
process.stdout.write('Something went wrong\n');
124+
throw error;
125+
}
126+
}
127+
128+
const execCommand = async (command: string) => {
129+
let childProcess = exec(command, { cwd: __dirname })
130+
childProcess.stdout.pipe(process.stdout);
131+
childProcess.stderr.pipe(process.stderr);
132+
133+
let [code] = await once(childProcess, 'exit') as [number];
134+
if (code !== 0) throw undefined;
135+
}
136+
137+
const prependBinDir = (p: string) =>
138+
path.join(__dirname, "/node_modules/.bin/", p);
139+
140+
type MergeAll = <T extends object[]>(xs: T) => UnionToIntersection<T[number]>;
141+
const mergeAll: MergeAll = xs => xs.reduce((m, x) => ({ ...m, ...x }), {}) as any;
142+
143+
type UnionToIntersection<U> =
144+
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
145+
146+
main();

generate-contexts.js

Lines changed: 0 additions & 35 deletions
This file was deleted.

package.json

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,28 @@
2121
"dist"
2222
],
2323
"scripts": {
24-
"build": "rimraf dist && npm run generate:parser && npm run generate:contexts && tsc",
25-
"format": "prettier --write src/**.ts **/*.json",
24+
"build": "ts-node build.ts",
25+
"format": "prettier --write build.ts src/**.ts **/*.json",
2626
"prepublish": "yarn build",
27-
"generate:parser": "antlr4ts -visitor -o src/parser -Xexact-output-dir src/parser/JavaLexer.g4 src/parser/JavaParser.g4",
28-
"generate:contexts": "node generate-contexts.js",
2927
"precommit": "lint-staged",
3028
"postcommit": "git update-index --again",
3129
"test": "jest"
3230
},
3331
"devDependencies": {
3432
"@types/jest": "^26.0.4",
3533
"@types/node": "^14.0.22",
34+
"@types/node-fetch": "^2.5.7",
35+
"@types/rimraf": "^3.0.0",
3636
"antlr4ts-cli": "^0.5.0-alpha.3",
37-
"husky": "^0.14.3",
37+
"husky": "^4.2.5",
3838
"jest": "^26.1.0",
39-
"lint-staged": "^7.2.0",
40-
"prettier": "^1.13.7",
41-
"rimraf": "^2.6.2",
39+
"lint-staged": "^10.2.11",
40+
"node-fetch": "^2.6.0",
41+
"prettier": "^2.0.5",
42+
"rimraf": "^3.0.2",
4243
"ts-jest": "^26.1.1",
43-
"tslint": "^5.10.0",
44+
"ts-node": "^8.10.2",
45+
"tslint": "^6.1.2",
4446
"typescript": "^3.9.6"
4547
},
4648
"dependencies": {

src/head.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"JavaParser.g4": null,
3+
"JavaLexer.g4": null
4+
}

src/parser/.gitkeep

Whitespace-only changes.

0 commit comments

Comments
 (0)