diff options
| author | Adam Goertz <adambgoertz@gmail.com> | 2023-11-04 23:00:28 +0000 |
|---|---|---|
| committer | Adam Goertz <adambgoertz@gmail.com> | 2023-11-06 04:31:55 +0000 |
| commit | 91570cc42d4fe973d15ac05cdecff42051f154ad (patch) | |
| tree | 933200ee149c2557d3739ed7332e59b4e7ca341e /src/reduce | |
| parent | 1b0b46a8a9f5ed3ebaf35e3018fd5402957552ae (diff) | |
| download | zig-91570cc42d4fe973d15ac05cdecff42051f154ad.tar.gz zig-91570cc42d4fe973d15ac05cdecff42051f154ad.zip | |
zig-reduce: Reduce `if` expressions
Perform these transformations in this priority order:
1. If the `else` expression is missing or an empty block, replace the condition with `if (true)` if it is not already.
2. If the `then` block is empty, replace the condition with `if (false)` if it is not already.
3. If the condition is `if (true)`, replace the `if` expression with the contents of the `then` expression.
4. If the condition is `if (false)`, replace the `if` expression with the contents of the `else` expression.
Diffstat (limited to 'src/reduce')
| -rw-r--r-- | src/reduce/Walk.zig | 64 |
1 files changed, 60 insertions, 4 deletions
diff --git a/src/reduce/Walk.zig b/src/reduce/Walk.zig index 94ef0eeb26..1c1a21f993 100644 --- a/src/reduce/Walk.zig +++ b/src/reduce/Walk.zig @@ -27,6 +27,15 @@ pub const Transformation = union(enum) { }, /// Replace an expression with `undefined`. replace_with_undef: Ast.Node.Index, + /// Replace an expression with `true`. + replace_with_true: Ast.Node.Index, + /// Replace an expression with `false`. + replace_with_false: Ast.Node.Index, + /// Replace a node with another node. + replace_node: struct { + to_replace: Ast.Node.Index, + replacement: Ast.Node.Index, + }, /// Replace an `@import` with the imported file contents wrapped in a struct. inline_imported_file: InlineImportedFile, @@ -558,7 +567,7 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void { .if_simple, .@"if", - => return walkIf(w, ast.fullIf(node).?), + => return walkIf(w, node, ast.fullIf(node).?), .asm_simple, .@"asm", @@ -861,8 +870,6 @@ fn walkWhile(w: *Walk, while_node: Ast.full.While) Error!void { try walkExpression(w, while_node.ast.cont_expr); } - try walkExpression(w, while_node.ast.cond_expr); // condition - if (while_node.ast.then_expr != 0) { try walkExpression(w, while_node.ast.then_expr); } @@ -881,7 +888,37 @@ fn walkFor(w: *Walk, for_node: Ast.full.For) Error!void { } } -fn walkIf(w: *Walk, if_node: Ast.full.If) Error!void { +fn walkIf(w: *Walk, node_index: Ast.Node.Index, if_node: Ast.full.If) Error!void { + assert(if_node.ast.cond_expr != 0); + assert(if_node.ast.then_expr != 0); + + // Perform these transformations in this priority order: + // 1. If the `else` expression is missing or an empty block, replace the condition with `if (true)` if it is not already. + // 2. If the `then` block is empty, replace the condition with `if (false)` if it is not already. + // 3. If the condition is `if (true)`, replace the `if` expression with the contents of the `then` expression. + // 4. If the condition is `if (false)`, replace the `if` expression with the contents of the `else` expression. + if (!isTrueIdent(w.ast, if_node.ast.cond_expr) and + (if_node.ast.else_expr == 0 or isEmptyBlock(w.ast, if_node.ast.else_expr))) + { + try w.transformations.ensureUnusedCapacity(1); + w.transformations.appendAssumeCapacity(.{ .replace_with_true = if_node.ast.cond_expr }); + } else if (!isFalseIdent(w.ast, if_node.ast.cond_expr) and isEmptyBlock(w.ast, if_node.ast.then_expr)) { + try w.transformations.ensureUnusedCapacity(1); + w.transformations.appendAssumeCapacity(.{ .replace_with_false = if_node.ast.cond_expr }); + } else if (isTrueIdent(w.ast, if_node.ast.cond_expr)) { + try w.transformations.ensureUnusedCapacity(1); + w.transformations.appendAssumeCapacity(.{ .replace_node = .{ + .to_replace = node_index, + .replacement = if_node.ast.then_expr, + } }); + } else if (isFalseIdent(w.ast, if_node.ast.cond_expr)) { + try w.transformations.ensureUnusedCapacity(1); + w.transformations.appendAssumeCapacity(.{ .replace_node = .{ + .to_replace = node_index, + .replacement = if_node.ast.else_expr, + } }); + } + try walkExpression(w, if_node.ast.cond_expr); // condition if (if_node.ast.then_expr != 0) { @@ -1002,6 +1039,14 @@ fn isUndefinedIdent(ast: *const Ast, node: Ast.Node.Index) bool { return isMatchingIdent(ast, node, "undefined"); } +fn isTrueIdent(ast: *const Ast, node: Ast.Node.Index) bool { + return isMatchingIdent(ast, node, "true"); +} + +fn isFalseIdent(ast: *const Ast, node: Ast.Node.Index) bool { + return isMatchingIdent(ast, node, "false"); +} + fn isMatchingIdent(ast: *const Ast, node: Ast.Node.Index, string: []const u8) bool { const node_tags = ast.nodes.items(.tag); const main_tokens = ast.nodes.items(.main_token); @@ -1014,3 +1059,14 @@ fn isMatchingIdent(ast: *const Ast, node: Ast.Node.Index, string: []const u8) bo else => return false, } } + +fn isEmptyBlock(ast: *const Ast, node: Ast.Node.Index) bool { + const node_tags = ast.nodes.items(.tag); + const node_data = ast.nodes.items(.data); + switch (node_tags[node]) { + .block_two => { + return node_data[node].lhs == 0 and node_data[node].rhs == 0; + }, + else => return false, + } +} |
