Skip to content

Commit

Permalink
test: Start validate parser with random generated AST expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
xpyctumo committed Dec 26, 2024
1 parent 911e7f0 commit 9d957f0
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 2 deletions.
3 changes: 2 additions & 1 deletion cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@
"Ints",
"workchain",
"xffff",
"привет"
"привет",
"letrec"
],
"ignoreRegExpList": [
"\\b[xB]\\{[a-fA-F0-9]*_?\\}", // binary literals in Fift-asm
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
"cross-env": "^7.0.3",
"cspell": "^8.8.3",
"eslint": "^8.56.0",
"fast-check": "^3.23.2",
"glob": "^8.1.0",
"husky": "^9.1.5",
"jest": "^29.3.1",
Expand Down
119 changes: 119 additions & 0 deletions src/test/prettyPrint/expressions.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import fc from "fast-check";
import {
AstConditional,
AstExpression,
AstNumber,
AstOpBinary,
AstOpUnary,
eqExpressions,
getAstFactory,
} from "../../grammar/ast";
import { prettyPrint } from "../../prettyPrinter";
import { dummySrcInfo, getParser } from "../../grammar";

describe("Pretty Print Expressions", () => {
// Max depth of the expression tree
const maxShrinks = 15;

const generateAstNumber = () =>
fc.record({
kind: fc.constant("number"),
base: fc.constantFrom(2, 8, 10, 16),
value: fc.bigInt().filter((n) => n > 0),
id: fc.constant(0),
loc: fc.constant(dummySrcInfo),
}) as fc.Arbitrary<AstNumber>;

const generateAstOpUnary = (expression: fc.Arbitrary<AstExpression>) =>
fc.record({
kind: fc.constant("op_unary"),
op: fc.constantFrom("+", "-", "!", "!!", "~"),
operand: expression,
id: fc.constant(0),
loc: fc.constant(dummySrcInfo),
}) as fc.Arbitrary<AstOpUnary>;

const generateAstOpBinary = (expression: fc.Arbitrary<AstExpression>) =>
fc.record({
kind: fc.constant("op_binary"),
op: fc.constantFrom(
"+",
"-",
"*",
"/",
"!=",
">",
"<",
">=",
"<=",
"==",
"&&",
"||",
"%",
"<<",
">>",
"&",
"|",
"^",
),
left: expression,
right: expression,
id: fc.constant(0),
loc: fc.constant(dummySrcInfo),
}) as fc.Arbitrary<AstOpBinary>;

const generateAstConditional = (expression: fc.Arbitrary<AstExpression>) =>
fc.record({
kind: fc.constant("conditional"),
condition: expression,
thenBranch: expression,
elseBranch: expression,
id: fc.constant(0),
loc: fc.constant(dummySrcInfo),
}) as fc.Arbitrary<AstConditional>;

const generateAstExpression: fc.Arbitrary<AstExpression> = fc.letrec(
(tie) => ({
AstExpression: fc.oneof(
generateAstNumber(),
tie("AstOpUnary") as fc.Arbitrary<AstOpUnary>,
tie("AstOpBinary") as fc.Arbitrary<AstOpBinary>,
tie("AstConditional") as fc.Arbitrary<AstConditional>,
),
AstOpUnary: fc.limitShrink(
generateAstOpUnary(
tie("AstExpression") as fc.Arbitrary<AstExpression>,
),
maxShrinks,
),
AstOpBinary: fc.limitShrink(
generateAstOpBinary(
tie("AstExpression") as fc.Arbitrary<AstExpression>,
),
maxShrinks,
),
AstConditional: fc.limitShrink(
generateAstConditional(
tie("AstExpression") as fc.Arbitrary<AstExpression>,
),
maxShrinks,
),
}),
).AstExpression;
it.each([
["AstConditional", generateAstConditional(generateAstExpression)],
["AstOpBinary", generateAstOpBinary(generateAstExpression)],
["AstOpUnary", generateAstOpUnary(generateAstExpression)],
])("should parse random %s expression", (_, astGenerator) => {
fc.assert(
fc.property(astGenerator, (astBefore) => {
const prettyBefore = prettyPrint(astBefore);
const astFactory = getAstFactory();
const parser = getParser(astFactory);
const astAfter = parser.parseExpression(prettyBefore);
expect(eqExpressions(astBefore, astAfter)).toBe(true);
}),
{ seed: 1 },
);
});
});
9 changes: 8 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2756,6 +2756,13 @@ external-editor@^3.1.0:
iconv-lite "^0.4.24"
tmp "^0.0.33"

fast-check@^3.23.2:
version "3.23.2"
resolved "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz#0129f1eb7e4f500f58e8290edc83c670e4a574a2"
integrity sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==
dependencies:
pure-rand "^6.1.0"

fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz"
Expand Down Expand Up @@ -4795,7 +4802,7 @@ pupa@^3.1.0:
dependencies:
escape-goat "^4.0.0"

pure-rand@^6.0.0:
pure-rand@^6.0.0, pure-rand@^6.1.0:
version "6.1.0"
resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz"
integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==
Expand Down

0 comments on commit 9d957f0

Please sign in to comment.