1. Jan Lahoda
  2. jackpot30

Commits

Jan Lahoda  committed 0a67da4

Bulk Tree Pattern Matching using regular expression (not very efficient).

  • Participants
  • Parent commits 17dcac3
  • Branches default

Comments (0)

Files changed (4)

File hints/src/org/netbeans/modules/jackpot30/hints/pm/BulkSearch.java

View file
  • Ignore whitespace
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2009 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.jackpot30.hints.pm;
+
+import com.sun.source.tree.Tree;
+import com.sun.source.util.SourcePositions;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.netbeans.api.java.source.CompilationInfo;
+
+/**
+ *
+ * @author lahvac
+ */
+public class BulkSearch {
+
+    public static Set<String> match(CompilationInfo info, Tree tree, BulkPattern pattern) {
+        Set<String> occurringPatterns = new HashSet<String>();
+        StringBuilder ser = new StringBuilder();
+
+        TreeSerializer.serializeText(tree, ser);
+
+        String serialized = ser.toString();
+
+        long s2 = System.currentTimeMillis();
+        Matcher m = pattern.toRegexpPattern().matcher(serialized);
+
+//        System.err.println("matcher=" + (System.currentTimeMillis() - s2));
+
+        while (m.find()) {
+            for (int cntr = 0; cntr < pattern.groups.length; cntr++) {
+                if (m.group(pattern.groups[cntr]) != null) {
+                    occurringPatterns.add(pattern.original.get(cntr));
+                }
+            }
+        }
+
+        long e2 = System.currentTimeMillis();
+
+//        System.err.println("match: " + (e2 - s2));
+        return occurringPatterns;
+    }
+    
+    public static BulkPattern create(CompilationInfo info, String... code) {
+        return create(info, Arrays.asList(code));
+    }
+
+    public static BulkPattern create(CompilationInfo info, Collection<String> code) {
+        StringBuilder ser = new StringBuilder();
+        Tree[] patterns = new Tree[code.size()];
+        int i = 0;
+
+        for (String c : code) {
+            patterns[i++] = info.getTreeUtilities().parseExpression(c, new SourcePositions[1]);
+        }
+
+        int[] groups = TreeSerializer.serializePatterns(ser, patterns);
+        
+        return BulkPattern.create(new LinkedList<String>(code), ser.toString(), groups);
+    }
+
+    public static class BulkPattern {
+
+        private final List<String> original;
+        private final String serialized;
+        private final Pattern p;
+        private final int[] groups;
+
+        private BulkPattern(List<String> original, String serialized, int[] groups) {
+            this.original = original;
+            this.serialized = serialized;
+            this.p = Pattern.compile(serialized);
+            this.groups = groups;
+        }
+
+        Pattern toRegexpPattern() {
+            return p;
+        }
+
+        private static BulkPattern create(List<String> original, String patterns, int[] groups) {
+            return new BulkPattern(original, patterns, groups);
+        }
+
+    }
+}

File hints/src/org/netbeans/modules/jackpot30/hints/pm/TreeSerializer.java

