@imc-trading/svlangserver
Version:
A language server for systemverilog
307 lines (306 loc) • 13.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.r = exports.GrammarEngine = exports.GrammarToken = void 0;
const genutils_1 = require("./genutils");
var TokenRegExpPatternActionType;
(function (TokenRegExpPatternActionType) {
TokenRegExpPatternActionType[TokenRegExpPatternActionType["None"] = 0] = "None";
TokenRegExpPatternActionType[TokenRegExpPatternActionType["Push"] = 1] = "Push";
TokenRegExpPatternActionType[TokenRegExpPatternActionType["Pop"] = 2] = "Pop";
TokenRegExpPatternActionType[TokenRegExpPatternActionType["PushScopes"] = 3] = "PushScopes";
TokenRegExpPatternActionType[TokenRegExpPatternActionType["PopScopes"] = 4] = "PopScopes";
})(TokenRegExpPatternActionType || (TokenRegExpPatternActionType = {}));
var StateActionType;
(function (StateActionType) {
StateActionType[StateActionType["None"] = 0] = "None";
StateActionType[StateActionType["Save"] = 1] = "Save";
StateActionType[StateActionType["Restore"] = 2] = "Restore";
StateActionType[StateActionType["Delete"] = 3] = "Delete";
})(StateActionType || (StateActionType = {}));
class TokenRegExpPatternActionNone {
constructor() {
this.kind = TokenRegExpPatternActionType.None;
}
}
class TokenRegExpPatternActionPush {
constructor(context) {
this.kind = TokenRegExpPatternActionType.Push;
this.context = context;
}
}
class TokenRegExpPatternActionPop {
constructor(context) {
this.kind = TokenRegExpPatternActionType.Pop;
this.context = (context == undefined) ? null : context;
}
}
class TokenRegExpPatternActionPushScopes {
constructor(scopes) {
this.kind = TokenRegExpPatternActionType.PushScopes;
this.scopes = scopes;
}
}
class TokenRegExpPatternActionPopScopes {
constructor(scopes) {
this.kind = TokenRegExpPatternActionType.PopScopes;
this.scopes = scopes;
}
}
class TokenRegExpPattern {
constructor(regExp, tokenNames, action, stateAction) {
this.regExp = new RegExp(regExp, 'y');
this.tokenNames = [];
this.tokenNames = this.tokenNames.concat(tokenNames);
this.action = (action == undefined) ? new TokenRegExpPatternActionNone : action;
this.stateAction = (stateAction == undefined) ? StateActionType.None : stateAction;
}
}
class Context {
constructor(scopeName, patterns) {
this.scopeName = scopeName;
this.patterns = [];
if (patterns) {
this.patterns = this.patterns.concat(patterns);
}
}
add(patterns) {
this.patterns = this.patterns.concat(patterns);
}
include(contexts) {
this.patterns = this.patterns.concat(contexts);
}
}
function getContextPatterns(contexts) {
let result = new Map();
for (let context of contexts) {
if (result.has(context)) {
continue;
}
result.set(context, []);
let patterns = [];
for (let pattern of context.patterns) {
if (pattern instanceof TokenRegExpPattern) {
patterns.push(pattern);
}
else if (pattern instanceof Context) {
let sresult = getContextPatterns([pattern]);
sresult.forEach((value, key) => {
result.set(key, value);
});
patterns = patterns.concat(sresult.get(pattern));
}
else {
genutils_1.ConnectionLogger.error("Unsupported pattern");
}
}
result.set(context, patterns);
}
return result;
}
function loadGrammar(grammar) {
let contexts = new Map();
let anonContextCount = 0;
for (let [contextName, context] of Object.entries(grammar)) {
contexts.set(contextName, new Context(context["scopeName"] || ""));
}
for (let [contextName, context] of Object.entries(grammar)) {
_processContext(contextName, context);
}
return contexts;
function _processContext(contextName, context) {
for (let pattern of context["patterns"]) {
let stateAction;
if (pattern.saveState) {
stateAction = StateActionType.Save;
}
else if (pattern.restoreState) {
stateAction = StateActionType.Restore;
}
else if (pattern.deleteState) {
stateAction = StateActionType.Delete;
}
else {
stateAction = StateActionType.None;
}
if (pattern.match != undefined) {
if (pattern.push != undefined) {
let actionContext;
if (typeof pattern.push === "string" || pattern.push instanceof String) {
if (!contexts.has(pattern.push)) {
genutils_1.ConnectionLogger.error(`${pattern.push} is not a valid context`);
return null;
}
actionContext = contexts.get(pattern.push);
}
else {
anonContextCount++;
let anonContext = new Context(pattern.push.scopeName || "");
let anonContextName = "&AnonContext" + anonContextCount.toString();
contexts.set(anonContextName, anonContext);
_processContext(anonContextName, pattern.push);
actionContext = anonContext;
}
contexts.get(contextName).add([new TokenRegExpPattern(pattern.match, pattern.tokens, new TokenRegExpPatternActionPush(actionContext), stateAction)]);
}
else if (pattern.pop != undefined) {
let actionContext = undefined;
if (typeof pattern.pop === "string" || pattern.pop instanceof String) {
if (pattern.pop) {
if (!contexts.has(pattern.pop)) {
genutils_1.ConnectionLogger.error(`${pattern.pop} is not a valid context`);
return null;
}
actionContext = contexts.get(pattern.pop);
}
}
else {
anonContextCount++;
let anonContext = new Context(pattern.pop.scopeName || "");
let anonContextName = "&AnonContext" + anonContextCount.toString();
contexts.set(anonContextName, anonContext);
_processContext(anonContextName, pattern.pop);
actionContext = anonContext;
}
contexts.get(contextName).add([new TokenRegExpPattern(pattern.match, pattern.tokens, new TokenRegExpPatternActionPop(actionContext), stateAction)]);
}
else if (pattern.pushScopes != undefined) {
contexts.get(contextName).add([new TokenRegExpPattern(pattern.match, pattern.tokens, new TokenRegExpPatternActionPushScopes(pattern.pushScopes), stateAction)]);
}
else if (pattern.popScopes != undefined) {
contexts.get(contextName).add([new TokenRegExpPattern(pattern.match, pattern.tokens, new TokenRegExpPatternActionPopScopes(pattern.popScopes), stateAction)]);
}
else {
contexts.get(contextName).add([new TokenRegExpPattern(pattern.match, pattern.tokens, undefined, stateAction)]);
}
}
else if (pattern.include != undefined) {
if (!contexts.has(pattern.include)) {
genutils_1.ConnectionLogger.error(`${pattern.include} is not a valid context`);
return null;
}
contexts.get(contextName).include([contexts.get(pattern.include)]);
}
else {
genutils_1.ConnectionLogger.error("Invalid grammar pattern found");
return null;
}
}
}
}
class GrammarToken {
}
exports.GrammarToken = GrammarToken;
class GrammarEngine {
constructor(grammar, invalidTokenScope) {
this._contextMap = loadGrammar(grammar);
this._contextPatterns = getContextPatterns([...this._contextMap.values()]);
this._invalidTokenScope = invalidTokenScope;
}
tokenize(text, initScopeStack) {
let result = [];
let lastIndex = 0;
let mainContext = this._contextMap.get("Main");
let contextStack = [mainContext];
let scopeStack = (initScopeStack == undefined) ? [mainContext.scopeName] : initScopeStack;
let stateStack = [];
let currInvalidToken = "";
let currInvalidTokenIndex = 0;
while (lastIndex < text.length) {
let prevLastIndex = lastIndex;
for (let pattern of this._contextPatterns.get(contextStack[contextStack.length - 1])) {
pattern.regExp.lastIndex = lastIndex;
let match = pattern.regExp.exec(text);
if (match) {
if (match[0].length == 0) {
genutils_1.ConnectionLogger.error(`Empty length pattern found. Pattern - ${pattern.regExp}`);
return [];
}
else if (pattern.tokenNames.length + 1 != match.length) {
genutils_1.ConnectionLogger.error(`Pattern token-names length different than captures. Pattern - ${pattern.regExp}, token-name=${pattern.tokenNames.join(", ")}`);
return [];
}
let offset = 0;
for (let i = 1; i < match.length; i++) {
if (match[i] && match[i].length > 0) {
offset += match[i].length;
}
}
if (offset != match[0].length) {
genutils_1.ConnectionLogger.error(`captures don't add up. Complete match - ${match[0]}, captures - "${match.slice(1).join('" ')}"`);
return [];
}
if (currInvalidToken) {
result.push({ text: currInvalidToken, index: currInvalidTokenIndex, scopes: scopeStack.concat([this._invalidTokenScope]) });
}
currInvalidToken = "";
offset = 0;
for (let i = 1; i < match.length; i++) {
if (match[i] && match[i].length > 0) {
result.push({ text: match[i], index: match.index + offset, scopes: scopeStack.concat([pattern.tokenNames[i - 1]]) });
offset += match[i].length;
}
}
if (pattern.stateAction == StateActionType.Save) {
stateStack.push([[...contextStack], [...scopeStack]]);
}
else if (pattern.stateAction == StateActionType.Restore) {
contextStack = [...stateStack[stateStack.length - 1][0]];
scopeStack = [...stateStack[stateStack.length - 1][1]];
}
else if (pattern.stateAction == StateActionType.Delete) {
stateStack.pop();
}
if (pattern.action.kind == TokenRegExpPatternActionType.Push) {
let context = (pattern.action).context;
contextStack.push(context);
if (context.scopeName) {
scopeStack.push(context.scopeName);
}
}
else if (pattern.action.kind == TokenRegExpPatternActionType.Pop) {
let poppedContext = contextStack.pop();
if (poppedContext.scopeName) {
scopeStack.pop();
}
let context = (pattern.action).context;
if (context) {
contextStack.push(context);
if (context.scopeName) {
scopeStack.push(context.scopeName);
}
}
}
else if (pattern.action.kind == TokenRegExpPatternActionType.PushScopes) {
scopeStack = scopeStack.concat((pattern.action).scopes);
}
else if (pattern.action.kind == TokenRegExpPatternActionType.PopScopes) {
for (let scope of (pattern.action).scopes) {
let poppedScope = "";
while ((poppedScope != scope) && (scopeStack.length > 0)) {
poppedScope = scopeStack.pop();
}
}
}
lastIndex = pattern.regExp.lastIndex;
break;
}
}
if (lastIndex == prevLastIndex) {
if (!currInvalidToken) {
currInvalidTokenIndex = lastIndex;
}
currInvalidToken += text[lastIndex];
lastIndex++;
}
}
if (currInvalidToken != "") {
result.push({ text: currInvalidToken, index: currInvalidTokenIndex, scopes: scopeStack.concat([this._invalidTokenScope]) });
}
return result;
}
}
exports.GrammarEngine = GrammarEngine;
function r(strings) {
return strings.raw[0];
}
exports.r = r;