Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First version of partial evaluator: support for +,-,* operators and associative rules #528

Merged
merged 25 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
fa5bb05
First commit for partial evaluator.
jeshecdom Jun 28, 2024
aae1dd0
Finished associative rule 3. Refactored Rule type into an interface. …
jeshecdom Jul 2, 2024
4533de6
Merge branch 'partial_evaluator'. Resolved conflicts in constEval. Ad…
jeshecdom Jul 2, 2024
34970cb
Added jest test cases for partial evaluator.
jeshecdom Jul 4, 2024
a109d38
Merge branch 'main' of https://github.com/tact-lang/tact
jeshecdom Jul 4, 2024
99b687f
Fixes for the linter, spell checker, and code prettifier.
jeshecdom Jul 4, 2024
2688771
Fixed another linter problem.
jeshecdom Jul 4, 2024
9e871ca
Merge branch 'main' of https://github.com/tact-lang/tact
jeshecdom Jul 5, 2024
bd89e02
Merge branch 'main' into partial_evaluator
jeshecdom Jul 5, 2024
cdb7cb2
Fixed compilation errors after merge.
jeshecdom Jul 5, 2024
15998a5
Merge branch 'main' into partial_evaluator
jeshecdom Jul 5, 2024
bfb37af
Fixed problems pointed out by linter and prettier.
jeshecdom Jul 5, 2024
648f188
- Changed all `Ref` in parameters for `Loc`. (https://github.com/tact…
jeshecdom Jul 5, 2024
0426245
fixes due to linter and prettier.
jeshecdom Jul 5, 2024
e207389
Merge branch 'main' of https://github.com/tact-lang/tact
jeshecdom Jul 5, 2024
82a9873
Merge branch 'main' into partial_evaluator
jeshecdom Jul 5, 2024
45289f8
- Added try/catch in switch of eqExpressions in ast.ts.
jeshecdom Jul 12, 2024
8d7b977
Merge branch 'main' of https://github.com/tact-lang/tact
jeshecdom Jul 12, 2024
0c77158
Merge branch 'main' into partial_evaluator
jeshecdom Jul 12, 2024
9405f98
Forgot to add test cases for initOf.
jeshecdom Jul 12, 2024
e10a838
Fixed problems indicated by knit.
jeshecdom Jul 12, 2024
8991852
- Moved `isValue` to ast.ts.
jeshecdom Jul 15, 2024
2ebd128
Merge branch 'main' of https://github.com/tact-lang/tact
jeshecdom Jul 15, 2024
4204dc0
Merge branch 'main' into partial_evaluator
jeshecdom Jul 15, 2024
607da81
Fixed compilation error after merge with main.
jeshecdom Jul 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
344 changes: 248 additions & 96 deletions src/constEval.ts

Large diffs are not rendered by default.

312 changes: 312 additions & 0 deletions src/grammar/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -679,4 +679,316 @@ export function __DANGER_resetNodeId() {
nextId = 1;
}

// Test equality of AstExpressions.
export function eqExpressions(
ast1: AstExpression,
ast2: AstExpression,
): boolean {
if (ast1.kind !== ast2.kind) {
return false;
}

try {
switch (ast1.kind) {
case "null":
return true;
case "boolean":
return ast1.value === (ast2 as AstBoolean).value;
case "number":
return ast1.value === (ast2 as AstNumber).value;
case "string":
return ast1.value === (ast2 as AstString).value;
case "id":
return eqNames(ast1, ast2 as AstId);
case "method_call":
return (
eqNames(ast1.method, (ast2 as AstMethodCall).method) &&
eqExpressions(ast1.self, (ast2 as AstMethodCall).self) &&
eqExpressionArrays(ast1.args, (ast2 as AstMethodCall).args)
);
case "init_of":
return (
eqNames(ast1.contract, (ast2 as AstInitOf).contract) &&
eqExpressionArrays(ast1.args, (ast2 as AstInitOf).args)
);
case "op_unary":
return (
ast1.op === (ast2 as AstOpUnary).op &&
eqExpressions(ast1.operand, (ast2 as AstOpUnary).operand)
);
case "op_binary":
return (
ast1.op === (ast2 as AstOpBinary).op &&
eqExpressions(ast1.left, (ast2 as AstOpBinary).left) &&
eqExpressions(ast1.right, (ast2 as AstOpBinary).right)
);
case "conditional":
return (
eqExpressions(
ast1.condition,
(ast2 as AstConditional).condition,
) &&
eqExpressions(
ast1.thenBranch,
(ast2 as AstConditional).thenBranch,
) &&
eqExpressions(
ast1.elseBranch,
(ast2 as AstConditional).elseBranch,
)
);
case "struct_instance":
return (
eqNames(ast1.type, (ast2 as AstStructInstance).type) &&
eqParameterArrays(
ast1.args,
(ast2 as AstStructInstance).args,
)
);
case "field_access":
return (
eqNames(ast1.field, (ast2 as AstFieldAccess).field) &&
eqExpressions(
ast1.aggregate,
(ast2 as AstFieldAccess).aggregate,
)
);
case "static_call":
return (
eqNames(ast1.function, (ast2 as AstStaticCall).function) &&
eqExpressionArrays(ast1.args, (ast2 as AstStaticCall).args)
);
}
} catch (e) {
// In principle, the assertions "as Ast___" should not fail
// because ast1 and ast2 have the same kind inside the switch.
return false;
anton-trunov marked this conversation as resolved.
Show resolved Hide resolved
}
}

function eqParameters(
arg1: AstStructFieldInitializer,
arg2: AstStructFieldInitializer,
): boolean {
return (
eqNames(arg1.field, arg2.field) &&
eqExpressions(arg1.initializer, arg2.initializer)
);
}

function eqParameterArrays(
arr1: AstStructFieldInitializer[],
arr2: AstStructFieldInitializer[],
): boolean {
if (arr1.length !== arr2.length) {
return false;
}

for (let i = 0; i < arr1.length; i++) {
if (!eqParameters(arr1[i]!, arr2[i]!)) {
return false;
}
}

return true;
}

function eqExpressionArrays(
arr1: AstExpression[],
arr2: AstExpression[],
): boolean {
if (arr1.length !== arr2.length) {
return false;
}

for (let i = 0; i < arr1.length; i++) {
if (!eqExpressions(arr1[i]!, arr2[i]!)) {
return false;
}
}

return true;
}

export function traverse(node: AstNode, callback: (node: AstNode) => void) {
anton-trunov marked this conversation as resolved.
Show resolved Hide resolved
callback(node);

if (node.kind === "module") {
for (const e of node.items) {
traverse(e, callback);
}
}
if (node.kind === "contract") {
for (const e of node.declarations) {
traverse(e, callback);
}
}
if (node.kind === "struct_decl") {
for (const e of node.fields) {
traverse(e, callback);
}
}
if (node.kind === "message_decl") {
for (const e of node.fields) {
traverse(e, callback);
}
}
if (node.kind === "trait") {
for (const e of node.declarations) {
traverse(e, callback);
}
}

//
// Functions
//

if (node.kind === "function_def") {
for (const e of node.params) {
traverse(e, callback);
}
for (const e of node.statements) {
traverse(e, callback);
}
}
if (node.kind === "function_decl") {
for (const e of node.params) {
traverse(e, callback);
}
}
if (node.kind === "contract_init") {
for (const e of node.params) {
traverse(e, callback);
}
for (const e of node.statements) {
traverse(e, callback);
}
}
if (node.kind === "receiver") {
for (const e of node.statements) {
traverse(e, callback);
}
}
if (node.kind === "native_function_decl") {
for (const e of node.params) {
traverse(e, callback);
}
}
if (node.kind === "field_decl") {
if (node.initializer) {
traverse(node.initializer, callback);
}
}
if (node.kind === "constant_def") {
traverse(node.initializer, callback);
}

//
// Statements
//

if (node.kind === "statement_let") {
traverse(node.expression, callback);
}
if (node.kind === "statement_return") {
if (node.expression) {
traverse(node.expression, callback);
}
}
if (node.kind === "statement_expression") {
traverse(node.expression, callback);
}
if (node.kind === "statement_assign") {
traverse(node.path, callback);
traverse(node.expression, callback);
}
if (node.kind === "statement_augmentedassign") {
traverse(node.path, callback);
traverse(node.expression, callback);
}
if (node.kind === "statement_condition") {
traverse(node.condition, callback);
for (const e of node.trueStatements) {
traverse(e, callback);
}
if (node.falseStatements) {
for (const e of node.falseStatements) {
traverse(e, callback);
}
}
if (node.elseif) {
traverse(node.elseif, callback);
}
}
if (node.kind === "statement_while") {
traverse(node.condition, callback);
for (const e of node.statements) {
traverse(e, callback);
}
}
if (node.kind === "statement_until") {
traverse(node.condition, callback);
for (const e of node.statements) {
traverse(e, callback);
}
}
if (node.kind === "statement_repeat") {
traverse(node.iterations, callback);
for (const e of node.statements) {
traverse(e, callback);
}
}
if (node.kind === "statement_try") {
for (const e of node.statements) {
traverse(e, callback);
}
}
if (node.kind === "statement_try_catch") {
for (const e of node.statements) {
traverse(e, callback);
}
for (const e of node.catchStatements) {
traverse(e, callback);
}
}
if (node.kind === "statement_foreach") {
for (const e of node.statements) {
traverse(e, callback);
}
}
if (node.kind === "op_binary") {
traverse(node.left, callback);
traverse(node.right, callback);
}
if (node.kind === "op_unary") {
traverse(node.operand, callback);
}
if (node.kind === "field_access") {
traverse(node.aggregate, callback);
}
if (node.kind === "method_call") {
traverse(node.self, callback);
for (const e of node.args) {
traverse(e, callback);
}
}
if (node.kind === "static_call") {
for (const e of node.args) {
traverse(e, callback);
}
}
if (node.kind === "struct_instance") {
for (const e of node.args) {
traverse(e, callback);
}
}
if (node.kind === "struct_field_initializer") {
traverse(node.initializer, callback);
}
if (node.kind === "conditional") {
traverse(node.condition, callback);
traverse(node.thenBranch, callback);
traverse(node.elseBranch, callback);
}
}
export { SrcInfo };
Loading
Loading