@maniascript/parser
Version:
Maniascript parser
317 lines (316 loc) • 11.6 kB
JavaScript
import { Kind, Node, VariableDeclaration, Identifier, Main, FunctionDeclaration, ConstDeclaration, ConstAliasing, IncludeDirective, BlockStatement, SettingDirective, CommandDirective, StructDeclaration, StructAliasing, LabelDeclaration, LabelStatement, ForeachStatement, ForStatement, SwitchtypeStatement } from './ast.js';
import { getUnknownType } from './type.js';
import { SourceLocationRange } from './position.js';
var SymbolKind;
(function (SymbolKind) {
SymbolKind["Base"] = "Base";
SymbolKind["Structure"] = "Structure";
SymbolKind["Label"] = "Label";
SymbolKind["Typed"] = "Typed";
SymbolKind["Setting"] = "Setting";
SymbolKind["Command"] = "Command";
SymbolKind["Constant"] = "Constant";
SymbolKind["Variable"] = "Variable";
SymbolKind["Parameter"] = "Parameter";
SymbolKind["Scope"] = "Scope";
SymbolKind["Block"] = "Block";
SymbolKind["LabelBlock"] = "LabelBlock";
SymbolKind["Namespace"] = "Namespace";
SymbolKind["Function"] = "Function";
SymbolKind["ControlFlow"] = "ControlFlow";
})(SymbolKind || (SymbolKind = {}));
class BaseSymbol {
#name;
#source;
_parent = null;
kind;
constructor(name, node, kind) {
this.#name = name;
this.#source = node.source;
this.kind = kind ?? SymbolKind.Base;
}
get name() {
return this.#name;
}
get source() {
return this.#source;
}
get parent() {
return this._parent;
}
}
class StructureSymbol extends BaseSymbol {
constructor(name, node, kind) {
super(name, node, kind ?? SymbolKind.Structure);
}
}
class LabelSymbol extends BaseSymbol {
constructor(name, node, kind) {
super(name, node, kind ?? SymbolKind.Label);
}
}
class TypedSymbol extends BaseSymbol {
type;
constructor(name, node, kind, type) {
super(name, node, kind ?? SymbolKind.Typed);
if (type === undefined) {
this.type = getUnknownType();
}
else {
this.type = type;
}
}
}
class SettingSymbol extends TypedSymbol {
constructor(name, node, kind) {
super(name, node, kind ?? SymbolKind.Setting);
}
}
class CommandSymbol extends TypedSymbol {
constructor(name, node, kind) {
super(name, node, kind ?? SymbolKind.Command);
}
}
class ConstantSymbol extends TypedSymbol {
constructor(name, node, kind) {
super(name, node, kind ?? SymbolKind.Constant);
}
}
class VariableSymbol extends TypedSymbol {
constructor(name, node, kind) {
super(name, node, kind ?? SymbolKind.Variable);
}
}
class ParameterSymbol extends TypedSymbol {
constructor(name, node, kind) {
super(name, node, kind ?? SymbolKind.Parameter);
}
}
class ScopeSymbol extends BaseSymbol {
constructor(name, node, kind) {
super(name, node, kind ?? SymbolKind.Scope);
}
_children = [];
get children() {
return this._children;
}
addSymbol(symbol) {
symbol._parent?.removeSymbol(symbol);
symbol._parent = this;
this._children.push(symbol);
}
removeSymbol(symbol) {
const index = this._children.indexOf(symbol);
if (index >= 0) {
this._children.splice(index, 1);
symbol._parent = null;
}
}
/**
* Get a list of symbols visible at the given position
* @param line line number 1..n
* @param column column number 0..n
* @returns A list of symbols
*/
getSymbolsAtPosition(line, column) {
const symbols = [];
if ((this.source.loc.start.line < line ||
(this.source.loc.start.line == line && this.source.loc.start.column <= column)) && (this.source.loc.end.line > line ||
(this.source.loc.end.line == line && this.source.loc.end.column > column))) {
for (const symbol of this._children) {
if (symbol.source.loc.start.line < line ||
(symbol.source.loc.start.line == line && symbol.source.loc.start.column <= column)) {
symbols.push(symbol);
if ((symbol instanceof ScopeSymbol) && (symbol.source.loc.end.line > line ||
(symbol.source.loc.end.line == line && symbol.source.loc.end.column > column))) {
symbols.push(...symbol.getSymbolsAtPosition(line, column));
}
}
}
}
return symbols;
}
}
class BlockSymbol extends ScopeSymbol {
constructor(name, node, kind) {
super(name, node, kind ?? SymbolKind.Block);
}
}
class LabelBlockSymbol extends ScopeSymbol {
constructor(name, node, kind) {
super(name, node, kind ?? SymbolKind.LabelBlock);
}
}
class NamespaceSymbol extends ScopeSymbol {
constructor(name, node, kind) {
super(name, node, kind ?? SymbolKind.Namespace);
}
}
class FunctionSymbol extends ScopeSymbol {
type;
constructor(name, node, kind, type) {
super(name, node, kind ?? SymbolKind.Function);
if (type === undefined) {
this.type = getUnknownType();
}
else {
this.type = type;
}
}
}
class ControlFlowSymbol extends ScopeSymbol {
constructor(node, kind) {
super('', node, kind ?? SymbolKind.ControlFlow);
}
}
class SymbolTable extends ScopeSymbol {
#labels = [];
get labels() {
return this.#labels;
}
addLabel(symbol) {
symbol._parent?.removeSymbol(symbol);
symbol._parent = this;
this.#labels.push(symbol);
}
removeLabel(symbol) {
const index = this.#labels.indexOf(symbol);
if (index >= 0) {
this.#labels.splice(index, 1);
symbol._parent = null;
}
}
/**
* Get a list of symbols visible at the given position
* @param line line number 1..n
* @param column column number 0..n
* @returns A list of symbols
*/
getSymbolsAtPosition(line, column) {
return this.#labels.concat(super.getSymbolsAtPosition(line, column));
}
}
function getNameFromIdentifier(identifier) {
return identifier.namespace !== undefined ? `${identifier.namespace}::${identifier.name}` : identifier.name;
}
function build(ast) {
if (ast.program === undefined)
return null;
const rootScope = new SymbolTable('', ast.program);
let currentScope = rootScope;
function openScope(scope) {
currentScope.addSymbol(scope);
currentScope = scope;
}
function closeScope() {
if (currentScope.parent === null) {
throw new Error('Trying to close root scope');
}
currentScope = currentScope.parent;
}
function canCreateBlockSymbol(blockStatement) {
return (blockStatement.parent === undefined || (blockStatement.parent.kind !== Kind.FunctionDeclaration &&
blockStatement.parent.kind !== Kind.ForeachStatement &&
blockStatement.parent.kind !== Kind.ForStatement &&
blockStatement.parent.kind !== Kind.SwitchtypeStatement &&
blockStatement.parent.kind !== Kind.Main));
}
ast.program.visit((node) => {
if (node instanceof VariableDeclaration) {
if (node.alias !== undefined) {
currentScope.addSymbol(new VariableSymbol(getNameFromIdentifier(node.alias), node));
}
else {
currentScope.addSymbol(new VariableSymbol(getNameFromIdentifier(node.name), node));
}
}
else if (node instanceof SettingDirective) {
currentScope.addSymbol(new SettingSymbol(getNameFromIdentifier(node.name), node));
}
else if (node instanceof CommandDirective) {
currentScope.addSymbol(new CommandSymbol(getNameFromIdentifier(node.name), node));
}
else if (node instanceof StructDeclaration) {
currentScope.addSymbol(new StructureSymbol(getNameFromIdentifier(node.name), node));
}
else if (node instanceof StructAliasing) {
currentScope.addSymbol(new StructureSymbol(getNameFromIdentifier(node.alias), node));
}
else if (node instanceof ConstDeclaration) {
currentScope.addSymbol(new ConstantSymbol(getNameFromIdentifier(node.name), node));
}
else if (node instanceof ConstAliasing) {
currentScope.addSymbol(new ConstantSymbol(getNameFromIdentifier(node.alias), node));
}
else if (node instanceof IncludeDirective) {
if (node.alias !== undefined) {
currentScope.addSymbol(new NamespaceSymbol(getNameFromIdentifier(node.alias), node));
}
}
else if (node instanceof Main) {
openScope(new FunctionSymbol('main', node));
}
else if (node instanceof FunctionDeclaration) {
openScope(new FunctionSymbol(getNameFromIdentifier(node.name), node));
for (const parameter of node.parameters) {
currentScope.addSymbol(new ParameterSymbol(getNameFromIdentifier(parameter.name), parameter));
}
}
else if (node instanceof BlockStatement) {
if (canCreateBlockSymbol(node)) {
openScope(new BlockSymbol('', node));
}
}
else if (node instanceof LabelDeclaration) {
openScope(new LabelBlockSymbol(getNameFromIdentifier(node.name), node));
}
else if (node instanceof LabelStatement) {
if (node.name instanceof Identifier) {
rootScope.addLabel(new LabelSymbol(getNameFromIdentifier(node.name), node));
}
}
else if (node instanceof ForeachStatement) {
openScope(new ControlFlowSymbol(node));
if (node.key !== undefined) {
currentScope.addSymbol(new ParameterSymbol(getNameFromIdentifier(node.key), node.key));
}
currentScope.addSymbol(new ParameterSymbol(getNameFromIdentifier(node.value), node.value));
}
else if (node instanceof ForStatement) {
openScope(new ControlFlowSymbol(node));
currentScope.addSymbol(new ParameterSymbol(getNameFromIdentifier(node.value), node.value));
}
else if (node instanceof SwitchtypeStatement) {
openScope(new ControlFlowSymbol(node));
if (node.alias !== undefined) {
currentScope.addSymbol(new ParameterSymbol(getNameFromIdentifier(node.alias), node.alias));
}
}
}, (node) => {
if (node instanceof Main) {
closeScope();
}
else if (node instanceof FunctionDeclaration) {
closeScope();
}
else if (node instanceof BlockStatement) {
if (canCreateBlockSymbol(node)) {
closeScope();
}
}
else if (node instanceof LabelDeclaration) {
closeScope();
}
else if (node instanceof ForeachStatement) {
closeScope();
}
else if (node instanceof ForStatement) {
closeScope();
}
else if (node instanceof SwitchtypeStatement) {
closeScope();
}
});
return rootScope;
}
export { BaseSymbol, StructureSymbol, LabelSymbol, SettingSymbol, CommandSymbol, ConstantSymbol, VariableSymbol, ParameterSymbol, ScopeSymbol, BlockSymbol, LabelBlockSymbol, NamespaceSymbol, FunctionSymbol, ControlFlowSymbol, SymbolTable, SymbolKind, build };