Skip to content

Commit

Permalink
breaking syntax change: orelse keyword instead of ?? (#1096)
Browse files Browse the repository at this point in the history
use the `zig-fmt-optional-default` branch to have zig fmt
automatically do the changes.

closes #1023
  • Loading branch information
andrewrk committed Jun 10, 2018
1 parent ec1b6f6 commit 77678b2
Show file tree
Hide file tree
Showing 33 changed files with 187 additions and 189 deletions.
6 changes: 3 additions & 3 deletions build.zig
Expand Up @@ -102,19 +102,19 @@ pub fn build(b: *Builder) !void {

b.default_step.dependOn(&exe.step);

const skip_self_hosted = b.option(bool, "skip-self-hosted", "Main test suite skips building self hosted compiler") ?? false;
const skip_self_hosted = b.option(bool, "skip-self-hosted", "Main test suite skips building self hosted compiler") orelse false;
if (!skip_self_hosted) {
test_step.dependOn(&exe.step);
}
const verbose_link_exe = b.option(bool, "verbose-link", "Print link command for self hosted compiler") ?? false;
const verbose_link_exe = b.option(bool, "verbose-link", "Print link command for self hosted compiler") orelse false;
exe.setVerboseLink(verbose_link_exe);

b.installArtifact(exe);
installStdLib(b, std_files);
installCHeaders(b, c_header_files);

const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");
const with_lldb = b.option(bool, "with-lldb", "Run tests in LLDB to get a backtrace if one fails") ?? false;
const with_lldb = b.option(bool, "with-lldb", "Run tests in LLDB to get a backtrace if one fails") orelse false;

test_step.dependOn(docs_step);

Expand Down
6 changes: 3 additions & 3 deletions doc/docgen.zig
Expand Up @@ -25,13 +25,13 @@ pub fn main() !void {

if (!args_it.skip()) @panic("expected self arg");

const zig_exe = try (args_it.next(allocator) ?? @panic("expected zig exe arg"));
const zig_exe = try (args_it.next(allocator) orelse @panic("expected zig exe arg"));
defer allocator.free(zig_exe);

const in_file_name = try (args_it.next(allocator) ?? @panic("expected input arg"));
const in_file_name = try (args_it.next(allocator) orelse @panic("expected input arg"));
defer allocator.free(in_file_name);

const out_file_name = try (args_it.next(allocator) ?? @panic("expected output arg"));
const out_file_name = try (args_it.next(allocator) orelse @panic("expected output arg"));
defer allocator.free(out_file_name);

var in_file = try os.File.openRead(allocator, in_file_name);
Expand Down
16 changes: 8 additions & 8 deletions doc/langref.html.in
Expand Up @@ -985,7 +985,7 @@ a ^= b</code></pre></td>
</td>
</tr>
<tr>
<td><pre><code class="zig">a ?? b</code></pre></td>
<td><pre><code class="zig">a orelse b</code></pre></td>
<td>
<ul>
<li>{#link|Optionals#}</li>
Expand All @@ -998,7 +998,7 @@ a ^= b</code></pre></td>
</td>
<td>
<pre><code class="zig">const value: ?u32 = null;
const unwrapped = value ?? 1234;
const unwrapped = value orelse 1234;
unwrapped == 1234</code></pre>
</td>
</tr>
Expand All @@ -1011,7 +1011,7 @@ unwrapped == 1234</code></pre>
</td>
<td>
Equivalent to:
<pre><code class="zig">a ?? unreachable</code></pre>
<pre><code class="zig">a orelse unreachable</code></pre>
</td>
<td>
<pre><code class="zig">const value: ?u32 = 5678;
Expand Down Expand Up @@ -1278,7 +1278,7 @@ x{} x.* x.?
== != &lt; &gt; &lt;= &gt;=
and
or
?? catch
orelse catch
= *= /= %= += -= &lt;&lt;= &gt;&gt;= &amp;= ^= |=</code></pre>
{#header_close#}
{#header_close#}
Expand Down Expand Up @@ -3062,7 +3062,7 @@ fn createFoo(param: i32) !Foo {
// but we want to return it if the function succeeds.
errdefer deallocateFoo(foo);

const tmp_buf = allocateTmpBuffer() ?? return error.OutOfMemory;
const tmp_buf = allocateTmpBuffer() orelse return error.OutOfMemory;
// tmp_buf is truly a temporary resource, and we for sure want to clean it up
// before this block leaves scope
defer deallocateTmpBuffer(tmp_buf);
Expand Down Expand Up @@ -3219,13 +3219,13 @@ struct Foo *do_a_thing(void) {
extern fn malloc(size: size_t) ?*u8;

fn doAThing() ?*Foo {
const ptr = malloc(1234) ?? return null;
const ptr = malloc(1234) orelse return null;
// ...
}
{#code_end#}
<p>
Here, Zig is at least as convenient, if not more, than C. And, the type of "ptr"
is <code>*u8</code> <em>not</em> <code>?*u8</code>. The <code>??</code> operator
is <code>*u8</code> <em>not</em> <code>?*u8</code>. The <code>orelse</code> keyword
unwrapped the optional type and therefore <code>ptr</code> is guaranteed to be non-null everywhere
it is used in the function.
</p>
Expand Down Expand Up @@ -5941,7 +5941,7 @@ AsmClobbers= ":" list(String, ",")

UnwrapExpression = BoolOrExpression (UnwrapOptional | UnwrapError) | BoolOrExpression

UnwrapOptional = "??" Expression
UnwrapOptional = "orelse" Expression

UnwrapError = "catch" option("|" Symbol "|") Expression

Expand Down
14 changes: 7 additions & 7 deletions src-self-hosted/main.zig
Expand Up @@ -212,7 +212,7 @@ fn cmdBuild(allocator: *Allocator, args: []const []const u8) !void {
const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig");
defer allocator.free(build_runner_path);

const build_file = flags.single("build-file") ?? "build.zig";
const build_file = flags.single("build-file") orelse "build.zig";
const build_file_abs = try os.path.resolve(allocator, ".", build_file);
defer allocator.free(build_file_abs);

Expand Down Expand Up @@ -516,7 +516,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo

const basename = os.path.basename(in_file.?);
var it = mem.split(basename, ".");
const root_name = it.next() ?? {
const root_name = it.next() orelse {
try stderr.write("file name cannot be empty\n");
os.exit(1);
};
Expand All @@ -535,7 +535,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo

const zig_root_source_file = in_file;

const full_cache_dir = os.path.resolve(allocator, ".", flags.single("cache-dir") ?? "zig-cache"[0..]) catch {
const full_cache_dir = os.path.resolve(allocator, ".", flags.single("cache-dir") orelse "zig-cache"[0..]) catch {
os.exit(1);
};
defer allocator.free(full_cache_dir);
Expand All @@ -555,9 +555,9 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
);
defer module.destroy();

module.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") ?? "0", 10);
module.version_minor = try std.fmt.parseUnsigned(u32, flags.single("ver-minor") ?? "0", 10);
module.version_patch = try std.fmt.parseUnsigned(u32, flags.single("ver-patch") ?? "0", 10);
module.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") orelse "0", 10);
module.version_minor = try std.fmt.parseUnsigned(u32, flags.single("ver-minor") orelse "0", 10);
module.version_patch = try std.fmt.parseUnsigned(u32, flags.single("ver-patch") orelse "0", 10);

module.is_test = false;

Expand Down Expand Up @@ -652,7 +652,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
}

try module.build();
try module.link(flags.single("out-file") ?? null);
try module.link(flags.single("out-file") orelse null);

if (flags.present("print-timing-info")) {
// codegen_print_timing_info(g, stderr);
Expand Down
8 changes: 4 additions & 4 deletions src-self-hosted/module.zig
Expand Up @@ -130,13 +130,13 @@ pub const Module = struct {
var name_buffer = try Buffer.init(allocator, name);
errdefer name_buffer.deinit();

const context = c.LLVMContextCreate() ?? return error.OutOfMemory;
const context = c.LLVMContextCreate() orelse return error.OutOfMemory;
errdefer c.LLVMContextDispose(context);

const module = c.LLVMModuleCreateWithNameInContext(name_buffer.ptr(), context) ?? return error.OutOfMemory;
const module = c.LLVMModuleCreateWithNameInContext(name_buffer.ptr(), context) orelse return error.OutOfMemory;
errdefer c.LLVMDisposeModule(module);

const builder = c.LLVMCreateBuilderInContext(context) ?? return error.OutOfMemory;
const builder = c.LLVMCreateBuilderInContext(context) orelse return error.OutOfMemory;
errdefer c.LLVMDisposeBuilder(builder);

const module_ptr = try allocator.create(Module);
Expand Down Expand Up @@ -223,7 +223,7 @@ pub const Module = struct {
c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);
}

const root_src_path = self.root_src_path ?? @panic("TODO handle null root src path");
const root_src_path = self.root_src_path orelse @panic("TODO handle null root src path");
const root_src_real_path = os.path.real(self.allocator, root_src_path) catch |err| {
try printError("unable to get real path '{}': {}", root_src_path, err);
return err;
Expand Down
7 changes: 6 additions & 1 deletion src/all_types.hpp
Expand Up @@ -387,6 +387,7 @@ enum NodeType {
NodeTypeSliceExpr,
NodeTypeFieldAccessExpr,
NodeTypePtrDeref,
NodeTypeUnwrapOptional,
NodeTypeUse,
NodeTypeBoolLiteral,
NodeTypeNullLiteral,
Expand Down Expand Up @@ -575,6 +576,10 @@ struct AstNodeCatchExpr {
AstNode *op2;
};

struct AstNodeUnwrapOptional {
AstNode *expr;
};

enum CastOp {
CastOpNoCast, // signifies the function call expression is not a cast
CastOpNoop, // fn call expr is a cast, but does nothing
Expand Down Expand Up @@ -624,7 +629,6 @@ enum PrefixOp {
PrefixOpNegation,
PrefixOpNegationWrap,
PrefixOpOptional,
PrefixOpUnwrapOptional,
PrefixOpAddrOf,
};

Expand Down Expand Up @@ -909,6 +913,7 @@ struct AstNode {
AstNodeTestDecl test_decl;
AstNodeBinOpExpr bin_op_expr;
AstNodeCatchExpr unwrap_err_expr;
AstNodeUnwrapOptional unwrap_optional;
AstNodePrefixOpExpr prefix_op_expr;
AstNodePointerType pointer_type;
AstNodeFnCallExpr fn_call_expr;
Expand Down
1 change: 1 addition & 0 deletions src/analyze.cpp
Expand Up @@ -3308,6 +3308,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypePtrDeref:
case NodeTypeUnwrapOptional:
case NodeTypeStructField:
case NodeTypeContainerInitExpr:
case NodeTypeStructValueField:
Expand Down
12 changes: 10 additions & 2 deletions src/ast_render.cpp
Expand Up @@ -50,7 +50,7 @@ static const char *bin_op_str(BinOpType bin_op) {
case BinOpTypeAssignBitXor: return "^=";
case BinOpTypeAssignBitOr: return "|=";
case BinOpTypeAssignMergeErrorSets: return "||=";
case BinOpTypeUnwrapOptional: return "??";
case BinOpTypeUnwrapOptional: return "orelse";
case BinOpTypeArrayCat: return "++";
case BinOpTypeArrayMult: return "**";
case BinOpTypeErrorUnion: return "!";
Expand All @@ -67,7 +67,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
case PrefixOpBoolNot: return "!";
case PrefixOpBinNot: return "~";
case PrefixOpOptional: return "?";
case PrefixOpUnwrapOptional: return "??";
case PrefixOpAddrOf: return "&";
}
zig_unreachable();
Expand Down Expand Up @@ -222,6 +221,8 @@ static const char *node_type_str(NodeType node_type) {
return "FieldAccessExpr";
case NodeTypePtrDeref:
return "PtrDerefExpr";
case NodeTypeUnwrapOptional:
return "UnwrapOptional";
case NodeTypeContainerDecl:
return "ContainerDecl";
case NodeTypeStructField:
Expand Down Expand Up @@ -711,6 +712,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
fprintf(ar->f, ".*");
break;
}
case NodeTypeUnwrapOptional:
{
AstNode *lhs = node->data.unwrap_optional.expr;
render_node_ungrouped(ar, lhs);
fprintf(ar->f, ".?");
break;
}
case NodeTypeUndefinedLiteral:
fprintf(ar->f, "undefined");
break;
Expand Down
31 changes: 13 additions & 18 deletions src/ir.cpp
Expand Up @@ -4661,21 +4661,6 @@ static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode
return ir_build_load_ptr(irb, scope, source_node, payload_ptr);
}

static IrInstruction *ir_gen_maybe_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
assert(node->type == NodeTypePrefixOpExpr);
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;

IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR);
if (maybe_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;

IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true);
if (lval.is_ptr)
return unwrapped_ptr;

return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
}

static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypePrefixOpExpr);
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
Expand Down Expand Up @@ -4705,8 +4690,6 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval);
case PrefixOpOptional:
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval);
case PrefixOpUnwrapOptional:
return ir_gen_maybe_assert_ok(irb, scope, node, lval);
case PrefixOpAddrOf: {
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR), lval);
Expand Down Expand Up @@ -6541,14 +6524,26 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_build_load_ptr(irb, scope, node, ptr_instruction);
}
case NodeTypePtrDeref: {
assert(node->type == NodeTypePtrDeref);
AstNode *expr_node = node->data.ptr_deref_expr.target;
IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval);
if (value == irb->codegen->invalid_instruction)
return value;

return ir_build_un_op(irb, scope, node, IrUnOpDereference, value);
}
case NodeTypeUnwrapOptional: {
AstNode *expr_node = node->data.unwrap_optional.expr;

IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR);
if (maybe_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;

IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true);
if (lval.is_ptr)
return unwrapped_ptr;

return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
}
case NodeTypeThisLiteral:
return ir_lval_wrap(irb, scope, ir_gen_this_literal(irb, scope, node), lval);
case NodeTypeBoolLiteral:
Expand Down
13 changes: 7 additions & 6 deletions src/parser.cpp
Expand Up @@ -1151,9 +1151,8 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
} else if (token->id == TokenIdQuestion) {
*token_index += 1;

AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, first_token);
node->data.prefix_op_expr.prefix_op = PrefixOpUnwrapOptional;
node->data.prefix_op_expr.primary_expr = primary_expr;
AstNode *node = ast_create_node(pc, NodeTypeUnwrapOptional, first_token);
node->data.unwrap_optional.expr = primary_expr;

primary_expr = node;
} else {
Expand All @@ -1173,7 +1172,6 @@ static PrefixOp tok_to_prefix_op(Token *token) {
case TokenIdMinusPercent: return PrefixOpNegationWrap;
case TokenIdTilde: return PrefixOpBinNot;
case TokenIdQuestion: return PrefixOpOptional;
case TokenIdDoubleQuestion: return PrefixOpUnwrapOptional;
case TokenIdAmpersand: return PrefixOpAddrOf;
default: return PrefixOpInvalid;
}
Expand Down Expand Up @@ -2312,7 +2310,7 @@ static BinOpType ast_parse_ass_op(ParseContext *pc, size_t *token_index, bool ma

/*
UnwrapExpression : BoolOrExpression (UnwrapOptional | UnwrapError) | BoolOrExpression
UnwrapOptional : "??" BoolOrExpression
UnwrapOptional = "orelse" Expression
UnwrapError = "catch" option("|" Symbol "|") Expression
*/
static AstNode *ast_parse_unwrap_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
Expand All @@ -2322,7 +2320,7 @@ static AstNode *ast_parse_unwrap_expr(ParseContext *pc, size_t *token_index, boo

Token *token = &pc->tokens->at(*token_index);

if (token->id == TokenIdDoubleQuestion) {
if (token->id == TokenIdKeywordOrElse) {
*token_index += 1;

AstNode *rhs = ast_parse_expression(pc, token_index, true);
Expand Down Expand Up @@ -3035,6 +3033,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypePtrDeref:
visit_field(&node->data.ptr_deref_expr.target, visit, context);
break;
case NodeTypeUnwrapOptional:
visit_field(&node->data.unwrap_optional.expr, visit, context);
break;
case NodeTypeUse:
visit_field(&node->data.use.expr, visit, context);
break;
Expand Down

0 comments on commit 77678b2

Please sign in to comment.