diff --git a/src/internals/tactIRBuilder.ts b/src/internals/tactIRBuilder.ts index 3a09e134..6be5a584 100644 --- a/src/internals/tactIRBuilder.ts +++ b/src/internals/tactIRBuilder.ts @@ -233,6 +233,13 @@ export class AstMapper { case "statement_foreach": stmt.statements.forEach((s) => this.processStmt(s)); break; + case "statement_try": + stmt.statements.forEach((s) => this.processStmt(s)); + break; + case "statement_try_catch": + stmt.statements.forEach((s) => this.processStmt(s)); + stmt.catchStatements.forEach((s) => this.processStmt(s)); + break; default: throw InternalException.make("Unsupported statement", { node: stmt }); } @@ -649,6 +656,41 @@ export class TactIRBuilder { } // Connect condition with the statement after loop. lastNodeIdxes = [newNode.idx]; + } else if ( + stmt.kind === "statement_try" || + stmt.kind === "statement_try_catch" + ) { + // Process the try branch. + const [tryNodes, tryEdges] = this.processStatements( + stmt.statements, + nodes, + edges, + [newNode.idx], + ); + nodes = tryNodes; + edges = tryEdges; + // Connect the last try block with statements after this `try` block or + // with `try` itself if it is empty. + lastNodeIdxes = + tryNodes.length > 0 + ? [tryNodes[tryNodes.length - 1].idx] + : [newNode.idx]; + + // Handle the `catch` clause. + if (stmt.kind === "statement_try_catch") { + const [catchNodes, catchEdges] = this.processStatements( + stmt.catchStatements, + nodes, + edges, + [newNode.idx], + ); + nodes = catchNodes; + edges = catchEdges; + // Catch block always terminates execution. + if (catchNodes.length > 0) { + tryNodes[tryNodes.length - 1].kind = { kind: "return" }; + } + } } else if (stmt.kind === "statement_return") { // No need to connect return statements to subsequent nodes lastNodeIdxes = []; diff --git a/test/contracts/try-1.cfg.dot b/test/contracts/try-1.cfg.dot new file mode 100644 index 00000000..7b8051d0 --- /dev/null +++ b/test/contracts/try-1.cfg.dot @@ -0,0 +1,13 @@ +digraph "try-1" { + node [shape=box]; + subgraph "cluster_test" { + label="test"; + "test_141" [label="let a: Int = 42"]; + "test_142" [label="try"]; + "test_144" [label="a += 1"]; + "test_146" [label="return 42",style=filled,fillcolor="#66A7DB"]; + "test_141" -> "test_142"; + "test_142" -> "test_144"; + "test_144" -> "test_146"; + } +} diff --git a/test/contracts/try-1.cfg.json b/test/contracts/try-1.cfg.json new file mode 100644 index 00000000..2da8fec4 --- /dev/null +++ b/test/contracts/try-1.cfg.json @@ -0,0 +1,66 @@ +{ + "projectName": "try-1", + "functions": [ + { + "name": "test", + "cfg": { + "nodes": [ + { + "id": 141, + "stmtID": 58765, + "srcEdges": [], + "dstEdges": [ + 143 + ] + }, + { + "id": 142, + "stmtID": 58769, + "srcEdges": [ + 143 + ], + "dstEdges": [ + 145 + ] + }, + { + "id": 144, + "stmtID": 58768, + "srcEdges": [ + 145 + ], + "dstEdges": [ + 147 + ] + }, + { + "id": 146, + "stmtID": 58771, + "srcEdges": [ + 147 + ], + "dstEdges": [] + } + ], + "edges": [ + { + "id": 143, + "src": 141, + "dst": 142 + }, + { + "id": 145, + "src": 142, + "dst": 144 + }, + { + "id": 147, + "src": 144, + "dst": 146 + } + ] + } + } + ], + "contracts": [] +} \ No newline at end of file diff --git a/test/contracts/try-1.expected.out b/test/contracts/try-1.expected.out new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/contracts/try-1.expected.out @@ -0,0 +1 @@ + diff --git a/test/contracts/try-1.tact b/test/contracts/try-1.tact new file mode 100644 index 00000000..4ae0e623 --- /dev/null +++ b/test/contracts/try-1.tact @@ -0,0 +1,7 @@ +fun test(): Int { + let a: Int = 42; + try { + a += 1; + } + return 42; +} diff --git a/test/contracts/try-2.cfg.dot b/test/contracts/try-2.cfg.dot new file mode 100644 index 00000000..5d5051fa --- /dev/null +++ b/test/contracts/try-2.cfg.dot @@ -0,0 +1,9 @@ +digraph "try-2" { + node [shape=box]; + subgraph "cluster_test" { + label="test"; + "test_141" [label="try"]; + "test_142" [label="return 42",style=filled,fillcolor="#66A7DB"]; + "test_141" -> "test_142"; + } +} diff --git a/test/contracts/try-2.cfg.json b/test/contracts/try-2.cfg.json new file mode 100644 index 00000000..48cd617b --- /dev/null +++ b/test/contracts/try-2.cfg.json @@ -0,0 +1,36 @@ +{ + "projectName": "try-2", + "functions": [ + { + "name": "test", + "cfg": { + "nodes": [ + { + "id": 141, + "stmtID": 61840, + "srcEdges": [], + "dstEdges": [ + 143 + ] + }, + { + "id": 142, + "stmtID": 61842, + "srcEdges": [ + 143 + ], + "dstEdges": [] + } + ], + "edges": [ + { + "id": 143, + "src": 141, + "dst": 142 + } + ] + } + } + ], + "contracts": [] +} \ No newline at end of file diff --git a/test/contracts/try-2.expected.out b/test/contracts/try-2.expected.out new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/contracts/try-2.expected.out @@ -0,0 +1 @@ + diff --git a/test/contracts/try-2.tact b/test/contracts/try-2.tact new file mode 100644 index 00000000..0b791ec5 --- /dev/null +++ b/test/contracts/try-2.tact @@ -0,0 +1,5 @@ +fun test(): Int { + try { /* empty */ } + return 42; +} + diff --git a/test/contracts/try-3.cfg.dot b/test/contracts/try-3.cfg.dot new file mode 100644 index 00000000..8b7b139c --- /dev/null +++ b/test/contracts/try-3.cfg.dot @@ -0,0 +1,15 @@ +digraph "try-3" { + node [shape=box]; + subgraph "cluster_test" { + label="test"; + "test_141" [label="let a: Int = 0"]; + "test_142" [label="try ... catch (err)"]; + "test_144" [label="a = 19"]; + "test_146" [label="dump(err)",style=filled,fillcolor="#66A7DB"]; + "test_148" [label="return a",style=filled,fillcolor="#66A7DB"]; + "test_141" -> "test_142"; + "test_142" -> "test_144"; + "test_142" -> "test_146"; + "test_144" -> "test_148"; + } +} diff --git a/test/contracts/try-3.cfg.json b/test/contracts/try-3.cfg.json new file mode 100644 index 00000000..ff181259 --- /dev/null +++ b/test/contracts/try-3.cfg.json @@ -0,0 +1,80 @@ +{ + "projectName": "try-3", + "functions": [ + { + "name": "test", + "cfg": { + "nodes": [ + { + "id": 141, + "stmtID": 64907, + "srcEdges": [], + "dstEdges": [ + 143 + ] + }, + { + "id": 142, + "stmtID": 64916, + "srcEdges": [ + 143 + ], + "dstEdges": [ + 145, + 147 + ] + }, + { + "id": 144, + "stmtID": 64910, + "srcEdges": [ + 145 + ], + "dstEdges": [ + 149 + ] + }, + { + "id": 146, + "stmtID": 64915, + "srcEdges": [ + 147 + ], + "dstEdges": [] + }, + { + "id": 148, + "stmtID": 64918, + "srcEdges": [ + 149 + ], + "dstEdges": [] + } + ], + "edges": [ + { + "id": 143, + "src": 141, + "dst": 142 + }, + { + "id": 145, + "src": 142, + "dst": 144 + }, + { + "id": 147, + "src": 142, + "dst": 146 + }, + { + "id": 149, + "src": 144, + "dst": 148 + } + ] + } + } + ], + "contracts": [] +} \ No newline at end of file diff --git a/test/contracts/try-3.expected.out b/test/contracts/try-3.expected.out new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/contracts/try-3.expected.out @@ -0,0 +1 @@ + diff --git a/test/contracts/try-3.tact b/test/contracts/try-3.tact new file mode 100644 index 00000000..da3ea8b9 --- /dev/null +++ b/test/contracts/try-3.tact @@ -0,0 +1,10 @@ +fun test(): Int { + let a: Int = 0; + try { + a = 19; + } catch (err) { + dump(err); + } + return a; +} + diff --git a/test/contracts/unbound-loop-1.cfg.json b/test/contracts/unbound-loop-1.cfg.json index dff36518..fb36b4d9 100644 --- a/test/contracts/unbound-loop-1.cfg.json +++ b/test/contracts/unbound-loop-1.cfg.json @@ -7,7 +7,7 @@ "nodes": [ { "id": 141, - "stmtID": 58765, + "stmtID": 67995, "srcEdges": [], "dstEdges": [ 143 @@ -15,7 +15,7 @@ }, { "id": 142, - "stmtID": 58769, + "stmtID": 67999, "srcEdges": [ 143, 144 @@ -27,7 +27,7 @@ }, { "id": 145, - "stmtID": 58771, + "stmtID": 68001, "srcEdges": [ 146 ], diff --git a/test/contracts/unbound-loop-2.cfg.json b/test/contracts/unbound-loop-2.cfg.json index 1cabeaad..f049e841 100644 --- a/test/contracts/unbound-loop-2.cfg.json +++ b/test/contracts/unbound-loop-2.cfg.json @@ -7,7 +7,7 @@ "nodes": [ { "id": 141, - "stmtID": 61843, + "stmtID": 71073, "srcEdges": [], "dstEdges": [ 143 @@ -15,7 +15,7 @@ }, { "id": 142, - "stmtID": 61847, + "stmtID": 71077, "srcEdges": [ 143, 144 @@ -27,7 +27,7 @@ }, { "id": 145, - "stmtID": 61849, + "stmtID": 71079, "srcEdges": [ 146 ], diff --git a/test/contracts/unbound-loop-3.cfg.json b/test/contracts/unbound-loop-3.cfg.json index 2031e59b..8ab58803 100644 --- a/test/contracts/unbound-loop-3.cfg.json +++ b/test/contracts/unbound-loop-3.cfg.json @@ -7,7 +7,7 @@ "nodes": [ { "id": 141, - "stmtID": 64921, + "stmtID": 74151, "srcEdges": [], "dstEdges": [ 143 @@ -15,7 +15,7 @@ }, { "id": 142, - "stmtID": 64928, + "stmtID": 74158, "srcEdges": [ 143, 146 @@ -27,7 +27,7 @@ }, { "id": 144, - "stmtID": 64927, + "stmtID": 74157, "srcEdges": [ 145 ], @@ -37,7 +37,7 @@ }, { "id": 147, - "stmtID": 64930, + "stmtID": 74160, "srcEdges": [ 148 ], diff --git a/test/contracts/unbound-loop-4.cfg.json b/test/contracts/unbound-loop-4.cfg.json index 8a8643aa..b142cd39 100644 --- a/test/contracts/unbound-loop-4.cfg.json +++ b/test/contracts/unbound-loop-4.cfg.json @@ -14,7 +14,7 @@ "nodes": [ { "id": 142, - "stmtID": 68010, + "stmtID": 77240, "srcEdges": [], "dstEdges": [ 144 @@ -22,7 +22,7 @@ }, { "id": 143, - "stmtID": 68018, + "stmtID": 77248, "srcEdges": [ 144, 147 @@ -34,7 +34,7 @@ }, { "id": 145, - "stmtID": 68017, + "stmtID": 77247, "srcEdges": [ 146 ], @@ -44,7 +44,7 @@ }, { "id": 148, - "stmtID": 68020, + "stmtID": 77250, "srcEdges": [ 149 ], diff --git a/test/contracts/zero-address.cfg.dot b/test/contracts/zero-address.cfg.dot index 39f47974..ab9be097 100644 --- a/test/contracts/zero-address.cfg.dot +++ b/test/contracts/zero-address.cfg.dot @@ -1,7 +1,7 @@ digraph "zero-address" { node [shape=box]; - subgraph "cluster_SampleContract__init_72757" { - label="SampleContract__init_72757"; - "SampleContract__init_72757_141" [label="newAddress(1, 0)"]; + subgraph "cluster_SampleContract__init_81987" { + label="SampleContract__init_81987"; + "SampleContract__init_81987_141" [label="newAddress(1, 0)"]; } } diff --git a/test/contracts/zero-address.cfg.json b/test/contracts/zero-address.cfg.json index dfebe9ef..f13c899b 100644 --- a/test/contracts/zero-address.cfg.json +++ b/test/contracts/zero-address.cfg.json @@ -6,12 +6,12 @@ "name": "SampleContract", "methods": [ { - "name": "SampleContract.init_71103", + "name": "SampleContract.init_80333", "cfg": { "nodes": [ { "id": 141, - "stmtID": 71101, + "stmtID": 80331, "srcEdges": [], "dstEdges": [] }