Merging in initial version of the IDE improving module. Includes conversion hint by Lahvac and Igor and @JavaScriptBody coloring by Tomas Z.
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 13 Feb 2013 16:54:32 +0100
changeset 724ad7be5819f5d
parent 714 ef50c4f07e4f
parent 723 5d1c3bc8d297
child 725 732b3e4cc544
Merging in initial version of the IDE improving module. Includes conversion hint by Lahvac and Igor and @JavaScriptBody coloring by Tomas Z.
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ide/editor/pom.xml	Wed Feb 13 16:54:32 2013 +0100
     1.3 @@ -0,0 +1,198 @@
     1.4 +<?xml version="1.0" encoding="UTF-8"?>
     1.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     1.6 +    <modelVersion>4.0.0</modelVersion>
     1.7 +    <parent>
     1.8 +        <artifactId>ide</artifactId>
     1.9 +        <groupId>org.apidesign.bck2brwsr</groupId>
    1.10 +        <version>0.3-SNAPSHOT</version>
    1.11 +    </parent>
    1.12 +
    1.13 +    <groupId>org.apidesign.bck2brwsr.ide.editor</groupId>
    1.14 +    <artifactId>editor</artifactId>
    1.15 +    <version>0.3-SNAPSHOT</version>
    1.16 +    <packaging>nbm</packaging>
    1.17 +
    1.18 +    <name>Editor Support for Bck2Brwsr</name>
    1.19 +
    1.20 +    <properties>
    1.21 +        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    1.22 +        <netbeans.version>RELEASE72</netbeans.version>
    1.23 +        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
    1.24 +    </properties>
    1.25 +
    1.26 +    <repositories>
    1.27 +        <!--
    1.28 +        Repository hosting NetBeans modules, especially APIs.
    1.29 +        Versions are based on IDE releases, e.g.: RELEASE691
    1.30 +        To create your own repository, use: nbm:populate-repository
    1.31 +        -->
    1.32 +        <repository>
    1.33 +            <id>netbeans</id>
    1.34 +            <name>NetBeans</name>
    1.35 +            <url>http://bits.netbeans.org/maven2/</url>
    1.36 +            <snapshots>
    1.37 +                <enabled>false</enabled>
    1.38 +            </snapshots>
    1.39 +        </repository>
    1.40 +    </repositories>
    1.41 +
    1.42 +    <dependencies>
    1.43 +        <dependency>
    1.44 +            <groupId>org.netbeans.api</groupId>
    1.45 +            <artifactId>org-netbeans-api-annotations-common</artifactId>
    1.46 +            <version>${netbeans.version}</version>
    1.47 +        </dependency>
    1.48 +        <dependency>
    1.49 +            <groupId>org.netbeans.api</groupId>
    1.50 +            <artifactId>org-netbeans-modules-java-source</artifactId>
    1.51 +            <version>${netbeans.version}</version>
    1.52 +        </dependency>
    1.53 +        <dependency>
    1.54 +            <groupId>org.netbeans.api</groupId>
    1.55 +            <artifactId>org-netbeans-libs-javacapi</artifactId>
    1.56 +            <version>${netbeans.version}</version>
    1.57 +        </dependency>
    1.58 +        <dependency>
    1.59 +            <groupId>org.netbeans.api</groupId>
    1.60 +            <artifactId>org-netbeans-spi-java-hints</artifactId>
    1.61 +            <version>${netbeans.version}</version>
    1.62 +        </dependency>
    1.63 +        <dependency>
    1.64 +            <groupId>org.netbeans.api</groupId>
    1.65 +            <artifactId>org-netbeans-modules-parsing-api</artifactId>
    1.66 +            <version>${netbeans.version}</version>
    1.67 +        </dependency>
    1.68 +        <dependency>
    1.69 +            <groupId>org.netbeans.api</groupId>
    1.70 +            <artifactId>org-netbeans-spi-editor-hints</artifactId>
    1.71 +            <version>${netbeans.version}</version>
    1.72 +        </dependency>
    1.73 +        <dependency>
    1.74 +            <groupId>org.netbeans.api</groupId>
    1.75 +            <artifactId>org-openide-util</artifactId>
    1.76 +            <version>${netbeans.version}</version>
    1.77 +        </dependency>
    1.78 +        <dependency>
    1.79 +            <groupId>org.netbeans.api</groupId>
    1.80 +            <artifactId>org-netbeans-modules-java-lexer</artifactId>
    1.81 +            <version>${netbeans.version}</version>
    1.82 +        </dependency>
    1.83 +        <dependency>
    1.84 +            <groupId>org.netbeans.api</groupId>
    1.85 +            <artifactId>org-netbeans-modules-lexer</artifactId>
    1.86 +            <version>${netbeans.version}</version>
    1.87 +        </dependency>
    1.88 +        <dependency>
    1.89 +            <groupId>org.apidesign.bck2brwsr</groupId>
    1.90 +            <artifactId>core</artifactId>
    1.91 +            <version>0.3-SNAPSHOT</version>
    1.92 +            <type>jar</type>
    1.93 +            <scope>test</scope>
    1.94 +        </dependency>
    1.95 +        <dependency>
    1.96 +            <groupId>org.netbeans.api</groupId>
    1.97 +            <artifactId>org-netbeans-modules-java-hints-test</artifactId>
    1.98 +            <version>${netbeans.version}</version>
    1.99 +            <scope>test</scope>
   1.100 +        </dependency>
   1.101 +        <dependency>
   1.102 +            <groupId>org.netbeans.api</groupId>
   1.103 +            <artifactId>org-netbeans-libs-junit4</artifactId>
   1.104 +            <version>${netbeans.version}</version>
   1.105 +            <scope>test</scope>
   1.106 +        </dependency>
   1.107 +        <dependency>
   1.108 +            <groupId>org.netbeans.modules</groupId>
   1.109 +            <artifactId>org-netbeans-lib-nbjavac</artifactId>
   1.110 +            <version>${netbeans.version}</version>
   1.111 +            <scope>test</scope>
   1.112 +        </dependency>
   1.113 +        <dependency>
   1.114 +            <groupId>org.testng</groupId>
   1.115 +            <artifactId>testng</artifactId>
   1.116 +            <scope>test</scope>
   1.117 +        </dependency>
   1.118 +    </dependencies>
   1.119 +
   1.120 +    <build>
   1.121 +        <plugins>
   1.122 +            <plugin>
   1.123 +                <groupId>org.codehaus.mojo</groupId>
   1.124 +                <artifactId>nbm-maven-plugin</artifactId>
   1.125 +                <version>3.8</version>
   1.126 +                <extensions>true</extensions>
   1.127 +            </plugin>
   1.128 +
   1.129 +            <plugin>
   1.130 +                <!-- NetBeans 6.9+ requires JDK 6 -->
   1.131 +                <groupId>org.apache.maven.plugins</groupId>
   1.132 +                <artifactId>maven-compiler-plugin</artifactId>
   1.133 +                <version>2.5.1</version>
   1.134 +                <configuration>
   1.135 +                    <source>1.6</source>
   1.136 +                    <target>1.6</target>
   1.137 +                    <compilerArguments>
   1.138 +                        <endorseddirs>${endorsed.dir}</endorseddirs>
   1.139 +                    </compilerArguments>
   1.140 +                </configuration>
   1.141 +            </plugin>
   1.142 +
   1.143 +            <plugin>
   1.144 +                <groupId>org.apache.maven.plugins</groupId>
   1.145 +                <artifactId>maven-jar-plugin</artifactId>
   1.146 +                <version>2.4</version>
   1.147 +                <configuration>
   1.148 +                    <!-- to have the jar plugin pickup the nbm generated manifest -->
   1.149 +                    <useDefaultManifestFile>true</useDefaultManifestFile>
   1.150 +                </configuration>
   1.151 +            </plugin>
   1.152 +
   1.153 +            <plugin>
   1.154 +                <groupId>org.apache.maven.plugins</groupId>
   1.155 +                <artifactId>maven-dependency-plugin</artifactId>
   1.156 +                <executions>
   1.157 +                    <execution>
   1.158 +                        <id>endorsed</id>
   1.159 +                        <phase>validate</phase>
   1.160 +                        <goals>
   1.161 +                            <goal>copy</goal>
   1.162 +                        </goals>
   1.163 +                    </execution>
   1.164 +                </executions>
   1.165 +                <configuration>
   1.166 +                    <outputDirectory>${endorsed.dir}</outputDirectory>
   1.167 +                    <silent>true</silent>
   1.168 +                    <artifactItems>
   1.169 +                        <artifactItem>
   1.170 +                            <groupId>org.netbeans.api</groupId>
   1.171 +                            <artifactId>org-netbeans-libs-javacapi</artifactId>
   1.172 +                            <version>${netbeans.version}</version>
   1.173 +                        </artifactItem>
   1.174 +                        <artifactItem>
   1.175 +                            <groupId>org.netbeans.external</groupId>
   1.176 +                            <artifactId>nb-javac-api</artifactId>
   1.177 +                            <version>${netbeans.version}</version>
   1.178 +                        </artifactItem>
   1.179 +                        <artifactItem>
   1.180 +                            <groupId>org.netbeans.modules</groupId>
   1.181 +                            <artifactId>org-netbeans-libs-javacimpl</artifactId>
   1.182 +                            <version>${netbeans.version}</version>
   1.183 +                        </artifactItem>
   1.184 +                        <artifactItem>
   1.185 +                            <groupId>org.netbeans.external</groupId>
   1.186 +                            <artifactId>nb-javac-impl</artifactId>
   1.187 +                            <version>${netbeans.version}</version>
   1.188 +                        </artifactItem>
   1.189 +                    </artifactItems>
   1.190 +                </configuration>
   1.191 +            </plugin>
   1.192 +            <plugin>
   1.193 +                <groupId>org.apache.maven.plugins</groupId>
   1.194 +                <artifactId>maven-surefire-plugin</artifactId>
   1.195 +                <configuration>
   1.196 +                    <argLine>-Djava.endorsed.dirs=${endorsed.dir}</argLine>
   1.197 +                </configuration>
   1.198 +            </plugin>
   1.199 +        </plugins>
   1.200 +    </build>
   1.201 +</project>
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JNIHelper.java	Wed Feb 13 16:54:32 2013 +0100
     2.3 @@ -0,0 +1,80 @@
     2.4 +/**
     2.5 + * Back 2 Browser Bytecode Translator
     2.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     2.7 + *
     2.8 + * This program is free software: you can redistribute it and/or modify
     2.9 + * it under the terms of the GNU General Public License as published by
    2.10 + * the Free Software Foundation, version 2 of the License.
    2.11 + *
    2.12 + * This program is distributed in the hope that it will be useful,
    2.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.15 + * GNU General Public License for more details.
    2.16 + *
    2.17 + * You should have received a copy of the GNU General Public License
    2.18 + * along with this program. Look for COPYING file in the top folder.
    2.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    2.20 + */
    2.21 +package org.apidesign.bck2brwsr.ide.editor;
    2.22 +
    2.23 +import java.lang.reflect.Method;
    2.24 +import java.util.HashMap;
    2.25 +import java.util.Map;
    2.26 +
    2.27 +/**
    2.28 + * JNI Helper.
    2.29 + * To facilitate lookup of methods by name and signature, instead of manually parsing signatures,
    2.30 + * constructs the map of all methods and uses Class.getName() to generate almost-correct signatures.
    2.31 + */
    2.32 +class JNIHelper {
    2.33 +
    2.34 +    static Method method(String clazz, String method, String signature) {
    2.35 +        final Map<String, Method> methods = methodMap(JNIHelper.clazz(clazz));
    2.36 +        return methods.get(methodKey(method, signature));
    2.37 +    }
    2.38 +
    2.39 +    static Class<?> clazz(String clazz) {
    2.40 +        try {
    2.41 +            return Class.forName(clazz);
    2.42 +        } catch (ClassNotFoundException e) {
    2.43 +            throw new IllegalArgumentException(e);
    2.44 +        }
    2.45 +    }
    2.46 +
    2.47 +    static Map<String, Method> methodMap(final Class<?> clazz) {
    2.48 +        final Map<String, Method> map = new HashMap<String, Method>();
    2.49 +        final Method[] methods = clazz.getDeclaredMethods();
    2.50 +        for (int i = 0; i < methods.length; i++) {
    2.51 +            final Method method = methods[i];
    2.52 +            map.put(methodKey(method.getName(), signature(method)), method);
    2.53 +        }
    2.54 +        return map;
    2.55 +    }
    2.56 +
    2.57 +    static String methodKey(String method, String signature) {
    2.58 +        return method + '@' + signature;
    2.59 +    }
    2.60 +
    2.61 +    static String signature(final Method method) {
    2.62 +        final Class<?>[] parameterTypes = method.getParameterTypes();
    2.63 +        final StringBuilder b = new StringBuilder();
    2.64 +        for (int j = 0; j < parameterTypes.length; j++) {
    2.65 +            b.append(signature(parameterTypes[j]));
    2.66 +        }
    2.67 +        return b.toString();
    2.68 +    }
    2.69 +
    2.70 +    static String signature(final Class<?> clazz) {
    2.71 +        if (clazz == boolean.class) return "Z";
    2.72 +        else if (clazz == byte.class) return "B";
    2.73 +        else if (clazz == char.class) return "C";
    2.74 +        else if (clazz == double.class) return "D";
    2.75 +        else if (clazz == float.class) return "F";
    2.76 +        else if (clazz == int.class) return "I";
    2.77 +        else if (clazz == long.class) return "J";
    2.78 +        else if (clazz == short.class) return "S";
    2.79 +        else if (clazz == void.class) return "V";
    2.80 +        else if (clazz.isArray()) return clazz.getName().replace('.','/');
    2.81 +        else return "L" + clazz.getName().replace('.','/') + ";";
    2.82 +    }
    2.83 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JSEmbeddingProvider.java	Wed Feb 13 16:54:32 2013 +0100
     3.3 @@ -0,0 +1,188 @@
     3.4 +/**
     3.5 + * Back 2 Browser Bytecode Translator
     3.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     3.7 + *
     3.8 + * This program is free software: you can redistribute it and/or modify
     3.9 + * it under the terms of the GNU General Public License as published by
    3.10 + * the Free Software Foundation, version 2 of the License.
    3.11 + *
    3.12 + * This program is distributed in the hope that it will be useful,
    3.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.15 + * GNU General Public License for more details.
    3.16 + *
    3.17 + * You should have received a copy of the GNU General Public License
    3.18 + * along with this program. Look for COPYING file in the top folder.
    3.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    3.20 + */
    3.21 +package org.apidesign.bck2brwsr.ide.editor;
    3.22 +
    3.23 +import com.sun.source.tree.AnnotationTree;
    3.24 +import com.sun.source.tree.AssignmentTree;
    3.25 +import com.sun.source.tree.CompilationUnitTree;
    3.26 +import com.sun.source.tree.ExpressionTree;
    3.27 +import com.sun.source.tree.LiteralTree;
    3.28 +import com.sun.source.tree.MethodTree;
    3.29 +import com.sun.source.util.SourcePositions;
    3.30 +import com.sun.source.util.TreePath;
    3.31 +import com.sun.source.util.TreePathScanner;
    3.32 +import com.sun.source.util.Trees;
    3.33 +import java.io.IOException;
    3.34 +import java.util.ArrayList;
    3.35 +import java.util.Collection;
    3.36 +import java.util.Collections;
    3.37 +import java.util.List;
    3.38 +import java.util.concurrent.atomic.AtomicBoolean;
    3.39 +import javax.lang.model.element.TypeElement;
    3.40 +import javax.swing.text.Document;
    3.41 +import org.netbeans.api.editor.mimelookup.MimeRegistration;
    3.42 +import org.netbeans.api.java.source.CompilationInfo;
    3.43 +import org.netbeans.api.java.source.JavaParserResultTask;
    3.44 +import org.netbeans.api.java.source.JavaSource;
    3.45 +import org.netbeans.api.lexer.Language;
    3.46 +import org.netbeans.api.lexer.TokenHierarchy;
    3.47 +import org.netbeans.api.lexer.TokenSequence;
    3.48 +import org.netbeans.modules.parsing.api.Snapshot;
    3.49 +import org.netbeans.modules.parsing.spi.Parser;
    3.50 +import org.netbeans.modules.parsing.spi.Scheduler;
    3.51 +import org.netbeans.modules.parsing.spi.SchedulerEvent;
    3.52 +import org.netbeans.modules.parsing.spi.SchedulerTask;
    3.53 +import org.netbeans.modules.parsing.spi.TaskFactory;
    3.54 +import org.openide.util.Exceptions;
    3.55 +
    3.56 +/**
    3.57 + *
    3.58 + * @author Tomas Zezula
    3.59 + */
    3.60 +public final class JSEmbeddingProvider extends JavaParserResultTask<Parser.Result> {
    3.61 +
    3.62 +    private static final int PRIORITY = 1000;
    3.63 +    private static final String JS_ANNOTATION = "org.apidesign.bck2brwsr.core.JavaScriptBody";  //NOI18N
    3.64 +    private static final String BODY = "body";                            //NOI18N
    3.65 +    private static final String JAVA_MIME_TYPE = "text/x-java";           //NOI18N
    3.66 +    private static final String JAVASCRIPT_MIME_TYPE = "text/javascript"; //NOI18N
    3.67 +    private final AtomicBoolean canceled = new AtomicBoolean();
    3.68 +
    3.69 +    private JSEmbeddingProvider() {
    3.70 +        super(JavaSource.Phase.ELEMENTS_RESOLVED);
    3.71 +    }
    3.72 +
    3.73 +    @Override
    3.74 +    public int getPriority() {
    3.75 +        return PRIORITY;
    3.76 +    }
    3.77 +
    3.78 +    @Override
    3.79 +    public void cancel() {
    3.80 +        canceled.set(true);
    3.81 +    }
    3.82 +
    3.83 +    @Override
    3.84 +    public Class<? extends Scheduler> getSchedulerClass() {
    3.85 +        return Scheduler.EDITOR_SENSITIVE_TASK_SCHEDULER;
    3.86 +    }
    3.87 +
    3.88 +    @Override
    3.89 +    public void run(Parser.Result t, SchedulerEvent se) {
    3.90 +        canceled.set(false);
    3.91 +        final CompilationInfo ci = CompilationInfo.get(t);
    3.92 +        final CompilationUnitTree cu = ci.getCompilationUnit();
    3.93 +        final Trees trees = ci.getTrees();
    3.94 +        final SourcePositions sp = trees.getSourcePositions();
    3.95 +        final Finder f = new Finder(trees);
    3.96 +        final List<LiteralTree> result = new ArrayList<LiteralTree>();
    3.97 +        f.scan(cu, result);
    3.98 +        if (!result.isEmpty()) {
    3.99 +            try {
   3.100 +                final TokenHierarchy<Document> tk = TokenHierarchy.get(ci.getDocument());
   3.101 +                final Language<?> java = Language.find(JAVA_MIME_TYPE);
   3.102 +                final Language<?> javaScript = Language.find(JAVASCRIPT_MIME_TYPE);
   3.103 +                if (java != null && javaScript != null) {
   3.104 +                    final TokenSequence<?> seq = tk.tokenSequence(java);
   3.105 +                    if (seq != null) {
   3.106 +                        for (LiteralTree lt : result) {
   3.107 +                            final int start = (int) sp.getStartPosition(cu, lt);
   3.108 +                            final int end = (int) sp.getEndPosition(cu, lt);
   3.109 +                            seq.move(start);
   3.110 +                            while (seq.moveNext() && seq.offset() < end) {
   3.111 +                                seq.createEmbedding(javaScript, 1, 1, true);
   3.112 +                            }
   3.113 +                        }
   3.114 +                    }
   3.115 +                }
   3.116 +            } catch (IOException ioe) {
   3.117 +                Exceptions.printStackTrace(ioe);
   3.118 +            }
   3.119 +        }
   3.120 +    }
   3.121 +
   3.122 +
   3.123 +
   3.124 +
   3.125 +    private static final class Finder extends TreePathScanner<Void, List<? super LiteralTree>> {
   3.126 +
   3.127 +        private final Trees trees;
   3.128 +        private CompilationUnitTree cu;
   3.129 +        private boolean inEmbedding;
   3.130 +
   3.131 +        Finder(final Trees trees) {
   3.132 +            this.trees = trees;
   3.133 +        }
   3.134 +
   3.135 +        @Override
   3.136 +        public Void visitCompilationUnit(
   3.137 +                final CompilationUnitTree unit,
   3.138 +                final List p) {
   3.139 +            this.cu = unit;
   3.140 +            return super.visitCompilationUnit(unit, p);
   3.141 +        }
   3.142 +
   3.143 +
   3.144 +
   3.145 +        @Override
   3.146 +        public Void visitMethod(
   3.147 +                final MethodTree m,
   3.148 +                final List<? super LiteralTree> p) {
   3.149 +            for (AnnotationTree a : m.getModifiers().getAnnotations()) {
   3.150 +                final TypeElement ae = (TypeElement) trees.getElement(TreePath.getPath(cu, a.getAnnotationType()));
   3.151 +                if (ae != null && JS_ANNOTATION.contentEquals(ae.getQualifiedName())) {
   3.152 +                    final List<? extends ExpressionTree> args =  a.getArguments();
   3.153 +                    for (ExpressionTree kvp : args) {
   3.154 +                        if (kvp instanceof AssignmentTree) {
   3.155 +                            final AssignmentTree assignemt = (AssignmentTree) kvp;
   3.156 +                            if (BODY.equals(assignemt.getVariable().toString())) {
   3.157 +                                inEmbedding = true;
   3.158 +                                try {
   3.159 +                                    scan(assignemt.getExpression(), p);
   3.160 +                                } finally {
   3.161 +                                    inEmbedding = false;
   3.162 +                                }
   3.163 +                            }
   3.164 +                        }
   3.165 +                    }
   3.166 +                }
   3.167 +            }
   3.168 +            return null;
   3.169 +        }
   3.170 +
   3.171 +        @Override
   3.172 +        public Void visitLiteral(LiteralTree node, List<? super LiteralTree> p) {
   3.173 +            if (inEmbedding) {
   3.174 +                p.add(node);
   3.175 +            }
   3.176 +            return super.visitLiteral(node, p);
   3.177 +        }
   3.178 +
   3.179 +    }
   3.180 +
   3.181 +    @MimeRegistration(
   3.182 +            service = TaskFactory.class,
   3.183 +            mimeType = JAVA_MIME_TYPE)
   3.184 +    public static final class Factory extends TaskFactory {
   3.185 +        @Override
   3.186 +        public Collection<? extends SchedulerTask> create(Snapshot snpsht) {
   3.187 +            return Collections.singleton(new JSEmbeddingProvider());
   3.188 +        }
   3.189 +    }
   3.190 +
   3.191 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JSNI2JavaScriptBody.java	Wed Feb 13 16:54:32 2013 +0100
     4.3 @@ -0,0 +1,149 @@
     4.4 +/**
     4.5 + * Back 2 Browser Bytecode Translator
     4.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4.7 + *
     4.8 + * This program is free software: you can redistribute it and/or modify
     4.9 + * it under the terms of the GNU General Public License as published by
    4.10 + * the Free Software Foundation, version 2 of the License.
    4.11 + *
    4.12 + * This program is distributed in the hope that it will be useful,
    4.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.15 + * GNU General Public License for more details.
    4.16 + *
    4.17 + * You should have received a copy of the GNU General Public License
    4.18 + * along with this program. Look for COPYING file in the top folder.
    4.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    4.20 + */
    4.21 +package org.apidesign.bck2brwsr.ide.editor;
    4.22 +
    4.23 +import com.sun.source.tree.AnnotationTree;
    4.24 +import com.sun.source.tree.ExpressionTree;
    4.25 +import com.sun.source.tree.LiteralTree;
    4.26 +import com.sun.source.tree.MethodTree;
    4.27 +import com.sun.source.tree.Tree.Kind;
    4.28 +import com.sun.source.tree.VariableTree;
    4.29 +import com.sun.source.util.TreePath;
    4.30 +import java.util.ArrayList;
    4.31 +import java.util.Arrays;
    4.32 +import java.util.Collections;
    4.33 +import java.util.List;
    4.34 +import org.netbeans.api.java.lexer.JavaTokenId;
    4.35 +import static org.netbeans.api.java.lexer.JavaTokenId.BLOCK_COMMENT;
    4.36 +import static org.netbeans.api.java.lexer.JavaTokenId.JAVADOC_COMMENT;
    4.37 +import static org.netbeans.api.java.lexer.JavaTokenId.LINE_COMMENT;
    4.38 +import static org.netbeans.api.java.lexer.JavaTokenId.WHITESPACE;
    4.39 +import org.netbeans.api.java.source.CompilationInfo;
    4.40 +import org.netbeans.api.java.source.TreeMaker;
    4.41 +import org.netbeans.api.lexer.Token;
    4.42 +import org.netbeans.api.lexer.TokenSequence;
    4.43 +import org.netbeans.spi.editor.hints.ErrorDescription;
    4.44 +import org.netbeans.spi.editor.hints.Fix;
    4.45 +import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
    4.46 +import org.netbeans.spi.java.hints.Hint;
    4.47 +import org.netbeans.spi.java.hints.HintContext;
    4.48 +import org.netbeans.spi.java.hints.JavaFix;
    4.49 +import org.netbeans.spi.java.hints.TriggerTreeKind;
    4.50 +import org.openide.util.NbBundle.Messages;
    4.51 +
    4.52 +@Hint(displayName = "#DN_JSNI2JavaScriptBody", description = "#DESC_JSNI2JavaScriptBody", category = "general")
    4.53 +@Messages({
    4.54 +    "DN_JSNI2JavaScriptBody=JSNI to @JavaScriptBody",
    4.55 +    "DESC_JSNI2JavaScriptBody=JSNI to @JavaScriptBody"
    4.56 +})
    4.57 +public class JSNI2JavaScriptBody {
    4.58 +
    4.59 +    @TriggerTreeKind(Kind.METHOD)
    4.60 +    @Messages("ERR_JSNI2JavaScriptBody=Can convert JSNI to @JavaScriptBody")
    4.61 +    public static ErrorDescription computeWarning(final HintContext ctx) {
    4.62 +        Token<JavaTokenId> token = findBlockToken(ctx.getInfo(), ctx.getPath(), ctx);
    4.63 +
    4.64 +        if (token == null) {
    4.65 +            return null;
    4.66 +        }
    4.67 +
    4.68 +        Fix fix = new FixImpl(ctx.getInfo(), ctx.getPath()).toEditorFix();
    4.69 +        return ErrorDescriptionFactory.forName(ctx, ctx.getPath(), Bundle.ERR_JSNI2JavaScriptBody(), fix);
    4.70 +    }
    4.71 +
    4.72 +    private static Token<JavaTokenId> findBlockToken(CompilationInfo info, TreePath path, HintContext ctx) {
    4.73 +        int end = (int) info.getTrees().getSourcePositions().getEndPosition(path.getCompilationUnit(), path.getLeaf());
    4.74 +        TokenSequence<JavaTokenId> ts = info.getTokenHierarchy().tokenSequence(JavaTokenId.language());
    4.75 +
    4.76 +        if (ts == null) return null;
    4.77 +
    4.78 +        ts.move(end);
    4.79 +
    4.80 +        if ((ctx != null && ctx.isCanceled()) || !ts.movePrevious() || ts.token().id() != JavaTokenId.SEMICOLON) return null;
    4.81 +
    4.82 +        OUTER: while (ts.movePrevious()) {
    4.83 +            if (ctx != null && ctx.isCanceled()) return null;
    4.84 +
    4.85 +            switch (ts.token().id()) {
    4.86 +                case WHITESPACE: break;
    4.87 +                case LINE_COMMENT: break;
    4.88 +                case JAVADOC_COMMENT: break;
    4.89 +                case BLOCK_COMMENT:
    4.90 +                    final CharSequence tok = ts.token().text();
    4.91 +                    final int l = tok.length(); 
    4.92 +                    if (l > 4 
    4.93 +                        && tok.subSequence(0, 4).toString().equals("/*-{") // NOI18N
    4.94 +                        && tok.subSequence(l - 4, l).toString().equals("}-*/") // NOI18N
    4.95 +                    ) {
    4.96 +                        return ts.offsetToken();
    4.97 +                    }
    4.98 +                    break;
    4.99 +                default:
   4.100 +                    break OUTER;
   4.101 +            }
   4.102 +        }
   4.103 +
   4.104 +        return null;
   4.105 +    }
   4.106 +
   4.107 +    private static final class FixImpl extends JavaFix {
   4.108 +
   4.109 +        public FixImpl(CompilationInfo info, TreePath tp) {
   4.110 +            super(info, tp);
   4.111 +        }
   4.112 +
   4.113 +        @Override
   4.114 +        @Messages("FIX_JSNI2JavaScriptBody=Convert JSNI to @JavaScriptBody")
   4.115 +        protected String getText() {
   4.116 +            return Bundle.FIX_JSNI2JavaScriptBody();
   4.117 +        }
   4.118 +
   4.119 +        @Override
   4.120 +        protected void performRewrite(TransformationContext ctx) {
   4.121 +            Token<JavaTokenId> jsniComment = findBlockToken(ctx.getWorkingCopy(), ctx.getPath(), null);
   4.122 +
   4.123 +            if (jsniComment == null) {
   4.124 +                //XXX: warn?
   4.125 +                return ;
   4.126 +            }
   4.127 +            
   4.128 +            JsniCommentTokenizer tok = new JsniCommentTokenizer();
   4.129 +            ManglingSink ms = new ManglingSink();
   4.130 +            final CharSequence cmnt = jsniComment.text();
   4.131 +            tok.process(cmnt.subSequence(4, cmnt.length() - 4), ms);
   4.132 +
   4.133 +            TreeMaker make = ctx.getWorkingCopy().getTreeMaker();
   4.134 +            MethodTree mt = (MethodTree) ctx.getPath().getLeaf();
   4.135 +            List<LiteralTree> params = new ArrayList<LiteralTree>();
   4.136 +
   4.137 +            for (VariableTree p : mt.getParameters()) {
   4.138 +                params.add(make.Literal(p.getName().toString()));
   4.139 +            }
   4.140 +
   4.141 +            AnnotationTree jsBody = make.Annotation(make.QualIdent("org.apidesign.bck2brwsr.core.JavaScriptBody"),
   4.142 +                Arrays.<ExpressionTree>asList(
   4.143 +                    make.Assignment(make.Identifier("args"), make.NewArray(null, Collections.<ExpressionTree>emptyList(), params)),
   4.144 +                    make.Assignment(make.Identifier("body"), make.Literal(ms.out.toString()))
   4.145 +                )
   4.146 +            );
   4.147 +
   4.148 +
   4.149 +            ctx.getWorkingCopy().rewrite(mt.getModifiers(), make.addModifiersAnnotation(mt.getModifiers(), jsBody));
   4.150 +        }
   4.151 +    }
   4.152 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JsniCommentTokenizer.java	Wed Feb 13 16:54:32 2013 +0100
     5.3 @@ -0,0 +1,70 @@
     5.4 +/**
     5.5 + * Back 2 Browser Bytecode Translator
     5.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     5.7 + *
     5.8 + * This program is free software: you can redistribute it and/or modify
     5.9 + * it under the terms of the GNU General Public License as published by
    5.10 + * the Free Software Foundation, version 2 of the License.
    5.11 + *
    5.12 + * This program is distributed in the hope that it will be useful,
    5.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.15 + * GNU General Public License for more details.
    5.16 + *
    5.17 + * You should have received a copy of the GNU General Public License
    5.18 + * along with this program. Look for COPYING file in the top folder.
    5.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    5.20 + */
    5.21 +package org.apidesign.bck2brwsr.ide.editor;
    5.22 +
    5.23 +import java.util.regex.Matcher;
    5.24 +import java.util.regex.Pattern;
    5.25 +
    5.26 +final class JsniCommentTokenizer {
    5.27 +
    5.28 +    /**
    5.29 +     * Tokenize the contents of JSNI comment into the provided {@linkplain Sink}.
    5.30 +     * @param in the contents of JSNI comment
    5.31 +     * @param out the sink that consumes parsed tokens
    5.32 +     */
    5.33 +    public void process(final CharSequence in, final Sink out) {
    5.34 +        final Matcher member = Pattern.compile("@([^:]+)::([a-zA-Z_$][a-zA-Z\\d_$]*)").matcher(in);
    5.35 +        final Matcher signature = Pattern.compile("\\(([^\\)]*)\\)").matcher(in);
    5.36 +
    5.37 +        int i = 0;
    5.38 +        while (true) {
    5.39 +            if (member.find(i)) {
    5.40 +                final int memberStart = member.start();
    5.41 +                final int memberEnd = member.end();
    5.42 +                if (memberStart > i) out.javascript(in.subSequence(i, memberStart).toString());
    5.43 +
    5.44 +                final String clazz = member.group(1);
    5.45 +                final String name = member.group(2);
    5.46 +
    5.47 +                if (in.charAt(memberEnd) == '(') {
    5.48 +                    if (!signature.find(memberEnd)) {
    5.49 +                        throw new IllegalStateException("Expected method signature");
    5.50 +                    }
    5.51 +                    assert signature.start() == memberEnd;
    5.52 +                    out.method(clazz, name, signature.group(1));
    5.53 +                    i = signature.end();
    5.54 +                } else {
    5.55 +                    out.field(clazz, name);
    5.56 +                    i = memberEnd;
    5.57 +                }
    5.58 +            } else {
    5.59 +                out.javascript(in.subSequence(i, in.length()).toString());
    5.60 +                break;
    5.61 +            }
    5.62 +        }
    5.63 +    }
    5.64 +
    5.65 +
    5.66 +    static interface Sink {
    5.67 +        void javascript(String s);
    5.68 +
    5.69 +        void method(String clazz, String method, String signature);
    5.70 +
    5.71 +        void field(String clazz, String field);
    5.72 +    }
    5.73 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/ManglingSink.java	Wed Feb 13 16:54:32 2013 +0100
     6.3 @@ -0,0 +1,71 @@
     6.4 +/**
     6.5 + * Back 2 Browser Bytecode Translator
     6.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     6.7 + *
     6.8 + * This program is free software: you can redistribute it and/or modify
     6.9 + * it under the terms of the GNU General Public License as published by
    6.10 + * the Free Software Foundation, version 2 of the License.
    6.11 + *
    6.12 + * This program is distributed in the hope that it will be useful,
    6.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    6.15 + * GNU General Public License for more details.
    6.16 + *
    6.17 + * You should have received a copy of the GNU General Public License
    6.18 + * along with this program. Look for COPYING file in the top folder.
    6.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    6.20 + */
    6.21 +package org.apidesign.bck2brwsr.ide.editor;
    6.22 +
    6.23 +/**
    6.24 + * An implementation of {@linkplain JsniCommentTokenizer.Sink} that generates B2B
    6.25 + */
    6.26 +class ManglingSink implements JsniCommentTokenizer.Sink {
    6.27 +
    6.28 +    final StringBuilder out = new StringBuilder();
    6.29 +
    6.30 +    public void javascript(String s) {
    6.31 +        out.append(s);
    6.32 +    }
    6.33 +
    6.34 +    public void method(String clazz, String method, String signature) {
    6.35 +        out.append(mangle(clazz, method, signature));
    6.36 +    }
    6.37 +
    6.38 +    public void field(String clazz, String field) {
    6.39 +//        out.append(field);
    6.40 +        out.append('_').append(field).append('(').append(')');
    6.41 +    }
    6.42 +
    6.43 +
    6.44 +    @Override
    6.45 +    public String toString() {
    6.46 +        return out.toString();
    6.47 +    }
    6.48 +
    6.49 +
    6.50 +    static String mangle(String clazz, String method, String signature) {
    6.51 +        final StringBuilder builder = new StringBuilder();
    6.52 +        builder.append(method);
    6.53 +        builder.append("__");
    6.54 +        builder.append(mangle(JNIHelper.signature(JNIHelper.method(clazz, method, signature).getReturnType())));
    6.55 +        builder.append(mangle(signature));
    6.56 +        return builder.toString();
    6.57 +    }
    6.58 +
    6.59 +
    6.60 +    static String mangle(String txt) {
    6.61 +        final StringBuilder sb = new StringBuilder();
    6.62 +        for (int i = 0; i < txt.length(); i++) {
    6.63 +            final char ch = txt.charAt(i);
    6.64 +            switch (ch) {
    6.65 +                case '/': sb.append('_'); break;
    6.66 +                case '_': sb.append("_1"); break;
    6.67 +                case ';': sb.append("_2"); break;
    6.68 +                case '[': sb.append("_3"); break;
    6.69 +                default: sb.append(ch); break;
    6.70 +            }
    6.71 +        }
    6.72 +        return sb.toString();
    6.73 +    }
    6.74 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/ide/editor/src/main/nbm/manifest.mf	Wed Feb 13 16:54:32 2013 +0100
     7.3 @@ -0,0 +1,2 @@
     7.4 +Manifest-Version: 1.0
     7.5 +OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/jackpot30/test/hints/Bundle.properties
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/ide/editor/src/main/resources/org/netbeans/modules/jackpot30/test/hints/Bundle.properties	Wed Feb 13 16:54:32 2013 +0100
     8.3 @@ -0,0 +1,21 @@
     8.4 +#
     8.5 +# Back 2 Browser Bytecode Translator
     8.6 +# Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     8.7 +#
     8.8 +# This program is free software: you can redistribute it and/or modify
     8.9 +# it under the terms of the GNU General Public License as published by
    8.10 +# the Free Software Foundation, version 2 of the License.
    8.11 +#
    8.12 +# This program is distributed in the hope that it will be useful,
    8.13 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    8.14 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    8.15 +# GNU General Public License for more details.
    8.16 +#
    8.17 +# You should have received a copy of the GNU General Public License
    8.18 +# along with this program. Look for COPYING file in the top folder.
    8.19 +# If not, see http://opensource.org/licenses/GPL-2.0.
    8.20 +#
    8.21 +
    8.22 +OpenIDE-Module-Name=Bck2Brwsr Editor Support
    8.23 +OpenIDE-Module-Short-Description=Provides hints, coloring, etc. for the bck2brwsr.apidesign.org project
    8.24 +OpenIDE-Module-Display-Category=Java
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/DejsniReaderTest.java	Wed Feb 13 16:54:32 2013 +0100
     9.3 @@ -0,0 +1,84 @@
     9.4 +/**
     9.5 + * Back 2 Browser Bytecode Translator
     9.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     9.7 + *
     9.8 + * This program is free software: you can redistribute it and/or modify
     9.9 + * it under the terms of the GNU General Public License as published by
    9.10 + * the Free Software Foundation, version 2 of the License.
    9.11 + *
    9.12 + * This program is distributed in the hope that it will be useful,
    9.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    9.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    9.15 + * GNU General Public License for more details.
    9.16 + *
    9.17 + * You should have received a copy of the GNU General Public License
    9.18 + * along with this program. Look for COPYING file in the top folder.
    9.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    9.20 + */
    9.21 +package org.apidesign.bck2brwsr.ide.editor;
    9.22 +
    9.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
    9.24 +import org.netbeans.modules.java.hints.test.api.HintTest;
    9.25 +import org.openide.filesystems.FileUtil;
    9.26 +import org.testng.annotations.Test;
    9.27 +
    9.28 +public class DejsniReaderTest {
    9.29 +
    9.30 +    @Test
    9.31 +    public void test1() throws Exception {
    9.32 +        String s = "class Test {\n" +
    9.33 +                "    /** javadoc */\n" +
    9.34 +                "    public native void test() /*-{\n" +
    9.35 +                "        // body\n" +
    9.36 +                "    }-*/;\n" +
    9.37 +                "}\n";
    9.38 +
    9.39 +        String expected = " import org.apidesign.bck2brwsr.core.JavaScriptBody;\n"
    9.40 +              + "class Test {\n" +
    9.41 +                "\n" +
    9.42 +                "    /** javadoc */\n" +
    9.43 +                "    @JavaScriptBody(args = {}, body = \"\\n        // body\\n  \")\n" +
    9.44 +                "    public native void test();\n" +
    9.45 +                "}\n";
    9.46 +        
    9.47 +          HintTest.create()
    9.48 +                .input(s)
    9.49 +                .classpath(FileUtil.getArchiveRoot(JavaScriptBody.class.getProtectionDomain().getCodeSource().getLocation()))
    9.50 +                .run(JSNI2JavaScriptBody.class)
    9.51 +                .findWarning("2:23-2:27:verifier:" + Bundle.ERR_JSNI2JavaScriptBody())
    9.52 +                .applyFix()
    9.53 +                .assertCompilable()
    9.54 +                .assertOutput(expected);
    9.55 +    }
    9.56 +
    9.57 +
    9.58 +    @Test
    9.59 +    public void test2() throws Exception {
    9.60 +        String s = "class Test {\n" +
    9.61 +                "    /** javadoc */\n" +
    9.62 +                "    @SuppressWarnings(\"unused\")\n" +
    9.63 +                "    // comment\n" +
    9.64 +                "    public native void test() /*-{\n" +
    9.65 +                "        // body\n" +
    9.66 +                "    }-*/;\n" +
    9.67 +                "}\n";
    9.68 +
    9.69 +        String expected = " import org.apidesign.bck2brwsr.core.JavaScriptBody;\n"
    9.70 +              + "class Test {\n" +
    9.71 +                "\n" +
    9.72 +                "    /** javadoc */\n" +
    9.73 +                "    @SuppressWarnings(\"unused\")\n" +
    9.74 +                "    // comment\n" +
    9.75 +                "    @JavaScriptBody(args = {}, body = \"\\n        // body\\n  \")\n" +
    9.76 +                "    public native void test();\n" +
    9.77 +                "}\n";
    9.78 +          HintTest.create()
    9.79 +                .input(s)
    9.80 +                .classpath(FileUtil.getArchiveRoot(JavaScriptBody.class.getProtectionDomain().getCodeSource().getLocation()))
    9.81 +                .run(JSNI2JavaScriptBody.class)
    9.82 +                .findWarning("4:23-4:27:verifier:" + Bundle.ERR_JSNI2JavaScriptBody())
    9.83 +                .applyFix()
    9.84 +                .assertCompilable()
    9.85 +                .assertOutput(expected);
    9.86 +    }
    9.87 +}
    9.88 \ No newline at end of file
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/JSNI2JavaScriptBodyTest.java	Wed Feb 13 16:54:32 2013 +0100
    10.3 @@ -0,0 +1,46 @@
    10.4 +/**
    10.5 + * Back 2 Browser Bytecode Translator
    10.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    10.7 + *
    10.8 + * This program is free software: you can redistribute it and/or modify
    10.9 + * it under the terms of the GNU General Public License as published by
   10.10 + * the Free Software Foundation, version 2 of the License.
   10.11 + *
   10.12 + * This program is distributed in the hope that it will be useful,
   10.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   10.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   10.15 + * GNU General Public License for more details.
   10.16 + *
   10.17 + * You should have received a copy of the GNU General Public License
   10.18 + * along with this program. Look for COPYING file in the top folder.
   10.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   10.20 + */
   10.21 +package org.apidesign.bck2brwsr.ide.editor;
   10.22 +
   10.23 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
   10.24 +import org.netbeans.modules.java.hints.test.api.HintTest;
   10.25 +import org.openide.filesystems.FileUtil;
   10.26 +import org.testng.annotations.Test;
   10.27 +
   10.28 +public class JSNI2JavaScriptBodyTest {
   10.29 +
   10.30 +    @Test
   10.31 +    public void testFixWorking() throws Exception {
   10.32 +        HintTest.create()
   10.33 +                .input("package test;\n" +
   10.34 +                       "public class Test {\n" +
   10.35 +                       "    public native void run(int a) /*-{ this.a = a; }-*/;\n" +
   10.36 +                       "}\n")
   10.37 +                .classpath(FileUtil.getArchiveRoot(JavaScriptBody.class.getProtectionDomain().getCodeSource().getLocation()))
   10.38 +                .run(JSNI2JavaScriptBody.class)
   10.39 +                .findWarning("2:23-2:26:verifier:" + Bundle.ERR_JSNI2JavaScriptBody())
   10.40 +                .applyFix()
   10.41 +                .assertCompilable()
   10.42 +                .assertOutput("package test;\n" +
   10.43 +                              "import org.apidesign.bck2brwsr.core.JavaScriptBody;\n" +
   10.44 +                              "public class Test {\n" +
   10.45 +                              "    @JavaScriptBody(args = {\"a\"}, body = \" this.a = a; \")\n" +
   10.46 +                              "    public native void run(int a);\n" +
   10.47 +                              "}\n");
   10.48 +    }
   10.49 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/JsniCommentTokenizerTest.java	Wed Feb 13 16:54:32 2013 +0100
    11.3 @@ -0,0 +1,154 @@
    11.4 +/**
    11.5 + * Back 2 Browser Bytecode Translator
    11.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    11.7 + *
    11.8 + * This program is free software: you can redistribute it and/or modify
    11.9 + * it under the terms of the GNU General Public License as published by
   11.10 + * the Free Software Foundation, version 2 of the License.
   11.11 + *
   11.12 + * This program is distributed in the hope that it will be useful,
   11.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11.15 + * GNU General Public License for more details.
   11.16 + *
   11.17 + * You should have received a copy of the GNU General Public License
   11.18 + * along with this program. Look for COPYING file in the top folder.
   11.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   11.20 + */
   11.21 +package org.apidesign.bck2brwsr.ide.editor;
   11.22 +
   11.23 +import java.io.IOException;
   11.24 +import java.util.ArrayList;
   11.25 +import java.util.List;
   11.26 +import org.testng.Assert;
   11.27 +import org.testng.annotations.Test;
   11.28 +
   11.29 +public class JsniCommentTokenizerTest {
   11.30 +
   11.31 +    private static class MockSink implements JsniCommentTokenizer.Sink {
   11.32 +        final List<String> out = new ArrayList<String>();
   11.33 +
   11.34 +        public void javascript(String s) {
   11.35 +            out.add("J " + s);
   11.36 +        }
   11.37 +
   11.38 +        public void method(String clazz, String method, String signature) {
   11.39 +            out.add("M " + clazz + "|" + method + "|" + signature);
   11.40 +        }
   11.41 +
   11.42 +        public void field(String clazz, String field) {
   11.43 +            out.add("F " + clazz + "|" + field);
   11.44 +        }
   11.45 +    }
   11.46 +
   11.47 +
   11.48 +    @Test
   11.49 +    public void testProcess_nop() throws IOException {
   11.50 +        final String in = "foo bar";
   11.51 +        final List<String> expected = new ArrayList<String>();
   11.52 +        expected.add("J foo bar");
   11.53 +
   11.54 +        final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
   11.55 +        final MockSink out = new MockSink();
   11.56 +        jsniCommentTokenizer.process(in, out);
   11.57 +
   11.58 +        Assert.assertEquals(expected, out.out);
   11.59 +    }
   11.60 +
   11.61 +    @Test
   11.62 +    public void testProcess_read_static_field() throws IOException {
   11.63 +        final String in = " @com.google.gwt.examples.JSNIExample::myStaticField = val + \" and stuff\";";
   11.64 +        final List<String> expected = new ArrayList<String>();
   11.65 +        expected.add("J  ");
   11.66 +        expected.add("F com.google.gwt.examples.JSNIExample|myStaticField");
   11.67 +        expected.add("J  = val + \" and stuff\";");
   11.68 +
   11.69 +        final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
   11.70 +        final MockSink out = new MockSink();
   11.71 +        jsniCommentTokenizer.process(in, out);
   11.72 +
   11.73 +        Assert.assertEquals(expected, out.out);
   11.74 +    }
   11.75 +
   11.76 +    @Test
   11.77 +    public void testProcess_write_instance_field() throws IOException {
   11.78 +        final String in = " x.@com.google.gwt.examples.JSNIExample::myInstanceField = val + \" and stuff\";";
   11.79 +        final List<String> expected = new ArrayList<String>();
   11.80 +        expected.add("J  x.");
   11.81 +        expected.add("F com.google.gwt.examples.JSNIExample|myInstanceField");
   11.82 +        expected.add("J  = val + \" and stuff\";");
   11.83 +
   11.84 +        final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
   11.85 +        final MockSink out = new MockSink();
   11.86 +        jsniCommentTokenizer.process(in, out);
   11.87 +
   11.88 +        Assert.assertEquals(expected, out.out);
   11.89 +    }
   11.90 +
   11.91 +    @Test
   11.92 +    public void testProcess_read_instance_field() throws IOException {
   11.93 +        final String in = " var val = this.@com.google.gwt.examples.JSNIExample::myInstanceField;";
   11.94 +        final List<String> expected = new ArrayList<String>();
   11.95 +        expected.add("J  var val = this.");
   11.96 +        expected.add("F com.google.gwt.examples.JSNIExample|myInstanceField");
   11.97 +        expected.add("J ;");
   11.98 +
   11.99 +        final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
  11.100 +        final MockSink out = new MockSink();
  11.101 +        jsniCommentTokenizer.process(in, out);
  11.102 +
  11.103 +        Assert.assertEquals(expected, out.out);
  11.104 +    }
  11.105 +
  11.106 +
  11.107 +    @Test
  11.108 +    public void testProcess_static_method() throws IOException {
  11.109 +        final String in = " @com.google.gwt.examples.JSNIExample::staticFoo(Ljava/lang/String;)(s);";
  11.110 +        final List<String> expected = new ArrayList<String>();
  11.111 +        expected.add("J  ");
  11.112 +        expected.add("M com.google.gwt.examples.JSNIExample|staticFoo|Ljava/lang/String;");
  11.113 +        expected.add("J (s);");
  11.114 +
  11.115 +        final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
  11.116 +        final MockSink out = new MockSink();
  11.117 +        jsniCommentTokenizer.process(in, out);
  11.118 +
  11.119 +        Assert.assertEquals(expected, out.out);
  11.120 +    }
  11.121 +
  11.122 +
  11.123 +    @Test
  11.124 +    public void testProcess_instance_method() throws IOException {
  11.125 +        final String in = " x.@com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s);";
  11.126 +        final List<String> expected = new ArrayList<String>();
  11.127 +        expected.add("J  x.");
  11.128 +        expected.add("M com.google.gwt.examples.JSNIExample|instanceFoo|Ljava/lang/String;");
  11.129 +        expected.add("J (s);");
  11.130 +
  11.131 +        final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
  11.132 +        final MockSink out = new MockSink();
  11.133 +        jsniCommentTokenizer.process(in, out);
  11.134 +
  11.135 +        Assert.assertEquals(expected, out.out);
  11.136 +    }
  11.137 +
  11.138 +
  11.139 +    @Test
  11.140 +    public void testProcess_multiline() throws IOException {
  11.141 +        final String in =
  11.142 +            " x.@com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s);" +
  11.143 +            " @com.google.gwt.examples.JSNIExample::myStaticField = val + \" and stuff\";";
  11.144 +        final List<String> expected = new ArrayList<String>();
  11.145 +        expected.add("J  x.");
  11.146 +        expected.add("M com.google.gwt.examples.JSNIExample|instanceFoo|Ljava/lang/String;");
  11.147 +        expected.add("J (s); ");
  11.148 +        expected.add("F com.google.gwt.examples.JSNIExample|myStaticField");
  11.149 +        expected.add("J  = val + \" and stuff\";");
  11.150 +
  11.151 +        final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
  11.152 +        final MockSink out = new MockSink();
  11.153 +        jsniCommentTokenizer.process(in, out);
  11.154 +
  11.155 +        Assert.assertEquals(expected, out.out);
  11.156 +    }
  11.157 +}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/ManglingSinkTest.java	Wed Feb 13 16:54:32 2013 +0100
    12.3 @@ -0,0 +1,58 @@
    12.4 +/**
    12.5 + * Back 2 Browser Bytecode Translator
    12.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    12.7 + *
    12.8 + * This program is free software: you can redistribute it and/or modify
    12.9 + * it under the terms of the GNU General Public License as published by
   12.10 + * the Free Software Foundation, version 2 of the License.
   12.11 + *
   12.12 + * This program is distributed in the hope that it will be useful,
   12.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12.15 + * GNU General Public License for more details.
   12.16 + *
   12.17 + * You should have received a copy of the GNU General Public License
   12.18 + * along with this program. Look for COPYING file in the top folder.
   12.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   12.20 + */
   12.21 +package org.apidesign.bck2brwsr.ide.editor;
   12.22 +
   12.23 +import org.testng.Assert;
   12.24 +import org.testng.annotations.Test;
   12.25 +
   12.26 +
   12.27 +public class ManglingSinkTest {
   12.28 +
   12.29 +    @Test
   12.30 +    public void testMangle_1() {
   12.31 +        Assert.assertEquals(
   12.32 +                "binarySearch__I_3BIIB",
   12.33 +                ManglingSink.mangle("java.util.Arrays", "binarySearch", "[BIIB")
   12.34 +        );
   12.35 +    }
   12.36 +
   12.37 +    @Test
   12.38 +    public void testMangle_2() {
   12.39 +        Assert.assertEquals(
   12.40 +                "sort__V_3I",
   12.41 +                ManglingSink.mangle("java.util.Arrays", "sort", "[I")
   12.42 +        );
   12.43 +    }
   12.44 +
   12.45 +    @Test
   12.46 +    public void testMangle_3() {
   12.47 +        Assert.assertEquals(
   12.48 +                "binarySearch__I_3Ljava_lang_Object_2IILjava_lang_Object_2",
   12.49 +                ManglingSink.mangle("java.util.Arrays", "binarySearch", "[Ljava/lang/Object;IILjava/lang/Object;")
   12.50 +        );
   12.51 +    }
   12.52 +
   12.53 +
   12.54 +    @Test
   12.55 +    public void testField() {
   12.56 +        final ManglingSink manglingSink = new ManglingSink();
   12.57 +        manglingSink.field(null, "value");
   12.58 +
   12.59 +        Assert.assertEquals("_value()", manglingSink.toString());
   12.60 +    }
   12.61 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/ide/pom.xml	Wed Feb 13 16:54:32 2013 +0100
    13.3 @@ -0,0 +1,17 @@
    13.4 +<?xml version="1.0" encoding="UTF-8"?>
    13.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    13.6 +  <modelVersion>4.0.0</modelVersion>
    13.7 +  <parent>
    13.8 +    <artifactId>bck2brwsr</artifactId>
    13.9 +    <groupId>org.apidesign</groupId>
   13.10 +    <version>0.3-SNAPSHOT</version>
   13.11 +  </parent>
   13.12 +  <groupId>org.apidesign.bck2brwsr</groupId>
   13.13 +  <artifactId>ide</artifactId>
   13.14 +  <version>0.3-SNAPSHOT</version>
   13.15 +  <packaging>pom</packaging>
   13.16 +  <name>IDE Support</name>
   13.17 +  <modules>
   13.18 +    <module>editor</module>
   13.19 +  </modules>
   13.20 +</project>
    14.1 --- a/pom.xml	Tue Feb 12 12:07:55 2013 +0100
    14.2 +++ b/pom.xml	Wed Feb 13 16:54:32 2013 +0100
    14.3 @@ -17,6 +17,7 @@
    14.4      <module>benchmarks</module>
    14.5      <module>launcher</module>
    14.6      <module>vmtest</module>
    14.7 +    <module>ide</module>
    14.8    </modules>
    14.9    <licenses>
   14.10        <license>