@abaplint/core
Version:
abaplint - Core API
297 lines • 9.33 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SpaghettiScope = exports.SpaghettiScopeNode = void 0;
const _typed_identifier_1 = require("../types/_typed_identifier");
const _identifier_1 = require("../4_file_information/_identifier");
const _reference_1 = require("./_reference");
const assert_error_1 = require("./assert_error");
class ScopeData {
constructor() {
this.data = {
vars: {},
cdefs: {},
idefs: {},
forms: [], // todo, refactor to object
types: {},
extraLikeTypes: {},
deferred: {},
references: [],
sqlConversion: [],
};
}
getData() {
return this.data;
}
}
class SpaghettiScopeNode extends ScopeData {
[Symbol.for("debug.description")]() {
return `SpaghettiSN ${this.identifier.sname} ${this.identifier.stype}`;
}
constructor(identifier, parent) {
super();
this.identifier = identifier;
this.parent = parent;
this.children = [];
}
getParent() {
return this.parent;
}
addChild(node) {
this.children.push(node);
}
getChildren() {
return this.children;
}
getFirstChild() {
return this.children[0];
}
getIdentifier() {
return this.identifier;
}
calcCoverage() {
if (this.identifier.end === undefined) {
throw new assert_error_1.AssertError("internal error, caclCoverage");
}
return { start: this.identifier.start, end: this.identifier.end };
}
setEnd(end) {
this.identifier.end = end;
}
findDeferred(name) {
let search = this;
while (search !== undefined) {
const found = search.getData().deferred[name.toUpperCase()];
if (found) {
return {
id: new _identifier_1.Identifier(found.token, search.identifier.filename),
ooType: found.ooType,
};
}
search = search.getParent();
}
return undefined;
}
findClassDefinition(name) {
let search = this;
const upper = name.toUpperCase();
while (search !== undefined) {
const c = search.getData().cdefs[upper];
if (c !== undefined) {
return c;
}
search = search.getParent();
}
return undefined;
}
listClassDefinitions() {
let search = this;
const ret = [];
while (search !== undefined) {
ret.push(...Object.values(search.getData().cdefs));
search = search.getParent();
}
return ret;
}
listInterfaceDefinitions() {
let search = this;
const ret = [];
while (search !== undefined) {
ret.push(...Object.values(search.getData().idefs));
search = search.getParent();
}
return ret;
}
findFormDefinition(name) {
let search = this;
const upper = name.toUpperCase();
while (search !== undefined) {
for (const form of search.getData().forms) {
if (form.getName().toUpperCase() === upper) {
return form;
}
}
search = search.getParent();
}
return undefined;
}
findInterfaceDefinition(name) {
let search = this;
const upper = name.toUpperCase();
while (search !== undefined) {
const idef = search.getData().idefs[upper];
if (idef) {
return idef;
}
search = search.getParent();
}
return undefined;
}
findType(name) {
let search = this;
const upper = name.toUpperCase();
while (search !== undefined) {
const found = search.getData().types[upper];
if (found) {
return found;
}
search = search.getParent();
}
return undefined;
}
findExtraLikeType(name) {
let search = this;
const upper = name.toUpperCase();
while (search !== undefined) {
const data = search.getData();
if (data.extraLikeTypes[upper]) {
return data.extraLikeTypes[upper];
}
search = search.getParent();
}
return undefined;
}
findVariable(name) {
let search = this;
const upper = name.toUpperCase();
while (search !== undefined) {
const data = search.getData();
if (data.vars[upper]) {
return data.vars[upper];
}
search = search.getParent();
}
return undefined;
}
findWriteReference(pos) {
for (const r of this.getData().references) {
if (r.referenceType === _reference_1.ReferenceType.DataWriteReference
&& r.position.getStart().equals(pos)) {
if (r.resolved instanceof _typed_identifier_1.TypedIdentifier) {
return r.resolved;
}
}
}
return undefined;
}
findTableReference(pos) {
for (const r of this.getData().references) {
if (r.referenceType === _reference_1.ReferenceType.TableReference
&& r.position.getStart().equals(pos)
&& r.resolved) {
return r.resolved.getName();
}
}
return undefined;
}
findTableVoidReference(pos) {
for (const r of this.getData().references) {
if (r.referenceType === _reference_1.ReferenceType.TableVoidReference
&& r.position.getStart().equals(pos)) {
return true;
}
}
return false;
}
// this method is used in the transpiler
findScopeForVariable(name) {
let search = this;
const upper = name.toUpperCase();
while (search !== undefined) {
if (search.getData().vars[upper] !== undefined) {
return search.getIdentifier();
}
search = search.getParent();
}
return undefined;
}
}
exports.SpaghettiScopeNode = SpaghettiScopeNode;
class SpaghettiScope {
constructor(top) {
this.node = top;
}
// list variable definitions across all nodes
listDefinitions(filename) {
const ret = [];
for (const n of this.allNodes()) {
if (n.getIdentifier().filename === filename) {
const vars = n.getData().vars;
for (const v in vars) {
if (vars[v].getFilename() === filename) {
ret.push({ name: v, identifier: vars[v] });
}
}
}
}
return ret;
}
listReadPositions(filename) {
const ret = [];
for (const n of this.allNodes()) {
if (n.getIdentifier().filename === filename) {
for (const v of n.getData().references) {
if (v.referenceType === _reference_1.ReferenceType.DataReadReference && v.position.getFilename() === filename) {
ret.push(v.position);
}
}
}
}
return ret;
}
listWritePositions(filename) {
const ret = [];
for (const n of this.allNodes()) {
if (n.getIdentifier().filename === filename) {
for (const v of n.getData().references) {
if (v.referenceType === _reference_1.ReferenceType.DataWriteReference && v.position.getFilename() === filename) {
ret.push(v.position);
}
}
}
}
return ret;
}
lookupPosition(p, filename) {
if (p === undefined || filename === undefined) {
return undefined;
}
return this.lookupPositionTraverse(p, filename, this.node);
}
getFirstChild() {
return this.node.getFirstChild();
}
getTop() {
return this.node;
}
/////////////////////////////
allNodes() {
const ret = [];
const stack = [this.node];
while (stack.length > 0) {
const current = stack.pop();
ret.push(current);
stack.push(...current.getChildren());
}
return ret;
}
lookupPositionTraverse(p, filename, node) {
const coverage = node.calcCoverage();
if (node.getIdentifier().filename === filename && p.isBetween(coverage.start, coverage.end) === false) {
return undefined;
}
// possible optimization: binary search the nodes
for (const c of node.getChildren()) {
const result = this.lookupPositionTraverse(p, filename, c);
if (result !== undefined) {
return result;
}
}
if (node.getIdentifier().filename === filename
&& p.isBetween(coverage.start, coverage.end)) {
return node;
}
return undefined;
}
}
exports.SpaghettiScope = SpaghettiScope;
//# sourceMappingURL=spaghetti_scope.js.map