antlr-ng
Version:
Next generation ANTLR Tool
214 lines (213 loc) • 7.1 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { writeFileSync } from "node:fs";
import { Token } from "antlr4ng";
import { AutoIndentWriter, ST, StringWriter } from "stringtemplate4ts";
import { Constants } from "../Constants.js";
import { IssueCode } from "../tool/Issues.js";
import { Grammar } from "../tool/Grammar.js";
import { OutputModelController } from "./OutputModelController.js";
import { OutputModelWalker } from "./OutputModelWalker.js";
import { ParserFactory } from "./ParserFactory.js";
import { CppTarget } from "./target/CppTarget.js";
import { CSharpTarget } from "./target/CSharpTarget.js";
import { DartTarget } from "./target/DartTarget.js";
import { GoTarget } from "./target/GoTarget.js";
import { JavaScriptTarget } from "./target/JavaScriptTarget.js";
import { JavaTarget } from "./target/JavaTarget.js";
import { PHPTarget } from "./target/PHPTarget.js";
import { Python3Target } from "./target/Python3Target.js";
import { SwiftTarget } from "./target/SwiftTarget.js";
import { TypeScriptTarget } from "./target/TypeScriptTarget.js";
const targetLanguages = [
"Cpp",
"CSharp",
"Dart",
"Go",
"JavaScript",
"Java",
"PHP",
"Python3",
"Swift",
"TypeScript"
];
class CodeGenerator {
static {
__name(this, "CodeGenerator");
}
static vocabFilePattern = "<tokens.keys:{t | <t>=<tokens.(t)>\n}><literals.keys:{t | <t>=<literals.(t)>\n}>";
static languageMap = /* @__PURE__ */ new Map([
["Cpp", CppTarget],
["CSharp", CSharpTarget],
["Dart", DartTarget],
["Go", GoTarget],
["JavaScript", JavaScriptTarget],
["Java", JavaTarget],
["PHP", PHPTarget],
["Python3", Python3Target],
["Swift", SwiftTarget],
["TypeScript", TypeScriptTarget]
]);
target;
g;
language;
tool;
lineWidth = 72;
constructor(grammarOrLanguage) {
this.g = grammarOrLanguage instanceof Grammar ? grammarOrLanguage : void 0;
this.tool = this.g?.tool;
this.language = grammarOrLanguage instanceof Grammar ? this.g.getLanguage() : grammarOrLanguage;
this.target = new (CodeGenerator.languageMap.get(this.language))(this);
}
get templates() {
return this.target.templates;
}
generateLexer(toolParameters, header) {
header ??= false;
return this.walk(this.createController(toolParameters.forceAtn).buildLexerOutputModel(header, toolParameters), header);
}
generateParser(toolParameters, header) {
header ??= false;
return this.walk(this.createController().buildParserOutputModel(header, toolParameters), header);
}
generateListener(header) {
header ??= false;
return this.walk(this.createController().buildListenerOutputModel(header), header);
}
generateBaseListener(header) {
header ??= false;
return this.walk(this.createController().buildBaseListenerOutputModel(header), header);
}
generateVisitor(header) {
header ??= false;
return this.walk(this.createController().buildVisitorOutputModel(header), header);
}
generateBaseVisitor(header) {
header ??= false;
return this.walk(this.createController().buildBaseVisitorOutputModel(header), header);
}
writeRecognizer(outputFileST, header) {
this.target.genFile(this.g, outputFileST, this.getRecognizerFileName(header));
}
writeListener(outputFileST, header) {
this.target.genFile(this.g, outputFileST, this.getListenerFileName(header));
}
writeBaseListener(outputFileST, header) {
this.target.genFile(this.g, outputFileST, this.getBaseListenerFileName(header));
}
writeVisitor(outputFileST, header) {
this.target.genFile(this.g, outputFileST, this.getVisitorFileName(header));
}
writeBaseVisitor(outputFileST, header) {
this.target.genFile(this.g, outputFileST, this.getBaseVisitorFileName(header));
}
writeVocabFile() {
const tokenVocabSerialization = this.getTokenVocabOutput();
const fileName = this.getVocabFileName();
if (fileName !== void 0) {
this.target.genFile(this.g, tokenVocabSerialization, fileName);
}
}
write(code, fileName) {
if (this.tool === void 0) {
return;
}
try {
fileName = this.tool.getOutputFile(this.g, fileName);
const w = new StringWriter();
const wr = new AutoIndentWriter(w);
wr.setLineWidth(this.lineWidth);
code.write(wr);
writeFileSync(fileName, w.toString(), "utf8");
} catch (cause) {
if (cause instanceof Error) {
this.g.tool.errorManager.toolError(IssueCode.CannotWriteFile, cause, fileName);
} else {
throw cause;
}
}
}
getRecognizerFileName(header) {
header ??= false;
return this.target.getRecognizerFileName(header);
}
getListenerFileName(header) {
header ??= false;
return this.target.getListenerFileName(header);
}
getVisitorFileName(header) {
header ??= false;
return this.target.getVisitorFileName(header);
}
getBaseListenerFileName(header) {
header ??= false;
return this.target.getBaseListenerFileName(header);
}
getBaseVisitorFileName(header) {
header ??= false;
return this.target.getBaseVisitorFileName(header);
}
/**
* What is the name of the vocab file generated for this grammar?
*
* @returns undefined if no ".tokens" file should be generated.
*/
getVocabFileName() {
return this.g.name + Constants.VocabFileExtension;
}
getHeaderFileName() {
const extST = this.templates.getInstanceOf("headerFileExtension");
if (extST === null) {
return void 0;
}
const recognizerName = this.g.getRecognizerName();
return recognizerName + extST.render();
}
/**
* Generates a token vocab file with all the token names/types. For example:
* ```
* ID=7
* FOR=8
* 'for'=8
* ```
* This is independent of the target language and used by antlr internally.
*
* @returns The token vocab file as a string template.
*/
getTokenVocabOutput() {
const vocabFileST = new ST(CodeGenerator.vocabFilePattern);
const tokens = /* @__PURE__ */ new Map();
for (const [key, value] of this.g.tokenNameToTypeMap) {
if (value >= Token.MIN_USER_TOKEN_TYPE) {
tokens.set(key, value);
}
}
vocabFileST.add("tokens", tokens);
const literals = /* @__PURE__ */ new Map();
for (const [key, value] of this.g.stringLiteralToTypeMap) {
if (value >= Token.MIN_USER_TOKEN_TYPE) {
literals.set(key, value);
}
}
vocabFileST.add("literals", literals);
return vocabFileST;
}
// CREATE TEMPLATES BY WALKING MODEL
createController(forceAtn) {
const factory = new ParserFactory(this, forceAtn);
const controller = new OutputModelController(factory);
factory.controller = controller;
return controller;
}
walk(outputModel, header) {
if (this.tool === void 0) {
throw new Error("Tool is undefined.");
}
const walker = new OutputModelWalker(this.tool, this.templates);
return walker.walk(outputModel, header);
}
}
export {
CodeGenerator,
targetLanguages
};