diff options
Diffstat (limited to 'plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend')
15 files changed, 749 insertions, 75 deletions
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/MiddleEnd.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/MiddleEnd.java new file mode 100644 index 00000000..989ed496 --- /dev/null +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/MiddleEnd.java @@ -0,0 +1,51 @@ +/* +Copyright (c) 2008 Arno Haase. +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: + Arno Haase - initial API and implementation + */ +package org.eclipse.xtend.middleend; + +import org.eclipse.xtend.backend.common.BackendTypesystem; +import org.eclipse.xtend.backend.common.ExecutionContext; +import org.eclipse.xtend.backend.common.FunctionDefContext; +import org.eclipse.xtend.backend.functions.FunctionDefContextInternal; + + +/** + * This interface is the generic entry point for parsing and executing code. Different + * languages can contribute their specific middle ends using extension points.<br> + * + * MiddleEnd instances are stateful in that they preserve caching of the contributed + * middle ends. They also preserve a single ExecutionContext instance throughout their + * life span, but they expose it to allows using code to selectively manipulate and / or + * re-initialize it between invocations. + * + * @author Arno Haase (http://www.haase-consulting.com) + */ +public interface MiddleEnd { + /** + * tells this middle end instance to apply the advice in a given resource to all + * subsequent invocations. + */ + void applyAdvice (String resourceName); + + FunctionDefContext getFunctions (String resourceName); + + /** + * This method exposes the execution context to using code with the explicit purpose of allowing others to + * inspect and manipulate / re-initialize it partially or in toto. <br> + * + * But beware: This data structure is used directly by the runtime, and modifications can significantly + * influence behavior at runtime! + */ + ExecutionContext getExecutionContext (); + + BackendTypesystem getTypesystem (); + + FunctionDefContextInternal createEmptyFdc (); +} diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/MiddleEndFactory.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/MiddleEndFactory.java new file mode 100644 index 00000000..6321bb2a --- /dev/null +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/MiddleEndFactory.java @@ -0,0 +1,49 @@ +/* +Copyright (c) 2008 Arno Haase. +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: + Arno Haase - initial API and implementation + */ +package org.eclipse.xtend.middleend; + +import java.util.List; +import java.util.Map; + +import org.eclipse.xtend.backend.common.BackendTypesystem; +import org.eclipse.xtend.middleend.internal.Activator; +import org.eclipse.xtend.middleend.internal.MiddleEndImpl; +import org.eclipse.xtend.middleend.plugins.LanguageSpecificMiddleEnd; + + +/** + * This class encapsulates the OSGi / Eclipse extension registry specific behavior and + * initialization code. It serves as an optional wrapper / convenience initialization + * code for the actual MiddleEnd class. + * + * @author Arno Haase (http://www.haase-consulting.com) + */ +public final class MiddleEndFactory { + /** + * This method creates a MiddleEnd instance based on an explicitly provided list of handlers. It works without + * OSGi. + */ + public static MiddleEnd create (BackendTypesystem ts, List<LanguageSpecificMiddleEnd> languageHandlers) { + return new MiddleEndImpl (ts, languageHandlers); + } + + /** + * This method creates a middle end based on the handlers registered with the extension point. It relies + * on OSGi and makes use of the Eclipse extension registry.<br> + * + * The map with "specific params" is used to initialize the contributed middle ends. + * The key must be the class implementing the LanguageSpecificMiddleEnd interface + * and contributed via the extension point. + */ + public static MiddleEnd createFromExtensions (BackendTypesystem ts, Map<Class<?>, Object> specificParams) { + return new MiddleEndImpl (ts, Activator.getInstance().getFreshMiddleEnds (specificParams)); + } +} diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/internal/Activator.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/internal/Activator.java new file mode 100644 index 00000000..ada8778e --- /dev/null +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/internal/Activator.java @@ -0,0 +1,105 @@ +/* +Copyright (c) 2008 Arno Haase. +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: + Arno Haase - initial API and implementation + */ +package org.eclipse.xtend.middleend.internal; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.RegistryFactory; +import org.eclipse.xtend.middleend.plugins.LanguageSpecificMiddleEnd; +import org.eclipse.xtend.middleend.plugins.LanguageSpecificMiddleEndFactory; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + + +/** + * + * @author Arno Haase (http://www.haase-consulting.com) + */ +public class Activator implements BundleActivator { + private static final Log _log = LogFactory.getLog (Activator.class); + + private static Activator _instance = null; + + public static Activator getInstance () { + return _instance; + } + + private final List<LanguageSpecificMiddleEndFactory> _middleEndContributions = new ArrayList<LanguageSpecificMiddleEndFactory> (); + private boolean _isInitialized = false; + + + public List<LanguageSpecificMiddleEnd> getFreshMiddleEnds (Map<Class<?>, Object> specificParams) { + init (); + + final List<LanguageSpecificMiddleEnd> result = new ArrayList<LanguageSpecificMiddleEnd>(); + + for (LanguageSpecificMiddleEndFactory factory: _middleEndContributions) { + try { + result.add (factory.create (specificParams.get (factory.getClass()))); + } + catch (IllegalArgumentException exc) { + // this is the official way for an implementation to withdraw from the pool for this call + _log.debug ("middle end implementation " + factory.getName() + " says it is not available: " + exc.getMessage()); + } + } + + return result; + } + + public void start (BundleContext context) throws Exception { + //TODO Bernd: implement error handling and logging to be both robust and independent of Eclipse + + _isInitialized = false; + _instance = this; + } + + private void init () { + if (_isInitialized) + return; + + _isInitialized = true; + _middleEndContributions.clear (); + + try { + final IConfigurationElement[] confEl = RegistryFactory.getRegistry().getConfigurationElementsFor ("org.eclipse.xtend.backend.MiddleEnd"); + + for (IConfigurationElement curEl: confEl) { + final Object o = curEl.createExecutableExtension ("class"); + _middleEndContributions.add ((LanguageSpecificMiddleEndFactory) o); + } + } + catch (Exception exc) { + exc.printStackTrace (); + } + + Collections.sort (_middleEndContributions, new Comparator <LanguageSpecificMiddleEndFactory> () { + public int compare (LanguageSpecificMiddleEndFactory o1, LanguageSpecificMiddleEndFactory o2) { + return o1.getPriority() - o2.getPriority(); + } + }); + + _log.info ("Activating Eclipse Modeling Middle End - the following middle ends are registered:"); + for (LanguageSpecificMiddleEndFactory factory: _middleEndContributions) + _log.info (" " + factory.getName()); + } + + public void stop (BundleContext context) throws Exception { + _instance = null; + _middleEndContributions.clear(); + } +} diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/internal/MiddleEndImpl.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/internal/MiddleEndImpl.java new file mode 100644 index 00000000..bdfe7d8d --- /dev/null +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/internal/MiddleEndImpl.java @@ -0,0 +1,223 @@ +/* +Copyright (c) 2008 Arno Haase. +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: + Arno Haase - initial API and implementation + */ +package org.eclipse.xtend.middleend.internal; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.eclipse.xtend.backend.BackendFacade; +import org.eclipse.xtend.backend.aop.AroundAdvice; +import org.eclipse.xtend.backend.common.BackendTypesystem; +import org.eclipse.xtend.backend.common.ExecutionContext; +import org.eclipse.xtend.backend.common.FunctionDefContext; +import org.eclipse.xtend.backend.common.NamedFunction; +import org.eclipse.xtend.backend.functions.FunctionDefContextInternal; +import org.eclipse.xtend.backend.functions.internal.FunctionDefContextImpl; +import org.eclipse.xtend.backend.syslib.SyslibContributor; +import org.eclipse.xtend.middleend.MiddleEnd; +import org.eclipse.xtend.middleend.javaannotations.JavaFunctionClassContributor; +import org.eclipse.xtend.middleend.plugins.ImportedResource; +import org.eclipse.xtend.middleend.plugins.LanguageSpecificMiddleEnd; +import org.eclipse.xtend.middleend.plugins.ParsedResource; + + +/** + * This class is the generic entry point for parsing and executing code. Different + * languages can contribute their specific middle ends using extension points.<br> + * + * MiddleEnd instances are stateful in that they preserve caching of the contributed + * middle ends. They also preserve a single ExecutionContext instance throughout their + * life span, but they expose it to allows using code to selectively manipulate and / or + * re-initialize it between invocations. + * + * @author Arno Haase (http://www.haase-consulting.com) + */ +public final class MiddleEndImpl implements MiddleEnd { + private static final Log _log = LogFactory.getLog (MiddleEndImpl.class); + + private final Map<String, ParsedResource> _parsedResources = new HashMap<String, ParsedResource> (); + private final Map<String, FunctionDefContext> _fdcs = new HashMap<String, FunctionDefContext> (); + + private final List<LanguageSpecificMiddleEnd> _languageHandlers; + private final ExecutionContext _ctx; + private final BackendTypesystem _ts; + + /** + * this flag marks the temporary state while the syslib is added to a newly created fdc. During + * this phase, newly created fdcs are returned *without* registering the syslib to avoid endless + * recursion. + */ + private boolean _isInitializingSyslib = false; + + /** + * The map with "specific params" is used to initialize the contributed middle ends. + * The key must be the class implementing the LanguageSpecificMiddleEnd interface + * and contributed via the extension point. + */ + public MiddleEndImpl (BackendTypesystem ts, List<LanguageSpecificMiddleEnd> languageHandlers) { + if (languageHandlers == null) + languageHandlers = new ArrayList<LanguageSpecificMiddleEnd> (); + + // this is a "built-in" handler that is, among other things, necessary for the syslib + languageHandlers.add (new JavaFunctionClassContributor ()); + + _ts = ts; + _languageHandlers = languageHandlers; + + for (LanguageSpecificMiddleEnd handler: languageHandlers) + handler.setMiddleEnd (this); + + // it is important that the middle end is properly initialized before an fdc is created because + // syslib registration relies on an initialized middle end. + _ctx = BackendFacade.createExecutionContext (createEmptyFdc(), ts, false); + } + + private LanguageSpecificMiddleEnd findHandler (String resourceName) { + for (LanguageSpecificMiddleEnd candidate: _languageHandlers) { + if (candidate.canHandle (resourceName)) { + _log.debug ("middle end " + candidate.getName() + " handles resource " + resourceName); + return candidate; + } + } + + _log.warn ("no middle end for resource " + resourceName); + throw new IllegalArgumentException ("no middle end for resource " + resourceName); + } + + private ParsedResource parseResource (String resourceName) { + if (_parsedResources.containsKey (resourceName)) + return _parsedResources.get (resourceName); + + final ParsedResource result = findHandler (resourceName).parseResource (resourceName); + _parsedResources.put (resourceName, result); + + final FunctionDefContext fdc = getFdc (resourceName); + for (NamedFunction f: result.getPrivateFunctions()) + f.getFunction().setFunctionDefContext (fdc); + for (NamedFunction f: result.getPublicFunctions()) + f.getFunction().setFunctionDefContext (fdc); + for (AroundAdvice advice: result.getAdvice()) + advice.setFunctionDefContext (fdc); + + return result; + } + + private FunctionDefContext getFdc (String resourceName) { + if (_fdcs.containsKey (resourceName)) + return _fdcs.get (resourceName); + + final FunctionDefContextInternal result = createEmptyFdc(); + _fdcs.put (resourceName, result); + + System.out.println ("*****" + resourceName); + final Set<String> reexported = new HashSet<String> (); + collectReexportedResources (reexported, new HashSet<String> (), resourceName); + System.out.println ("/////" + resourceName); + + for (String importedReexp: reexported) + for (NamedFunction f: parseResource (importedReexp).getPublicFunctions()) + result.register (f, true); + + for (ImportedResource ir: parseResource (resourceName).getImports()) { + if (ir.isReexported()) + continue; + + for (NamedFunction f: parseResource (ir.getResourceName ()).getPublicFunctions ()) + result.register (f, false); + } + + for (NamedFunction f: parseResource (resourceName).getPrivateFunctions()) + result.register(f, false); + for (NamedFunction f: parseResource (resourceName).getPublicFunctions()) + result.register(f, true); + + _log.debug ("fdc for " + resourceName + ": "); + _log.debug (" reexported: " + reexported); + _log.debug (" public functions: " + result.getPublicFunctions()); + + return result; + } + + /** + * tells this middle end instance to apply the advice in a given resource to all + * subsequent invocations. + */ + public void applyAdvice (String resourceName) { + for (AroundAdvice advice: parseResource (resourceName).getAdvice()) + _ctx.setAdviceContext (_ctx.getAdviceContext().copyWithAdvice (advice)); + } + + public FunctionDefContext getFunctions (String resourceName) { + return getFdc (resourceName); + } + + private void collectReexportedResources (Set<String> result, Set<String> visited, String curResource) { + if (visited.contains (curResource)) + return; + visited.add (curResource); + + for (ImportedResource candidate: parseResource (curResource).getImports()) { + final String candidateName = candidate.getResourceName(); + + if (! candidate.isReexported()) + continue; + + if (visited.contains (candidateName)) + continue; + + result.add (candidateName); + collectReexportedResources (result, visited, candidateName); + } + } + + + /** + * This method exposes the execution context to using code with the explicit purpose of allowing others to + * inspect and manipulate / re-initialize it partially or in toto. <br> + * + * But beware: This data structure is used directly by the runtime, and modifications can significantly + * influence behavior at runtime! + */ + public ExecutionContext getExecutionContext () { + return _ctx; + } + + public BackendTypesystem getTypesystem () { + return _ts; + } + + //TODO make this private? + public FunctionDefContextInternal createEmptyFdc () { + final FunctionDefContextInternal result = new FunctionDefContextImpl (); + + if (_isInitializingSyslib) + return result; + + _isInitializingSyslib = true; + + try { + for (String resourceName: SyslibContributor.getSysLibResources()) + for (NamedFunction f: getFunctions(resourceName).getPublicFunctions()) + result.register (f, true); + + return result; + } + finally { + _isInitializingSyslib = false; + } + } +} diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/AbstractExecutionContextAware.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/AbstractExecutionContextAware.java index 8ff34c55..872c24a4 100644 --- a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/AbstractExecutionContextAware.java +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/AbstractExecutionContextAware.java @@ -25,6 +25,8 @@ public abstract class AbstractExecutionContextAware implements ExecutionContextA _ctx = ctx; } + //TODO add "invoke" method - and rename this to AbstractJavaDefinedFunctions, with implementations for the import methods as well + protected ExecutionContext getExecutionContext () { return _ctx; } diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/JavaFunctionClassContributor.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/JavaFunctionClassContributor.java index 5e1aaa44..8c24dd56 100644 --- a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/JavaFunctionClassContributor.java +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/JavaFunctionClassContributor.java @@ -10,17 +10,16 @@ Contributors: */ package org.eclipse.xtend.middleend.javaannotations; -import java.util.ArrayList; -import java.util.List; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; -import org.eclipose.xtend.middleend.MiddleEnd; -import org.eclipose.xtend.middleend.plugins.LanguageSpecificMiddleEnd; import org.eclipse.emf.mwe.core.resources.ResourceLoader; import org.eclipse.emf.mwe.core.resources.ResourceLoaderFactory; -import org.eclipse.xtend.backend.aop.AroundAdvice; -import org.eclipse.xtend.backend.common.FunctionDefContext; import org.eclipse.xtend.backend.common.NamedFunction; -import org.eclipse.xtend.backend.functions.FunctionDefContextInternal; +import org.eclipse.xtend.middleend.MiddleEnd; +import org.eclipse.xtend.middleend.javaannotations.internal.JavaDefinedFunction; +import org.eclipse.xtend.middleend.plugins.LanguageSpecificMiddleEnd; +import org.eclipse.xtend.middleend.plugins.ParsedResource; /** @@ -55,21 +54,54 @@ public final class JavaFunctionClassContributor implements LanguageSpecificMiddl } } - public List<AroundAdvice> getContributedAdvice (String resourceName) { - return new ArrayList<AroundAdvice> (); //TODO add support for advice - } - - public FunctionDefContext getContributedFunctions (String resourceName) { - final FunctionDefContextInternal result = _middleEnd.createEmptyFdc(); + public ParsedResource parseResource (String resourceName) { + final ParsedResource result = new ParsedResource (); - //TODO add support for imported resources + //TODO imports + //TODO advice + //TODO guards + + final Class<?> cls = getCls (resourceName); - for (JavaDefinedFunction f: JavaDefinedFunction.createForEntireClass (getCls (resourceName), _middleEnd.getTypesystem())) - result.register (new NamedFunction (f.getName(), f), true); //TODO add support for non-public functions + for (Method mtd: cls.getDeclaredMethods()) { + // register only public methods + if (! isPublic (mtd)) + continue; + + if(isInfrastructureMethod (mtd, cls)) + continue; + + if (mtd.getAnnotation (M2tNoFunction.class) != null) + continue; + + final boolean isPublicFunction = (mtd.getAnnotation (M2tPrivateFunction.class) == null); + final NamedFunction f = new NamedFunction (mtd.getName(), new JavaDefinedFunction (mtd, null, _middleEnd.getTypesystem())); + + if (isPublicFunction) + result.getPublicFunctions().add (f); + else + result.getPrivateFunctions().add (f); + } return result; } + private boolean isPublic (Method mtd) { + return (mtd.getModifiers() & Modifier.PUBLIC) != 0; + } + + private boolean isInfrastructureMethod (Method mtd, Class<?> cls) { + if (ExecutionContextAware.class.isAssignableFrom (cls)) { + try { + ExecutionContextAware.class.getMethod (mtd.getName(), mtd.getParameterTypes()); + return true; + } + catch (NoSuchMethodException e) { + } + } + return false; + } + public String getName () { return MIDDLE_END_NAME; } diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/M2tAroundAdvice.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/M2tAroundAdvice.java new file mode 100644 index 00000000..2fce92ab --- /dev/null +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/M2tAroundAdvice.java @@ -0,0 +1,31 @@ +/* +Copyright (c) 2008 Arno Haase. +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: + Arno Haase - initial API and implementation + */ +package org.eclipse.xtend.middleend.javaannotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +/** + * Methods marked with this annotation are treated as "around" advice + * rather than functions. They must take exactly two parameters of the + * types ThisJoinPointStaticPart and ThisJoinPoint, respectively. + * + * @author Arno Haase (http://www.haase-consulting.com) + */ +@Retention (RetentionPolicy.RUNTIME) +@Target (ElementType.METHOD) +public @interface M2tAroundAdvice { + //TODO add name matching pattern + //TODO add type parameters for the function params, including support for wildcard arguments +} diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/M2tCached.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/M2tCached.java new file mode 100644 index 00000000..17ff70a8 --- /dev/null +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/M2tCached.java @@ -0,0 +1,27 @@ +/* +Copyright (c) 2008 Arno Haase. +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: + Arno Haase - initial API and implementation + */ +package org.eclipse.xtend.middleend.javaannotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +/** + * Methods marked with this annotation will be cached + * + * @author Arno Haase (http://www.haase-consulting.com) + */ +@Retention (RetentionPolicy.RUNTIME) +@Target (ElementType.METHOD) +public @interface M2tCached { +} diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/M2tHidden.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/M2tNoFunction.java index 8d377c17..613a4e65 100644 --- a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/M2tHidden.java +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/M2tNoFunction.java @@ -23,5 +23,5 @@ import java.lang.annotation.Target; */ @Retention (RetentionPolicy.RUNTIME) @Target (ElementType.METHOD) -public @interface M2tHidden { +public @interface M2tNoFunction { } diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/M2tPrivateFunction.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/M2tPrivateFunction.java new file mode 100644 index 00000000..e906db5c --- /dev/null +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/M2tPrivateFunction.java @@ -0,0 +1,28 @@ +/* +Copyright (c) 2008 Arno Haase. +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: + Arno Haase - initial API and implementation + */ +package org.eclipse.xtend.middleend.javaannotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +/** + * Methods marked with this annotation will be registered as private extensions, i.e. they will be visible for + * invocations from within the class but not from other resources + * + * @author Arno Haase (http://www.haase-consulting.com) + */ +@Retention (RetentionPolicy.RUNTIME) +@Target (ElementType.METHOD) +public @interface M2tPrivateFunction { +} diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/JavaDefinedFunction.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/internal/JavaDefinedFunction.java index 8c22e3f4..8a67eb23 100644 --- a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/JavaDefinedFunction.java +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/javaannotations/internal/JavaDefinedFunction.java @@ -8,7 +8,7 @@ http://www.eclipse.org/legal/epl-v10.html Contributors: Arno Haase - initial API and implementation */ -package org.eclipse.xtend.middleend.javaannotations; +package org.eclipse.xtend.middleend.javaannotations.internal; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -20,11 +20,13 @@ import org.eclipse.xtend.backend.common.BackendType; import org.eclipse.xtend.backend.common.BackendTypesystem; import org.eclipse.xtend.backend.common.ExecutionContext; import org.eclipse.xtend.backend.common.ExpressionBase; -import org.eclipse.xtend.backend.common.Function; +import org.eclipse.xtend.backend.functions.AbstractFunction; import org.eclipse.xtend.backend.functions.java.internal.JavaBuiltinConverter; import org.eclipse.xtend.backend.functions.java.internal.JavaBuiltinConverterFactory; import org.eclipse.xtend.backend.functions.java.internal.ParameterConverter; import org.eclipse.xtend.backend.util.ErrorHandler; +import org.eclipse.xtend.middleend.javaannotations.ExecutionContextAware; +import org.eclipse.xtend.middleend.javaannotations.M2tCached; /** @@ -37,57 +39,19 @@ import org.eclipse.xtend.backend.util.ErrorHandler; * * @author Arno Haase (http://www.haase-consulting.com) */ -public final class JavaDefinedFunction implements Function { +public final class JavaDefinedFunction extends AbstractFunction { private final Method _mtd; - private final List<BackendType> _parameterTypes; - private final ExpressionBase _guard; private final boolean _isStatic; - + private final List<ParameterConverter> _parameterConverters = new ArrayList<ParameterConverter>(); private final JavaBuiltinConverter _returnValueConverter; - //TODO move this factory to JavaFunctionClassContributor - //TODO separate internal API - /** - * This is a convenience factory method that creates functions for all public methods for an entire class. - */ - public static List<JavaDefinedFunction> createForEntireClass (Class<?> cls, BackendTypesystem ts) { - final List<JavaDefinedFunction> result = new ArrayList<JavaDefinedFunction>(); - - for (Method mtd: cls.getDeclaredMethods()) { - // register only public methods - if (! isPublic (mtd)) - continue; - - // do not register infrastructure methods inherited from ExecutionContextAware - if (ExecutionContextAware.class.isAssignableFrom (cls)) { - try { - ExecutionContextAware.class.getMethod (mtd.getName(), mtd.getParameterTypes()); - continue; - } - catch (NoSuchMethodException e) { - } - } - - if (mtd.getAnnotation (M2tHidden.class) != null) - continue; - - result.add (new JavaDefinedFunction (mtd, null, ts)); - } - return result; - } - - private static boolean isPublic (Method mtd) { - return (mtd.getModifiers() & Modifier.PUBLIC) != 0; - } - - /** * shortcut constructor that attempts to derive the parameter types from the method's signature */ public JavaDefinedFunction (Method mtd, ExpressionBase guard, BackendTypesystem ts) { - this (mtd, guessParameterTypes(mtd, ts), guard); + this (mtd, guessParameterTypes (mtd, ts), guard); } @@ -95,9 +59,9 @@ public final class JavaDefinedFunction implements Function { * This constructor provides full control */ public JavaDefinedFunction (Method mtd, List<BackendType> parameterTypes, ExpressionBase guard) { + super (guard, parameterTypes, mtd.getAnnotation (M2tCached.class) != null); + _mtd = mtd; - _parameterTypes = parameterTypes; - _guard = guard; for (int i=0; i<mtd.getParameterTypes().length; i++) { final ParameterConverter pc = JavaBuiltinConverterFactory.getParameterConverter (mtd.getParameterTypes()[i], i); @@ -141,14 +105,6 @@ public final class JavaDefinedFunction implements Function { return _mtd.getName(); } - public boolean isCached () { - return false; - } - - public List<BackendType> getParameterTypes() { - return _parameterTypes; - } - public Object invoke (ExecutionContext ctx, Object[] params) { for (ParameterConverter pc: _parameterConverters) pc.convert(params); @@ -175,14 +131,10 @@ public final class JavaDefinedFunction implements Function { return null; // to make the compiler happy - this is never executed } } - - public ExpressionBase getGuard () { - return _guard; - } @Override public String toString () { - return "JavaDefinedFunction '" + getName() + "' " + _parameterTypes; + return "JavaDefinedFunction '" + getName() + "' " + getParameterTypes(); } } diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/plugins/ImportedResource.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/plugins/ImportedResource.java new file mode 100644 index 00000000..bc7968b0 --- /dev/null +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/plugins/ImportedResource.java @@ -0,0 +1,34 @@ +/* +Copyright (c) 2008 Arno Haase. +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: + Arno Haase - initial API and implementation + */ +package org.eclipse.xtend.middleend.plugins; + + +/** + * + * @author Arno Haase (http://www.haase-consulting.com) + */ +public final class ImportedResource { + private final String _resourceName; + private final boolean _isReexported; + + public ImportedResource (String resourceName, boolean isReexported) { + _resourceName = resourceName; + _isReexported = isReexported; + } + + public String getResourceName () { + return _resourceName; + } + + public boolean isReexported () { + return _isReexported; + } +} diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/plugins/LanguageSpecificMiddleEnd.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/plugins/LanguageSpecificMiddleEnd.java new file mode 100644 index 00000000..5216b5c5 --- /dev/null +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/plugins/LanguageSpecificMiddleEnd.java @@ -0,0 +1,46 @@ +/* +Copyright (c) 2008 Arno Haase. +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: + Arno Haase - initial API and implementation + */ +package org.eclipse.xtend.middleend.plugins; + +import org.eclipse.xtend.middleend.MiddleEnd; + + +/** + * This interface is the common abstraction through which all handlers for different + * languages can contribute their middle ends. + * + * @author Arno Haase (http://www.haase-consulting.com) + */ +public interface LanguageSpecificMiddleEnd { + /** + * This method is used to break the circular dependency between MiddleEnd and the + * language specific handlers. It is called by the MiddleEnd on creation. + */ + void setMiddleEnd (MiddleEnd middleEnd); + + String getName (); + + /** + * gives the middle end a way to declare if it can and wants to handle a given + * source file / resource. If and only if it returns true, it will be asked for + * the functions and advice provided in this resource. + */ + boolean canHandle (String resourceName); + + /** + * This method asks the middle end to parse a resource for which it declared + * that it is the appropriate handler, and return the functions contained therein.<br> + * + * Implementations are not required to perform any caching because the MiddleEnd + * implementation takes care of that. + */ + ParsedResource parseResource (String resourceName); +} diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/plugins/LanguageSpecificMiddleEndFactory.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/plugins/LanguageSpecificMiddleEndFactory.java new file mode 100644 index 00000000..c5143859 --- /dev/null +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/plugins/LanguageSpecificMiddleEndFactory.java @@ -0,0 +1,48 @@ +/* +Copyright (c) 2008 Arno Haase. +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: + Arno Haase - initial API and implementation + */ +package org.eclipse.xtend.middleend.plugins; + + +/** + * This interface is the common abstraction through which all handlers for different + * languages can contribute their middle ends. Every language should contribute its + * MiddleEnd implementation factory through the extension point. + * + * @author Arno Haase (http://www.haase-consulting.com) + */ +public interface LanguageSpecificMiddleEndFactory { + /** + * a clear text name describing the language / middle end + */ + String getName (); + + /** + * the priority is a possible way to determine the order in which the middle ends + * are asked if they can handle a given resource. Typically, only one middle end + * implementation should declare that it can handle a given resource (i.e. source + * file), and in this case a priority of 0 should be returned. <br> + * + * In the rare case where it is needed, highest priority is asked first. + */ + int getPriority (); + + /** + * This method creates the actual implementation of the middle end. The specificData parameter is + * passed through from the MiddleEnd constructor.<br> + * + * It is permitted for implementations to throw an IllegalArgumentException, + * which is the official way for an implementation to say that it views the + * passed data as insufficient to perform, and therefore needs to be removed + * from the list of registered middle ends. This is done on a per-call basis + * and avoids the necessity to always initialize all middle end implementations. + */ + LanguageSpecificMiddleEnd create (Object specificData); +} diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/plugins/ParsedResource.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/plugins/ParsedResource.java new file mode 100644 index 00000000..29ece5f5 --- /dev/null +++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/middleend/plugins/ParsedResource.java @@ -0,0 +1,46 @@ +/* +Copyright (c) 2008 Arno Haase. +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: + Arno Haase - initial API and implementation + */ +package org.eclipse.xtend.middleend.plugins; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.xtend.backend.aop.AroundAdvice; +import org.eclipse.xtend.backend.common.NamedFunction; + + +/** + * This class represents all information about a resource that is relevant for the backend. + * + * @author Arno Haase (http://www.haase-consulting.com) + */ +public final class ParsedResource { + private final List<ImportedResource> _imports = new ArrayList<ImportedResource> (); + private final List<NamedFunction> _privateFunctions = new ArrayList<NamedFunction> (); + private final List<NamedFunction> _publicFunctions = new ArrayList<NamedFunction> (); + private final List<AroundAdvice> _advice = new ArrayList<AroundAdvice> (); + + public List<ImportedResource> getImports () { + return _imports; + } + + public List<NamedFunction> getPrivateFunctions () { + return _privateFunctions; + } + + public List<NamedFunction> getPublicFunctions () { + return _publicFunctions; + } + + public List<AroundAdvice> getAdvice () { + return _advice; + } +} |