UNPKG

@abaplint/core

Version:
364 lines • 19.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Source = void 0; const nodes_1 = require("../../nodes"); const Expressions = require("../../2_statements/expressions"); const method_call_chain_1 = require("./method_call_chain"); const unknown_type_1 = require("../../types/basic/unknown_type"); const field_chain_1 = require("./field_chain"); const basic_1 = require("../../types/basic"); const constant_1 = require("./constant"); const basic_types_1 = require("../basic_types"); const component_chain_1 = require("./component_chain"); const string_template_1 = require("./string_template"); const value_body_1 = require("./value_body"); const cond_1 = require("./cond"); const reduce_body_1 = require("./reduce_body"); const _reference_1 = require("../_reference"); const switch_body_1 = require("./switch_body"); const cond_body_1 = require("./cond_body"); const conv_body_1 = require("./conv_body"); const filter_body_1 = require("./filter_body"); const corresponding_body_1 = require("./corresponding_body"); const _builtin_1 = require("../_builtin"); const attribute_chain_1 = require("./attribute_chain"); const dereference_1 = require("./dereference"); const _typed_identifier_1 = require("../../types/_typed_identifier"); const _type_utils_1 = require("../_type_utils"); const _syntax_input_1 = require("../_syntax_input"); const assert_error_1 = require("../assert_error"); /* * Type interference, valid scenarios: * typed = VALUE #( ... ). right hand side must follow left hand type * DATA(bar) = VALUE type( ... ). left gets the type of rigthand * typed = VALUE type( ... ). types must match and be compatible??? ************* ERRORS ********* * VALUE #( ... ). syntax error * DATA(bar) = VALUE #( ... ). give error, no type can be derived */ // TODO: refactor all these method parameters to objects, this is getting messy class Source { static runSyntax(node, input, targetType, writeReference = false, allowGenericDeference = false) { if (node === undefined) { return undefined; } const children = node.getChildren().slice(); let first = children.shift(); if (first instanceof nodes_1.TokenNode) { const token = first.getFirstToken(); const tok = token.getStr().toUpperCase(); switch (tok) { case "(": case "-": case "+": case "BIT": break; case "BOOLC": { const method = _builtin_1.BuiltIn.searchBuiltin(tok); input.scope.addReference(token, method, _reference_1.ReferenceType.BuiltinMethodReference, input.filename); cond_1.Cond.runSyntax(node.findDirectExpression(Expressions.Cond), input); return basic_1.StringType.get(); } case "XSDBOOL": { const method = _builtin_1.BuiltIn.searchBuiltin(tok); input.scope.addReference(token, method, _reference_1.ReferenceType.BuiltinMethodReference, input.filename); cond_1.Cond.runSyntax(node.findDirectExpression(Expressions.Cond), input); return new basic_1.CharacterType(1, { qualifiedName: "ABAP_BOOL", ddicName: "ABAP_BOOL" }); } case "REDUCE": { const foundType = this.determineType(node, input, targetType); const bodyType = reduce_body_1.ReduceBody.runSyntax(node.findDirectExpression(Expressions.ReduceBody), input, foundType); if (foundType === undefined || foundType.isGeneric()) { this.addIfInferred(node, input, bodyType); } else { this.addIfInferred(node, input, foundType); } return foundType ? foundType : bodyType; } case "SWITCH": { const foundType = this.determineType(node, input, targetType); const bodyType = switch_body_1.SwitchBody.runSyntax(node.findDirectExpression(Expressions.SwitchBody), input); if (foundType === undefined || foundType.isGeneric()) { this.addIfInferred(node, input, bodyType); } else { this.addIfInferred(node, input, foundType); } return foundType ? foundType : bodyType; } case "COND": { const foundType = this.determineType(node, input, targetType); const bodyType = cond_body_1.CondBody.runSyntax(node.findDirectExpression(Expressions.CondBody), input, foundType); /* console.log("COND BODY type;:"); console.dir(bodyType); */ if (foundType === undefined || foundType.isGeneric()) { this.addIfInferred(node, input, bodyType); } else { this.addIfInferred(node, input, foundType); } children.shift(); children.shift(); children.shift(); children.shift(); this.traverseRemainingChildren(children, input); return foundType ? foundType : bodyType; } case "CONV": { const foundType = this.determineType(node, input, targetType); const bodyType = conv_body_1.ConvBody.runSyntax(node.findDirectExpression(Expressions.ConvBody), input); if (new _type_utils_1.TypeUtils(input.scope).isConvable(foundType, bodyType) === false) { const message = `CONV: Types not compatible, ${foundType === null || foundType === void 0 ? void 0 : foundType.constructor.name}, ${bodyType === null || bodyType === void 0 ? void 0 : bodyType.constructor.name}`; input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message)); return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey); } this.addIfInferred(node, input, foundType); return foundType; } case "REF": { let foundType = this.determineType(node, input, targetType); const s = Source.runSyntax(node.findDirectExpression(Expressions.Source), input); /* console.dir(node.concatTokens()); console.dir(targetType); console.dir(foundType); console.dir(s); */ if (foundType && foundType.isGeneric() && s) { foundType = new basic_1.DataReference(s); } else if (foundType === undefined && s) { foundType = new basic_1.DataReference(s); } else if (foundType && targetType === undefined) { foundType = new basic_1.DataReference(foundType); } /* if (targetType && !(targetType instanceof DataReference)) { const message = `REF: Types not compatible, ` + targetType.constructor.name; input.issues.push(syntaxIssue(input, node.getFirstToken(), message)); } */ this.addIfInferred(node, input, foundType); return foundType; } case "FILTER": { const foundType = this.determineType(node, input, targetType); const bodyType = filter_body_1.FilterBody.runSyntax(node.findDirectExpression(Expressions.FilterBody), input, foundType); if (foundType === undefined || foundType.isGeneric()) { this.addIfInferred(node, input, bodyType); } else { this.addIfInferred(node, input, foundType); } if (foundType && !(foundType instanceof unknown_type_1.UnknownType)) { return foundType; } else { return bodyType; } } case "CORRESPONDING": { const foundType = this.determineType(node, input, targetType); corresponding_body_1.CorrespondingBody.runSyntax(node.findDirectExpression(Expressions.CorrespondingBody), input, foundType); this.addIfInferred(node, input, foundType); return foundType; } case "EXACT": { const foundType = this.determineType(node, input, targetType); Source.runSyntax(node.findDirectExpression(Expressions.Source), input, foundType); this.addIfInferred(node, input, foundType); return foundType; } case "VALUE": { const foundType = this.determineType(node, input, targetType); const bodyType = value_body_1.ValueBody.runSyntax(node.findDirectExpression(Expressions.ValueBody), input, foundType); if (foundType === undefined || foundType.isGeneric()) { this.addIfInferred(node, input, bodyType); } else { this.addIfInferred(node, input, foundType); } return foundType ? foundType : bodyType; } default: return new unknown_type_1.UnknownType("todo, Source type " + tok); } } else if (first === undefined || !(first instanceof nodes_1.ExpressionNode)) { return undefined; } let context = new unknown_type_1.UnknownType("todo, Source type"); const type = [_reference_1.ReferenceType.DataReadReference]; if (writeReference) { type.push(_reference_1.ReferenceType.DataWriteReference); } let hexExpected = false; let hexNext = false; while (children.length >= 0) { if (first instanceof nodes_1.ExpressionNode) { const get = first.get(); if (get instanceof Expressions.MethodCallChain) { context = method_call_chain_1.MethodCallChain.runSyntax(first, input, targetType); if (context === undefined) { const message = "Method has no RETURNING value"; input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message)); return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey); } } else if (get instanceof Expressions.FieldChain) { context = field_chain_1.FieldChain.runSyntax(first, input, type, allowGenericDeference); } else if (get instanceof Expressions.StringTemplate) { context = string_template_1.StringTemplate.runSyntax(first, input); } else if (get instanceof Expressions.Source) { const found = Source.runSyntax(first, input); context = this.infer(context, found); } else if (get instanceof Expressions.Constant) { const found = constant_1.Constant.runSyntax(first); context = this.infer(context, found); } else if (get instanceof Expressions.Dereference) { context = dereference_1.Dereference.runSyntax(first, context, input); } else if (get instanceof Expressions.ComponentChain) { context = component_chain_1.ComponentChain.runSyntax(context, first, input); } else if (get instanceof Expressions.ArithOperator) { if (first.concatTokens() === "**") { context = new basic_1.FloatType(); } const operator = first.concatTokens().toUpperCase(); if (operator === "BIT-OR" || operator === "BIT-AND" || operator === "BIT-XOR") { hexExpected = true; hexNext = true; } } else if (get instanceof Expressions.AttributeChain) { context = attribute_chain_1.AttributeChain.runSyntax(context, first, input, type); } } if (hexExpected === true) { if (!(context instanceof basic_1.VoidType) && !(context instanceof basic_1.XStringType) && !(context instanceof basic_1.HexType) && !(context instanceof basic_1.XGenericType) && !(context instanceof basic_1.XSequenceType) && !(context instanceof unknown_type_1.UnknownType)) { const message = "Operator only valid for XSTRING or HEX"; input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message)); return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey); } if (hexNext === false) { hexExpected = false; } hexNext = false; } first = children.shift(); if (first === undefined) { break; } } if (node.findDirectTokenByText("&&")) { return basic_1.StringType.get(); } return context; } //////////////////////////////// static traverseRemainingChildren(children, input) { const last = children[children.length - 1]; if (last && last.get() instanceof Expressions.Source) { Source.runSyntax(last, input); } } static infer(context, found) { if (context instanceof basic_1.FloatType && found instanceof basic_1.IntegerType) { return context; } else { return found; } } static addIfInferred(node, input, inferredType) { const basic = new basic_types_1.BasicTypes(input); const typeExpression = node.findDirectExpression(Expressions.TypeNameOrInfer); const typeToken = typeExpression === null || typeExpression === void 0 ? void 0 : typeExpression.getFirstToken(); // const typeName = typeToken?.getStr(); /* console.dir(inferredType); console.dir(typeToken); */ if (inferredType && typeToken) { const found = basic.lookupQualifiedName(inferredType.getQualifiedName()); if (found) { const tid = new _typed_identifier_1.TypedIdentifier(typeToken, input.filename, inferredType); input.scope.addReference(typeToken, tid, _reference_1.ReferenceType.InferredType, input.filename, { foundQualified: true }); } else if (inferredType instanceof basic_1.ObjectReferenceType) { const def = input.scope.findObjectDefinition(inferredType.getQualifiedName()); const tid = new _typed_identifier_1.TypedIdentifier(typeToken, input.filename, inferredType); if (def) { input.scope.addReference(typeToken, tid, _reference_1.ReferenceType.InferredType, input.filename, { foundQualified: true }); } else { input.scope.addReference(typeToken, tid, _reference_1.ReferenceType.InferredType, input.filename, { foundQualified: false }); } } else { const tid = new _typed_identifier_1.TypedIdentifier(typeToken, input.filename, inferredType); input.scope.addReference(typeToken, tid, _reference_1.ReferenceType.InferredType, input.filename, { foundQualified: false }); } } } static determineType(node, input, targetType) { const basic = new basic_types_1.BasicTypes(input); const typeExpression = node.findDirectExpression(Expressions.TypeNameOrInfer); const typeToken = typeExpression === null || typeExpression === void 0 ? void 0 : typeExpression.getFirstToken(); const typeName = typeToken === null || typeToken === void 0 ? void 0 : typeToken.getStr(); if (typeExpression === undefined) { throw new assert_error_1.AssertError("determineType, child TypeNameOrInfer not found"); } else if (typeName === "#" && targetType) { return targetType; } if (typeName !== "#" && typeToken) { const found = basic.parseType(typeExpression); if (found && found instanceof unknown_type_1.UnknownType) { if (input.scope.getDDIC().inErrorNamespace(typeName) === false) { input.scope.addReference(typeToken, undefined, _reference_1.ReferenceType.VoidType, input.filename); return basic_1.VoidType.get(typeName); } else { const tid = new _typed_identifier_1.TypedIdentifier(typeToken, input.filename, found); input.scope.addReference(typeToken, tid, _reference_1.ReferenceType.TypeReference, input.filename); return found; } } else if (found === undefined) { const message = "Type \"" + typeName + "\" not found in scope, VALUE"; input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message)); return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey); } return found; } return targetType; } } exports.Source = Source; //# sourceMappingURL=source.js.map