ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JSEmbeddingProvider.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 13 Feb 2013 16:52:50 +0100
branchide
changeset 723 5d1c3bc8d297
parent 720 d5c565eb0986
permissions -rw-r--r--
Adding missing license
jaroslav@723
     1
/**
jaroslav@723
     2
 * Back 2 Browser Bytecode Translator
jaroslav@723
     3
 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
jaroslav@723
     4
 *
jaroslav@723
     5
 * This program is free software: you can redistribute it and/or modify
jaroslav@723
     6
 * it under the terms of the GNU General Public License as published by
jaroslav@723
     7
 * the Free Software Foundation, version 2 of the License.
jaroslav@723
     8
 *
jaroslav@723
     9
 * This program is distributed in the hope that it will be useful,
jaroslav@723
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
jaroslav@723
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
jaroslav@723
    12
 * GNU General Public License for more details.
jaroslav@723
    13
 *
jaroslav@723
    14
 * You should have received a copy of the GNU General Public License
jaroslav@723
    15
 * along with this program. Look for COPYING file in the top folder.
jaroslav@723
    16
 * If not, see http://opensource.org/licenses/GPL-2.0.
tzezula@720
    17
 */
tzezula@720
    18
package org.apidesign.bck2brwsr.ide.editor;
tzezula@720
    19
tzezula@720
    20
import com.sun.source.tree.AnnotationTree;
tzezula@720
    21
import com.sun.source.tree.AssignmentTree;
tzezula@720
    22
import com.sun.source.tree.CompilationUnitTree;
tzezula@720
    23
import com.sun.source.tree.ExpressionTree;
tzezula@720
    24
import com.sun.source.tree.LiteralTree;
tzezula@720
    25
import com.sun.source.tree.MethodTree;
tzezula@720
    26
import com.sun.source.util.SourcePositions;
tzezula@720
    27
import com.sun.source.util.TreePath;
tzezula@720
    28
import com.sun.source.util.TreePathScanner;
tzezula@720
    29
import com.sun.source.util.Trees;
tzezula@720
    30
import java.io.IOException;
tzezula@720
    31
import java.util.ArrayList;
tzezula@720
    32
import java.util.Collection;
tzezula@720
    33
import java.util.Collections;
tzezula@720
    34
import java.util.List;
tzezula@720
    35
import java.util.concurrent.atomic.AtomicBoolean;
tzezula@720
    36
import javax.lang.model.element.TypeElement;
tzezula@720
    37
import javax.swing.text.Document;
tzezula@720
    38
import org.netbeans.api.editor.mimelookup.MimeRegistration;
tzezula@720
    39
import org.netbeans.api.java.source.CompilationInfo;
tzezula@720
    40
import org.netbeans.api.java.source.JavaParserResultTask;
tzezula@720
    41
import org.netbeans.api.java.source.JavaSource;
tzezula@720
    42
import org.netbeans.api.lexer.Language;
tzezula@720
    43
import org.netbeans.api.lexer.TokenHierarchy;
tzezula@720
    44
import org.netbeans.api.lexer.TokenSequence;
tzezula@720
    45
import org.netbeans.modules.parsing.api.Snapshot;
tzezula@720
    46
import org.netbeans.modules.parsing.spi.Parser;
tzezula@720
    47
import org.netbeans.modules.parsing.spi.Scheduler;
tzezula@720
    48
import org.netbeans.modules.parsing.spi.SchedulerEvent;
tzezula@720
    49
import org.netbeans.modules.parsing.spi.SchedulerTask;
tzezula@720
    50
import org.netbeans.modules.parsing.spi.TaskFactory;
tzezula@720
    51
import org.openide.util.Exceptions;
tzezula@720
    52
tzezula@720
    53
/**
tzezula@720
    54
 *
tzezula@720
    55
 * @author Tomas Zezula
tzezula@720
    56
 */
tzezula@720
    57
