Skip to content

Commit

Permalink
Add parser fuzzer and a completely sane test case
Browse files Browse the repository at this point in the history
  • Loading branch information
Kha committed Nov 7, 2014
1 parent fcf505a commit 84fd005
Show file tree
Hide file tree
Showing 3 changed files with 308 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ Directory layout

List of tests/tools (please keep up to date):
* `lexfuzz.py`: lexer fuzzer, prints string to be lexed to stdout, expected result (in --lextest format) to stderr.
* `parsefuzz.scala`: parser fuzzer for positive syntactic test cases, run as `scala parsefuzz.scala`.
117 changes: 117 additions & 0 deletions parsefuzz.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import scala.util.Random
import scala.language.implicitConversions

val maxDepth = 30

var r = new Random()

def choose[A](from: Seq[A]): A = from(r.nextInt(from.length))

abstract class Node {
def produce(depth: Int): Unit

def ? = new Opt(this)
def *(min: Int = 0) = new Star(this, min)
def ++(other: Node): Node = new Concat(this, other)
def | : Node => Node = new Or(this, _)
}

case object IDENT extends Node {
override def produce(depth: Int): Unit = {
System.out.print(choose('a' to 'z'))
}
}

case object INTEGER_LITERAL extends Node {
override def produce(depth: Int): Unit = {
System.out.print(choose('0' to '9'))
}
}

case class Terminal(s: String) extends Node {
override def produce(depth: Int): Unit = {
System.out.print(s)
}
}

implicit def String2Terminal(s: String): Node = new Terminal(s)

case class Or(n1: Node, n2: Node) extends Node {
private def flatten(n: Node): Seq[Node] = n match {
case or: Or => or.flattened
case _ => Seq(n)
}

val flattened: Seq[Node] = flatten(n1) ++ flatten(n2)

override def produce(depth: Int): Unit = {
choose(flattened).produce(depth+1)
}
}

case class Concat(n1: Node, n2: Node) extends Node {
override def produce(depth: Int): Unit = {
n1.produce(depth+1)
n2.produce(depth+1)
}
}

case class Opt(n: Node) extends Node {
override def produce(depth: Int): Unit = {
if (depth < maxDepth && r.nextBoolean()) {
n.produce(depth+1)
}
}
}

case class Star(n: Node, min: Int = 0) extends Node {
override def produce(depth: Int): Unit = {
if (depth >= maxDepth) return
1 to min foreach (_ => n.produce(depth+1))
while (r.nextBoolean()) {
n.produce(depth+1)
}
}
}

class Ind(n: => Node) extends Node {
override def produce(depth: Int): Unit = n.produce(depth)
}

val Ind = new Ind(_)
def OneOf(ss: Seq[String]): Node = ss map Terminal reduce Or

val Program = ClassDeclaration.*(2)
lazy val ClassDeclaration: Node = "class " ++ IDENT ++ " {\n" ++ (" " ++ ClassMember).*(5) ++ "\n}\n\n"
lazy val ClassMember: Node = Field | Method | MainMethod
lazy val Field: Node = "public " ++ Type ++ " " ++ IDENT ++ ";\n"
lazy val MainMethod: Node = "public static void " ++ IDENT ++ "(String[] " ++ IDENT ++ ") " ++ Block
lazy val Method: Node = "public " ++ Type ++ " " ++ IDENT ++ "(" ++ Parameters.? ++ ") " ++ Block
lazy val Parameters: Node = Parameter | Parameter ++ ", " ++ Ind(Parameters)
lazy val Parameter: Node = Type ++ " " ++ IDENT
lazy val Type: Node = Ind(Type) ++ "[]" | BasicType
lazy val BasicType: Node = "int" | "boolean" | "void" | IDENT
lazy val Statement: Node = Block | EmptyStatement | IfStatement | ExpressionStatement | WhileStatement | ReturnStatement
lazy val Block: Node = "{\n " ++ BlockStatement.*() ++ " \n }\n"
lazy val BlockStatement: Node = Ind(Statement) | LocalVariableDeclarationStatement
lazy val LocalVariableDeclarationStatement: Node = Type ++ " " ++ IDENT ++ (" = " ++ Expression).? ++ ";\n "
lazy val EmptyStatement: Node = ";\n "
lazy val WhileStatement: Node = "while (" ++ Expression ++ ")\n " ++ Ind(Statement)
lazy val IfStatement: Node = "if (" ++ Expression ++ ")\n " ++ Ind(Statement) ++ ("else\n " ++ Ind(Statement)).?
lazy val ExpressionStatement: Node = Expression ++ ";\n "
lazy val ReturnStatement: Node = "return " ++ Expression.? ++ ";\n "
lazy val Expression: Node =
Ind(Expression) ++ " " ++ OneOf(List("!=", "*", "+", "-", "/", "<=", "<", "==", "=", ">=", ">", "%", "&&", "||")) ++ " " ++ Ind(Expression) |
UnaryExpression
lazy val UnaryExpression: Node = PostfixExpression | ("!" | "-") ++ Ind(UnaryExpression)
lazy val PostfixExpression: Node = PrimaryExpression ++ PostfixOp.*()
lazy val PostfixOp: Node = MethodInvocation | FieldAccess | ArrayAccess
lazy val MethodInvocation: Node = "." ++ IDENT ++ "(" ++ Arguments ++ ")"
lazy val FieldAccess: Node = "." ++ IDENT
lazy val ArrayAccess: Node = "[" ++ Ind(Expression) ++ "]"
lazy val Arguments: Node = (Ind(Expression) ++ (", " ++ Ind(Expression)).*()).?
lazy val PrimaryExpression: Node = "null" | "false" | "true" | INTEGER_LITERAL | IDENT | IDENT ++ "(" ++ Arguments ++ ")" | "this" | "(" ++ Ind(Expression) ++ ")" | NewObjectExpression | NewArrayExpression
lazy val NewObjectExpression: Node = "new " ++ IDENT ++ "()"
lazy val NewArrayExpression: Node = "new " ++ BasicType ++ "[" ++ Ind(Expression) ++ "]" ++ Terminal("[]").*()

