@abaplint/core 2.120.38 → 2.120.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/abaplint.d.ts +7 -0
- package/build/src/abap/5_syntax/_current_scope.js +15 -0
- package/build/src/abap/5_syntax/_procedural.js +1 -0
- package/build/src/abap/5_syntax/global_definitions/find_global_definitions.js +1 -0
- package/build/src/abap/5_syntax/statements/form.js +3 -0
- package/build/src/abap/5_syntax/statements/perform.js +13 -6
- package/build/src/abap/5_syntax/statements/selectoption.js +1 -15
- package/build/src/abap/5_syntax/syntax.js +9 -0
- package/build/src/registry.js +1 -1
- package/package.json +1 -1
package/build/abaplint.d.ts
CHANGED
|
@@ -1612,6 +1612,9 @@ export declare class CurrentScope {
|
|
|
1612
1612
|
addExtraLikeTypeNamed(name: string, type: TypedIdentifier | undefined): void;
|
|
1613
1613
|
addClassDefinition(c: IClassDefinition): void;
|
|
1614
1614
|
addFormDefinitions(f: readonly IFormDefinition[]): void;
|
|
1615
|
+
/** The FORM definitions are built up front, at that point the program level types are not known.
|
|
1616
|
+
* When the FORM statement is traversed it is replaced with one resolved in the scope of the FORM */
|
|
1617
|
+
updateFormDefinition(f: IFormDefinition): void;
|
|
1615
1618
|
addInterfaceDefinition(i: IInterfaceDefinition): void;
|
|
1616
1619
|
addNamedIdentifier(name: string, identifier: TypedIdentifier): void;
|
|
1617
1620
|
addNamedIdentifierToParent(name: string, identifier: TypedIdentifier): void;
|
|
@@ -7872,11 +7875,15 @@ declare type SyntaxInput = {
|
|
|
7872
7875
|
scope: CurrentScope;
|
|
7873
7876
|
filename: string;
|
|
7874
7877
|
issues: Issue[];
|
|
7878
|
+
/** checks which can only run once the full object has been traversed, eg. PERFORM parameters,
|
|
7879
|
+
* the FORM might be defined after the PERFORM */
|
|
7880
|
+
deferred: (() => void)[];
|
|
7875
7881
|
};
|
|
7876
7882
|
|
|
7877
7883
|
export declare class SyntaxLogic {
|
|
7878
7884
|
private currentFile;
|
|
7879
7885
|
private issues;
|
|
7886
|
+
private deferred;
|
|
7880
7887
|
private readonly object;
|
|
7881
7888
|
private readonly reg;
|
|
7882
7889
|
private scope;
|
|
@@ -107,6 +107,21 @@ class CurrentScope {
|
|
|
107
107
|
}
|
|
108
108
|
this.current.getData().forms.push(...f);
|
|
109
109
|
}
|
|
110
|
+
/** The FORM definitions are built up front, at that point the program level types are not known.
|
|
111
|
+
* When the FORM statement is traversed it is replaced with one resolved in the scope of the FORM */
|
|
112
|
+
updateFormDefinition(f) {
|
|
113
|
+
let search = this.current;
|
|
114
|
+
while (search !== undefined) {
|
|
115
|
+
const forms = search.getData().forms;
|
|
116
|
+
for (let i = 0; i < forms.length; i++) {
|
|
117
|
+
if (forms[i].equals(f)) {
|
|
118
|
+
forms[i] = f;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
search = search.getParent();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
110
125
|
addInterfaceDefinition(i) {
|
|
111
126
|
if (this.current === undefined) {
|
|
112
127
|
return;
|
|
@@ -59,6 +59,7 @@ class Procedural {
|
|
|
59
59
|
scope: _current_scope_1.CurrentScope.buildDefault(this.reg, obj),
|
|
60
60
|
filename: file.getFilename(),
|
|
61
61
|
issues: [],
|
|
62
|
+
deferred: [],
|
|
62
63
|
};
|
|
63
64
|
for (const found of structure.findAllStructures(Structures.Form)) {
|
|
64
65
|
this.scope.addFormDefinitions([new types_1.FormDefinition(found, input)]);
|
|
@@ -151,6 +151,7 @@ class FindGlobalDefinitions {
|
|
|
151
151
|
filename: file.getFilename(),
|
|
152
152
|
scope: _current_scope_1.CurrentScope.buildDefault(this.reg, obj),
|
|
153
153
|
issues: [],
|
|
154
|
+
deferred: [],
|
|
154
155
|
};
|
|
155
156
|
if (obj instanceof interface_1.Interface) {
|
|
156
157
|
const found = struc.findFirstStructure(Structures.Interface);
|
|
@@ -20,6 +20,9 @@ class Form {
|
|
|
20
20
|
}
|
|
21
21
|
input.scope.push(_scope_type_1.ScopeType.Form, name, node.getFirstToken().getStart(), input.filename);
|
|
22
22
|
const form = new form_definition_1.FormDefinition(node, input);
|
|
23
|
+
// the definitions are built up front, before the program level types are known, replace it
|
|
24
|
+
// with this one, which is resolved in the scope of the FORM
|
|
25
|
+
input.scope.updateFormDefinition(form);
|
|
23
26
|
input.scope.addList(form.getUsingParameters());
|
|
24
27
|
input.scope.addList(form.getChangingParameters());
|
|
25
28
|
input.scope.addList(form.getTablesParameters());
|
|
@@ -92,12 +92,19 @@ class Perform {
|
|
|
92
92
|
input.scope.addReference(expr.getFirstToken(), found, _reference_1.ReferenceType.FormReference, input.filename);
|
|
93
93
|
////////////////////////////
|
|
94
94
|
// check parameters match
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
// deferred, the FORM might be defined after the PERFORM, its parameters are only typed
|
|
96
|
+
// once the FORM statement itself has been traversed
|
|
97
|
+
input.deferred.push(() => {
|
|
98
|
+
var _a;
|
|
99
|
+
// look up again, the definition is replaced when the FORM statement is traversed
|
|
100
|
+
const def = (_a = input.scope.findFormDefinition(name)) !== null && _a !== void 0 ? _a : found;
|
|
101
|
+
if (this.checkParameters(node, tables, def.getTablesParameters(), "TABLES", input) === false) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
// USING and CHANGING are interchangeable, the actual parameters form a single positional list
|
|
105
|
+
const formal = def.getUsingParameters().concat(def.getChangingParameters());
|
|
106
|
+
this.checkParameters(node, using.concat(changing), formal, "USING/CHANGING", input);
|
|
107
|
+
});
|
|
101
108
|
}
|
|
102
109
|
// returns false if an issue was reported
|
|
103
110
|
checkParameters(node, actual, formal, kind, input) {
|
|
@@ -64,22 +64,8 @@ class SelectOption {
|
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
66
|
const nameChain = node.findFirstExpression(Expressions.FieldChain);
|
|
67
|
-
|
|
67
|
+
const found = new basic_types_1.BasicTypes(input).resolveLikeName(nameChain);
|
|
68
68
|
if (found) {
|
|
69
|
-
if (found instanceof basic_1.StructureType) {
|
|
70
|
-
let length = 0;
|
|
71
|
-
for (const c of found.getComponents()) {
|
|
72
|
-
if (c.type instanceof basic_1.CharacterType) {
|
|
73
|
-
length += c.type.getLength();
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
if (length === 0) {
|
|
77
|
-
found = basic_1.VoidType.get("Selectoption, fallback");
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
found = new basic_1.CharacterType(length);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
69
|
const stru = new basic_1.StructureType([
|
|
84
70
|
{ name: "SIGN", type: new basic_1.CharacterType(1) },
|
|
85
71
|
{ name: "OPTION", type: new basic_1.CharacterType(2) },
|
|
@@ -337,6 +337,7 @@ class SyntaxLogic {
|
|
|
337
337
|
constructor(reg, object) {
|
|
338
338
|
this.reg = reg;
|
|
339
339
|
this.issues = [];
|
|
340
|
+
this.deferred = [];
|
|
340
341
|
this.object = object;
|
|
341
342
|
}
|
|
342
343
|
run() {
|
|
@@ -350,6 +351,7 @@ class SyntaxLogic {
|
|
|
350
351
|
proc: new _procedural_1.Procedural(this.reg, this.scope),
|
|
351
352
|
};
|
|
352
353
|
this.issues = [];
|
|
354
|
+
this.deferred = [];
|
|
353
355
|
this.reg.getDDICReferences().clear(this.object);
|
|
354
356
|
this.reg.getMSAGReferences().clear(this.object);
|
|
355
357
|
if (this.object instanceof objects_1.Program && this.object.isInclude()) {
|
|
@@ -357,6 +359,11 @@ class SyntaxLogic {
|
|
|
357
359
|
return { issues: [], spaghetti: this.scope.pop(new position_1.Position(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER)) };
|
|
358
360
|
}
|
|
359
361
|
this.traverseObject();
|
|
362
|
+
// the FORM definitions are now all traversed, ie. their parameters are typed
|
|
363
|
+
for (const d of this.deferred) {
|
|
364
|
+
d();
|
|
365
|
+
}
|
|
366
|
+
this.deferred = [];
|
|
360
367
|
for (;;) {
|
|
361
368
|
const spaghetti = this.scope.pop(new position_1.Position(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER)); // pop built-in scopes
|
|
362
369
|
if (spaghetti.getTop().getIdentifier().stype === _scope_type_1.ScopeType.BuiltIn) {
|
|
@@ -456,6 +463,7 @@ class SyntaxLogic {
|
|
|
456
463
|
scope: this.scope,
|
|
457
464
|
filename,
|
|
458
465
|
issues: this.issues,
|
|
466
|
+
deferred: this.deferred,
|
|
459
467
|
};
|
|
460
468
|
if (stru instanceof Structures.ClassDefinition) {
|
|
461
469
|
new class_definition_1.ClassDefinition(node, input);
|
|
@@ -507,6 +515,7 @@ class SyntaxLogic {
|
|
|
507
515
|
scope: this.scope,
|
|
508
516
|
filename,
|
|
509
517
|
issues: this.issues,
|
|
518
|
+
deferred: this.deferred,
|
|
510
519
|
};
|
|
511
520
|
// todo, refactor
|
|
512
521
|
if (s instanceof Statements.Type) {
|
package/build/src/registry.js
CHANGED