All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redhat.ceylon.langtools.tools.javac.util.Context Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
/*
 * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.redhat.ceylon.langtools.tools.javac.util;

import java.util.*;

/**
 * Support for an abstract context, modelled loosely after ThreadLocal
 * but using a user-provided context instead of the current thread.
 *
 * 

Within the compiler, a single Context is used for each * invocation of the compiler. The context is then used to ensure a * single copy of each compiler phase exists per compiler invocation. * *

The context can be used to assist in extending the compiler by * extending its components. To do that, the extended component must * be registered before the base component. We break initialization * cycles by (1) registering a factory for the component rather than * the component itself, and (2) a convention for a pattern of usage * in which each base component registers itself by calling an * instance method that is overridden in extended components. A base * phase supporting extension would look something like this: * *

 * public class Phase {
 *     protected static final Context.Key phaseKey =
 *         new Context.Key();
 *
 *     public static Phase instance(Context context) {
 *         Phase instance = context.get(phaseKey);
 *         if (instance == null)
 *             // the phase has not been overridden
 *             instance = new Phase(context);
 *         return instance;
 *     }
 *
 *     protected Phase(Context context) {
 *         context.put(phaseKey, this);
 *         // other intitialization follows...
 *     }
 * }
 * 
* *

In the compiler, we simply use Phase.instance(context) to get * the reference to the phase. But in extensions of the compiler, we * must register extensions of the phases to replace the base phase, * and this must be done before any reference to the phase is accessed * using Phase.instance(). An extended phase might be declared thus: * *

 * public class NewPhase extends Phase {
 *     protected NewPhase(Context context) {
 *         super(context);
 *     }
 *     public static void preRegister(final Context context) {
 *         context.put(phaseKey, new Context.Factory() {
 *             public Phase make() {
 *                 return new NewPhase(context);
 *             }
 *         });
 *     }
 * }
 * 
* *

And is registered early in the extended compiler like this * *

 *     NewPhase.preRegister(context);
 * 
* *

This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice. */ public class Context { /** The client creates an instance of this class for each key. */ public static class Key { // note: we inherit identity equality from Object. } /** * The client can register a factory for lazy creation of the * instance. */ public static interface Factory { T make(Context c); }; /** * The underlying map storing the data. * We maintain the invariant that this table contains only * mappings of the form * Key -> T or Key -> Factory */ private Map,Object> ht = new HashMap,Object>(); /** Set the factory for the key in this context. */ public void put(Key key, Factory fac) { checkState(ht); Object old = ht.put(key, fac); if (old != null) throw new AssertionError("duplicate context value"); checkState(ft); ft.put(key, fac); // cannot be duplicate if unique in ht } /** Set the value for the key in this context. */ public void put(Key key, T data) { if (data instanceof Factory) throw new AssertionError("T extends Context.Factory"); checkState(ht); Object old = ht.put(key, data); if (old != null && !(old instanceof Factory) && old != data && data != null) throw new AssertionError("duplicate context value"); } /** Get the value for the key in this context. */ public T get(Key key) { checkState(ht); Object o = ht.get(key); if (o instanceof Factory) { Factory fac = (Factory)o; o = fac.make(this); if (o instanceof Factory) throw new AssertionError("T extends Context.Factory"); Assert.check(ht.get(key) == o); } /* The following cast can't fail unless there was * cheating elsewhere, because of the invariant on ht. * Since we found a key of type Key, the value must * be of type T. */ return Context.uncheckedCast(o); } public Context() {} /** * The table of preregistered factories. */ private Map,Factory> ft = new HashMap,Factory>(); public Context(Context prev) { kt.putAll(prev.kt); // retain all implicit keys ft.putAll(prev.ft); // retain all factory objects ht.putAll(prev.ft); // init main table with factories } /* * The key table, providing a unique Key for each Class. */ private Map, Key> kt = new HashMap, Key>(); private Key key(Class clss) { checkState(kt); Key k = uncheckedCast(kt.get(clss)); if (k == null) { k = new Key(); kt.put(clss, k); } return k; } public T get(Class clazz) { return get(key(clazz)); } public void put(Class clazz, T data) { put(key(clazz), data); } public void put(Class clazz, Factory fac) { put(key(clazz), fac); } /** * TODO: This method should be removed and Context should be made type safe. * This can be accomplished by using class literals as type tokens. */ @SuppressWarnings("unchecked") private static T uncheckedCast(Object o) { return (T)o; } public void dump() { for (Object value : ht.values()) System.err.println(value == null ? null : value.getClass()); } public void clear() { ht = null; kt = null; ft = null; } private static void checkState(Map t) { if (t == null) throw new IllegalStateException(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy