/****************************************************************************** * Copyright (c) 2007,2010 E.D.Willink and others. * 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: * E.D.Willink - initial API and implementation * * </copyright> * * $Id: CSTNodeEnvironment.java,v 1.2 2010/04/08 06:26:27 ewillink Exp $ */ package org.eclipse.ocl.examples.parser.environment; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.ocl.LookupException; import org.eclipse.ocl.cst.CSTNode; /** * CSTNodeEnvironment<E,AST,CST> revises the inherited EcoreEnvironment behaviour * to support operation appropriate to the construct defined by a CST node and * realised by an AST node. The environment is installed as an adapter on the AST * node so that the environment may be regarded as an extension of the AST model * providing state and functionality that are inappropriate for direct inclusion * within the AST. A derived CSTRootEnvironment<E,CST> defines the rrot of an * environment hierarchy comprising an AST XMIResource and a top level CST node. * Further derived CSTChildEnvironment<E,P,AST,CST> define more specific nested * environments. A CSTFileEnvironment is the parent of the CSTRootEnvironment * and supervises lexing, parsing and analysis. * <p> * Environments may be used to capture context during a two-phase declare/define * CST to AST conversion, in which the first declare phase creates the AST * hierarchy from the CST to ensure that all declarations are available for * resolution during a second definition phase. Thereafter the environments * could be discarded. Alternatively they may be preserved or indeed created * to support validation of either a parsed AST or an externally supplied AST. * <p> * The environment is an adapter on the AST and may be obtained from the * AST node by CSTNodeEnvironment.getEnvironmentFromAST(astNode, environmentClass) * or the CST by CSTNodeEnvironment.getEnvironmentFromCST(cstNode, environmentClass). * This assumes that the AST /CST has an associated environment. * <p> * The AST node may be obtained from the cst node by cstNode.getAst(). * <p> * The AST or CST may be obtained from the environment by env.getAst() or env.getCST(). * <p> * The CST may always be obtained from the AST by env.getASTtoCSTMapping().get(astNode) * where env is any environment in the hierarchy. There is no need for AST or CST to have * an associated environment. * <p> * CSTChildEnvironment<E,P,AST,CST> defines hierarchy of environments in which all * environments implement E and for which the parent environment implements P. * Lookups are re-implemented to traverse the environment hierarchy. * <p> * lookupXXX methods are therefore deprecated in favour of tryLookupXXX methods * that support a LookupException to report ambiguous lookups. * <p> * Look-ups are performed first using the derived implementation assuming * that the derived application is OCL-like. A failed derived look-up * is then delegated to the parent environment. * <p> * This provides a default semantics that may often be useful. It is expected * that derived environments will re-implement whenever another semantics is needed. * Total re-implementation of semantics by a derived environment is supported by * the ability to use the lookupOCLXXX method to access the underyling OCL functionality. * * @param <V> The derived ICSTEnvironment from which all environments derive * @param <P> The derived E of the parent environment * @param <AST> The type of the associated AST node * @param <CST> The type of the associated CST node */ public abstract class CSTNodeEnvironment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E, V extends ICSTNodeEnvironment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>, AST extends Notifier, CST extends CSTNode> extends CSTEnvironment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E, V> implements ICSTNodeEnvironment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>, Adapter { public static <PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E, V extends ICSTNodeEnvironment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>> V getEnvironmentFromAST(Notifier ast, Class<V> envClass) { if (ast != null) { @SuppressWarnings("unchecked") V adapter = (V) EcoreUtil.getAdapter(ast.eAdapters(), envClass); return adapter; } else return null; } public static <PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E, V extends ICSTNodeEnvironment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>> V getEnvironmentFromCST(CSTNode cst, Class<V> envClass) { Object ast = cst.getAst(); if (ast instanceof Notifier) { @SuppressWarnings("unchecked") V adapter = (V) EcoreUtil.getAdapter(((Notifier)ast).eAdapters(), envClass); return adapter; } else return null; } protected AST ast; protected CST cst; protected CSTNodeEnvironment(ICSTEnvironment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> parent, AST astNode, CST cstNode) { super(parent); // assert (astNode != null); assert (cstNode != null); this.ast = astNode; this.cst = cstNode; if (astNode != null) internalSetAdapter(); } /* public InvalidLiteralExp<C> createInvalidLiteralExp(CSTNode cstNode) { InvalidLiteralExp<C> invalidLiteralExp = org.eclipse.ocl.ecore.EcoreFactory.eINSTANCE.createInvalidLiteralExp(); initASTMapping(invalidLiteralExp, cstNode); return invalidLiteralExp; } */ public String formatLookupException(LookupException e) { List<?> matches = e.getAmbiguousMatches(); List<String> matchNames = new ArrayList<String>(); for (Object match : matches) matchNames.add(formatQualifiedName(match)); Collections.sort(matchNames); StringBuilder s = new StringBuilder(); s.append(e.getMessage()); String separator = " { "; for (String matchName : matchNames) { s.append(separator); s.append(matchName); separator = ", "; } s.append(" }"); return s.toString(); } public String formatName(Object object) { return getFormatter().formatName(object); } public String formatPath(List<String> names) { return getFormatter().formatPath(names); } @Deprecated public String formatPathName(Object object) { return formatQualifiedName(object); } public String formatQualifiedName(Object object) { return getFormatter().formatQualifiedName(object); } public String formatString(String string) { return getFormatter().formatString(string); } public String formatType(Object type) { return getFormatter().formatType(type); } public AST getASTNode() { return ast; } public CST getCSTNode() { return cst; } public Notifier getTarget() { return ast; } protected void internalSetAST(AST astNode) { assert (ast == null) == (astNode != null); ast = astNode; } protected void internalSetAdapter() { ast.eAdapters().add(this); } public boolean isAdapterForType(Object type) { return (type instanceof Class<?>) && ((Class<?>)type).isAssignableFrom(getClass()); } public C lookupClassifier(List<String> names) { return getFileEnvironment().lookupClassifier(getContextPackage(), names); } public void notifyChanged(Notification notification) {} @SuppressWarnings("unchecked") @Deprecated // Use createNestedEnvironment public CSTNode setCSTNode(CSTNode cstNode) { CSTNode oldCSTNode = this.cst; this.cst = (CST)cstNode; return oldCSTNode; } /** * Implementation of the Adapter method that imposes the set once policy of setASTNode. */ public final void setTarget(Notifier newTarget) { if (newTarget == null) // removing adapter internalSetAST(null); else if (newTarget == ast) // adding adapter ; else // something unexpected throw new UnsupportedOperationException(getClass().getName() + ".setTarget"); } @Override public String toString() { String parentString = getInternalParent() != null ? (getInternalParent().toString() + ".") : ""; CSTNode cstNode = getCSTNode(); String childString = cstNode instanceof IHasName ? ((IHasName)cstNode).getName() : getClass().getSimpleName(); return parentString + childString; } }