Program.produce(0)
190 changes: 190 additions & 0 deletions pos-parser/sane1.mj
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
class f {
public int r;
public static void m(String[] k) {
{
int i;
boolean w;

}
int h;
!!null;
void k = 1;
boolean[] x = !true;

}
public boolean e;
public int[] w(void a) {

}
public boolean b() {
void k;

}
public static void l(String[] x) {

}

}

class z {
public static void j(String[] j) {

}
public static void f(String[] k) {

}
public boolean n(void[] e, int v) {

}
public static void u(String[] u) {
if (-null != !8)
;
a[] e;
if (new boolean[false].f())
while (-7.k.n()[!5 - !!!!h % new t() < false != --!new a() - -false == true + u < false || -(!!true)][null].e().u.p())
{
return ;

}
int s;
return ;

}
public static void g(String[] k) {
while (----!!2)
{
int d = -q;
{
while (new e())
{

}
{
void p;

}
{

}

}

}
boolean e = !-!-!true * new t() && new int[---new x[o()] >= -true / (-false) / this % !-(!4) != -this].q() < this || z(!w);

}
public void m;
public static void p(String[] d) {
return ;
int z;
int k = !-new boolean[!--!m() && s()[8][(!--g) / -!this == new int[2 || new int[-(-this < 1)] < 3 < 5 || !new int[-!!-new g()] + -f <= -3] >= !true < new boolean[!-null]].u][];

}
public static void a(String[] e) {

}

}

class g {
public static void d(String[] k) {

}
public int s() {

}
public g[] c(boolean l, d x) {
while (i()[!---b()].z.h.k())
return -this <= 4[z[d() % -(r()) + 9 || c].i];

}
public static void z(String[] z) {

}
public w b(int[] m) {
void e = false;

}

}

class i {
public int h;
public boolean y;
public int d(k v, void[][][] x) {
a v;
{
!a(null, this, --null)[!!true < 8].i.o().y[new int[new boolean[-n()] % 9 % --k()] % true == -j()];

}

}
public void g;
public boolean[] u;

}

class u {
public void[] e(k i) {

}
public static void p(String[] a) {
null;

}
public static void z(String[] x) {

}
public static void e(String[] w) {

}
public void y() {
while ((!(2).u() = null[v() == b() + (this) * new r() && !--!(false == null) = !!new int[this != null > !m() / !w] = !6 <= false >= 0 + true * (3) = !-!6 = new c()] >= new int[l][][]))
;

}

}

class c {
public static void e(String[] i) {

}
public static void l(String[] b) {

}
public void s(v v, void[] r, boolean[] m, k[][] j) {

}
public static void z(String[] c) {
void w;

}
public static void t(String[] a) {
{

}

}

}

class r {
public void b() {
j c;

}
public int s(void z) {

}
public y z;
public static void v(String[] q) {
void r = (new w() = true.j);

}
public static void b(String[] d) {

}

}

0 comments on commit 84fd005

Please sign in to comment.