antlr-ng
Version:
Next generation ANTLR Tool
126 lines (125 loc) • 4.18 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import {
AtomTransition,
BlockEndState,
CodePointTransitions,
EpsilonTransition,
IntervalSet,
NotSetTransition,
RangeTransition,
SetTransition
} from "antlr4ng";
import { CharSupport } from "../misc/CharSupport.js";
import { Character } from "../support/Character.js";
import { IssueCode } from "../tool/Issues.js";
class ATNOptimizer {
static {
__name(this, "ATNOptimizer");
}
static optimize(g, atn) {
ATNOptimizer.optimizeSets(g, atn);
ATNOptimizer.optimizeStates(atn);
}
static optimizeSets(g, atn) {
if (g.isParser()) {
return;
}
const decisions = atn.decisionToState;
for (const decision of decisions) {
if (decision.ruleIndex >= 0) {
const rule = g.getRule(decision.ruleIndex);
if (Character.isLowerCase(rule.name.codePointAt(0))) {
continue;
}
}
const setTransitions = new IntervalSet();
for (let i = 0; i < decision.transitions.length; i++) {
const epsTransition = decision.transitions[i];
if (!(epsTransition instanceof EpsilonTransition)) {
continue;
}
if (epsTransition.target.transitions.length !== 1) {
continue;
}
const transition = epsTransition.target.transitions[0];
if (!(transition.target instanceof BlockEndState)) {
continue;
}
if (transition instanceof NotSetTransition) {
continue;
}
if (transition instanceof AtomTransition || transition instanceof RangeTransition || transition instanceof SetTransition) {
setTransitions.addOne(i);
}
}
const setIntervals = Array.from(setTransitions);
for (let i = setIntervals.length - 1; i >= 0; i--) {
const interval = setIntervals[i];
if (interval.length <= 1) {
continue;
}
const blockEndState = decision.transitions[interval.start].target.transitions[0].target;
const matchSet = new IntervalSet();
for (let j = interval.start; j <= interval.stop; j++) {
const matchTransition = decision.transitions[j].target.transitions[0];
if (matchTransition instanceof NotSetTransition) {
throw new Error("Not yet implemented.");
}
const set = matchTransition.label;
for (const setInterval of set) {
const a = setInterval.start;
const b = setInterval.stop;
if (a !== -1 && b !== -1) {
for (let v = a; v <= b; v++) {
if (matchSet.contains(v)) {
g.tool.errorManager.grammarError(
IssueCode.CharactersCollisionInSet,
g.fileName,
null,
CharSupport.getANTLRCharLiteralForChar(v),
CharSupport.getIntervalSetEscapedString(matchSet)
);
break;
}
}
}
}
matchSet.addSet(set);
}
let newTransition;
const intervals = Array.from(matchSet);
if (intervals.length === 1) {
const matchInterval = intervals[0];
newTransition = CodePointTransitions.createWithCodePointRange(
blockEndState,
matchInterval.start,
matchInterval.stop
);
} else {
newTransition = new SetTransition(blockEndState, matchSet);
}
decision.transitions[interval.start].target.setTransition(0, newTransition);
for (let j = interval.start + 1; j <= interval.stop; j++) {
const removed = decision.removeTransition(interval.start + 1);
atn.removeState(removed.target);
}
}
}
}
static optimizeStates(atn) {
const compressed = new Array();
let i = 0;
for (const s of atn.states) {
if (s !== null) {
compressed.push(s);
s.stateNumber = i;
i++;
}
}
atn.states.splice(0, atn.states.length, ...compressed);
}
}
export {
ATNOptimizer
};