View Javadoc

1   /***
2    * Cecilia ADL Compiler
3    * Copyright (C) 2006-2007 STMicroelectronics
4    *
5    * This library is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU Lesser General Public
7    * License as published by the Free Software Foundation; either
8    * version 2 of the License, or (at your option) any later version.
9    *
10   * This library is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   * Lesser General Public License for more details.
14   *
15   * You should have received a copy of the GNU Lesser General Public
16   * License along with this library; if not, write to the Free Software
17   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   *
19   * Contact: fractal@objectweb.org
20   *
21   * Author: Matthieu Leclercq, Ali Erdem Ozcan
22   * Contributors: Alessio Pace
23   */
24  
25  package org.objectweb.fractal.cecilia.primitive.thinkMC.implementations;
26  
27  import static org.objectweb.fractal.adl.NodeUtil.castNodeError;
28  import static org.objectweb.fractal.cecilia.adl.implementations.ImplementationDecorationUtil.getCode;
29  import static org.objectweb.fractal.cecilia.adl.implementations.ImplementationHelper.hasConstructor;
30  import static org.objectweb.fractal.cecilia.adl.implementations.ImplementationHelper.hasDestructor;
31  
32  import java.util.ArrayList;
33  import java.util.Collection;
34  import java.util.List;
35  import java.util.Map;
36  
37  import org.objectweb.fractal.adl.ADLException;
38  import org.objectweb.fractal.adl.CompilerError;
39  import org.objectweb.fractal.adl.ComponentVisitor;
40  import org.objectweb.fractal.adl.Node;
41  import org.objectweb.fractal.adl.components.ComponentContainer;
42  import org.objectweb.fractal.adl.error.GenericErrors;
43  import org.objectweb.fractal.adl.implementations.Implementation;
44  import org.objectweb.fractal.adl.implementations.ImplementationContainer;
45  import org.objectweb.fractal.api.Component;
46  import org.objectweb.fractal.cecilia.adl.AbstractDefinitionTask;
47  import org.objectweb.fractal.cecilia.adl.SourceCodeProvider;
48  import org.objectweb.fractal.cecilia.adl.directives.Include;
49  import org.objectweb.fractal.cecilia.adl.directives.IncludeContainer;
50  import org.objectweb.fractal.cecilia.adl.file.CodeWriter;
51  import org.objectweb.fractal.cecilia.adl.file.SourceFile;
52  import org.objectweb.fractal.task.core.AbstractTaskFactoryUser;
53  import org.objectweb.fractal.task.core.TaskException;
54  import org.objectweb.fractal.task.core.TaskFactory;
55  import org.objectweb.fractal.task.core.primitive.annotations.ClientInterface;
56  import org.objectweb.fractal.task.core.primitive.annotations.ServerInterface;
57  import org.objectweb.fractal.task.core.primitive.annotations.ServerInterfaces;
58  import org.objectweb.fractal.task.core.primitive.annotations.TaskParameters;
59  
60  /**
61   * Visitor component that provides the inclusion code of the implementation file
62   * for <code>ThinkMC</code> dialect.
63   */
64  public class MacroDefinitionVisitor extends AbstractTaskFactoryUser
65      implements
66        ComponentVisitor {
67  
68    // ---------------------------------------------------------------------------
69    // Implementation of the ComponentVisitor interface
70    // ---------------------------------------------------------------------------
71  
72    /**
73     * Visits {@link ComponentContainer} nodes and creates a task that includes
74     * the implementation file, and that defines some macros that are used in the
75     * implementation file.
76     */
77    public Component visit(final List<Node> path,
78        final ComponentContainer container, final Map<Object, Object> context)
79        throws ADLException, TaskException {
80      final Implementation impl = castNodeError(container,
81          ImplementationContainer.class).getImplementation();
82      if (impl == null) {
83        throw new CompilerError(GenericErrors.INTERNAL_ERROR,
84            "This visitor is only applicable for primitive component.");
85      }
86      final Component implTask = createImplementationTask(container, impl);
87      if (impl instanceof IncludeContainer
88          && ((IncludeContainer) impl).getIncludes().length != 0) {
89        final Include[] includes = ((IncludeContainer) impl).getIncludes();
90  
91        final Collection<Component> tasks = new ArrayList<Component>(
92            includes.length + 1);
93        tasks.add(implTask);
94  
95        for (final Include include : includes) {
96          // if the module is an assembly, file, it should not be included in
97          // implementation.
98          if (!((SourceFile) getCode((Node) include)).isAssemblyFile())
99            tasks.add(createModuleImplementationTask(container, include));
100       }
101       return taskFactoryItf.newCompositeTask(tasks, TaskFactory.EXPORT_ALL,
102           null);
103     } else {
104       return implTask;
105     }
106   }
107 
108   // ---------------------------------------------------------------------------
109   // Utility methods
110   // ---------------------------------------------------------------------------
111 
112   protected Component createImplementationTask(
113       final ComponentContainer container, final Implementation impl)
114       throws TaskException {
115     return taskFactoryItf.newPrimitiveTask(new ImplementationTask(
116         hasConstructor(container), hasDestructor(container)), container);
117   }
118 
119   protected Component createModuleImplementationTask(
120       final ComponentContainer container, final Include include)
121       throws TaskException {
122     return taskFactoryItf.newPrimitiveTask(new ModuleImplementationTask(
123         hasConstructor(container), hasDestructor(container)), container,
124         include);
125   }
126 
127   // ---------------------------------------------------------------------------
128   // Task classes
129   // ---------------------------------------------------------------------------
130 
131   protected abstract static class AbstractImplementationTask
132       extends
133         AbstractDefinitionTask {
134 
135     protected final boolean hasConstructor;
136     protected final boolean hasDestructor;
137 
138     // -------------------------------------------------------------------------
139     // Task constructor
140     // -------------------------------------------------------------------------
141 
142     /**
143      * @param hasConstructor <code>true</code> if the component has a
144      *          constructor.
145      * @param hasDestructor <code>true</code> if the component has a destructor.
146      */
147     public AbstractImplementationTask(final boolean hasConstructor,
148         final boolean hasDestructor) {
149       this.hasConstructor = hasConstructor;
150       this.hasDestructor = hasDestructor;
151     }
152 
153     // -------------------------------------------------------------------------
154     // Abstract methods
155     // -------------------------------------------------------------------------
156 
157     protected abstract void appendImplementationCode(CodeWriter cw);
158 
159     // -------------------------------------------------------------------------
160     // Implementation of abstract methods of AbstractDefinitionTask
161     // -------------------------------------------------------------------------
162 
163     @Override
164     protected String processSourceCode() throws Exception {
165       final CodeWriter cw = new CodeWriter(
166           "Primitive Implementation Definition Builder");
167       final String componentCName = typeNameProviderItf.getCTypeName();
168 
169       /* Define specified DECLARE_DATA macro for this component */
170       cw.append("#define DECLARE_DATA \\").endl();
171       cw.append("  struct ").append(componentCName).append("_instancedata")
172           .endl();
173       /* Define the specific METHOD macro for this component */
174       if (hasConstructor) {
175         cw.append("#define CONSTRUCTOR \\").endl();
176         cw.append(componentCName).append("_constructor").endl();
177       }
178       if (hasDestructor) {
179         cw.append("#define DESTRUCTOR \\").endl();
180         cw.append(componentCName).append("_destructor").endl();
181       }
182 
183       cw.append("#define METHOD(i, m) \\").endl();
184       cw.append(componentCName).append("##_##i##_##m##_method").endl();
185       cw.append("#define CALLMINE(itf,proc,args...) \\").endl();
186       cw.append("  ").append(componentCName).append(
187           "##_##itf##_##proc##_method(_this, ##args)").endl();
188       /* Define REQUIRED, ATTRIBUTES and DATA as a component specific macros */
189       cw.append("#define REQUIRED \\").endl();
190       cw.append("  ((struct ").append(componentCName).append(
191           "_t *)_this)->type.imported ").endl();
192       cw.append("#define ATTRIBUTES \\").endl();
193       cw.append("  ((struct ").append(componentCName).append(
194           "_t *)_this)->attributes ").endl();
195       cw.append("#define DATA \\").endl();
196       cw.append("  ((struct ").append(componentCName + "_t *)_this)->data ")
197           .endl();
198       /* Define the GETSELF macro according to above defined structures */
199       cw.append("#define GETSELF \\").endl();
200       cw.append("  struct ").append(componentCName).append(
201           "_t *self = (struct " + componentCName).append("_t *) _this ").endl();
202 
203       // Define the GET_MY_OWNER macro
204       cw.append("#define GET_MY_OWNER \\").endl();
205       cw.append("  ((Rfractal_api_Component *) _this)").endl();
206 
207       // Define the GET_MY_INTERFACE macro
208       cw.append("#define GET_MY_INTERFACE(itf) \\").endl();
209       cw.append("  (&(((struct ").append(componentCName).append(
210           "_t *)_this)->type.exported.itf))").endl();
211 
212       if (hasConstructor) {
213         cw.appendln("// declare constructor.");
214         cw.appendln("void CONSTRUCTOR(void *_this);");
215       }
216       if (hasDestructor) {
217         cw.appendln("// declare destructor.");
218         cw.appendln("void DESTRUCTOR(void *_this);");
219       }
220 
221       // Print the implementation code.
222       appendImplementationCode(cw);
223       return cw.toString();
224     }
225   }
226 
227   /**
228    * Builds definition of implementation source code for the given component
229    * node. This task defines the macros that are used in the implementation file
230    * and then includes the implementation file.
231    */
232   @TaskParameters("componentNode")
233   @ServerInterfaces(@ServerInterface(name = "implementation-provider", signature = SourceCodeProvider.class, record = "role:implementation, id:%", parameters = "componentNode"))
234   public static class ImplementationTask extends AbstractImplementationTask {
235 
236     // -------------------------------------------------------------------------
237     // Task client interfaces
238     // -------------------------------------------------------------------------
239 
240     /** Client interface used to retrieve the implementation code. */
241     @ClientInterface(name = "implementation-source-code", record = "role:implementationSourceCode, id:%", parameters = "componentNode")
242     public SourceCodeProvider implementationSourceCodeProviderItf;
243 
244     // -------------------------------------------------------------------------
245     // Task constructor
246     // -------------------------------------------------------------------------
247 
248     /**
249      * @param hasConstructor <code>true</code> if the component has a
250      *          constructor.
251      * @param hasDestructor <code>true</code> if the component has a destructor.
252      */
253     public ImplementationTask(final boolean hasConstructor,
254         final boolean hasDestructor) {
255       super(hasConstructor, hasDestructor);
256     }
257 
258     // -------------------------------------------------------------------------
259     // Implementation of abstract methods of AbstractImplementationTask
260     // -------------------------------------------------------------------------
261 
262     @Override
263     protected void appendImplementationCode(final CodeWriter cw) {
264       cw.appendln(implementationSourceCodeProviderItf.getSourceCode());
265 
266       cw.append("#ifndef __CECILIA__COMPONENT_TYPE_DEFINITION_DONE").endl();
267       cw.append(
268           "#warning implementation file should include the header cecilia.h")
269           .endl();
270       cw.append("#endif").endl();
271     }
272   }
273 
274   /**
275    * Builds definition of implementation source code for the given module of the
276    * given component node. This task defines the macros that are used in the
277    * implementation file and then includes the implementation file.
278    */
279   @TaskParameters({"componentNode", "moduleNode"})
280   @ServerInterfaces(@ServerInterface(name = "implementation-provider", signature = SourceCodeProvider.class, record = "role:implementation, id:%, module:%", parameters = {
281       "componentNode", "moduleNode"}))
282   public static class ModuleImplementationTask
283       extends
284         AbstractImplementationTask {
285 
286     // -------------------------------------------------------------------------
287     // Task client interfaces
288     // -------------------------------------------------------------------------
289 
290     /** Client interface used to retrieve the module of implementation code. */
291     @ClientInterface(name = "implementation-source-code", record = "role:implementationSourceCode, id:%, module:%", parameters = {
292         "componentNode", "moduleNode"})
293     public SourceCodeProvider implementationModuleSourceCodeProviderItf;
294 
295     // -------------------------------------------------------------------------
296     // Task constructor
297     // -------------------------------------------------------------------------
298 
299     /**
300      * @param hasConstructor <code>true</code> if the component has a
301      *          constructor.
302      * @param hasDestructor <code>true</code> if the component has a destructor.
303      */
304     public ModuleImplementationTask(final boolean hasConstructor,
305         final boolean hasDestructor) {
306       super(hasConstructor, hasDestructor);
307     }
308 
309     // -------------------------------------------------------------------------
310     // Implementation of abstract methods of AbstractImplementationTask
311     // -------------------------------------------------------------------------
312 
313     @Override
314     protected void appendImplementationCode(final CodeWriter cw) {
315       cw.appendln(implementationModuleSourceCodeProviderItf.getSourceCode());
316     }
317   }
318 }