2007-02-02 17:17:13 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* Copyright (c) 2002 - 2006 IBM Corporation.
|
|
|
|
* All rights reserved. This program and the accompanying materials
|
|
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
|
|
* which accompanies this distribution, and is available at
|
|
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
|
|
*
|
|
|
|
* Contributors:
|
|
|
|
* IBM Corporation - initial API and implementation
|
|
|
|
*****************************************************************************/
|
|
|
|
package com.ibm.wala.cast.util;
|
|
|
|
|
2007-02-08 19:08:31 +00:00
|
|
|
import java.lang.reflect.Field;
|
|
|
|
import java.util.ArrayList;
|
2012-03-01 02:45:51 +00:00
|
|
|
import java.util.Collection;
|
2007-02-08 19:08:31 +00:00
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.TreeMap;
|
2012-03-01 02:45:51 +00:00
|
|
|
import java.util.regex.Pattern;
|
2007-02-08 19:08:31 +00:00
|
|
|
|
2012-03-01 02:45:51 +00:00
|
|
|
import com.ibm.wala.cast.tree.CAstEntity;
|
2007-02-08 19:08:31 +00:00
|
|
|
import com.ibm.wala.cast.tree.CAstNode;
|
2012-08-30 16:10:30 +00:00
|
|
|
import com.ibm.wala.cast.tree.CAstSourcePositionMap;
|
2012-03-01 02:45:51 +00:00
|
|
|
import com.ibm.wala.cast.tree.visit.CAstVisitor;
|
|
|
|
import com.ibm.wala.cast.tree.visit.CAstVisitor.Context;
|
2007-07-11 21:07:32 +00:00
|
|
|
import com.ibm.wala.util.collections.HashMapFactory;
|
2012-03-01 02:45:51 +00:00
|
|
|
import com.ibm.wala.util.collections.HashSetFactory;
|
2007-02-08 19:08:31 +00:00
|
|
|
import com.ibm.wala.util.debug.Assertions;
|
2007-02-02 17:17:13 +00:00
|
|
|
|
|
|
|
public class CAstPattern {
|
|
|
|
private static boolean DEBUG_PARSER = false;
|
2007-02-08 20:45:07 +00:00
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
private static boolean DEBUG_MATCH = false;
|
|
|
|
|
|
|
|
private final static int CHILD_KIND = -1;
|
2007-02-08 20:45:07 +00:00
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
private final static int CHILDREN_KIND = -2;
|
2007-02-08 20:45:07 +00:00
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
private final static int REPEATED_PATTERN_KIND = -3;
|
2007-02-08 20:45:07 +00:00
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
private final static int ALTERNATIVE_PATTERN_KIND = -4;
|
2007-02-08 20:45:07 +00:00
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
private final static int OPTIONAL_PATTERN_KIND = -5;
|
2007-02-08 20:45:07 +00:00
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
private final static int REFERENCE_PATTERN_KIND = -6;
|
2012-03-01 02:45:51 +00:00
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
private final static int IGNORE_KIND = -99;
|
|
|
|
|
|
|
|
private final String name;
|
|
|
|
|
|
|
|
private final int kind;
|
2007-02-08 20:45:07 +00:00
|
|
|
|
2012-03-01 02:45:51 +00:00
|
|
|
private final Object value;
|
2007-02-08 20:45:07 +00:00
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
private final CAstPattern[] children;
|
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
private final Map<String, CAstPattern> references;
|
|
|
|
|
|
|
|
public static class Segments extends TreeMap<String,Object> {
|
|
|
|
|
2017-08-03 00:46:45 +00:00
|
|
|
private static final long serialVersionUID = 4119719848336209576L;
|
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
public CAstNode getSingle(String name) {
|
2009-04-30 13:16:52 +00:00
|
|
|
assert containsKey(name) : name;
|
2007-02-02 17:17:13 +00:00
|
|
|
return (CAstNode) get(name);
|
|
|
|
}
|
|
|
|
|
2007-02-09 15:33:45 +00:00
|
|
|
@SuppressWarnings("unchecked")
|
2012-03-01 02:45:51 +00:00
|
|
|
public List<CAstNode> getMultiple(String name) {
|
2007-02-08 20:45:07 +00:00
|
|
|
if (!containsKey(name)) {
|
|
|
|
return Collections.emptyList();
|
2007-02-02 17:17:13 +00:00
|
|
|
} else {
|
2007-02-08 20:45:07 +00:00
|
|
|
Object o = get(name);
|
|
|
|
if (o instanceof CAstNode) {
|
2012-03-01 02:45:51 +00:00
|
|
|
return Collections.singletonList((CAstNode)o);
|
2007-02-08 20:45:07 +00:00
|
|
|
} else {
|
2009-04-30 13:16:52 +00:00
|
|
|
assert o instanceof List;
|
2012-03-01 02:45:51 +00:00
|
|
|
return (List<CAstNode>) o;
|
2007-02-08 20:45:07 +00:00
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void addAll(Segments other) {
|
Fix nearly all Eclipse warnings about using raw types
Along the way, I also converted many "for (;;)" loops into modern
"for (:)" loops. I didn't systematically look for all opportunities
to do this, though. I merely made this change where I was already
converting raw Iterator uses into modern Iterator<...> uses.
Better use of generics also allowed many casts to become statically
redundant. I have removed all such redundant casts.
Only three raw-types warnings remain after this batch of fixes. All
three involve raw uses of CallGraphBuilder. I've tried to fix these
too, but it quickly snowballs into a cascade of changes that may or
may not eventually reach a statically-type-save fixed point. I may
give these last few problem areas another go in the future. For now,
though, the hundreds of other fixes seem worth keeping even if there
are a few stragglers.
This commit may change some public APIs, but only by making weaker
type signatures stronger by replacing raw types with generic types.
For example, we may change something like "Set" into "Set<String>",
but we're not adding new arguments, changing any
underlying (post-generics-erasure) types, etc.
2017-07-09 18:38:35 +00:00
|
|
|
for (Map.Entry<String, Object> e : other.entrySet()) {
|
|
|
|
String name = e.getKey();
|
2007-02-08 20:45:07 +00:00
|
|
|
if (e.getValue() instanceof CAstNode) {
|
|
|
|
add(name, (CAstNode) e.getValue());
|
|
|
|
} else {
|
Fix nearly all Eclipse warnings about using raw types
Along the way, I also converted many "for (;;)" loops into modern
"for (:)" loops. I didn't systematically look for all opportunities
to do this, though. I merely made this change where I was already
converting raw Iterator uses into modern Iterator<...> uses.
Better use of generics also allowed many casts to become statically
redundant. I have removed all such redundant casts.
Only three raw-types warnings remain after this batch of fixes. All
three involve raw uses of CallGraphBuilder. I've tried to fix these
too, but it quickly snowballs into a cascade of changes that may or
may not eventually reach a statically-type-save fixed point. I may
give these last few problem areas another go in the future. For now,
though, the hundreds of other fixes seem worth keeping even if there
are a few stragglers.
This commit may change some public APIs, but only by making weaker
type signatures stronger by replacing raw types with generic types.
For example, we may change something like "Set" into "Set<String>",
but we're not adding new arguments, changing any
underlying (post-generics-erasure) types, etc.
2017-07-09 18:38:35 +00:00
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
final List<CAstNode> nodes = (List<CAstNode>) e.getValue();
|
|
|
|
for (CAstNode v : nodes) {
|
|
|
|
add(name, v);
|
2007-02-08 20:45:07 +00:00
|
|
|
}
|
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-09 15:33:45 +00:00
|
|
|
@SuppressWarnings("unchecked")
|
2007-02-02 17:17:13 +00:00
|
|
|
private void add(String name, CAstNode result) {
|
|
|
|
if (containsKey(name)) {
|
2007-02-08 20:45:07 +00:00
|
|
|
Object o = get(name);
|
|
|
|
if (o instanceof List) {
|
|
|
|
((List<CAstNode>) o).add(result);
|
|
|
|
} else {
|
2009-04-30 13:16:52 +00:00
|
|
|
assert o instanceof CAstNode;
|
2017-03-12 03:20:51 +00:00
|
|
|
List<Object> x = new ArrayList<>();
|
2007-02-08 20:45:07 +00:00
|
|
|
x.add(o);
|
|
|
|
x.add(result);
|
|
|
|
put(name, x);
|
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
} else {
|
2007-02-08 20:45:07 +00:00
|
|
|
put(name, result);
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public CAstPattern(String name, int kind, CAstPattern[] children) {
|
|
|
|
this.name = name;
|
|
|
|
this.kind = kind;
|
|
|
|
this.value = null;
|
|
|
|
this.children = children;
|
|
|
|
this.references = null;
|
|
|
|
}
|
|
|
|
|
2012-03-01 02:45:51 +00:00
|
|
|
public CAstPattern(String name, Object value) {
|
2007-02-02 17:17:13 +00:00
|
|
|
this.name = name;
|
|
|
|
this.kind = IGNORE_KIND;
|
|
|
|
this.value = value;
|
|
|
|
this.children = null;
|
|
|
|
this.references = null;
|
|
|
|
}
|
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
public CAstPattern(String patternName, Map<String, CAstPattern> references) {
|
2007-02-02 17:17:13 +00:00
|
|
|
this.name = null;
|
|
|
|
this.kind = REFERENCE_PATTERN_KIND;
|
|
|
|
this.value = patternName;
|
|
|
|
this.references = references;
|
|
|
|
this.children = null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:17:13 +00:00
|
|
|
public String toString() {
|
|
|
|
StringBuffer sb = new StringBuffer();
|
|
|
|
|
|
|
|
if (name != null) {
|
|
|
|
sb.append("<").append(name).append(">");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value != null) {
|
|
|
|
if (kind == REFERENCE_PATTERN_KIND) {
|
|
|
|
sb.append("ref:").append(value);
|
2012-03-01 02:45:51 +00:00
|
|
|
} else if (value instanceof Pattern) {
|
|
|
|
sb.append("/").append(value).append("/");
|
2007-02-02 17:17:13 +00:00
|
|
|
} else {
|
2007-02-08 20:45:07 +00:00
|
|
|
sb.append("literal:").append(value);
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
} else if (kind == CHILD_KIND) {
|
|
|
|
sb.append("*");
|
|
|
|
} else if (kind == CHILDREN_KIND) {
|
|
|
|
sb.append("**");
|
|
|
|
} else if (kind == REPEATED_PATTERN_KIND) {
|
|
|
|
sb.append("@");
|
|
|
|
} else if (kind == ALTERNATIVE_PATTERN_KIND) {
|
|
|
|
sb.append("|");
|
|
|
|
} else if (kind == OPTIONAL_PATTERN_KIND) {
|
|
|
|
sb.append("?");
|
|
|
|
} else {
|
|
|
|
sb.append(CAstPrinter.kindAsString(kind));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (children != null) {
|
|
|
|
sb.append("(");
|
2007-02-08 20:45:07 +00:00
|
|
|
for (int i = 0; i < children.length; i++) {
|
|
|
|
sb.append(children[i].toString());
|
|
|
|
if (i == children.length - 1) {
|
|
|
|
sb.append(")");
|
|
|
|
} else {
|
|
|
|
sb.append(",");
|
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return sb.toString();
|
|
|
|
}
|
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
private static boolean matchChildren(CAstNode tree, int i, CAstPattern[] cs, int j, Segments s) {
|
2007-02-02 17:17:13 +00:00
|
|
|
if (i >= tree.getChildCount() && j >= cs.length) {
|
|
|
|
return true;
|
|
|
|
} else if (i < tree.getChildCount() && j >= cs.length) {
|
|
|
|
return false;
|
|
|
|
} else if (i >= tree.getChildCount() && j < cs.length) {
|
|
|
|
switch (cs[j].kind) {
|
|
|
|
case CHILDREN_KIND:
|
|
|
|
case OPTIONAL_PATTERN_KIND:
|
|
|
|
case REPEATED_PATTERN_KIND:
|
2007-02-08 20:45:07 +00:00
|
|
|
return matchChildren(tree, i, cs, j + 1, s);
|
2007-02-02 17:17:13 +00:00
|
|
|
|
|
|
|
default:
|
2007-02-08 20:45:07 +00:00
|
|
|
return false;
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (cs[j].kind == CHILD_KIND) {
|
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
if (DEBUG_MATCH) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println(("* matches " + CAstPrinter.print(tree.getChild(i))));
|
2007-02-08 20:45:07 +00:00
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
if (s != null && cs[j].name != null) {
|
|
|
|
s.add(cs[j].name, tree.getChild(i));
|
|
|
|
}
|
|
|
|
return matchChildren(tree, i + 1, cs, j + 1, s);
|
2007-02-02 17:17:13 +00:00
|
|
|
|
|
|
|
} else if (cs[j].kind == CHILDREN_KIND) {
|
2007-02-08 20:45:07 +00:00
|
|
|
if (tryMatchChildren(tree, i, cs, j + 1, s)) {
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
if (DEBUG_MATCH) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println("** matches nothing");
|
2007-02-08 20:45:07 +00:00
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
return true;
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
} else {
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
if (DEBUG_MATCH) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println(("** matches " + CAstPrinter.print(tree.getChild(i))));
|
2007-02-08 20:45:07 +00:00
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
if (s != null && cs[j].name != null) {
|
|
|
|
s.add(cs[j].name, tree.getChild(i));
|
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
return matchChildren(tree, i + 1, cs, j, s);
|
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
|
|
|
|
} else if (cs[j].kind == REPEATED_PATTERN_KIND) {
|
2007-02-08 20:45:07 +00:00
|
|
|
CAstPattern repeatedPattern = cs[j].children[0];
|
|
|
|
if (repeatedPattern.tryMatch(tree.getChild(i), s)) {
|
|
|
|
if (s != null && cs[j].name != null) {
|
|
|
|
s.add(cs[j].name, tree.getChild(i));
|
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
if (DEBUG_MATCH) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println((cs[j] + " matches " + CAstPrinter.print(tree.getChild(i))));
|
2007-02-08 20:45:07 +00:00
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
return matchChildren(tree, i + 1, cs, j, s);
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
} else {
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
if (DEBUG_MATCH) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println((cs[j] + " matches nothing"));
|
2007-02-08 20:45:07 +00:00
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
return matchChildren(tree, i, cs, j + 1, s);
|
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
|
|
|
|
} else if (cs[j].kind == OPTIONAL_PATTERN_KIND) {
|
2007-02-08 20:45:07 +00:00
|
|
|
if (tryMatchChildren(tree, i, cs, j + 1, s)) {
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
if (DEBUG_MATCH) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println((cs[j] + " matches nothing"));
|
2007-02-08 20:45:07 +00:00
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
CAstPattern optionalPattern = cs[j].children[0];
|
|
|
|
if (optionalPattern.tryMatch(tree.getChild(i), s)) {
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
if (DEBUG_MATCH) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println((cs[j] + " matches " + CAstPrinter.print(tree.getChild(i))));
|
2007-02-08 20:45:07 +00:00
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
return matchChildren(tree, i + 1, cs, j + 1, s);
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
|
|
|
|
} else {
|
2007-02-08 20:45:07 +00:00
|
|
|
return cs[j].match(tree.getChild(i), s) && matchChildren(tree, i + 1, cs, j + 1, s);
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-02-08 20:45:07 +00:00
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
public boolean match(CAstNode tree, Segments s) {
|
|
|
|
if (DEBUG_MATCH) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println(("matching " + this + " against " + CAstPrinter.print(tree)));
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (kind == REFERENCE_PATTERN_KIND) {
|
2007-02-08 20:45:07 +00:00
|
|
|
return references.get(value).match(tree, s);
|
2007-02-02 17:17:13 +00:00
|
|
|
|
|
|
|
} else if (kind == ALTERNATIVE_PATTERN_KIND) {
|
2017-11-28 20:26:09 +00:00
|
|
|
for (CAstPattern element : children) {
|
|
|
|
if (element.tryMatch(tree, s)) {
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
if (s != null && name != null)
|
|
|
|
s.add(name, tree);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (DEBUG_MATCH) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println("match failed (a)");
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} else {
|
2012-03-01 02:45:51 +00:00
|
|
|
if ((value == null) ? tree.getKind() != kind :
|
|
|
|
(tree.getKind() != CAstNode.CONSTANT ||
|
|
|
|
(value instanceof Pattern
|
|
|
|
? !((Pattern)value).matcher(tree.getValue().toString()).matches()
|
|
|
|
: !value.equals(tree.getValue().toString()))))
|
|
|
|
{
|
2007-02-08 20:45:07 +00:00
|
|
|
if (DEBUG_MATCH) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println("match failed (b)");
|
2007-02-08 20:45:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
if (s != null && name != null)
|
|
|
|
s.add(name, tree);
|
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
if (children == null || children.length == 0) {
|
2007-02-08 20:45:07 +00:00
|
|
|
if (DEBUG_MATCH && tree.getChildCount() != 0) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println("match failed (c)");
|
2007-02-08 20:45:07 +00:00
|
|
|
}
|
|
|
|
return tree.getChildCount() == 0;
|
2007-02-02 17:17:13 +00:00
|
|
|
} else {
|
2007-02-08 20:45:07 +00:00
|
|
|
return matchChildren(tree, 0, children, 0, s);
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
private static boolean tryMatchChildren(CAstNode tree, int i, CAstPattern[] cs, int j, Segments s) {
|
2007-02-02 17:17:13 +00:00
|
|
|
if (s == null) {
|
|
|
|
return matchChildren(tree, i, cs, j, s);
|
|
|
|
} else {
|
|
|
|
Segments ss = new Segments();
|
|
|
|
boolean result = matchChildren(tree, i, cs, j, ss);
|
2007-02-08 20:45:07 +00:00
|
|
|
if (result)
|
|
|
|
s.addAll(ss);
|
2007-02-02 17:17:13 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean tryMatch(CAstNode tree, Segments s) {
|
|
|
|
if (s == null) {
|
|
|
|
return match(tree, s);
|
|
|
|
} else {
|
|
|
|
Segments ss = new Segments();
|
|
|
|
boolean result = match(tree, ss);
|
2007-02-08 20:45:07 +00:00
|
|
|
if (result)
|
|
|
|
s.addAll(ss);
|
2007-02-02 17:17:13 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Segments match(CAstPattern p, CAstNode n) {
|
|
|
|
Segments s = new Segments();
|
|
|
|
if (p.match(n, s)) {
|
|
|
|
return s;
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static CAstPattern parse(String patternString) {
|
|
|
|
try {
|
|
|
|
return (new Parser(patternString)).parse();
|
|
|
|
} catch (NoSuchFieldException e) {
|
|
|
|
Assertions.UNREACHABLE("no such kind in pattern: " + e.getMessage());
|
|
|
|
return null;
|
|
|
|
} catch (IllegalAccessException e) {
|
|
|
|
Assertions.UNREACHABLE("internal error in CAstPattern" + e);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-01 02:45:51 +00:00
|
|
|
public static Collection<Segments> findAll(final CAstPattern p, final CAstEntity e) {
|
2014-06-26 15:07:31 +00:00
|
|
|
return p.new Matcher().findAll(new Context() {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-03-01 02:45:51 +00:00
|
|
|
public CAstEntity top() {
|
|
|
|
return e;
|
|
|
|
}
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2012-08-30 16:10:30 +00:00
|
|
|
public CAstSourcePositionMap getSourceMap() {
|
|
|
|
return e.getSourceMap();
|
|
|
|
}
|
2014-06-26 15:07:31 +00:00
|
|
|
}, e.getAST());
|
2012-03-01 02:45:51 +00:00
|
|
|
}
|
|
|
|
|
2014-06-26 15:07:31 +00:00
|
|
|
public class Matcher extends CAstVisitor<Context> {
|
|
|
|
private final Collection<Segments> result = HashSetFactory.make();
|
|
|
|
|
|
|
|
@Override
|
Fix nearly all Eclipse warnings about using raw types
Along the way, I also converted many "for (;;)" loops into modern
"for (:)" loops. I didn't systematically look for all opportunities
to do this, though. I merely made this change where I was already
converting raw Iterator uses into modern Iterator<...> uses.
Better use of generics also allowed many casts to become statically
redundant. I have removed all such redundant casts.
Only three raw-types warnings remain after this batch of fixes. All
three involve raw uses of CallGraphBuilder. I've tried to fix these
too, but it quickly snowballs into a cascade of changes that may or
may not eventually reach a statically-type-save fixed point. I may
give these last few problem areas another go in the future. For now,
though, the hundreds of other fixes seem worth keeping even if there
are a few stragglers.
This commit may change some public APIs, but only by making weaker
type signatures stronger by replacing raw types with generic types.
For example, we may change something like "Set" into "Set<String>",
but we're not adding new arguments, changing any
underlying (post-generics-erasure) types, etc.
2017-07-09 18:38:35 +00:00
|
|
|
public void leaveNode(CAstNode n, Context c, CAstVisitor<Context> visitor) {
|
2014-06-26 15:07:31 +00:00
|
|
|
Segments s = match(CAstPattern.this, n);
|
|
|
|
if (s != null) {
|
|
|
|
result.add(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Collection<Segments> findAll(final Context c, final CAstNode top) {
|
|
|
|
visit(top, c, this);
|
|
|
|
return result;
|
|
|
|
}
|
2018-04-28 10:05:49 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
protected boolean doVisit(CAstNode n, Context context, CAstVisitor<Context> visitor) {
|
|
|
|
return true;
|
|
|
|
}
|
2018-10-16 04:34:31 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
protected boolean doVisitAssignNodes(CAstNode n, Context context, CAstNode v, CAstNode a, CAstVisitor<Context> visitor) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-06-26 15:07:31 +00:00
|
|
|
}
|
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
private static class Parser {
|
2007-07-11 21:07:32 +00:00
|
|
|
private final Map<String, CAstPattern> namedPatterns = HashMapFactory.make();
|
2007-02-08 20:45:07 +00:00
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
private final String patternString;
|
2007-02-08 20:45:07 +00:00
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
private int start;
|
2007-02-08 20:45:07 +00:00
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
private int end;
|
|
|
|
|
|
|
|
private Parser(String patternString) {
|
|
|
|
this.patternString = patternString;
|
|
|
|
}
|
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
// private Parser(String patternString, int start) {
|
|
|
|
// this(patternString);
|
|
|
|
// this.start = start;
|
|
|
|
// }
|
2007-02-02 17:17:13 +00:00
|
|
|
|
|
|
|
private String parseName(boolean internal) {
|
2007-02-08 20:45:07 +00:00
|
|
|
if (patternString.charAt(start) == (internal ? '{' : '<')) {
|
|
|
|
int nameStart = start + 1;
|
|
|
|
int nameEnd = patternString.indexOf(internal ? '}' : '>', nameStart);
|
|
|
|
start = nameEnd + 1;
|
|
|
|
return patternString.substring(nameStart, nameEnd);
|
2007-02-02 17:17:13 +00:00
|
|
|
} else {
|
2007-02-08 20:45:07 +00:00
|
|
|
return null;
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
public CAstPattern parse() throws NoSuchFieldException, IllegalAccessException {
|
2007-02-02 17:17:13 +00:00
|
|
|
if (DEBUG_PARSER) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println(("parsing " + patternString.substring(start)));
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
String internalName = parseName(true);
|
|
|
|
String name = parseName(false);
|
|
|
|
|
|
|
|
CAstPattern result;
|
|
|
|
if (patternString.charAt(start) == '`') {
|
2007-02-08 20:45:07 +00:00
|
|
|
int strEnd = patternString.indexOf('`', start + 1);
|
|
|
|
end = strEnd + 1;
|
|
|
|
String patternName = patternString.substring(start + 1, strEnd);
|
2009-04-30 13:16:52 +00:00
|
|
|
assert internalName == null;
|
2007-02-08 20:45:07 +00:00
|
|
|
result = new CAstPattern(patternName, namedPatterns);
|
2007-02-02 17:17:13 +00:00
|
|
|
|
|
|
|
} else if (patternString.charAt(start) == '"') {
|
2007-02-08 20:45:07 +00:00
|
|
|
int strEnd = patternString.indexOf('"', start + 1);
|
|
|
|
end = strEnd + 1;
|
|
|
|
result = new CAstPattern(name, patternString.substring(start + 1, strEnd));
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2012-03-01 02:45:51 +00:00
|
|
|
} else if (patternString.charAt(start) == '/') {
|
|
|
|
int strEnd = patternString.indexOf('/', start + 1);
|
|
|
|
end = strEnd + 1;
|
|
|
|
result = new CAstPattern(name, Pattern.compile(patternString.substring(start + 1, strEnd)));
|
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
} else if (patternString.startsWith("**", start)) {
|
2007-02-08 20:45:07 +00:00
|
|
|
end = start + 2;
|
|
|
|
result = new CAstPattern(name, CHILDREN_KIND, null);
|
2007-02-02 17:17:13 +00:00
|
|
|
|
|
|
|
} else if (patternString.startsWith("*", start)) {
|
2007-02-08 20:45:07 +00:00
|
|
|
end = start + 1;
|
|
|
|
result = new CAstPattern(name, CHILD_KIND, null);
|
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
} else if (patternString.startsWith("|(", start)) {
|
2017-03-12 03:20:51 +00:00
|
|
|
List<CAstPattern> alternatives = new ArrayList<>();
|
2007-02-08 20:45:07 +00:00
|
|
|
start += 2;
|
|
|
|
do {
|
|
|
|
alternatives.add(parse());
|
|
|
|
start = end + 2;
|
|
|
|
} while (patternString.startsWith("||", end));
|
2009-04-30 13:16:52 +00:00
|
|
|
assert patternString.startsWith(")|", end) : patternString;
|
2007-02-08 20:45:07 +00:00
|
|
|
end += 2;
|
|
|
|
result = new CAstPattern(name, ALTERNATIVE_PATTERN_KIND, alternatives.toArray(new CAstPattern[alternatives.size()]));
|
|
|
|
|
2007-02-02 17:17:13 +00:00
|
|
|
} else if (patternString.startsWith("@(", start)) {
|
2007-02-08 20:45:07 +00:00
|
|
|
start += 2;
|
|
|
|
CAstPattern children[] = new CAstPattern[] { parse() };
|
2009-04-30 13:16:52 +00:00
|
|
|
assert patternString.startsWith(")@", end);
|
2007-02-08 20:45:07 +00:00
|
|
|
end += 2;
|
|
|
|
|
|
|
|
if (DEBUG_PARSER) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println(("repeated pattern: " + children[0]));
|
2007-02-08 20:45:07 +00:00
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
result = new CAstPattern(name, REPEATED_PATTERN_KIND, children);
|
2007-02-02 17:17:13 +00:00
|
|
|
|
|
|
|
} else if (patternString.startsWith("?(", start)) {
|
2007-02-08 20:45:07 +00:00
|
|
|
start += 2;
|
|
|
|
CAstPattern children[] = new CAstPattern[] { parse() };
|
2009-04-30 13:16:52 +00:00
|
|
|
assert patternString.startsWith(")?", end);
|
2007-02-08 20:45:07 +00:00
|
|
|
end += 2;
|
|
|
|
|
|
|
|
if (DEBUG_PARSER) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println(("optional pattern: " + children[0]));
|
2007-02-08 20:45:07 +00:00
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
|
2007-02-08 20:45:07 +00:00
|
|
|
result = new CAstPattern(name, OPTIONAL_PATTERN_KIND, children);
|
2007-02-02 17:17:13 +00:00
|
|
|
|
|
|
|
} else {
|
2007-02-08 20:45:07 +00:00
|
|
|
int kindEnd = patternString.indexOf('(', start);
|
|
|
|
String kindStr = patternString.substring(start, kindEnd);
|
|
|
|
Field kindField = CAstNode.class.getField(kindStr);
|
|
|
|
int kind = kindField.getInt(null);
|
|
|
|
|
|
|
|
if (patternString.charAt(kindEnd + 1) == ')') {
|
|
|
|
end = kindEnd + 2;
|
|
|
|
result = new CAstPattern(name, kind, null);
|
|
|
|
|
|
|
|
} else {
|
2017-03-12 03:20:51 +00:00
|
|
|
List<CAstPattern> children = new ArrayList<>();
|
2007-02-08 20:45:07 +00:00
|
|
|
start = patternString.indexOf('(', start) + 1;
|
|
|
|
do {
|
|
|
|
children.add(parse());
|
|
|
|
start = end + 1;
|
|
|
|
|
|
|
|
if (DEBUG_PARSER) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println(("parsing children: " + patternString.substring(end)));
|
2007-02-08 20:45:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} while (patternString.charAt(end) == ',');
|
|
|
|
|
2009-04-30 13:16:52 +00:00
|
|
|
assert patternString.charAt(end) == ')';
|
2007-02-08 20:45:07 +00:00
|
|
|
end++;
|
|
|
|
|
|
|
|
result = new CAstPattern(name, kind, children.toArray(new CAstPattern[children.size()]));
|
|
|
|
}
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (internalName != null) {
|
2007-02-08 20:45:07 +00:00
|
|
|
namedPatterns.put(internalName, result);
|
2007-02-02 17:17:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|