Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions build.zig
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading