From d1b7234a5e62e66610ec1a05dc3baf0bdbc1a553 Mon Sep 17 00:00:00 2001 From: mmews Date: Wed, 13 Dec 2023 15:37:18 +0100 Subject: [PATCH] fix and migration --- .../es/assistants/DelegationAssistant.java | 3 +- .../utils/TranspilerDebugUtils.java | 233 ++++++++++++++++++ .../utils/TranspilerDebugUtils.xtend | 207 ---------------- 3 files changed, 235 insertions(+), 208 deletions(-) create mode 100644 plugins/org.eclipse.n4js.transpiler/src/org/eclipse/n4js/transpiler/utils/TranspilerDebugUtils.java delete mode 100644 plugins/org.eclipse.n4js.transpiler/src/org/eclipse/n4js/transpiler/utils/TranspilerDebugUtils.xtend diff --git a/plugins/org.eclipse.n4js.transpiler.es/src/org/eclipse/n4js/transpiler/es/assistants/DelegationAssistant.java b/plugins/org.eclipse.n4js.transpiler.es/src/org/eclipse/n4js/transpiler/es/assistants/DelegationAssistant.java index 7331bd74c2..bded2e2cf1 100644 --- a/plugins/org.eclipse.n4js.transpiler.es/src/org/eclipse/n4js/transpiler/es/assistants/DelegationAssistant.java +++ b/plugins/org.eclipse.n4js.transpiler.es/src/org/eclipse/n4js/transpiler/es/assistants/DelegationAssistant.java @@ -62,6 +62,7 @@ import org.eclipse.n4js.utils.N4JSLanguageUtils; import org.eclipse.n4js.utils.RecursionGuard; +import com.google.common.collect.Lists; import com.google.inject.Inject; /** @@ -162,7 +163,7 @@ public DelegatingMember createDelegatingMember(TClassifier origin, TMember targe * declaration. */ public void replaceDelegatingMembersByOrdinaryMembers(N4ClassifierDeclaration classifierDecl) { - for (N4MemberDeclaration currMember : classifierDecl.getOwnedMembersRaw()) { + for (N4MemberDeclaration currMember : Lists.newArrayList(classifierDecl.getOwnedMembersRaw())) { if (currMember instanceof DelegatingMember) { N4MemberDeclaration resolvedDelegatingMember = createOrdinaryMemberForDelegatingMember( (DelegatingMember) currMember); diff --git a/plugins/org.eclipse.n4js.transpiler/src/org/eclipse/n4js/transpiler/utils/TranspilerDebugUtils.java b/plugins/org.eclipse.n4js.transpiler/src/org/eclipse/n4js/transpiler/utils/TranspilerDebugUtils.java new file mode 100644 index 0000000000..db34156653 --- /dev/null +++ b/plugins/org.eclipse.n4js.transpiler/src/org/eclipse/n4js/transpiler/utils/TranspilerDebugUtils.java @@ -0,0 +1,233 @@ +/** + * Copyright (c) 2016 NumberFour AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * NumberFour AG - Initial API and implementation + */ +package org.eclipse.n4js.transpiler.utils; + +import static org.eclipse.xtext.xbase.lib.IterableExtensions.exists; +import static org.eclipse.xtext.xbase.lib.IterableExtensions.filter; +import static org.eclipse.xtext.xbase.lib.IterableExtensions.forall; +import static org.eclipse.xtext.xbase.lib.IterableExtensions.toList; +import static org.eclipse.xtext.xbase.lib.IteratorExtensions.exists; +import static org.eclipse.xtext.xbase.lib.IteratorExtensions.filter; +import static org.eclipse.xtext.xbase.lib.IteratorExtensions.findFirst; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.n4js.n4JS.ImportSpecifier; +import org.eclipse.n4js.n4JS.N4JSPackage; +import org.eclipse.n4js.n4JS.NamedElement; +import org.eclipse.n4js.n4JS.VariableDeclaration; +import org.eclipse.n4js.transpiler.TranspilerState; +import org.eclipse.n4js.transpiler.im.Script_IM; +import org.eclipse.n4js.transpiler.im.SymbolTable; +import org.eclipse.n4js.transpiler.im.SymbolTableEntry; +import org.eclipse.n4js.transpiler.im.SymbolTableEntryOriginal; +import org.eclipse.n4js.ts.typeRefs.TypeRefsPackage; +import org.eclipse.n4js.ts.types.IdentifiableElement; +import org.eclipse.xtext.EcoreUtil2; + +/** + * Some utilities for transpiler debugging, mainly dumping a {@link TranspilerState} to {@code stdout}, etc. + */ +public class TranspilerDebugUtils { + + /** + * Perform some consistency checks on the transpiler state. For example, this asserts that no node in the + * intermediate model has a direct cross-reference to the original AST or an original TModule element. + */ + public void validateState(TranspilerState state, boolean allowDanglingSecondaryReferencesInSTEs) + throws AssertionError { + // IM should not contain entities from n4js.xcore / TypeRefs.xcore for which a replacement in IM.xcore exists + List replacedEClasses = List.of( + N4JSPackage.eINSTANCE.getParameterizedPropertyAccessExpression(), + N4JSPackage.eINSTANCE.getIdentifierRef(), + TypeRefsPackage.eINSTANCE.getParameterizedTypeRef()); + EObject badObject = findFirst(state.im.eAllContents(), elem -> replacedEClasses.contains(elem.eClass())); + assertNull("intermediate model should not contain objects of type " + + (badObject != null + ? badObject.eClass() != null ? badObject.eClass().getName() : "null" + : "null"), + badObject); + // no cross reference in the IM to an element outside the IM (except in SymbolTableEntry) + assertFalse( + "intermediate model should not have a cross-reference to an element outside the intermediate model" + + " (except for SymbolTableEntry)", + exists(filter(state.im.eAllContents(), elem -> !(allowedCrossRefToOutside(elem))), + elem -> hasCrossRefToOutsideOf(elem, state))); + + // symbol table should exist + SymbolTable st = state.im.getSymbolTable(); + assertNotNull("intermediate model should have a symbol table", st); + // check entries in symbol table + for (SymbolTableEntry ste : st.getEntries()) { + if (ste instanceof SymbolTableEntryOriginal) { + assertNotNull("originalTarget should not be null", + ((SymbolTableEntryOriginal) ste).getOriginalTarget()); + assertFalse("originalTarget should not be an element in the intermediate model", + isElementInIntermediateModelOf(((SymbolTableEntryOriginal) ste).getOriginalTarget(), state)); + } + if (allowDanglingSecondaryReferencesInSTEs) { + // we allow dangling references in this case for the time being to make replacements in IM faster + // -> no checks here + // TODO consider disallowing dangling secondary references in symbol table entries + } else { + assertTrue("all elementsOfThisName should be elements in the intermediate model", + forall(ste.getElementsOfThisName(), elem -> isElementInIntermediateModelOf(elem, state))); + assertTrue("all referencingElements should be elements in the intermediate model", + forall(ste.getReferencingElements(), elem -> isElementInIntermediateModelOf(elem, state))); + if (ste instanceof SymbolTableEntryOriginal) { + if (((SymbolTableEntryOriginal) ste).getImportSpecifier() != null) { + assertTrue("importSpecifier should be an element in the intermediate model", + isElementInIntermediateModelOf(((SymbolTableEntryOriginal) ste).getImportSpecifier(), + state)); + } + } + } + } + } + + private boolean allowedCrossRefToOutside(EObject eobj) { + if (eobj instanceof SymbolTableEntry) { + return true; + } + return false; + } + + private static boolean hasCrossRefToOutsideOf(EObject elementInIntermediateModel, TranspilerState state) { + return exists(elementInIntermediateModel.eCrossReferences(), + cref -> !isElementInIntermediateModelOf(cref, state)); + } + + private static boolean isElementInIntermediateModelOf(EObject eobj, TranspilerState state) { + return EcoreUtil2.getContainerOfType(eobj, Script_IM.class) == state.im; + } + + /** Asserts {@code value} to be true and throws an {@link AssertionError} otherwise. */ + public static void assertTrue(String message, boolean value) throws AssertionError { + if (!value) + assertionFailure(message); + } + + /** Asserts {@code value} to be false and throws an {@link AssertionError} otherwise. */ + public static void assertFalse(String message, boolean value) throws AssertionError { + if (value) + assertionFailure(message); + } + + /** Asserts {@code value} to be null and throws an {@link AssertionError} otherwise. */ + public static void assertNull(String message, Object value) throws AssertionError { + if (value != null) + assertionFailure(message); + } + + /** Asserts {@code value} to be non-null and throws an {@link AssertionError} otherwise. */ + public static void assertNotNull(String message, Object value) throws AssertionError { + if (value == null) + assertionFailure(message); + } + + private static void assertionFailure(String message) throws AssertionError { + AssertionError ex = new AssertionError(message); + ex.printStackTrace(); // make sure we see this on the console even if exceptions are eaten up by someone + throw ex; + } + + /***/ + public static void dump(TranspilerState state) { + System.out.println(dumpToString(state)); + } + + /***/ + public static String dumpToString(TranspilerState state) { + StringWriter w = new StringWriter(); + dump(state, w); + return w.toString(); + } + + /** + * Dumps the transpiler state to the given writer. + */ + public static void dump(TranspilerState state, Writer out) { + PrintWriter w = new PrintWriter(out); + dump(w, state.im, 0); + } + + private static void dump(PrintWriter w, EObject obj, int indentLevel) { + indent(w, indentLevel); + printObj(w, obj, true, indentLevel); + w.println(); + + for (EObject child : obj.eContents()) { + dump(w, child, indentLevel + 1); + } + } + + private static void printObj(PrintWriter w, EObject obj, boolean includeCrossRefs, int indentLevel) { + w.print(obj.eClass().getName()); + if (obj instanceof IdentifiableElement || obj instanceof NamedElement || obj instanceof VariableDeclaration + || obj instanceof ImportSpecifier || obj instanceof SymbolTableEntry) { + w.print(" @" + Integer.toHexString(obj.hashCode())); + } + String objStr = obj.toString(); + int idx = objStr.indexOf("("); + if (idx >= 0) { + w.print(" " + objStr.substring(idx)); + } + if (includeCrossRefs) { + List crossRefs = toList(filter(obj.eClass().getEAllReferences(), ref -> !ref.isContainment())); + if (!crossRefs.isEmpty()) { + for (EReference ref : crossRefs) { + w.println(); + indent(w, indentLevel); + w.print("--" + ref.getName() + "--> "); + if (ref.isMany()) { + w.print("["); + @SuppressWarnings("unchecked") + EList targets = (EList) obj.eGet(ref); + Iterator iter = targets.iterator(); + while (iter.hasNext()) { + EObject currTarget = iter.next(); + if (currTarget != null) { + printObj(w, currTarget, false, indentLevel); + } else { + w.print("null"); + } + if (iter.hasNext()) { + w.print(", "); + } + } + w.print("]"); + } else { + EObject target = (EObject) obj.eGet(ref); + if (target != null) { + printObj(w, target, false, indentLevel); + } else { + w.print("null"); + } + } + } + } + } + } + + private static void indent(PrintWriter w, int indentLevel) { + for (int i = 0; i < indentLevel; i++) { + w.print("\t"); + } + } +} diff --git a/plugins/org.eclipse.n4js.transpiler/src/org/eclipse/n4js/transpiler/utils/TranspilerDebugUtils.xtend b/plugins/org.eclipse.n4js.transpiler/src/org/eclipse/n4js/transpiler/utils/TranspilerDebugUtils.xtend deleted file mode 100644 index 114ef77aab..0000000000 --- a/plugins/org.eclipse.n4js.transpiler/src/org/eclipse/n4js/transpiler/utils/TranspilerDebugUtils.xtend +++ /dev/null @@ -1,207 +0,0 @@ -/** - * Copyright (c) 2016 NumberFour AG. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * NumberFour AG - Initial API and implementation - */ -package org.eclipse.n4js.transpiler.utils - -import java.io.PrintWriter -import java.io.StringWriter -import java.io.Writer -import org.eclipse.emf.common.util.EList -import org.eclipse.emf.ecore.EObject -import org.eclipse.n4js.n4JS.ImportSpecifier -import org.eclipse.n4js.n4JS.N4JSPackage -import org.eclipse.n4js.n4JS.NamedElement -import org.eclipse.n4js.n4JS.VariableDeclaration -import org.eclipse.n4js.transpiler.InformationRegistry -import org.eclipse.n4js.transpiler.TranspilerState -import org.eclipse.n4js.transpiler.im.Script_IM -import org.eclipse.n4js.transpiler.im.SymbolTableEntry -import org.eclipse.n4js.transpiler.im.SymbolTableEntryOriginal -import org.eclipse.n4js.ts.typeRefs.TypeRefsPackage -import org.eclipse.n4js.ts.types.IdentifiableElement -import org.eclipse.xtext.EcoreUtil2 - -/** - * Some utilities for transpiler debugging, mainly dumping a {@link TranspilerState} to {@code stdout}, etc. - */ -class TranspilerDebugUtils { - - /** - * Perform some consistency checks on the transpiler state. For example, this asserts that no node in the - * intermediate model has a direct cross-reference to the original AST or an original TModule element. - */ - def public void validateState(TranspilerState state, boolean allowDanglingSecondaryReferencesInSTEs) throws AssertionError { - // IM should not contain entities from n4js.xcore / TypeRefs.xcore for which a replacement in IM.xcore exists - val replacedEClasses = #[ - N4JSPackage.eINSTANCE.parameterizedPropertyAccessExpression, - N4JSPackage.eINSTANCE.identifierRef, - TypeRefsPackage.eINSTANCE.parameterizedTypeRef - ]; - val badObject = state.im.eAllContents.findFirst[replacedEClasses.contains(it.eClass)]; - assertNull("intermediate model should not contain objects of type " + badObject?.eClass?.name, badObject); - // no cross reference in the IM to an element outside the IM (except in SymbolTableEntry) - assertFalse( - "intermediate model should not have a cross-reference to an element outside the intermediate model" - + " (except for SymbolTableEntry)", - state.im.eAllContents.filter[!(allowedCrossRefToOutside(state.info))].exists[hasCrossRefToOutsideOf(state)]); - // symbol table should exist - val st = state.im.symbolTable; - assertNotNull("intermediate model should have a symbol table", st); - // check entries in symbol table - for(ste : st.entries) { - if(ste instanceof SymbolTableEntryOriginal) { - assertNotNull("originalTarget should not be null", ste.originalTarget); - assertFalse("originalTarget should not be an element in the intermediate model", - ste.originalTarget.isElementInIntermediateModelOf(state)); - } - if(allowDanglingSecondaryReferencesInSTEs) { - // we allow dangling references in this case for the time being to make replacements in IM faster - // -> no checks here - // TODO consider disallowing dangling secondary references in symbol table entries - } else { - assertTrue("all elementsOfThisName should be elements in the intermediate model", - ste.elementsOfThisName.forall[isElementInIntermediateModelOf(state)]); - assertTrue("all referencingElements should be elements in the intermediate model", - ste.referencingElements.forall[isElementInIntermediateModelOf(state)]); - if(ste instanceof SymbolTableEntryOriginal) { - if(ste.importSpecifier!==null) { - assertTrue("importSpecifier should be an element in the intermediate model", - ste.importSpecifier.isElementInIntermediateModelOf(state)); - } - } - } - } - } - - def private allowedCrossRefToOutside(EObject eobj, InformationRegistry info) { - switch eobj { - SymbolTableEntry: true - default: false - } - } - - def private static boolean hasCrossRefToOutsideOf(EObject elementInIntermediateModel, TranspilerState state) { - return elementInIntermediateModel.eCrossReferences.exists[ - if(!isElementInIntermediateModelOf(state)) { - return true; - } - return false; - ]; - } - - def private static boolean isElementInIntermediateModelOf(EObject eobj, TranspilerState state) { - return EcoreUtil2.getContainerOfType(eobj,Script_IM)===state.im - } - - /** Asserts {@code value} to be true and throws an {@link AssertionError} otherwise. */ - def public static void assertTrue(String message, boolean value) throws AssertionError { - if (!value) assertionFailure(message); - } - - /** Asserts {@code value} to be false and throws an {@link AssertionError} otherwise. */ - def public static void assertFalse(String message, boolean value) throws AssertionError { - if (value) assertionFailure(message); - } - - /** Asserts {@code value} to be null and throws an {@link AssertionError} otherwise. */ - def public static void assertNull(String message, Object value) throws AssertionError { - if (value!==null) assertionFailure(message); - } - - /** Asserts {@code value} to be non-null and throws an {@link AssertionError} otherwise. */ - def public static void assertNotNull(String message, Object value) throws AssertionError { - if (value===null) assertionFailure(message); - } - - def private static void assertionFailure(String message) throws AssertionError { - val ex = new AssertionError(message); - ex.printStackTrace; // make sure we see this on the console even if exceptions are eaten up by someone - throw ex; - } - - def public static void dump(TranspilerState state) { - println(dumpToString(state)); - } - def public static String dumpToString(TranspilerState state) { - val w = new StringWriter(); - dump(state, w); - return w.toString; - } - /** - * Dumps the transpiler state to the given writer. - */ - def public static void dump(TranspilerState state, Writer out) { - val w = new PrintWriter(out); - w.dump(state.im, 0); - } - - def private static void dump(PrintWriter w, EObject obj, int indentLevel) { - w.indent(indentLevel); - w.printObj(obj, true, indentLevel); - w.println(); - - for(child : obj.eContents) { - w.dump(child, indentLevel+1); - } - } - - def private static void printObj(PrintWriter w, EObject obj, boolean includeCrossRefs, int indentLevel) { - w.print(obj.eClass.name); - if(obj instanceof IdentifiableElement || obj instanceof NamedElement || obj instanceof VariableDeclaration - || obj instanceof ImportSpecifier || obj instanceof SymbolTableEntry) { - w.print(' @'+Integer.toHexString(obj.hashCode)); - } - val objStr = obj.toString; - val idx = objStr.indexOf('('); - if(idx>=0) { - w.print(' ' + objStr.substring(idx)); - } - if(includeCrossRefs) { - val crossRefs = obj.eClass.getEAllReferences.filter[!containment]; - if(!crossRefs.empty) { - for(ref : crossRefs) { - w.println(); - w.indent(indentLevel); - w.print('--'+ref.name+'--> '); - if(ref.many) { - w.print('['); - val targets = obj.eGet(ref) as EList; - val iter = targets.iterator(); - while(iter.hasNext) { - val currTarget = iter.next; - if(currTarget!==null) { - w.printObj(currTarget, false, indentLevel); - } else { - w.print('null'); - } - if(iter.hasNext) { - w.print(', '); - } - } - w.print(']'); - } else { - val target = obj.eGet(ref) as EObject; - if(target!==null) { - w.printObj(target, false, indentLevel); - } else { - w.print('null'); - } - } - } - } - } - } - - def private static void indent(PrintWriter w, int indentLevel) { - for(i : 0 ..< indentLevel) { - w.print('\t'); - } - } -}