UNPKG

@making-sense/antlr-editor

Version:
265 lines 9.95 kB
"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