mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
RA parser first draft
This commit is contained in:
109
ql/ql/src/experimental/RA.qll
Normal file
109
ql/ql/src/experimental/RA.qll
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* Parses RA expressions.
|
||||
*/
|
||||
signature class RAstring extends string;
|
||||
|
||||
signature class RApredicate {
|
||||
string getLineOfRA(int n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses strings of RA provided by an RA predicate,
|
||||
*/
|
||||
module RAParser<RApredicate Predicate> {
|
||||
private string parseRaExpr(Predicate p, int line, int arity, int lhs) {
|
||||
exists(string str | str = p.getLineOfRA(line).trim() |
|
||||
arity = str.regexpCapture("\\{([0-9]+)\\} r([0-9]+) = (.+)", 1).toInt() and
|
||||
lhs = str.regexpCapture("\\{([0-9]+)\\} r([0-9]+) = (.+)", 2).toInt() and
|
||||
result = str.regexpCapture("\\{([0-9]+)\\} r([0-9]+) = (.+)", 3)
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[str]
|
||||
private int parseReturn(string str) {
|
||||
result = str.trim().regexpCapture("return r([0-9]+)", 1).toInt()
|
||||
}
|
||||
|
||||
private newtype TRA =
|
||||
TReturn(Predicate p, int line, int v) { v = parseReturn(p.getLineOfRA(line)) } or
|
||||
TUnknown(Predicate p, int line, int lhs, int arity, string rhs) {
|
||||
rhs = parseRaExpr(p, line, arity, lhs)
|
||||
}
|
||||
|
||||
/** An RA Expression. */
|
||||
abstract class RAExpr extends TRA {
|
||||
/** Gets the predicate this RA expression belongs to. */
|
||||
abstract Predicate getPredicate();
|
||||
|
||||
/** Gets the line index of this RA expression. */
|
||||
abstract int getLine();
|
||||
|
||||
/** Gets the LHS of the expression of the form `rNN = ...` */
|
||||
abstract int getLhs();
|
||||
|
||||
/** Gets a variable of the form `rNN` in the RHS of the RA expression. */
|
||||
abstract int getARhsVariable();
|
||||
|
||||
/** Gets the given arity of the RA expression. */
|
||||
abstract int getArity();
|
||||
|
||||
/** Gets a predicate name referenced in the RHS of an RA expression. */
|
||||
abstract string getARhsPredicate();
|
||||
|
||||
final string toString() { result = getPredicate().getLineOfRA(getLine()) }
|
||||
|
||||
/** Gets a child of this RA expression - not by index yet. */
|
||||
RAExpr getAChild() {
|
||||
result.getPredicate() = this.getPredicate() and result.getLhs() = this.getARhsVariable()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic RA expression - where we haven't precisely parsed the RA expression type.
|
||||
* For Hackathon purposes, we probably don't need more than this.
|
||||
*/
|
||||
class RAUnknownExpr extends RAExpr, TUnknown {
|
||||
Predicate p;
|
||||
int line;
|
||||
string rhs;
|
||||
int arity;
|
||||
int lhs;
|
||||
|
||||
RAUnknownExpr() { this = TUnknown(p, line, lhs, arity, rhs) }
|
||||
|
||||
override int getLine() { result = line }
|
||||
|
||||
override Predicate getPredicate() { result = p }
|
||||
|
||||
override int getLhs() { result = lhs }
|
||||
|
||||
override int getARhsVariable() {
|
||||
result = rhs.splitAt(" ").regexpCapture("r([0-9]+)", 1).toInt()
|
||||
}
|
||||
|
||||
// This is a dumb regex to find a predicate name - they always contain a `#` (TODO...)
|
||||
override string getARhsPredicate() { result = rhs.splitAt(" ") and result.indexOf("#") > 0 }
|
||||
|
||||
override int getArity() { result = arity }
|
||||
}
|
||||
|
||||
class RAReturnExpr extends RAExpr, TReturn {
|
||||
RAReturnExpr() { this = TReturn(p, line, res) }
|
||||
|
||||
Predicate p;
|
||||
int line;
|
||||
int res;
|
||||
|
||||
override Predicate getPredicate() { result = p }
|
||||
|
||||
override int getLine() { result = line }
|
||||
|
||||
override int getLhs() { none() }
|
||||
|
||||
override int getARhsVariable() { result = res }
|
||||
|
||||
override int getArity() { none() }
|
||||
|
||||
override string getARhsPredicate() { none() }
|
||||
}
|
||||
}
|
||||
17
ql/ql/test/experimental/raparser.expected
Normal file
17
ql/ql/test/experimental/raparser.expected
Normal file
@@ -0,0 +1,17 @@
|
||||
children
|
||||
| return r7 | {4} r7 = r3 UNION r6 |
|
||||
| {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} 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" |
|
||||
| {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"] |
|
||||
| {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" |
|
||||
| {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) | {4} r5 = STREAM DEDUP r4 |
|
||||
| {4} r7 = r3 UNION r6 | {4} r3 = STREAM DEDUP r2 |
|
||||
| {4} r7 = r3 UNION r6 | {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) |
|
||||
#select
|
||||
| p1 | 1 | {1} r1 = CONSTANT(unique string)["p1"] | 1 | 1 | 0 | 0 |
|
||||
| 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 |
|
||||
| p1 | 5 | {4} r3 = STREAM DEDUP r2 | 3 | 4 | 0 | 1 |
|
||||
| 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 |
|
||||
| p1 | 7 | {4} r5 = STREAM DEDUP r4 | 5 | 4 | 0 | 1 |
|
||||
| p1 | 8 | {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) | 6 | 4 | 1 | 1 |
|
||||
| p1 | 9 | {4} r7 = r3 UNION r6 | 7 | 4 | 0 | 2 |
|
||||
42
ql/ql/test/experimental/raparser.ql
Normal file
42
ql/ql/test/experimental/raparser.ql
Normal file
@@ -0,0 +1,42 @@
|
||||
import experimental.RA
|
||||
|
||||
class TestPredicate extends string {
|
||||
TestPredicate() { this = "p1" }
|
||||
|
||||
string getLineOfRA(int line) {
|
||||
line = 1 and
|
||||
result = " {1} r1 = CONSTANT(unique string)[\"p1\"]"
|
||||
or
|
||||
line = 2 and result = ""
|
||||
or
|
||||
line = 3 and
|
||||
result =
|
||||
" {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT \"p1\", toString(\"p1\"), 123, \" r1 = SCAN fubar\\n r1\""
|
||||
or
|
||||
line = 4 and result = ""
|
||||
or
|
||||
line = 5 and result = " {4} r3 = STREAM DEDUP r2"
|
||||
or
|
||||
line = 6 and
|
||||
result =
|
||||
" {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT \"p1\", \"(no string representation)\", 123, \" r1 = SCAN fubar\\n r1\""
|
||||
or
|
||||
line = 7 and result = " {4} r5 = STREAM DEDUP r4"
|
||||
or
|
||||
line = 8 and result = " {4} r6 = r5 AND NOT project##select#query#ffff#nullary({})"
|
||||
or
|
||||
line = 9 and result = " {4} r7 = r3 UNION r6"
|
||||
or
|
||||
line = 10 and result = " return r7"
|
||||
}
|
||||
}
|
||||
|
||||
query predicate children(
|
||||
RAParser<TestPredicate>::RAExpr parent, RAParser<TestPredicate>::RAExpr child
|
||||
) {
|
||||
child = parent.getAChild()
|
||||
}
|
||||
|
||||
from RAParser<TestPredicate>::RAExpr expr
|
||||
select expr.getPredicate(), expr.getLine(), expr, expr.getLhs(), expr.getArity(),
|
||||
count(expr.getARhsPredicate()), count(expr.getARhsVariable())
|
||||
Reference in New Issue
Block a user