mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
parent
bee1ae68ef
commit
d5346d7a80
@ -85,9 +85,9 @@ ForExpression(body) = "for" "(" Expression ")" option("|" option("*") Symbol opt
|
|||||||
|
|
||||||
BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression
|
BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression
|
||||||
|
|
||||||
ReturnExpression = option("%" | "?") "return" option(Expression)
|
ReturnExpression = option("%") "return" option(Expression)
|
||||||
|
|
||||||
Defer(body) = option("%" | "?") "defer" body
|
Defer(body) = option("%") "defer" body
|
||||||
|
|
||||||
IfExpression(body) = IfVarExpression(body) | IfBoolExpression(body)
|
IfExpression(body) = IfVarExpression(body) | IfBoolExpression(body)
|
||||||
|
|
||||||
|
|||||||
@ -11,8 +11,6 @@
|
|||||||
libc.
|
libc.
|
||||||
* **cat** - implementation of the `cat` UNIX utility in Zig, with no dependency
|
* **cat** - implementation of the `cat` UNIX utility in Zig, with no dependency
|
||||||
on libc.
|
on libc.
|
||||||
|
|
||||||
## Work-In-Progress Examples
|
|
||||||
|
|
||||||
* **shared_library** - demonstration of building a shared library and generating
|
* **shared_library** - demonstration of building a shared library and generating
|
||||||
a header file and documentation for interop with C code.
|
a header file for interop with C code.
|
||||||
|
* **mix_o_files** - how to mix .zig and .c files together as object files
|
||||||
|
|||||||
@ -408,7 +408,6 @@ struct AstNodeBlock {
|
|||||||
|
|
||||||
enum ReturnKind {
|
enum ReturnKind {
|
||||||
ReturnKindUnconditional,
|
ReturnKindUnconditional,
|
||||||
ReturnKindMaybe,
|
|
||||||
ReturnKindError,
|
ReturnKindError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -92,7 +92,6 @@ static const char *return_string(ReturnKind kind) {
|
|||||||
switch (kind) {
|
switch (kind) {
|
||||||
case ReturnKindUnconditional: return "return";
|
case ReturnKindUnconditional: return "return";
|
||||||
case ReturnKindError: return "%return";
|
case ReturnKindError: return "%return";
|
||||||
case ReturnKindMaybe: return "?return";
|
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
@ -101,7 +100,6 @@ static const char *defer_string(ReturnKind kind) {
|
|||||||
switch (kind) {
|
switch (kind) {
|
||||||
case ReturnKindUnconditional: return "defer";
|
case ReturnKindUnconditional: return "defer";
|
||||||
case ReturnKindError: return "%defer";
|
case ReturnKindError: return "%defer";
|
||||||
case ReturnKindMaybe: return "?defer";
|
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
|
|||||||
74
src/ir.cpp
74
src/ir.cpp
@ -3091,7 +3091,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
|
|||||||
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
|
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
|
||||||
results[ReturnKindUnconditional] = 0;
|
results[ReturnKindUnconditional] = 0;
|
||||||
results[ReturnKindError] = 0;
|
results[ReturnKindError] = 0;
|
||||||
results[ReturnKindMaybe] = 0;
|
|
||||||
|
|
||||||
while (inner_scope != outer_scope) {
|
while (inner_scope != outer_scope) {
|
||||||
assert(inner_scope);
|
assert(inner_scope);
|
||||||
@ -3111,9 +3110,7 @@ static IrInstruction *ir_mark_gen(IrInstruction *instruction) {
|
|||||||
return instruction;
|
return instruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope,
|
static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) {
|
||||||
bool gen_error_defers, bool gen_maybe_defers)
|
|
||||||
{
|
|
||||||
Scope *scope = inner_scope;
|
Scope *scope = inner_scope;
|
||||||
while (scope != outer_scope) {
|
while (scope != outer_scope) {
|
||||||
if (!scope)
|
if (!scope)
|
||||||
@ -3124,8 +3121,7 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
|
|||||||
assert(defer_node->type == NodeTypeDefer);
|
assert(defer_node->type == NodeTypeDefer);
|
||||||
ReturnKind defer_kind = defer_node->data.defer.kind;
|
ReturnKind defer_kind = defer_node->data.defer.kind;
|
||||||
if (defer_kind == ReturnKindUnconditional ||
|
if (defer_kind == ReturnKindUnconditional ||
|
||||||
(gen_error_defers && defer_kind == ReturnKindError) ||
|
(gen_error_defers && defer_kind == ReturnKindError))
|
||||||
(gen_maybe_defers && defer_kind == ReturnKindMaybe))
|
|
||||||
{
|
{
|
||||||
AstNode *defer_expr_node = defer_node->data.defer.expr;
|
AstNode *defer_expr_node = defer_node->data.defer.expr;
|
||||||
ir_gen_node(irb, defer_expr_node, defer_node->data.defer.expr_scope);
|
ir_gen_node(irb, defer_expr_node, defer_node->data.defer.expr_scope);
|
||||||
@ -3188,7 +3184,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
|
|||||||
return_value = ir_build_const_void(irb, scope, node);
|
return_value = ir_build_const_void(irb, scope, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t defer_counts[3];
|
size_t defer_counts[2];
|
||||||
ir_count_defers(irb, scope, outer_scope, defer_counts);
|
ir_count_defers(irb, scope, outer_scope, defer_counts);
|
||||||
if (defer_counts[ReturnKindError] > 0) {
|
if (defer_counts[ReturnKindError] > 0) {
|
||||||
IrBasicBlock *err_block = ir_build_basic_block(irb, scope, "ErrRetErr");
|
IrBasicBlock *err_block = ir_build_basic_block(irb, scope, "ErrRetErr");
|
||||||
@ -3206,37 +3202,15 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
|
|||||||
ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));
|
ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));
|
||||||
|
|
||||||
ir_set_cursor_at_end(irb, err_block);
|
ir_set_cursor_at_end(irb, err_block);
|
||||||
ir_gen_defers_for_block(irb, scope, outer_scope, true, false);
|
ir_gen_defers_for_block(irb, scope, outer_scope, true);
|
||||||
ir_build_return(irb, scope, node, return_value);
|
ir_build_return(irb, scope, node, return_value);
|
||||||
|
|
||||||
ir_set_cursor_at_end(irb, ok_block);
|
ir_set_cursor_at_end(irb, ok_block);
|
||||||
ir_gen_defers_for_block(irb, scope, outer_scope, false, false);
|
ir_gen_defers_for_block(irb, scope, outer_scope, false);
|
||||||
return ir_build_return(irb, scope, node, return_value);
|
|
||||||
} else if (defer_counts[ReturnKindMaybe] > 0) {
|
|
||||||
IrBasicBlock *null_block = ir_build_basic_block(irb, scope, "MaybeRetNull");
|
|
||||||
IrBasicBlock *ok_block = ir_build_basic_block(irb, scope, "MaybeRetOk");
|
|
||||||
|
|
||||||
IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, return_value);
|
|
||||||
|
|
||||||
IrInstruction *is_comptime;
|
|
||||||
if (ir_should_inline(irb->exec, scope)) {
|
|
||||||
is_comptime = ir_build_const_bool(irb, scope, node, true);
|
|
||||||
} else {
|
|
||||||
is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null);
|
|
||||||
}
|
|
||||||
|
|
||||||
ir_mark_gen(ir_build_cond_br(irb, scope, node, is_non_null, ok_block, null_block, is_comptime));
|
|
||||||
|
|
||||||
ir_set_cursor_at_end(irb, null_block);
|
|
||||||
ir_gen_defers_for_block(irb, scope, outer_scope, false, true);
|
|
||||||
ir_build_return(irb, scope, node, return_value);
|
|
||||||
|
|
||||||
ir_set_cursor_at_end(irb, ok_block);
|
|
||||||
ir_gen_defers_for_block(irb, scope, outer_scope, false, false);
|
|
||||||
return ir_build_return(irb, scope, node, return_value);
|
return ir_build_return(irb, scope, node, return_value);
|
||||||
} else {
|
} else {
|
||||||
// generate unconditional defers
|
// generate unconditional defers
|
||||||
ir_gen_defers_for_block(irb, scope, outer_scope, false, false);
|
ir_gen_defers_for_block(irb, scope, outer_scope, false);
|
||||||
return ir_build_return(irb, scope, node, return_value);
|
return ir_build_return(irb, scope, node, return_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3255,7 +3229,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
|
|||||||
ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));
|
ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));
|
||||||
|
|
||||||
ir_set_cursor_at_end(irb, return_block);
|
ir_set_cursor_at_end(irb, return_block);
|
||||||
ir_gen_defers_for_block(irb, scope, outer_scope, true, false);
|
ir_gen_defers_for_block(irb, scope, outer_scope, true);
|
||||||
IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
|
IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
|
||||||
ir_build_return(irb, scope, node, err_val);
|
ir_build_return(irb, scope, node, err_val);
|
||||||
|
|
||||||
@ -3266,32 +3240,6 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
|
|||||||
else
|
else
|
||||||
return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
|
return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
|
||||||
}
|
}
|
||||||
case ReturnKindMaybe:
|
|
||||||
{
|
|
||||||
assert(expr_node);
|
|
||||||
IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR);
|
|
||||||
if (maybe_val_ptr == irb->codegen->invalid_instruction)
|
|
||||||
return irb->codegen->invalid_instruction;
|
|
||||||
IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr);
|
|
||||||
IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_val);
|
|
||||||
|
|
||||||
IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "MaybeRetReturn");
|
|
||||||
IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "MaybeRetContinue");
|
|
||||||
IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, ir_should_inline(irb->exec, scope));
|
|
||||||
ir_mark_gen(ir_build_cond_br(irb, scope, node, is_non_null, continue_block, return_block, is_comptime));
|
|
||||||
|
|
||||||
ir_set_cursor_at_end(irb, return_block);
|
|
||||||
ir_gen_defers_for_block(irb, scope, outer_scope, false, true);
|
|
||||||
IrInstruction *null = ir_build_const_null(irb, scope, node);
|
|
||||||
ir_build_return(irb, scope, node, null);
|
|
||||||
|
|
||||||
ir_set_cursor_at_end(irb, continue_block);
|
|
||||||
IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_val_ptr, false);
|
|
||||||
if (lval.is_ptr)
|
|
||||||
return unwrapped_ptr;
|
|
||||||
else
|
|
||||||
return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
@ -3490,7 +3438,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
|
|||||||
return_value = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
|
return_value = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
|
||||||
}
|
}
|
||||||
|
|
||||||
ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false, false);
|
ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(return_value != nullptr);
|
assert(return_value != nullptr);
|
||||||
@ -5420,7 +5368,7 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
IrBasicBlock *dest_block = loop_stack_item->break_block;
|
IrBasicBlock *dest_block = loop_stack_item->break_block;
|
||||||
ir_gen_defers_for_block(irb, scope, dest_block->scope, false, false);
|
ir_gen_defers_for_block(irb, scope, dest_block->scope, false);
|
||||||
return ir_build_br(irb, scope, node, dest_block, is_comptime);
|
return ir_build_br(irb, scope, node, dest_block, is_comptime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5443,7 +5391,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *scope, AstNode *nod
|
|||||||
}
|
}
|
||||||
|
|
||||||
IrBasicBlock *dest_block = loop_stack_item->continue_block;
|
IrBasicBlock *dest_block = loop_stack_item->continue_block;
|
||||||
ir_gen_defers_for_block(irb, scope, dest_block->scope, false, false);
|
ir_gen_defers_for_block(irb, scope, dest_block->scope, false);
|
||||||
return ir_build_br(irb, scope, node, dest_block, is_comptime);
|
return ir_build_br(irb, scope, node, dest_block, is_comptime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5784,7 +5732,7 @@ static bool ir_goto_pass2(IrBuilder *irb) {
|
|||||||
|
|
||||||
IrInstruction *is_comptime = ir_build_const_bool(irb, goto_item->scope, source_node,
|
IrInstruction *is_comptime = ir_build_const_bool(irb, goto_item->scope, source_node,
|
||||||
ir_should_inline(irb->exec, goto_item->scope) || source_node->data.goto_expr.is_inline);
|
ir_should_inline(irb->exec, goto_item->scope) || source_node->data.goto_expr.is_inline);
|
||||||
if (!ir_gen_defers_for_block(irb, goto_item->scope, label->bb->scope, false, false)) {
|
if (!ir_gen_defers_for_block(irb, goto_item->scope, label->bb->scope, false)) {
|
||||||
add_node_error(irb->codegen, source_node,
|
add_node_error(irb->codegen, source_node,
|
||||||
buf_sprintf("no label in scope named '%s'", buf_ptr(label_name)));
|
buf_sprintf("no label in scope named '%s'", buf_ptr(label_name)));
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -1483,7 +1483,7 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, size_t *token_index, bool ma
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ReturnExpression : option("%" | "?") "return" option(Expression)
|
ReturnExpression : option("%") "return" option(Expression)
|
||||||
*/
|
*/
|
||||||
static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) {
|
static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) {
|
||||||
Token *token = &pc->tokens->at(*token_index);
|
Token *token = &pc->tokens->at(*token_index);
|
||||||
@ -1500,15 +1500,6 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) {
|
|||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
} else if (token->id == TokenIdMaybe) {
|
|
||||||
Token *next_token = &pc->tokens->at(*token_index + 1);
|
|
||||||
if (next_token->id == TokenIdKeywordReturn) {
|
|
||||||
kind = ReturnKindMaybe;
|
|
||||||
node_type = NodeTypeReturnExpr;
|
|
||||||
*token_index += 2;
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
} else if (token->id == TokenIdKeywordReturn) {
|
} else if (token->id == TokenIdKeywordReturn) {
|
||||||
kind = ReturnKindUnconditional;
|
kind = ReturnKindUnconditional;
|
||||||
node_type = NodeTypeReturnExpr;
|
node_type = NodeTypeReturnExpr;
|
||||||
@ -1525,7 +1516,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Defer(body) = option("%" | "?") "defer" body
|
Defer(body) = option("%") "defer" body
|
||||||
*/
|
*/
|
||||||
static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
|
static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
|
||||||
Token *token = &pc->tokens->at(*token_index);
|
Token *token = &pc->tokens->at(*token_index);
|
||||||
@ -1542,15 +1533,6 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
|
|||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
} else if (token->id == TokenIdMaybe) {
|
|
||||||
Token *next_token = &pc->tokens->at(*token_index + 1);
|
|
||||||
if (next_token->id == TokenIdKeywordDefer) {
|
|
||||||
kind = ReturnKindMaybe;
|
|
||||||
node_type = NodeTypeDefer;
|
|
||||||
*token_index += 2;
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
} else if (token->id == TokenIdKeywordDefer) {
|
} else if (token->id == TokenIdKeywordDefer) {
|
||||||
kind = ReturnKindUnconditional;
|
kind = ReturnKindUnconditional;
|
||||||
node_type = NodeTypeDefer;
|
node_type = NodeTypeDefer;
|
||||||
|
|||||||
@ -13,14 +13,6 @@ fn runSomeErrorDefers(x: bool) -> %bool {
|
|||||||
return if (x) x else error.FalseNotAllowed;
|
return if (x) x else error.FalseNotAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn runSomeMaybeDefers(x: bool) -> ?bool {
|
|
||||||
index = 0;
|
|
||||||
defer {result[index] = 'a'; index += 1;};
|
|
||||||
?defer {result[index] = 'b'; index += 1;};
|
|
||||||
defer {result[index] = 'c'; index += 1;};
|
|
||||||
return if (x) x else null;
|
|
||||||
}
|
|
||||||
|
|
||||||
test "mixingNormalAndErrorDefers" {
|
test "mixingNormalAndErrorDefers" {
|
||||||
assert(%%runSomeErrorDefers(true));
|
assert(%%runSomeErrorDefers(true));
|
||||||
assert(result[0] == 'c');
|
assert(result[0] == 'c');
|
||||||
@ -35,15 +27,3 @@ test "mixingNormalAndErrorDefers" {
|
|||||||
assert(result[1] == 'b');
|
assert(result[1] == 'b');
|
||||||
assert(result[2] == 'a');
|
assert(result[2] == 'a');
|
||||||
}
|
}
|
||||||
|
|
||||||
test "mixingNormalAndMaybeDefers" {
|
|
||||||
assert(??runSomeMaybeDefers(true));
|
|
||||||
assert(result[0] == 'c');
|
|
||||||
assert(result[1] == 'a');
|
|
||||||
|
|
||||||
const ok = runSomeMaybeDefers(false) ?? true;
|
|
||||||
assert(ok);
|
|
||||||
assert(result[0] == 'c');
|
|
||||||
assert(result[1] == 'b');
|
|
||||||
assert(result[2] == 'a');
|
|
||||||
}
|
|
||||||
|
|||||||
@ -42,7 +42,7 @@ test "rhsMaybeUnwrapReturn" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
test "maybeReturn" {
|
test "maybe return" {
|
||||||
maybeReturnImpl();
|
maybeReturnImpl();
|
||||||
comptime maybeReturnImpl();
|
comptime maybeReturnImpl();
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ fn maybeReturnImpl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn foo(x: ?i32) -> ?bool {
|
fn foo(x: ?i32) -> ?bool {
|
||||||
const value = ?return x;
|
const value = x ?? return null;
|
||||||
return value > 1234;
|
return value > 1234;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user