Skip to main content
summaryrefslogtreecommitdiffstats
blob: c7ba5582d33d2ff81f70206c4c1fecd0febfa233 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
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.eclipose.xtend.middleend;

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipose.xtend.middleend.plugins.LanguageSpecificMiddleEnd;
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.functions.FunctionDefContextFactory;


/**
 * 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 MiddleEnd {
    private static final Log _log = LogFactory.getLog (MiddleEnd.class);
    
    private final List<LanguageSpecificMiddleEnd> _languageHandlers;
    private final ExecutionContext _ctx;
    private final BackendTypesystem _ts;
    
    /**
     * 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 MiddleEnd (BackendTypesystem ts, List<LanguageSpecificMiddleEnd> languageHandlers) {
        _ctx = BackendFacade.createExecutionContext (new FunctionDefContextFactory (ts).create(), ts, false);
        _ts = ts;
        _languageHandlers = languageHandlers;

        for (LanguageSpecificMiddleEnd handler: languageHandlers)
            handler.setMiddleEnd (this);
    }
    
    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);
    }
    
    /**
     * 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: findHandler(resourceName).getContributedAdvice(resourceName))
            _ctx.setAdviceContext (_ctx.getAdviceContext().copyWithAdvice (advice));
    }
    
    public FunctionDefContext getFunctions (String resourceName) {
        return findHandler (resourceName).getContributedFunctions (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!
     */
    public ExecutionContext getExecutionContext () {
        return _ctx;
    }
    
    public BackendTypesystem getTypesystem () {
        return _ts;
    }
}

Back to the top