antlr-ng
Version:
Next generation ANTLR Tool
284 lines (283 loc) • 10.6 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { ANTLRv4Parser } from "../generated/ANTLRv4Parser.js";
import { CommonTreeNodeStream } from "../tree/CommonTreeNodeStream.js";
import { SourceGenTriggers } from "../tree/walkers/SourceGenTriggers.js";
import { Utils } from "../misc/Utils.js";
import { IssueCode } from "../tool/Issues.js";
import { LeftRecursiveRule } from "../tool/LeftRecursiveRule.js";
import { PredAST } from "../tool/ast/PredAST.js";
import { Action } from "./model/Action.js";
import { AltBlock } from "./model/AltBlock.js";
import { BaseListenerFile } from "./model/BaseListenerFile.js";
import { BaseVisitorFile } from "./model/BaseVisitorFile.js";
import { Choice } from "./model/Choice.js";
import { Lexer } from "./model/Lexer.js";
import { LexerFile } from "./model/LexerFile.js";
import { ListenerFile } from "./model/ListenerFile.js";
import { RuleActionFunction } from "./model/RuleActionFunction.js";
import { RuleSempredFunction } from "./model/RuleSempredFunction.js";
import { VisitorFile } from "./model/VisitorFile.js";
class OutputModelController {
static {
__name(this, "OutputModelController");
}
/** Who does the work? */
factory;
currentBlock;
currentOuterMostAlt;
/** While walking code in rules, this is set to the tree walker that triggers actions. */
walker;
currentRuleStack = new Array();
errorManager;
constructor(factory) {
this.factory = factory;
this.errorManager = factory.g.tool.errorManager;
}
/**
* Build a file with a parser containing rule functions. Use the controller as factory in SourceGenTriggers so
* it triggers codegen extensions too, not just the factory functions in this factory.
*/
buildParserOutputModel(header, toolParameters) {
const gen = this.factory.getGenerator();
const file = this.parserFile(gen.getRecognizerFileName(header), toolParameters);
file.parser = this.parser(file);
const g = this.factory.g;
for (const r of g.rules.values()) {
this.buildRuleFunction(file.parser, r);
}
return file;
}
buildLexerOutputModel(header, toolParameters) {
const gen = this.factory.getGenerator();
const file = this.lexerFile(gen.getRecognizerFileName(header), toolParameters);
file.lexer = this.lexer(file);
const g = this.factory.g;
for (const r of g.rules.values()) {
this.buildLexerRuleActions(file.lexer, r);
}
return file;
}
buildListenerOutputModel(header) {
const gen = this.factory.getGenerator();
return new ListenerFile(this.factory, gen.getListenerFileName(header));
}
buildBaseListenerOutputModel(header) {
const gen = this.factory.getGenerator();
return new BaseListenerFile(this.factory, gen.getBaseListenerFileName(header));
}
buildVisitorOutputModel(header) {
const gen = this.factory.getGenerator();
return new VisitorFile(this.factory, gen.getVisitorFileName(header));
}
buildBaseVisitorOutputModel(header) {
const gen = this.factory.getGenerator();
return new BaseVisitorFile(this.factory, gen.getBaseVisitorFileName(header));
}
parserFile(fileName, toolParameters) {
return this.factory.parserFile(fileName, toolParameters);
}
parser(file) {
return this.factory.parser(file);
}
lexerFile(fileName, toolParameters) {
return new LexerFile(this.factory, fileName, toolParameters);
}
lexer(file) {
return new Lexer(this.factory, file);
}
/**
* Create RuleFunction per rule and update sempreds,actions of parser output object with stuff found in r.
*/
buildRuleFunction(parser, r) {
const ruleFunction = this.rule(r);
parser.funcs.push(ruleFunction);
this.pushCurrentRule(ruleFunction);
ruleFunction.fillNamedActions(this.factory, r);
if (r instanceof LeftRecursiveRule) {
this.buildLeftRecursiveRuleFunction(r, ruleFunction);
} else {
this.buildNormalRuleFunction(r, ruleFunction);
}
const g = this.getGrammar();
for (const a of r.actions) {
if (a instanceof PredAST) {
const p = a;
let rsf = parser.sempredFuncs.get(r);
if (rsf === void 0) {
rsf = new RuleSempredFunction(this.factory, r, ruleFunction.ctxType);
parser.sempredFuncs.set(r, rsf);
}
rsf.actions.set(g.sempreds.get(p), new Action(this.factory, p));
}
}
this.popCurrentRule();
}
buildLeftRecursiveRuleFunction(r, ruleFunction) {
this.buildNormalRuleFunction(r, ruleFunction);
const gen = this.factory.getGenerator();
const codegenTemplates = gen.templates;
const outerAlt = ruleFunction.code[0];
const primaryAltsCode = new Array();
const primaryStuff = outerAlt.ops[0];
if (primaryStuff instanceof Choice) {
const primaryAltBlock = primaryStuff;
primaryAltsCode.push(...primaryAltBlock.alts);
} else {
primaryAltsCode.push(primaryStuff);
}
const opAltStarBlock = outerAlt.ops[1];
const altForOpAltBlock = opAltStarBlock.alts[0];
const opAltsCode = new Array();
const opStuff = altForOpAltBlock.ops[0];
if (opStuff instanceof AltBlock) {
const opAltBlock = opStuff;
opAltsCode.push(...opAltBlock.alts);
} else {
opAltsCode.push(opStuff);
}
for (let i = 0; i < primaryAltsCode.length; i++) {
const altInfo = r.recPrimaryAlts[i];
if (altInfo.altLabel === void 0) {
continue;
}
const altActionST = codegenTemplates.getInstanceOf("recRuleReplaceContext");
altActionST.add("ctxName", Utils.capitalize(altInfo.altLabel));
const altAction = new Action(this.factory, ruleFunction.altLabelCtxs.get(altInfo.altLabel), altActionST);
const alt = primaryAltsCode[i];
alt.insertOp(0, altAction);
}
const setStopTokenAST = codegenTemplates.getInstanceOf("recRuleSetStopToken");
const setStopTokenAction = new Action(this.factory, ruleFunction.ruleCtx, setStopTokenAST);
outerAlt.insertOp(1, setStopTokenAction);
const setPrevCtx = codegenTemplates.getInstanceOf("recRuleSetPrevCtx");
const setPrevCtxAction = new Action(this.factory, ruleFunction.ruleCtx, setPrevCtx);
opAltStarBlock.addIterationOp(setPrevCtxAction);
for (let i = 0; i < opAltsCode.length; i++) {
let altActionST;
const altInfo = r.recOpAlts.getElement(i);
let templateName;
if (altInfo.altLabel !== void 0) {
templateName = "recRuleLabeledAltStartAction";
altActionST = codegenTemplates.getInstanceOf(templateName);
altActionST.add("currentAltLabel", altInfo.altLabel);
} else {
templateName = "recRuleAltStartAction";
altActionST = codegenTemplates.getInstanceOf(templateName);
altActionST.add("ctxName", Utils.capitalize(r.name));
}
altActionST.add("ruleName", r.name);
altActionST.add("label", altInfo.leftRecursiveRuleRefLabel);
if (altActionST.impl.formalArguments.has("isListLabel")) {
altActionST.add("isListLabel", altInfo.isListLabel);
} else if (altInfo.isListLabel) {
this.errorManager.toolError(IssueCode.CodeTemaplateArgIssue, templateName, "isListLabel");
}
const decl = ruleFunction.altLabelCtxs.get(altInfo.altLabel);
const altAction = new Action(this.factory, decl, altActionST);
opAltsCode[i].insertOp(0, altAction);
}
}
buildNormalRuleFunction(r, ruleFunction) {
const gen = this.factory.getGenerator();
const blk = r.ast.getFirstChildWithType(ANTLRv4Parser.BLOCK);
const nodes = new CommonTreeNodeStream(blk);
this.walker = new SourceGenTriggers(this.errorManager, nodes, this);
ruleFunction.code = this.walker.block(null, null);
ruleFunction.hasLookaheadBlock = this.walker.hasLookaheadBlock;
ruleFunction.ctxType = gen.target.getRuleFunctionContextStructName(ruleFunction);
ruleFunction.postamble = this.rulePostamble(ruleFunction, r);
}
buildLexerRuleActions(lexer, r) {
if (r.actions.length === 0) {
return;
}
const gen = this.factory.getGenerator();
const g = this.factory.g;
const ctxType = gen.target.getRuleFunctionContextStructName(r);
const raf = lexer.actionFuncs.get(r) ?? new RuleActionFunction(this.factory, r, ctxType);
for (const a of r.actions) {
if (a instanceof PredAST) {
const p = a;
let rsf = lexer.sempredFuncs.get(r);
if (!rsf) {
rsf = new RuleSempredFunction(this.factory, r, ctxType);
lexer.sempredFuncs.set(r, rsf);
}
rsf.actions.set(g.sempreds.get(p), new Action(this.factory, p));
} else if (a.getType() === ANTLRv4Parser.ACTION) {
raf.actions.set(g.lexerActions.get(a), new Action(this.factory, a));
}
}
if (raf.actions.size > 0 && !lexer.actionFuncs.has(r)) {
lexer.actionFuncs.set(r, raf);
}
}
rule(r) {
return this.factory.rule(r);
}
rulePostamble(ruleFunction, r) {
return this.factory.rulePostamble(ruleFunction, r);
}
getGrammar() {
return this.factory.g;
}
alternative(alt, outerMost) {
return this.factory.alternative(alt, outerMost);
}
finishAlternative(blk, ops, outerMost) {
return this.factory.finishAlternative(blk, ops);
}
ruleRef(id, label, args) {
return this.factory.ruleRef(id, label, args);
}
tokenRef(id, label, args) {
return this.factory.tokenRef(id, label, args);
}
stringRef(id, label) {
return this.factory.stringRef(id, label);
}
/** (A|B|C) possibly with ebnfRoot and label. */
set(setAST, labelAST, invert) {
return this.factory.set(setAST, labelAST, invert);
}
epsilon(alt, outerMost) {
return this.factory.epsilon(alt, outerMost);
}
wildcard(ast, labelAST) {
return this.factory.wildcard(ast, labelAST);
}
action(ast) {
return this.factory.action(ast);
}
sempred(ast) {
return this.factory.sempred(ast);
}
getChoiceBlock(blkAST, alts, label) {
return this.factory.getChoiceBlock(blkAST, alts, label);
}
getEBNFBlock(ebnfRoot, alts) {
return this.factory.getEBNFBlock(ebnfRoot, alts);
}
needsImplicitLabel(id, op) {
return this.factory.needsImplicitLabel(id, op);
}
get currentRuleFunction() {
if (this.currentRuleStack.length > 0) {
return this.currentRuleStack[this.currentRuleStack.length - 1];
}
return void 0;
}
pushCurrentRule(r) {
this.currentRuleStack.push(r);
}
popCurrentRule() {
if (this.currentRuleStack.length > 0) {
return this.currentRuleStack.pop();
}
return null;
}
}
export {
OutputModelController
};