Skip to content

Commit 9980756

Browse files
committed
RA parser first draft
1 parent dffb120 commit 9980756

File tree

3 files changed

+168
-0
lines changed

3 files changed

+168
-0
lines changed

ql/ql/src/experimental/RA.qll

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* Parses RA expressions.
3+
*/
4+
signature class RAstring extends string;
5+
6+
signature class RApredicate {
7+
string getLineOfRA(int n);
8+
}
9+
10+
/**
11+
* Parses strings of RA provided by an RA predicate,
12+
*/
13+
module RAParser<RApredicate Predicate> {
14+
private string parseRaExpr(Predicate p, int line, int arity, int lhs) {
15+
exists(string str | str = p.getLineOfRA(line).trim() |
16+
arity = str.regexpCapture("\\{([0-9]+)\\} r([0-9]+) = (.+)", 1).toInt() and
17+
lhs = str.regexpCapture("\\{([0-9]+)\\} r([0-9]+) = (.+)", 2).toInt() and
18+
result = str.regexpCapture("\\{([0-9]+)\\} r([0-9]+) = (.+)", 3)
19+
)
20+
}
21+
22+
bindingset[str]
23+
private int parseReturn(string str) {
24+
result = str.trim().regexpCapture("return r([0-9]+)", 1).toInt()
25+
}
26+
27+
private newtype TRA =
28+
TReturn(Predicate p, int line, int v) { v = parseReturn(p.getLineOfRA(line)) } or
29+
TUnknown(Predicate p, int line, int lhs, int arity, string rhs) {
30+
rhs = parseRaExpr(p, line, arity, lhs)
31+
}
32+
33+
/** An RA Expression. */
34+
abstract class RAExpr extends TRA {
35+
/** Gets the predicate this RA expression belongs to. */
36+
abstract Predicate getPredicate();
37+
38+
/** Gets the line index of this RA expression. */
39+
abstract int getLine();
40+
41+
/** Gets the LHS of the expression of the form `rNN = ...` */
42+
abstract int getLhs();
43+
44+
/** Gets a variable of the form `rNN` in the RHS of the RA expression. */
45+
abstract int getARhsVariable();
46+
47+
/** Gets the given arity of the RA expression. */
48+
abstract int getArity();
49+
50+
/** Gets a predicate name referenced in the RHS of an RA expression. */
51+
abstract string getARhsPredicate();
52+
53+
final string toString() { result = getPredicate().getLineOfRA(getLine()) }
54+
55+
/** Gets a child of this RA expression - not by index yet. */
56+
RAExpr getAChild() {
57+
result.getPredicate() = this.getPredicate() and result.getLhs() = this.getARhsVariable()
58+
}
59+
}
60+
61+
/**
62+
* A generic RA expression - where we haven't precisely parsed the RA expression type.
63+
* For Hackathon purposes, we probably don't need more than this.
64+
*/
65+
class RAUnknownExpr extends RAExpr, TUnknown {
66+
Predicate p;
67+
int line;
68+
string rhs;
69+
int arity;
70+
int lhs;
71+
72+
RAUnknownExpr() { this = TUnknown(p, line, lhs, arity, rhs) }
73+
74+
override int getLine() { result = line }
75+
76+
override Predicate getPredicate() { result = p }
77+
78+
override int getLhs() { result = lhs }
79+
80+
override int getARhsVariable() {
81+
result = rhs.splitAt(" ").regexpCapture("r([0-9]+)", 1).toInt()
82+
}
83+
84+
// This is a dumb regex to find a predicate name - they always contain a `#` (TODO...)
85+
override string getARhsPredicate() { result = rhs.splitAt(" ") and result.indexOf("#") > 0 }
86+
87+
override int getArity() { result = arity }
88+
}
89+
90+
class RAReturnExpr extends RAExpr, TReturn {
91+
RAReturnExpr() { this = TReturn(p, line, res) }
92+
93+
Predicate p;
94+
int line;
95+
int res;
96+
97+
override Predicate getPredicate() { result = p }
98+
99+
override int getLine() { result = line }
100+
101+
override int getLhs() { none() }
102+
103+
override int getARhsVariable() { result = res }
104+
105+
override int getArity() { none() }
106+
107+
override string getARhsPredicate() { none() }
108+
}
109+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
children
2+
| return r7 | {4} r7 = r3 UNION r6 |
3+
| {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", toString("p1"), 123, " r1 = SCAN fubar\\n r1" | {1} r1 = CONSTANT(unique string)["p1"] |
4+
| {4} r3 = STREAM DEDUP r2 | {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", toString("p1"), 123, " r1 = SCAN fubar\\n r1" |
5+
| {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", "(no string representation)", 123, " r1 = SCAN fubar\\n r1" | {1} r1 = CONSTANT(unique string)["p1"] |
6+
| {4} r5 = STREAM DEDUP r4 | {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", "(no string representation)", 123, " r1 = SCAN fubar\\n r1" |
7+
| {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) | {4} r5 = STREAM DEDUP r4 |
8+
| {4} r7 = r3 UNION r6 | {4} r3 = STREAM DEDUP r2 |
9+
| {4} r7 = r3 UNION r6 | {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) |
10+
#select
11+
| p1 | 1 | {1} r1 = CONSTANT(unique string)["p1"] | 1 | 1 | 0 | 0 |
12+
| p1 | 3 | {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", toString("p1"), 123, " r1 = SCAN fubar\\n r1" | 2 | 4 | 1 | 1 |
13+
| p1 | 5 | {4} r3 = STREAM DEDUP r2 | 3 | 4 | 0 | 1 |
14+
| p1 | 6 | {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", "(no string representation)", 123, " r1 = SCAN fubar\\n r1" | 4 | 4 | 1 | 1 |
15+
| p1 | 7 | {4} r5 = STREAM DEDUP r4 | 5 | 4 | 0 | 1 |
16+
| p1 | 8 | {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) | 6 | 4 | 1 | 1 |
17+
| p1 | 9 | {4} r7 = r3 UNION r6 | 7 | 4 | 0 | 2 |

ql/ql/test/experimental/raparser.ql

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import experimental.RA
2+
3+
class TestPredicate extends string {
4+
TestPredicate() { this = "p1" }
5+
6+
string getLineOfRA(int line) {
7+
line = 1 and
8+
result = " {1} r1 = CONSTANT(unique string)[\"p1\"]"
9+
or
10+
line = 2 and result = ""
11+
or
12+
line = 3 and
13+
result =
14+
" {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT \"p1\", toString(\"p1\"), 123, \" r1 = SCAN fubar\\n r1\""
15+
or
16+
line = 4 and result = ""
17+
or
18+
line = 5 and result = " {4} r3 = STREAM DEDUP r2"
19+
or
20+
line = 6 and
21+
result =
22+
" {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT \"p1\", \"(no string representation)\", 123, \" r1 = SCAN fubar\\n r1\""
23+
or
24+
line = 7 and result = " {4} r5 = STREAM DEDUP r4"
25+
or
26+
line = 8 and result = " {4} r6 = r5 AND NOT project##select#query#ffff#nullary({})"
27+
or
28+
line = 9 and result = " {4} r7 = r3 UNION r6"
29+
or
30+
line = 10 and result = " return r7"
31+
}
32+
}
33+
34+
query predicate children(
35+
RAParser<TestPredicate>::RAExpr parent, RAParser<TestPredicate>::RAExpr child
36+
) {
37+
child = parent.getAChild()
38+
}
39+
40+
from RAParser<TestPredicate>::RAExpr expr
41+
select expr.getPredicate(), expr.getLine(), expr, expr.getLhs(), expr.getArity(),
42+
count(expr.getARhsPredicate()), count(expr.getARhsVariable())

0 commit comments

Comments
 (0)