UNPKG

@maniascript/parser

Version:
317 lines (316 loc) 11.6 kB
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 };