Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 21x 21x 21x 21x 1x 1x 21x 21x 21x 27x 27x 27x 27x 16x 27x 9x 9x 11x 2x 2x 2x 27x 27x 1x 1x 1x 1x 26x 26x 20x 21x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 21x 5x 5x 3x 4x 4x 4x 4x 4x 4x 1x 1x 1x 1x 4x 4x 2x 5x 21x 21x 1x 1x 3x 3x 6x 6x 6x 6x 14x 14x 14x 14x 6x 6x 3x 3x 3x 3x 1x | import * as Expressions from "../../2_statements/expressions";
import {StatementNode} from "../../nodes";
import {TypedIdentifier, IdentifierMeta} from "../../types/_typed_identifier";
import {ObjectReferenceType, VoidType} from "../../types/basic";
import {Target} from "../expressions/target";
import {IReferenceExtras, ReferenceType} from "../_reference";
import {StatementSyntax} from "../_statement_syntax";
import {SyntaxInput, syntaxIssue} from "../_syntax_input";
import {TypeUtils} from "../_type_utils";
import {IClassDefinition} from "../../types/_class_definition";
export class Catch implements StatementSyntax {
public runSyntax(node: StatementNode, input: SyntaxInput): void {
const target = node.findDirectExpression(Expressions.Target);
const inlineTarget = target?.findDirectExpression(Expressions.InlineData)
?.findFirstExpression(Expressions.TargetField)?.getFirstToken();
if (inlineTarget && inlineTarget.getStr().length > 30) {
input.issues.push(syntaxIssue(input, inlineTarget, "Inline exception name longer than 30 characters"));
}
const names = new Set<string>();
for (const c of node.findDirectExpressions(Expressions.ClassName)) {
const token = c.getFirstToken();
const className = token.getStr().toUpperCase();
const found = input.scope.existsObject(className);
if (found?.id) {
input.scope.addReference(token, found.id, ReferenceType.ObjectOrientedReference, input.filename);
} else if (input.scope.getDDIC().inErrorNamespace(className) === false) {
const extra: IReferenceExtras = {ooName: className, ooType: "Void"};
input.scope.addReference(token, undefined, ReferenceType.ObjectOrientedVoidReference, input.filename, extra);
} else {
const message = "CATCH, unknown class " + className;
input.issues.push(syntaxIssue(input, token, message));
}
if (names.has(className)) {
const message = "Duplicate class name in CATCH: " + className;
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
}
names.add(className);
}
if (target?.findDirectExpression(Expressions.InlineData)) {
const token = target.findFirstExpression(Expressions.TargetField)?.getFirstToken();
if (token) {
const classNames = Array.from(names);
const unknownClass = classNames.find(name => input.scope.findClassDefinition(name) === undefined);
const commonSuperclass = unknownClass === undefined
? this.findCommonSuperclass(classNames, input)
: undefined;
const type = commonSuperclass
? new ObjectReferenceType(commonSuperclass)
: VoidType.get(unknownClass || classNames.join(" "));
const identifier = new TypedIdentifier(token, input.filename, type, [IdentifierMeta.InlineDefinition]);
input.scope.addIdentifier(identifier);
input.scope.addReference(token, identifier, ReferenceType.DataWriteReference, input.filename);
}
} else if (target) {
const targetType = Target.runSyntax(target, input);
if (targetType instanceof ObjectReferenceType) {
for (const c of node.findDirectExpressions(Expressions.ClassName)) {
const token = c.getFirstToken();
const className = token.getStr().toUpperCase();
const found = input.scope.existsObject(className);
if (found?.id) {
const catchType = new ObjectReferenceType(found.id);
if (new TypeUtils(input.scope).isAssignableStrict(catchType, targetType) === false) {
const message = "CATCH target not compatible with " + className;
input.issues.push(syntaxIssue(input, token, message));
return;
}
}
}
}
}
}
private findCommonSuperclass(classNames: readonly string[], input: SyntaxInput): IClassDefinition | undefined {
const lineages: IClassDefinition[][] = [];
for (const className of classNames) {
const lineage: IClassDefinition[] = [];
let current = input.scope.findClassDefinition(className);
const visited = new Set<string>();
while (current && visited.has(current.getName().toUpperCase()) === false) {
lineage.push(current);
visited.add(current.getName().toUpperCase());
current = input.scope.findClassDefinition(current.getSuperClass());
}
lineages.push(lineage);
}
return lineages[0]?.find(candidate => lineages.every(lineage =>
lineage.some(item => item.getName().toUpperCase() === candidate.getName().toUpperCase())));
}
}
|