Skip to content

Commit 3afde3e

Browse files
committed
initial work on pattern matching classes
1 parent 8d308d7 commit 3afde3e

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
class Nothing:
2+
def act(self):
3+
print("Nothing")
4+
5+
6+
def id(x):
7+
return x
8+
9+
10+
class Something:
11+
a = 0
12+
b = 0
13+
14+
def __init__(self, a, b):
15+
self.a = id(a)
16+
self.b = id(b)
17+
18+
def act(self):
19+
print(self.a + self.b)
20+
21+
22+
def doit(x):
23+
match x:
24+
case Nothing():
25+
x.act()
26+
case Something(a=5, b=7):
27+
x.act()
28+
case Something():
29+
print("unexpected something")
30+
case _:
31+
print("unexpected value")
32+
33+
34+
doit(Nothing())
35+
doit(Something(5, 7))
36+
doit(Something(3, 4))
37+
doit(10)

jep/com.ibm.wala.cast.python.cpython/source/com/ibm/wala/cast/python/jep/ast/CPythonAstToCAstTranslator.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2460,6 +2460,40 @@ public CAstNode matchVar() {
24602460
return result;
24612461
}
24622462

2463+
public CAstNode visitMatchClass(PyObject cls, WalkContext context) {
2464+
PyObject klass = cls.getAttr("cls", PyObject.class);
2465+
CAstNode result =
2466+
ast.makeNode(CAstNode.INSTANCEOF, visit(klass, context), context.matchVar());
2467+
2468+
@SuppressWarnings("unchecked")
2469+
Iterator<String> names = cls.getAttr("kwd_attrs", List.class).iterator();
2470+
@SuppressWarnings("unchecked")
2471+
Iterator<PyObject> patterns = cls.getAttr("kwd_patterns", List.class).iterator();
2472+
while (names.hasNext()) {
2473+
String name = names.next();
2474+
WalkContext eltContext =
2475+
new WalkContext() {
2476+
2477+
@Override
2478+
public WalkContext getParent() {
2479+
return context;
2480+
}
2481+
2482+
@Override
2483+
public CAstNode matchVar() {
2484+
return ast.makeNode(
2485+
CAstNode.OBJECT_REF, context.matchVar(), ast.makeConstant(name));
2486+
}
2487+
};
2488+
2489+
CAstNode eltNode = visit(patterns.next(), eltContext);
2490+
2491+
result = ast.makeNode(CAstNode.IF_EXPR, result, eltNode, ast.makeConstant(false));
2492+
}
2493+
2494+
return result;
2495+
}
2496+
24632497
private int nextDecl = 0;
24642498

24652499
public CAstNode visitMatch(PyObject match, WalkContext context) {

jep/com.ibm.wala.cast.python.cpython/test/com/ibm/wala/cast/python/cpython/test/TestMatch.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,4 +140,39 @@ public void testMatch4()
140140

141141
verifyGraphAssertions(CG, assertionsForMatch4);
142142
}
143+
144+
protected static final Object[][] assertionsForMatch5 =
145+
new Object[][] {
146+
new Object[] {ROOT, new String[] {"script match5.py"}},
147+
new Object[] {"script match5.py", new String[] {"script match5.py/doit"}},
148+
new Object[] {
149+
"script match5.py/doit",
150+
new String[] {
151+
"$script match5.py/Nothing/act:trampoline1",
152+
"$script match5.py/Something/act:trampoline1",
153+
}
154+
},
155+
new Object[] {
156+
"$script match5.py/Nothing/act:trampoline1", new String[] {"script match5.py/Nothing/act"}
157+
},
158+
new Object[] {
159+
"$script match5.py/Something/act:trampoline1",
160+
new String[] {"script match5.py/Something/act"}
161+
}
162+
};
163+
164+
@Test
165+
public void testMatch5()
166+
throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException {
167+
PythonAnalysisEngine<?> E = makeEngine("match5.py");
168+
PythonSSAPropagationCallGraphBuilder B = E.defaultCallGraphBuilder();
169+
CallGraph CG = B.makeCallGraph(B.getOptions());
170+
171+
System.err.println(CG);
172+
CAstCallGraphUtil.AVOID_DUMP.set(false);
173+
CAstCallGraphUtil.dumpCG(
174+
(SSAContextInterpreter) B.getContextInterpreter(), B.getPointerAnalysis(), CG);
175+
176+
verifyGraphAssertions(CG, assertionsForMatch5);
177+
}
143178
}

0 commit comments

Comments
 (0)