ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JSEmbeddingProvider.java
2 * Back 2 Browser Bytecode Translator
3 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. Look for COPYING file in the top folder.
16 * If not, see http://opensource.org/licenses/GPL-2.0.
18 package org.apidesign.bck2brwsr.ide.editor;
20 import com.sun.source.tree.AnnotationTree;
21 import com.sun.source.tree.AssignmentTree;
22 import com.sun.source.tree.CompilationUnitTree;
23 import com.sun.source.tree.ExpressionTree;
24 import com.sun.source.tree.LiteralTree;
25 import com.sun.source.tree.MethodTree;
26 import com.sun.source.util.SourcePositions;
27 import com.sun.source.util.TreePath;
28 import com.sun.source.util.TreePathScanner;
29 import com.sun.source.util.Trees;
30 import java.io.IOException;
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.Collections;
34 import java.util.List;
35 import java.util.concurrent.atomic.AtomicBoolean;
36 import javax.lang.model.element.TypeElement;
37 import javax.swing.text.Document;
38 import org.netbeans.api.editor.mimelookup.MimeRegistration;
39 import org.netbeans.api.java.source.CompilationInfo;
40 import org.netbeans.api.java.source.JavaParserResultTask;
41 import org.netbeans.api.java.source.JavaSource;
42 import org.netbeans.api.lexer.Language;
43 import org.netbeans.api.lexer.TokenHierarchy;
44 import org.netbeans.api.lexer.TokenSequence;
45 import org.netbeans.modules.parsing.api.Snapshot;
46 import org.netbeans.modules.parsing.spi.Parser;
47 import org.netbeans.modules.parsing.spi.Scheduler;
48 import org.netbeans.modules.parsing.spi.SchedulerEvent;
49 import org.netbeans.modules.parsing.spi.SchedulerTask;
50 import org.netbeans.modules.parsing.spi.TaskFactory;
51 import org.openide.util.Exceptions;
55 * @author Tomas Zezula
57 public final class JSEmbeddingProvider extends JavaParserResultTask<Parser.Result> {
59 private static final int PRIORITY = 1000;
60 private static final String JS_ANNOTATION = "org.apidesign.bck2brwsr.core.JavaScriptBody"; //NOI18N
61 private static final String BODY = "body"; //NOI18N
62 private static final String JAVA_MIME_TYPE = "text/x-java"; //NOI18N
63 private static final String JAVASCRIPT_MIME_TYPE = "text/javascript"; //NOI18N
64 private final AtomicBoolean canceled = new AtomicBoolean();
66 private JSEmbeddingProvider() {
67 super(JavaSource.Phase.ELEMENTS_RESOLVED);
71 public int getPriority() {
76 public void cancel() {
81 public Class<? extends Scheduler> getSchedulerClass() {
82 return Scheduler.EDITOR_SENSITIVE_TASK_SCHEDULER;
86 public void run(Parser.Result t, SchedulerEvent se) {
88 final CompilationInfo ci = CompilationInfo.get(t);
89 final CompilationUnitTree cu = ci.getCompilationUnit();
90 final Trees trees = ci.getTrees();
91 final SourcePositions sp = trees.getSourcePositions();
92 final Finder f = new Finder(trees);
93 final List<LiteralTree> result = new ArrayList<LiteralTree>();
95 if (!result.isEmpty()) {
97 final TokenHierarchy<Document> tk = TokenHierarchy.get(ci.getDocument());
98 final Language<?> java = Language.find(JAVA_MIME_TYPE);
99 final Language<?> javaScript = Language.find(JAVASCRIPT_MIME_TYPE);
100 if (java != null && javaScript != null) {
101 final TokenSequence<?> seq = tk.tokenSequence(java);
103 for (LiteralTree lt : result) {
104 final int start = (int) sp.getStartPosition(cu, lt);
105 final int end = (int) sp.getEndPosition(cu, lt);
107 while (seq.moveNext() && seq.offset() < end) {
108 seq.createEmbedding(javaScript, 1, 1, true);
113 } catch (IOException ioe) {
114 Exceptions.printStackTrace(ioe);
122 private static final class Finder extends TreePathScanner<Void, List<? super LiteralTree>> {
124 private final Trees trees;
125 private CompilationUnitTree cu;
126 private boolean inEmbedding;
128 Finder(final Trees trees) {
133 public Void visitCompilationUnit(
134 final CompilationUnitTree unit,
137 return super.visitCompilationUnit(unit, p);
143 public Void visitMethod(
145 final List<? super LiteralTree> p) {
146 for (AnnotationTree a : m.getModifiers().getAnnotations()) {
147 final TypeElement ae = (TypeElement) trees.getElement(TreePath.getPath(cu, a.getAnnotationType()));
148 if (ae != null && JS_ANNOTATION.contentEquals(ae.getQualifiedName())) {
149 final List<? extends ExpressionTree> args = a.getArguments();
150 for (ExpressionTree kvp : args) {
151 if (kvp instanceof AssignmentTree) {
152 final AssignmentTree assignemt = (AssignmentTree) kvp;
153 if (BODY.equals(assignemt.getVariable().toString())) {
156 scan(assignemt.getExpression(), p);
169 public Void visitLiteral(LiteralTree node, List<? super LiteralTree> p) {
173 return super.visitLiteral(node, p);
179 service = TaskFactory.class,
180 mimeType = JAVA_MIME_TYPE)
181 public static final class Factory extends TaskFactory {
183 public Collection<? extends SchedulerTask> create(Snapshot snpsht) {
184 return Collections.singleton(new JSEmbeddingProvider());