public final class JSEmbeddingProvider extends JavaParserResultTask<Parser.Result> {
tzezula@720
    58
tzezula@720
    59
    private static final int PRIORITY = 1000;
tzezula@720
    60
    private static final String JS_ANNOTATION = "org.apidesign.bck2brwsr.core.JavaScriptBody";  //NOI18N
tzezula@720
    61
    private static final String BODY = "body";                            //NOI18N
tzezula@720
    62
    private static final String JAVA_MIME_TYPE = "text/x-java";           //NOI18N
tzezula@720
    63
    private static final String JAVASCRIPT_MIME_TYPE = "text/javascript"; //NOI18N
tzezula@720
    64
    private final AtomicBoolean canceled = new AtomicBoolean();
tzezula@720
    65
tzezula@720
    66
    private JSEmbeddingProvider() {
tzezula@720
    67
        super(JavaSource.Phase.ELEMENTS_RESOLVED);
tzezula@720
    68
    }
tzezula@720
    69
tzezula@720
    70
    @Override
tzezula@720
    71
    public int getPriority() {
tzezula@720
    72
        return PRIORITY;
tzezula@720
    73
    }
tzezula@720
    74
tzezula@720
    75
    @Override
tzezula@720
    76
    public void cancel() {
tzezula@720
    77
        canceled.set(true);
tzezula@720
    78
    }
tzezula@720
    79
tzezula@720
    80
    @Override
tzezula@720
    81
    public Class<? extends Scheduler> getSchedulerClass() {
tzezula@720
    82
        return Scheduler.EDITOR_SENSITIVE_TASK_SCHEDULER;
tzezula@720
    83
    }
tzezula@720
    84
tzezula@720
    85
    @Override
tzezula@720
    86
    public void run(Parser.Result t, SchedulerEvent se) {
tzezula@720
    87
        canceled.set(false);
tzezula@720
    88
        final CompilationInfo ci = CompilationInfo.get(t);
tzezula@720
    89
        final CompilationUnitTree cu = ci.getCompilationUnit();
tzezula@720
    90
        final Trees trees = ci.getTrees();
tzezula@720
    91
        final SourcePositions sp = trees.getSourcePositions();
tzezula@720
    92
        final Finder f = new Finder(trees);
tzezula@720
    93
        final List<LiteralTree> result = new ArrayList<LiteralTree>();
tzezula@720
    94
        f.scan(cu, result);
tzezula@720
    95
        if (!result.isEmpty()) {
tzezula@720
    96
            try {
tzezula@720
    97
                final TokenHierarchy<Document> tk = TokenHierarchy.get(ci.getDocument());
tzezula@720
    98
                final Language<?> java = Language.find(JAVA_MIME_TYPE);
tzezula@720
    99
                final Language<?> javaScript = Language.find(JAVASCRIPT_MIME_TYPE);
tzezula@720
   100
                if (java != null && javaScript != null) {
tzezula@720
   101
                    final TokenSequence<?> seq = tk.tokenSequence(java);
tzezula@720
   102
                    if (seq != null) {
tzezula@720
   103
                        for (LiteralTree lt : result) {
tzezula@720
   104
                            final int start = (int) sp.getStartPosition(cu, lt);
tzezula@720
   105
                            final int end = (int) sp.getEndPosition(cu, lt);
tzezula@720
   106
                            seq.move(start);
tzezula@720
   107
                            while (seq.moveNext() && seq.offset() < end) {
tzezula@720
   108
                                seq.createEmbedding(javaScript, 1, 1, true);
tzezula@720
   109
                            }
tzezula@720
   110
                        }
tzezula@720
   111
                    }
tzezula@720
   112
                }
tzezula@720
   113
            } catch (IOException ioe) {
tzezula@720
   114
                Exceptions.printStackTrace(ioe);
tzezula@720
   115
            }
tzezula@720
   116
        }
tzezula@720
   117
    }
tzezula@720
   118
tzezula@720
   119
tzezula@720
   120
tzezula@720
   121
tzezula@720
   122
    private static final class Finder extends TreePathScanner<Void, List<? super LiteralTree>> {
tzezula@720
   123
tzezula@720
   124
        private final Trees trees;
tzezula@720
   125
        private CompilationUnitTree cu;
tzezula@720
   126
        private boolean inEmbedding;
tzezula@720
   127
tzezula@720
   128
        Finder(final Trees trees) {
tzezula@720
   129
            this.trees = trees;
tzezula@720
   130
        }
tzezula@720
   131
tzezula@720
   132
        @Override
tzezula@720
   133
        public Void visitCompilationUnit(
tzezula@720
   134
                final CompilationUnitTree unit,
tzezula@720
   135
                final List p) {
tzezula@720
   136
            this.cu = unit;
tzezula@720
   137
            return super.visitCompilationUnit(unit, p);
tzezula@720
   138
        }
tzezula@720
   139
tzezula@720
   140
tzezula@720
   141
tzezula@720
   142
        @Override
tzezula@720
   143
        public Void visitMethod(
tzezula@720
   144
                final MethodTree m,
tzezula@720
   145
                final List<? super LiteralTree> p) {
tzezula@720
   146
            for (AnnotationTree a : m.getModifiers().getAnnotations()) {
tzezula@720
   147
                final TypeElement ae = (TypeElement) trees.getElement(TreePath.getPath(cu, a.getAnnotationType()));
tzezula@720
   148
                if (ae != null && JS_ANNOTATION.contentEquals(ae.getQualifiedName())) {
tzezula@720
   149
                    final List<? extends ExpressionTree> args =  a.getArguments();
tzezula@720
   150
                    for (ExpressionTree kvp : args) {
tzezula@720
   151
                        if (kvp instanceof AssignmentTree) {
tzezula@720
   152
                            final AssignmentTree assignemt = (AssignmentTree) kvp;
tzezula@720
   153
                            if (BODY.equals(assignemt.getVariable().toString())) {
tzezula@720
   154
                                inEmbedding = true;
tzezula@720
   155
                                try {
tzezula@720
   156
                                    scan(assignemt.getExpression(), p);
tzezula@720
   157
                                } finally {
tzezula@720
   158
                                    inEmbedding = false;
tzezula@720
   159
                                }
tzezula@720
   160
                            }
tzezula@720
   161
                        }
tzezula@720
   162
                    }
tzezula@720
   163
                }
tzezula@720
   164
            }
tzezula@720
   165
            return null;
tzezula@720
   166
        }
tzezula@720
   167
tzezula@720
   168
        @Override
tzezula@720
   169
        public Void visitLiteral(LiteralTree node, List<? super LiteralTree> p) {
tzezula@720
   170
            if (inEmbedding) {
tzezula@720
   171
                p.add(node);
tzezula@720
   172
            }
tzezula@720
   173
            return super.visitLiteral(node, p);
tzezula@720
   174
        }
tzezula@720
   175
tzezula@720
   176
    }
tzezula@720
   177
tzezula@720
   178
    @MimeRegistration(
tzezula@720
   179
            service = TaskFactory.class,
tzezula@720
   180
            mimeType = JAVA_MIME_TYPE)
tzezula@720
   181
    public static final class Factory extends TaskFactory {
tzezula@720
   182
        @Override
tzezula@720
   183
        public Collection<? extends SchedulerTask> create(Snapshot snpsht) {
tzezula@720
   184
            return Collections.singleton(new JSEmbeddingProvider());
tzezula@720
   185
        }
tzezula@720
   186
    }
tzezula@720
   187
tzezula@720
   188
}