View file
  • Ignore whitespace
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2009 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.jackpot30.hints.pm;
+
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.IdentifierTree;
+import com.sun.source.tree.MemberSelectTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.Tree.Kind;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.TreeScanner;
+import java.io.IOException;
+import java.util.EnumMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *
+ * @author Jan Lahoda
+ */
+public class TreeSerializer extends TreeScanner<Void, Appendable> {
+
+    public static void serializeText(Tree tree, Appendable p) {
+        new TreeSerializer(false).scan(tree, p);
+    }
+
+    public static int[] serializePatterns(Appendable p, Tree... patterns) {
+        TreeSerializer ts = new TreeSerializer(true);
+        int[] groups = new int[patterns.length];
+        int i = 0;
+
+        for (Tree tree : patterns) {
+            groups[i] = ts.group++;
+            append(p, i > 0 ? "|(" : "(");
+            ts.scan(tree, p);
+            append(p, ")");
+            i++;
+        }
+
+        return groups;
+    }
+
+    private int depth;
+    private int group;
+
+    private TreeSerializer(boolean pattern) {
+        this.depth = !pattern ? 0 : -1;
+        this.group = 1;
+    }
+    
+    @Override
+    public Void scan(Tree tree, Appendable p) {
+        if (tree == null) {
+            return null;
+        }
+
+        if (   tree.getKind() == Kind.IDENTIFIER
+            && ((IdentifierTree) tree).getName().toString().startsWith("$")) {
+            append(p, "<([0-9a-z]+)>.*?</\\" + (group++) + ">");
+            return null;
+        }
+
+        append(p, "<");
+        if (depth != (-1)) {
+            append(p, Integer.toHexString(depth++));
+        } else {
+            append(p, "[0-9a-f]+");
+        }
+        append(p, ">");
+        append(p, kindToShortName.get(tree.getKind()));
+        super.scan(tree, p);
+        append(p, "</");
+        if (depth != (-1)) {
+            append(p, Integer.toHexString(--depth));
+        } else {
+            append(p, "[0-9a-f]+");
+        }
+        append(p, ">");
+
+        return null;
+    }
+
+//    @Override
+//    public Void visitIdentifier(IdentifierTree node, Appendable p) {
+//        append(p, node.getName());
+//        return super.visitIdentifier(node, p);
+//    }
+
+    @Override
+    public Void visitMemberSelect(MemberSelectTree node, Appendable p) {
+        append(p, node.getIdentifier());
+        return super.visitMemberSelect(node, p);
+    }
+
+    @Override
+    public Void visitClass(ClassTree node, Appendable p) {
+        append(p, node.getSimpleName());
+        return super.visitClass(node, p);
+    }
+
+    @Override
+    public Void visitVariable(VariableTree node, Appendable p) {
+        append(p, node.getName());
+        return super.visitVariable(node, p);
+    }
+
+    @Override
+    public Void visitMethod(MethodTree node, Appendable p) {
+        append(p, node.getName());
+        return super.visitMethod(node, p);
+    }
+
+    private static void append(Appendable a, CharSequence what) {
+        try {
+            a.append(what);
+        } catch (IOException ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+    private static final Map<Kind, String> kindToShortName;
+
+    static {
+        kindToShortName = new EnumMap<Kind, String>(Kind.class);
+        Set<String> used = new HashSet<String>();
+
+        for (Kind k : Kind.values()) {
+            String classSimpleName = k.name();
+            StringBuilder shortNameBuilder = new StringBuilder();
+
+            for (String s : classSimpleName.split("_")) {
+                shortNameBuilder.append(s.substring(0, 2));
+            }
+
+            String shortName = shortNameBuilder.toString();
+            
+            if (used.contains(shortName)) {
+                shortName = classSimpleName;
+            }
+
+            kindToShortName.put(k, shortName);
+            used.add(shortName);
+        }
+    }
+
+}

File hints/test/unit/src/org/netbeans/modules/jackpot30/hints/pm/BulkSearchTest.java

View file
  • Ignore whitespace
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2009 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.jackpot30.hints.pm;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import javax.swing.text.Document;
+import org.netbeans.api.java.lexer.JavaTokenId;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.JavaSource.Phase;
+import org.netbeans.api.java.source.SourceUtilsTestUtil;
+import org.netbeans.api.java.source.TestUtilities;
+import org.netbeans.api.lexer.Language;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.jackpot30.hints.pm.BulkSearch.BulkPattern;
+import org.netbeans.modules.java.source.TreeLoader;
+import org.openide.cookies.EditorCookie;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.loaders.DataObject;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author lahvac
+ */
+public class BulkSearchTest extends NbTestCase {
+
+    public BulkSearchTest(String name) {
+        super(name);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        SourceUtilsTestUtil.prepareTest(new String[] {"org/netbeans/modules/java/editor/resources/layer.xml"}, new Object[0]);
+        TreeLoader.DISABLE_CONFINEMENT_TEST = true;
+    }
+
+    public void testSimple1() throws Exception {
+        performTest("package test; public class Test { private void test() { System.err.println(\"\");}}",
+                    Arrays.asList("System.err.println(\"\")"),
+                    Arrays.asList("System.err.println(\"\" + \"\")"));
+    }
+
+    public void testDontCare() throws Exception {
+        performTest("package test; public class Test { private void test() { System.err.println(\"\" + \"\");}}",
+                    Arrays.asList("System.err.println($1)"),
+                    Collections.<String>emptyList());
+    }
+
+    public void XtestMeasureTime() throws Exception {
+        String code = TestUtilities.copyFileToString(new File("/usr/local/home/lahvac/src/nb//outgoing/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionProvider.java"));
+        List<String> patterns = new LinkedList<String>();
+
+        for (int cntr = 0; cntr < 1000; cntr++) {
+            patterns.add("System.err.println($1)");
+        }
+        
+        performTest(code,
+                    Collections.<String>emptyList(),
+                    patterns);
+    }
+
+    private void performTest(String text, Collection<String> containedPatterns, Collection<String> notContainedPatterns) throws Exception {
+        prepareTest("test/Test.java", text);
+
+        List<String> patterns = new LinkedList<String>();
+
+        patterns.addAll(containedPatterns);
+        patterns.addAll(notContainedPatterns);
+
+        long s1 = System.currentTimeMillis();
+        BulkPattern p = BulkSearch.create(info, patterns);
+        long e1 = System.currentTimeMillis();
+
+//        System.err.println("create: " + (e1 - s1));
+
+        long s2 = System.currentTimeMillis();
+        Set<String> result = BulkSearch.match(info, info.getCompilationUnit(), p);
+        long e2 = System.currentTimeMillis();
+
+//        System.err.println("match: " + (e2 - s2));
+
+        assertTrue(result.containsAll(containedPatterns));
+
+        Set<String> none = new HashSet<String>(result);
+
+        none.retainAll(notContainedPatterns);
+
+        assertTrue(none.isEmpty());
+    }
+    
+    private void prepareTest(String fileName, String code) throws Exception {
+        clearWorkDir();
+
+        FileUtil.refreshFor(File.listRoots());
+
+        FileObject workFO = FileUtil.toFileObject(getWorkDir());
+
+        assertNotNull(workFO);
+
+        workFO.refresh();
+
+        sourceRoot = workFO.createFolder("src");
+        FileObject buildRoot  = workFO.createFolder("build");
+        FileObject cache = workFO.createFolder("cache");
+
+        FileObject data = FileUtil.createData(sourceRoot, fileName);
+        File dataFile = FileUtil.toFile(data);
+
+        assertNotNull(dataFile);
+
+        TestUtilities.copyStringToFile(dataFile, code);
+
+        SourceUtilsTestUtil.prepareTest(sourceRoot, buildRoot, cache);
+
+        DataObject od = DataObject.find(data);
+        EditorCookie ec = od.getLookup().lookup(EditorCookie.class);
+
+        assertNotNull(ec);
+
+        doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+
+        JavaSource js = JavaSource.forFileObject(data);
+
+        assertNotNull(js);
+
+        info = SourceUtilsTestUtil.getCompilationInfo(js, Phase.RESOLVED);
+
+        assertNotNull(info);
+    }
+
+    private FileObject sourceRoot;
+    private CompilationInfo info;
+    private Document doc;
+
+}

File hints/test/unit/src/org/netbeans/modules/jackpot30/hints/pm/TreeSerializerTest.java

View file
  • Ignore whitespace
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2009 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.jackpot30.hints.pm;
+
+import java.io.File;
+import javax.swing.text.Document;
+import org.netbeans.api.java.lexer.JavaTokenId;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.JavaSource.Phase;
+import org.netbeans.api.java.source.SourceUtilsTestUtil;
+import org.netbeans.api.java.source.TestUtilities;
+import org.netbeans.api.lexer.Language;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.java.source.TreeLoader;
+import org.openide.cookies.EditorCookie;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.loaders.DataObject;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author lahvac
+ */
+public class TreeSerializerTest extends NbTestCase {
+
+    public TreeSerializerTest(String name) {
+        super(name);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        SourceUtilsTestUtil.prepareTest(new String[] {"org/netbeans/modules/java/editor/resources/layer.xml"}, new Object[0]);
+        TreeLoader.DISABLE_CONFINEMENT_TEST = true;
+    }
+
+    public void testProhibittedCharacters() throws Exception {
+        prepareTest("test/Test.java", "package test; public class Test {}");
+
+        StringBuilder sb = new StringBuilder();
+
+        TreeSerializer.serializeText(info.getCompilationUnit(), sb);
+
+        String serialized = sb.toString();
+
+        for (char c : new char[] {'(', ')', '|', '[', ']'}) {
+            assertEquals(-1, serialized.indexOf(c));
+        }
+    }
+
+    private void prepareTest(String fileName, String code) throws Exception {
+        clearWorkDir();
+
+        FileUtil.refreshFor(File.listRoots());
+
+        FileObject workFO = FileUtil.toFileObject(getWorkDir());
+
+        assertNotNull(workFO);
+
+        workFO.refresh();
+
+        sourceRoot = workFO.createFolder("src");
+        FileObject buildRoot  = workFO.createFolder("build");
+        FileObject cache = workFO.createFolder("cache");
+
+        FileObject data = FileUtil.createData(sourceRoot, fileName);
+        File dataFile = FileUtil.toFile(data);
+
+        assertNotNull(dataFile);
+
+        TestUtilities.copyStringToFile(dataFile, code);
+
+        SourceUtilsTestUtil.prepareTest(sourceRoot, buildRoot, cache);
+
+        DataObject od = DataObject.find(data);
+        EditorCookie ec = od.getLookup().lookup(EditorCookie.class);
+
+        assertNotNull(ec);
+
+        doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+
+        JavaSource js = JavaSource.forFileObject(data);
+
+        assertNotNull(js);
+
+        info = SourceUtilsTestUtil.getCompilationInfo(js, Phase.RESOLVED);
+
+        assertNotNull(info);
+    }
+
+    private FileObject sourceRoot;
+    private CompilationInfo info;
+    private Document doc;
+
+}