@abaplint/core
Version:
abaplint - Core API
483 lines • 17.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CurrentScope = void 0;
const _builtin_1 = require("./_builtin");
const ddic_1 = require("../../ddic");
const position_1 = require("../../position");
const spaghetti_scope_1 = require("./spaghetti_scope");
const _identifier_1 = require("../4_file_information/_identifier");
const _scope_type_1 = require("./_scope_type");
const syntax_1 = require("./syntax");
class CurrentScope {
static buildDefault(reg, obj) {
const s = new CurrentScope(reg, obj);
s.push(_scope_type_1.ScopeType.BuiltIn, _scope_type_1.ScopeType.BuiltIn, new position_1.Position(1, 1), _builtin_1.BuiltIn.filename);
this.addBuiltIn(s, reg.getConfig().getSyntaxSetttings().globalConstants);
let name = _scope_type_1.ScopeType.Global;
if (obj) {
name = name + "_" + obj.getName();
}
s.push(_scope_type_1.ScopeType.Global, name, new position_1.Position(1, 1), name);
return s;
}
static addBuiltIn(s, extras) {
const b = new _builtin_1.BuiltIn();
const builtin = b.get(extras);
s.addList(builtin);
for (const t of b.getTypes()) {
s.addType(t);
}
}
constructor(reg, obj) {
this.current = undefined;
this.parentObj = obj;
this.reg = reg;
}
///////////////////////////
getVersion() {
return this.reg.getConfig().getVersion();
}
getRegistry() {
return this.reg;
}
addType(type) {
if (type === undefined) {
return;
}
this.addTypeNamed(type.getName(), type);
}
addTypeNamed(name, type) {
if (type === undefined) {
return;
}
if (this.current === undefined) {
return;
}
const upper = name.toUpperCase();
if (this.current.getData().types[upper] !== undefined) {
throw new Error(`Type name "${name}" already defined`);
}
else if (this.isOO() && this.current.getData().vars[upper] !== undefined) {
throw new Error(`"${name}" already defined`);
}
this.current.getData().types[upper] = type;
}
addExtraLikeType(type) {
if (type === undefined) {
return;
}
this.addExtraLikeTypeNamed(type.getName(), type);
}
addExtraLikeTypeNamed(name, type) {
if (type === undefined) {
return;
}
if (this.current === undefined) {
return;
}
const upper = name.toUpperCase();
if (this.current.getData().extraLikeTypes[upper] !== undefined) {
throw new Error(`Type name "${name}" already defined`);
}
this.current.getData().extraLikeTypes[upper] = type;
}
addClassDefinition(c) {
if (this.current === undefined) {
return;
}
const name = c.getName().toUpperCase();
if (this.current.getData().cdefs[name] !== undefined) {
throw new Error(`Class "${name}" already defined`);
}
this.current.getData().cdefs[name] = c;
}
addFormDefinitions(f) {
if (this.current === undefined) {
return;
}
this.current.getData().forms.push(...f);
}
addInterfaceDefinition(i) {
if (this.current === undefined) {
return;
}
const name = i.getName().toUpperCase();
if (this.current.getData().cdefs[name] !== undefined) {
throw new Error(`Interface "${name}" already defined`);
}
this.current.getData().idefs[name] = i;
}
addNamedIdentifier(name, identifier) {
if (this.current === undefined) {
return;
}
const upper = name.toUpperCase();
if (this.current.getData().vars[upper] !== undefined) {
// console.dir(new Error().stack);
throw new Error(`Variable name "${name}" already defined`);
}
else if (this.isOO() && this.current.getData().types[upper] !== undefined) {
throw new Error(`"${name}" already defined`);
}
this.current.getData().vars[upper] = identifier;
}
addNamedIdentifierToParent(name, identifier) {
if (this.current === undefined) {
return;
}
const parent = this.current.getParent();
if (parent === undefined) {
return;
}
const upper = name.toUpperCase();
if (parent.getData().vars[upper] !== undefined) {
// console.dir(new Error().stack);
throw new Error(`Variable name "${name}" already defined`);
}
else if (this.isOO() && parent.getData().types[upper] !== undefined) {
throw new Error(`"${name}" already defined`);
}
parent.getData().vars[upper] = identifier;
}
addIdentifier(identifier) {
if (identifier === undefined) {
return;
}
this.addNamedIdentifier(identifier.getName(), identifier);
}
addDeferred(token, type) {
if (token === undefined) {
return;
}
this.current.getData().deferred[token.getStr().toUpperCase()] = { token, ooType: type };
}
addListPrefix(identifiers, prefix) {
for (const id of identifiers) {
this.addNamedIdentifier(prefix + id.getName(), id);
}
}
addList(identifiers) {
for (const id of identifiers) {
this.addIdentifier(id);
}
}
addReference(usage, referencing, type, filename, extra) {
var _a, _b;
if (usage === undefined || type === undefined) {
return;
}
const position = new _identifier_1.Identifier(usage, filename);
if (Array.isArray(type)) {
for (const t of type) {
(_a = this.current) === null || _a === void 0 ? void 0 : _a.getData().references.push({ position, resolved: referencing, referenceType: t, extra });
}
}
else {
(_b = this.current) === null || _b === void 0 ? void 0 : _b.getData().references.push({ position, resolved: referencing, referenceType: type, extra });
}
}
addSQLConversion(fieldName, message, token) {
var _a;
(_a = this.current) === null || _a === void 0 ? void 0 : _a.getData().sqlConversion.push({ fieldName, message, token });
}
///////////////////////////
findFunctionModule(name) {
if (name === undefined) {
return undefined;
}
for (const fugr of this.reg.getObjectsByType("FUGR")) {
const func = fugr.getModule(name);
if (func !== undefined) {
return func;
}
}
return undefined;
}
findObjectDefinition(name) {
if (name === undefined) {
return undefined;
}
const clas = this.findClassDefinition(name);
if (clas) {
return clas;
}
const intf = this.findInterfaceDefinition(name);
if (intf) {
return intf;
}
return undefined;
}
isBadiDef(name) {
const upper = name.toUpperCase();
for (const enhs of this.reg.getObjectsByType("ENHS")) {
for (const def of enhs.listBadiDefinitions()) {
if (def.name.toUpperCase() === upper) {
return true;
}
}
}
return false;
}
existsObject(name) {
var _a, _b, _c;
if (name === undefined) {
return undefined;
}
let prefixRTTI = "";
if (this.parentObj.getType() === "PROG") {
prefixRTTI = "\\PROGRAM=" + this.parentObj.getName();
}
else if (this.parentObj.getType() === "CLAS") {
prefixRTTI = "\\CLASS-POOL=" + this.parentObj.getName();
}
const findLocalClass = (_a = this.current) === null || _a === void 0 ? void 0 : _a.findClassDefinition(name);
if (findLocalClass) {
if (findLocalClass.isGlobal() === true) {
prefixRTTI = "";
}
return { id: findLocalClass, ooType: "CLAS", RTTIName: prefixRTTI + "\\CLASS=" + findLocalClass.getName() };
}
const globalClas = this.reg.getObject("CLAS", name);
if (globalClas) {
return { id: globalClas.getIdentifier(), ooType: "CLAS", RTTIName: "\\CLASS=" + globalClas.getName() };
}
const findLocalInterface = (_b = this.current) === null || _b === void 0 ? void 0 : _b.findInterfaceDefinition(name);
if (findLocalInterface) {
if (findLocalInterface.isGlobal() === true) {
prefixRTTI = "";
}
return { id: findLocalInterface, ooType: "INTF", RTTIName: prefixRTTI + "\\INTERFACE=" + findLocalInterface.getName() };
}
const globalIntf = this.reg.getObject("INTF", name);
if (globalIntf) {
return { id: globalIntf.getIdentifier(), ooType: "INTF", RTTIName: "\\INTERFACE=" + globalIntf.getName() };
}
const def = (_c = this.current) === null || _c === void 0 ? void 0 : _c.findDeferred(name);
if (def !== undefined) {
let rttiName = prefixRTTI;
switch (def.ooType) {
case "INTF":
rttiName = rttiName + "\\INTERFACE=" + name;
break;
default:
rttiName = rttiName + "\\CLASS=" + name;
break;
}
return { id: def.id, ooType: def.ooType, RTTIName: rttiName };
}
return undefined;
}
///////////////////////////
/** Lookup class in local and global scope */
findClassDefinition(name) {
var _a;
if (name === undefined) {
return undefined;
}
const clocal = (_a = this.current) === null || _a === void 0 ? void 0 : _a.findClassDefinition(name);
if (clocal) {
return clocal;
}
const cglobal = this.reg.getObject("CLAS", name);
if (cglobal) {
return cglobal.getDefinition();
}
return undefined;
}
findTypePoolConstant(name) {
var _a;
if (name === undefined || name.includes("_") === undefined) {
return undefined;
}
const typePoolName = name.split("_")[0];
if (typePoolName.length <= 1 || typePoolName.length > 5) {
return undefined;
}
if (this.parentObj.getType() === "TYPE"
&& this.parentObj.getName().toUpperCase() === typePoolName.toUpperCase()) {
// dont recurse into itself
return undefined;
}
const typePool = this.reg.getObject("TYPE", typePoolName);
if (typePool === undefined) {
return undefined;
}
const spag = (_a = new syntax_1.SyntaxLogic(this.reg, typePool).run().spaghetti.getFirstChild()) === null || _a === void 0 ? void 0 : _a.getFirstChild();
const found = spag === null || spag === void 0 ? void 0 : spag.findVariable(name);
return found;
}
findTypePoolType(name) {
var _a;
if (name.includes("_") === undefined) {
return undefined;
}
const typePoolName = name.split("_")[0];
if (typePoolName.length <= 2 || typePoolName.length > 5) {
return undefined;
}
if (this.parentObj.getType() === "TYPE"
&& this.parentObj.getName().toUpperCase() === typePoolName.toUpperCase()) {
// dont recurse into itself
return undefined;
}
if (new ddic_1.DDIC(this.reg).lookupNoVoid(name) !== undefined) {
// this is tricky, it should not do recursion when parsing the type pool itself,
// think about DTEL ABAP_ENCOD vs TYPE ABAP
return undefined;
}
const typePool = this.reg.getObject("TYPE", typePoolName);
if (typePool === undefined) {
return undefined;
}
const spag = (_a = new syntax_1.SyntaxLogic(this.reg, typePool).run().spaghetti.getFirstChild()) === null || _a === void 0 ? void 0 : _a.getFirstChild();
const found = spag === null || spag === void 0 ? void 0 : spag.findType(name);
return found;
}
/** Lookup interface in local and global scope */
findInterfaceDefinition(name) {
var _a;
if (name === undefined) {
return undefined;
}
const ilocal = (_a = this.current) === null || _a === void 0 ? void 0 : _a.findInterfaceDefinition(name);
if (ilocal) {
return ilocal;
}
const iglobal = this.reg.getObject("INTF", name);
if (iglobal) {
return iglobal.getDefinition();
}
return undefined;
}
findFormDefinition(name) {
var _a;
return (_a = this.current) === null || _a === void 0 ? void 0 : _a.findFormDefinition(name);
}
findType(name) {
var _a;
if (name === undefined) {
return undefined;
}
return (_a = this.current) === null || _a === void 0 ? void 0 : _a.findType(name);
}
findExtraLikeType(name) {
var _a;
if (name === undefined) {
return undefined;
}
return (_a = this.current) === null || _a === void 0 ? void 0 : _a.findExtraLikeType(name);
}
findVariable(name) {
var _a;
if (name === undefined) {
return undefined;
}
const found = (_a = this.current) === null || _a === void 0 ? void 0 : _a.findVariable(name);
if (found) {
return found;
}
return this.findTypePoolConstant(name);
}
findReturningParameter() {
var _a;
for (const v in ((_a = this.current) === null || _a === void 0 ? void 0 : _a.getData().vars) || {}) {
const variable = this.current.getData().vars[v];
if (variable.getMeta().includes("returning" /* IdentifierMeta.MethodReturning */)) {
return variable;
}
}
return undefined;
}
///////////////////////////
getDDIC() {
return new ddic_1.DDIC(this.reg);
}
getDDICReferences() {
return this.reg.getDDICReferences();
}
getMSAGReferences() {
return this.reg.getMSAGReferences();
}
getParentObj() {
return this.parentObj;
}
getName() {
if (this.current === undefined) {
throw new Error("error, getName");
}
return this.current.getIdentifier().sname;
}
getType() {
if (this.current === undefined) {
throw new Error("error, getType");
}
return this.current.getIdentifier().stype;
}
push(stype, sname, start, filename) {
const identifier = { stype, sname, start, filename, end: undefined };
// console.dir("push scope, " + stype);
if (this.current === undefined) {
// the top node
this.current = new spaghetti_scope_1.SpaghettiScopeNode(identifier, undefined);
}
else {
const parent = this.current;
this.current = new spaghetti_scope_1.SpaghettiScopeNode(identifier, parent);
parent.addChild(this.current);
}
}
isOO() {
let curr = this.current;
while (curr !== undefined) {
const stype = curr.getIdentifier().stype;
if (stype === _scope_type_1.ScopeType.ClassDefinition
// || stype === ScopeType.ClassImplementation
|| stype === _scope_type_1.ScopeType.Interface) {
return true;
}
curr = curr.getParent();
}
return false;
}
isAnyOO() {
let curr = this.current;
while (curr !== undefined) {
const stype = curr.getIdentifier().stype;
if (stype === _scope_type_1.ScopeType.ClassDefinition
|| stype === _scope_type_1.ScopeType.ClassImplementation
|| stype === _scope_type_1.ScopeType.Interface) {
return true;
}
curr = curr.getParent();
}
return false;
}
isGlobalOO() {
return this.parentObj.getType() === "INTF" || this.parentObj.getType() === "CLAS";
}
isTypePool() {
var _a;
return ((_a = this.current) === null || _a === void 0 ? void 0 : _a.getIdentifier().filename.endsWith(".type.abap")) === true || false;
}
setAllowHeaderUse(name) {
// workaround for SELECT FOR ALL ENTRIES
this.allowHeaderUse = name;
}
isAllowHeaderUse(name) {
var _a;
return name.toUpperCase() === ((_a = this.allowHeaderUse) === null || _a === void 0 ? void 0 : _a.toUpperCase());
}
pop(end) {
// console.dir("pop scope, " + this.current?.getIdentifier().stype);
this.allowHeaderUse = undefined;
if (this.current === undefined) {
throw new Error("something wrong, top scope popped");
}
this.current.setEnd(end);
const current = this.current;
this.current = this.current.getParent();
return new spaghetti_scope_1.SpaghettiScope(current);
}
}
exports.CurrentScope = CurrentScope;
//# sourceMappingURL=_current_scope.js.map