@making-sense/antlr-editor
Version:
ANTLR Typescript editor
265 lines • 9.95 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SyntaxLink = void 0;
const log_1 = require("../utils/log");
const multiplyMode_1 = require("./multiplyMode");
const statementType_1 = require("./statementType");
const identifierPrefix = "⟨⟨";
const identifierPostfix = "⟩⟩";
const alternativesPrefix = "{";
const alternativesPostfix = "}¹";
const optionalPrefix = "{";
const optionalPostfix = "}";
const zeromorePrefix = "{";
const zeromorePostfix = "}*";
const onemorePrefix = "{";
const onemorePostfix = "}+";
class SyntaxLink {
constructor(value) {
this._type = statementType_1.StatementType.Unknown;
this._chain = [];
this._keywords = [];
this._value = "";
this._syntax = "";
this._alternatives = false;
this._multiplied = multiplyMode_1.MultiplyMode.None;
this.hasKeyword = () => this._keywords.length !== 0;
this.hasChain = () => this._chain.length !== 0;
this.hasValue = () => this._value !== "";
this.isEmpty = () => !this.hasChain() && !this.hasValue();
this.isMultiplied = () => this._multiplied === multiplyMode_1.MultiplyMode.Optional ||
this._multiplied === multiplyMode_1.MultiplyMode.Onemore ||
this._multiplied === multiplyMode_1.MultiplyMode.Zeromore;
this.isOptional = () => this._multiplied === multiplyMode_1.MultiplyMode.Optional || this._multiplied === multiplyMode_1.MultiplyMode.Zeromore;
if (value)
this._value = value;
}
add(entry) {
this._chain.push(entry);
if (this._alternatives || !this.hasKeyword())
this._keywords.push(...entry._keywords);
this._type = statementType_1.StatementType.Block;
this.constructSyntax();
}
addAll(entries) {
entries.forEach(entry => this.add(entry));
}
collapse() {
// Remove empty links
this._chain = this._chain.filter(link => !link.isEmpty());
// One alternative means this block doesn't contain alternatives
if (this._alternatives && this._chain.length < 2)
this._alternatives = false;
// If there's only one sublink, elevate it
if (this._chain.length === 1)
this.overwrite(this._chain[0]);
// If chain is empty, skip the rest
if (this._chain.length === 0)
return;
// If there are child alternatives or children with keywords only, elevate them
if (this._alternatives) {
const added = [];
const removed = [];
this._chain.forEach(link => {
if (link._alternatives) {
removed.push(link);
link._chain.forEach(sublink => {
sublink._multiplied = (0, multiplyMode_1.mergeMultiplyMode)(sublink._multiplied, link._multiplied);
added.push(sublink);
});
}
});
this._chain = this._chain.filter(link => !removed.includes(link));
this._chain.push(...added);
}
else {
if (this._chain[0].isAlternativeKeywords()) {
this._alternatives = true;
const link = this._chain.shift();
const chain = this._chain;
this._chain = [];
if (link) {
link._chain.forEach(sublink => {
sublink._multiplied = (0, multiplyMode_1.mergeMultiplyMode)(sublink._multiplied, link._multiplied);
const alternative = new SyntaxLink();
alternative.add(sublink);
alternative.addAll(chain);
alternative.collapse();
this._chain.push(alternative);
});
}
}
}
this.constructSyntax();
}
overwrite(other) {
this._chain = other._chain;
this._keywords = other._keywords;
this._alternatives = other._alternatives;
this._syntax = other._syntax;
this._value = other._value;
this._multiplied = (0, multiplyMode_1.mergeMultiplyMode)(this._multiplied, other._multiplied);
this._type = other._type;
}
constructSyntax() {
if (this.hasValue()) {
this._syntax =
this.multiplyPrefix() +
(this.isType([statementType_1.StatementType.Rule, statementType_1.StatementType.Operand])
? identifierPrefix + this._value + identifierPostfix
: this._value) +
this.multiplyPostfix();
if (this.hasChain())
log_1.Log.warn("Link with chain and value " + this._value, "SyntaxLink");
}
else {
if (this._alternatives) {
this._syntax =
(this.isMultiplied() ? this.multiplyPrefix() : alternativesPrefix) +
this._chain.map(link => link._syntax).join(" | ") +
(this.isMultiplied() ? this.multiplyPostfix() : alternativesPostfix);
}
else {
this._syntax =
(this.isMultiplied() ? this.multiplyPrefix() : "") +
this._chain.map(link => link._syntax).join(" ") +
(this.isMultiplied() ? this.multiplyPostfix() : "");
}
}
}
multiplyPrefix() {
switch (this._multiplied) {
case multiplyMode_1.MultiplyMode.None:
return "";
case multiplyMode_1.MultiplyMode.Optional:
return optionalPrefix;
case multiplyMode_1.MultiplyMode.Onemore:
return onemorePrefix;
case multiplyMode_1.MultiplyMode.Zeromore:
return zeromorePrefix;
}
}
multiplyPostfix() {
switch (this._multiplied) {
case multiplyMode_1.MultiplyMode.None:
return "";
case multiplyMode_1.MultiplyMode.Optional:
return optionalPostfix;
case multiplyMode_1.MultiplyMode.Onemore:
return onemorePostfix;
case multiplyMode_1.MultiplyMode.Zeromore:
return zeromorePostfix;
}
}
contains(value) {
return this._chain.some(entry => entry._value === value);
}
get alternatives() {
return this._alternatives;
}
set alternatives(alternatives) {
this._alternatives = alternatives;
}
get value() {
return this._value;
}
get chain() {
return this._chain;
}
set keyword(value) {
this._value = value;
this._keywords.push(this._value);
this._type = statementType_1.StatementType.Keyword;
this.constructSyntax();
}
set operator(value) {
this._value = value;
this._type = statementType_1.StatementType.Operator;
this.constructSyntax();
}
set operand(value) {
this._value = value.toLocaleLowerCase();
this._type = statementType_1.StatementType.Operand;
this.constructSyntax();
}
set rule(value) {
this._value = value;
this._type = statementType_1.StatementType.Rule;
this.constructSyntax();
}
get syntax() {
return this._syntax;
}
get multiplied() {
return this._multiplied;
}
set multiplied(value) {
this._multiplied = value;
}
get type() {
return this._type;
}
isType(types) {
return types.includes(this._type);
}
isAlternativeKeywords() {
return (this._alternatives &&
this.hasChain() &&
this._chain.every(link => link.isType([statementType_1.StatementType.Keyword])));
}
collectSyntax(keywords) {
keywords.createLevel(this.isOptional());
if (!this._alternatives) {
this._chain.forEach(link => {
switch (link._type) {
case statementType_1.StatementType.Keyword: {
keywords.addKeyword(link._value, link._syntax, link._value, link.isOptional());
break;
}
case statementType_1.StatementType.Operator: {
if (link.isOptional()) {
keywords.append(link._syntax, "");
}
else {
keywords.append(link._syntax, link._value);
}
break;
}
case statementType_1.StatementType.Operand: {
keywords.append(link._syntax, "");
break;
}
case statementType_1.StatementType.Rule: {
keywords.append(link._syntax, "");
break;
}
case statementType_1.StatementType.Block: {
link.collectSyntax(keywords);
break;
}
default: {
log_1.Log.warn("Unknown syntax link type", "SyntaxLink");
break;
}
}
});
}
keywords.terminateLevel();
}
/**
* Removes erroneous optional flags added to tokens and statements during tokenizing process.
*/
unOption() {
this._multiplied = multiplyMode_1.MultiplyMode.None;
if (this._alternatives) {
this._chain.forEach(link => link.unOption());
}
else {
const link = this._chain[0];
if (link)
link.unOption();
}
}
}
exports.SyntaxLink = SyntaxLink;
//# sourceMappingURL=syntaxLink.js.map