parse async fn calls and cancel expressions
This commit is contained in:
parent
af10b0fec2
commit
3d58d7232a
@ -5663,7 +5663,7 @@ ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression
|
||||
|
||||
BlockOrExpression = Block | Expression
|
||||
|
||||
Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression
|
||||
Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression
|
||||
|
||||
AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")"
|
||||
|
||||
@ -5707,6 +5707,8 @@ TryExpression = "try" Expression
|
||||
|
||||
BreakExpression = "break" option(":" Symbol) option(Expression)
|
||||
|
||||
CancelExpression = "cancel" Expression;
|
||||
|
||||
Defer(body) = ("defer" | "deferror") body
|
||||
|
||||
IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body))
|
||||
@ -5745,7 +5747,7 @@ MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
|
||||
|
||||
PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression
|
||||
|
||||
SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
|
||||
SuffixOpExpression = ("async" option("(" Expression ")") PrimaryExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
|
||||
|
||||
FieldAccessExpression = "." Symbol
|
||||
|
||||
|
@ -393,6 +393,7 @@ enum NodeType {
|
||||
NodeTypeIfErrorExpr,
|
||||
NodeTypeTestExpr,
|
||||
NodeTypeErrorSetDecl,
|
||||
NodeTypeCancel,
|
||||
};
|
||||
|
||||
struct AstNodeRoot {
|
||||
@ -567,6 +568,8 @@ struct AstNodeFnCallExpr {
|
||||
AstNode *fn_ref_expr;
|
||||
ZigList<AstNode *> params;
|
||||
bool is_builtin;
|
||||
bool is_async;
|
||||
AstNode *async_allocator;
|
||||
};
|
||||
|
||||
struct AstNodeArrayAccessExpr {
|
||||
@ -829,6 +832,10 @@ struct AstNodeBreakExpr {
|
||||
AstNode *expr; // may be null
|
||||
};
|
||||
|
||||
struct AstNodeCancelExpr {
|
||||
AstNode *expr;
|
||||
};
|
||||
|
||||
struct AstNodeContinueExpr {
|
||||
Buf *name;
|
||||
};
|
||||
@ -900,6 +907,7 @@ struct AstNode {
|
||||
AstNodeErrorType error_type;
|
||||
AstNodeVarLiteral var_literal;
|
||||
AstNodeErrorSetDecl err_set_decl;
|
||||
AstNodeCancelExpr cancel_expr;
|
||||
} data;
|
||||
};
|
||||
|
||||
@ -1495,6 +1503,7 @@ struct CodeGen {
|
||||
TypeTableEntry *entry_var;
|
||||
TypeTableEntry *entry_global_error_set;
|
||||
TypeTableEntry *entry_arg_tuple;
|
||||
TypeTableEntry *entry_promise;
|
||||
} builtin_types;
|
||||
|
||||
EmitFileType emit_file_type;
|
||||
@ -1939,6 +1948,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdExport,
|
||||
IrInstructionIdErrorReturnTrace,
|
||||
IrInstructionIdErrorUnion,
|
||||
IrInstructionIdCancel,
|
||||
};
|
||||
|
||||
struct IrInstruction {
|
||||
@ -2776,6 +2786,12 @@ struct IrInstructionErrorUnion {
|
||||
IrInstruction *payload;
|
||||
};
|
||||
|
||||
struct IrInstructionCancel {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *target;
|
||||
};
|
||||
|
||||
static const size_t slice_ptr_index = 0;
|
||||
static const size_t slice_len_index = 1;
|
||||
|
||||
|
@ -3117,6 +3117,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
|
||||
case NodeTypeIfErrorExpr:
|
||||
case NodeTypeTestExpr:
|
||||
case NodeTypeErrorSetDecl:
|
||||
case NodeTypeCancel:
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
@ -244,6 +244,8 @@ static const char *node_type_str(NodeType node_type) {
|
||||
return "TestExpr";
|
||||
case NodeTypeErrorSetDecl:
|
||||
return "ErrorSetDecl";
|
||||
case NodeTypeCancel:
|
||||
return "Cancel";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -1037,6 +1039,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
fprintf(ar->f, "}");
|
||||
break;
|
||||
}
|
||||
case NodeTypeCancel:
|
||||
{
|
||||
fprintf(ar->f, "cancel ");
|
||||
render_node_grouped(ar, node->data.cancel_expr.expr);
|
||||
break;
|
||||
}
|
||||
case NodeTypeFnDecl:
|
||||
case NodeTypeParamDecl:
|
||||
case NodeTypeTestDecl:
|
||||
|
@ -3088,6 +3088,10 @@ static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *execu
|
||||
return g->cur_err_ret_trace_val;
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrInstructionCancel *instruction) {
|
||||
zig_panic("TODO ir_render_cancel");
|
||||
}
|
||||
|
||||
static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
|
||||
switch (atomic_order) {
|
||||
case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
|
||||
@ -3862,6 +3866,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);
|
||||
case IrInstructionIdErrorReturnTrace:
|
||||
return ir_render_error_return_trace(g, executable, (IrInstructionErrorReturnTrace *)instruction);
|
||||
case IrInstructionIdCancel:
|
||||
return ir_render_cancel(g, executable, (IrInstructionCancel *)instruction);
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -5271,6 +5277,16 @@ static void define_builtin_types(CodeGen *g) {
|
||||
|
||||
g->primitive_type_table.put(&entry->name, entry);
|
||||
}
|
||||
{
|
||||
TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid);
|
||||
entry->type_ref = u8_ptr_type->type_ref;
|
||||
entry->zero_bits = false;
|
||||
buf_init_from_str(&entry->name, "promise");
|
||||
entry->di_type = u8_ptr_type->di_type;
|
||||
g->builtin_types.entry_promise = entry;
|
||||
g->primitive_type_table.put(&entry->name, entry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
46
src/ir.cpp
46
src/ir.cpp
@ -637,6 +637,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnion *) {
|
||||
return IrInstructionIdErrorUnion;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionCancel *) {
|
||||
return IrInstructionIdCancel;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
|
||||
T *special_instruction = allocate<T>(1);
|
||||
@ -2396,6 +2400,17 @@ static IrInstruction *ir_build_error_union(IrBuilder *irb, Scope *scope, AstNode
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_cancel(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *target)
|
||||
{
|
||||
IrInstructionCancel *instruction = ir_build_instruction<IrInstructionCancel>(irb, scope, source_node);
|
||||
instruction->target = target;
|
||||
|
||||
ir_ref_instruction(target, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
|
||||
results[ReturnKindUnconditional] = 0;
|
||||
results[ReturnKindError] = 0;
|
||||
@ -3873,6 +3888,10 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
|
||||
return args[i];
|
||||
}
|
||||
|
||||
if (node->data.fn_call_expr.is_async) {
|
||||
zig_panic("TODO ir_gen_fn_call for async fn calls");
|
||||
}
|
||||
|
||||
return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto);
|
||||
}
|
||||
|
||||
@ -5598,6 +5617,16 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
|
||||
return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, is_var_args);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
|
||||
assert(node->type == NodeTypeCancel);
|
||||
|
||||
IrInstruction *target_inst = ir_gen_node(irb, node->data.cancel_expr.expr, parent_scope);
|
||||
if (target_inst == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
|
||||
return ir_build_cancel(irb, parent_scope, node, target_inst);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
|
||||
LVal lval)
|
||||
{
|
||||
@ -5694,6 +5723,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
|
||||
return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval);
|
||||
case NodeTypeErrorSetDecl:
|
||||
return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval);
|
||||
case NodeTypeCancel:
|
||||
return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval);
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -16459,6 +16490,17 @@ static TypeTableEntry *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruc
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_cancel(IrAnalyze *ira, IrInstructionCancel *instruction) {
|
||||
IrInstruction *casted_target = ir_implicit_cast(ira, instruction->target->other, ira->codegen->builtin_types.entry_promise);
|
||||
if (type_is_invalid(casted_target->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
IrInstruction *result = ir_build_cancel(&ira->new_irb, instruction->base.scope, instruction->base.source_node, casted_target);
|
||||
result->value.type = casted_target->value.type;
|
||||
ir_link_new_instruction(result, &instruction->base);
|
||||
return result->value.type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
|
||||
switch (instruction->id) {
|
||||
case IrInstructionIdInvalid:
|
||||
@ -16661,6 +16703,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
|
||||
return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);
|
||||
case IrInstructionIdErrorUnion:
|
||||
return ir_analyze_instruction_error_union(ira, (IrInstructionErrorUnion *)instruction);
|
||||
case IrInstructionIdCancel:
|
||||
return ir_analyze_instruction_cancel(ira, (IrInstructionCancel *)instruction);
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -16774,7 +16818,9 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
case IrInstructionIdPtrTypeOf:
|
||||
case IrInstructionIdSetAlignStack:
|
||||
case IrInstructionIdExport:
|
||||
case IrInstructionIdCancel:
|
||||
return true;
|
||||
|
||||
case IrInstructionIdPhi:
|
||||
case IrInstructionIdUnOp:
|
||||
case IrInstructionIdBinOp:
|
||||
|
@ -1010,6 +1010,11 @@ static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruct
|
||||
ir_print_other_instruction(irp, instruction->payload);
|
||||
}
|
||||
|
||||
static void ir_print_cancel(IrPrint *irp, IrInstructionCancel *instruction) {
|
||||
fprintf(irp->f, "cancel ");
|
||||
ir_print_other_instruction(irp, instruction->target);
|
||||
}
|
||||
|
||||
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
ir_print_prefix(irp, instruction);
|
||||
switch (instruction->id) {
|
||||
@ -1330,6 +1335,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdErrorUnion:
|
||||
ir_print_error_union(irp, (IrInstructionErrorUnion *)instruction);
|
||||
break;
|
||||
case IrInstructionIdCancel:
|
||||
ir_print_cancel(irp, (IrInstructionCancel *)instruction);
|
||||
break;
|
||||
}
|
||||
fprintf(irp->f, "\n");
|
||||
}
|
||||
|
@ -920,7 +920,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde
|
||||
}
|
||||
|
||||
/*
|
||||
SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
|
||||
SuffixOpExpression = ("async" option("(" Expression ")") PrimaryExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
|
||||
FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
|
||||
ArrayAccessExpression : token(LBracket) Expression token(RBracket)
|
||||
SliceExpression = "[" Expression ".." option(Expression) "]"
|
||||
@ -928,9 +928,34 @@ FieldAccessExpression : token(Dot) token(Symbol)
|
||||
StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
|
||||
*/
|
||||
static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
||||
AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory);
|
||||
if (!primary_expr)
|
||||
return nullptr;
|
||||
AstNode *primary_expr;
|
||||
|
||||
Token *async_token = &pc->tokens->at(*token_index);
|
||||
if (async_token->id == TokenIdKeywordAsync) {
|
||||
*token_index += 1;
|
||||
|
||||
AstNode *allocator_expr_node = nullptr;
|
||||
Token *async_lparen_tok = &pc->tokens->at(*token_index);
|
||||
if (async_lparen_tok->id == TokenIdLParen) {
|
||||
*token_index += 1;
|
||||
allocator_expr_node = ast_parse_expression(pc, token_index, true);
|
||||
ast_eat_token(pc, token_index, TokenIdRParen);
|
||||
}
|
||||
|
||||
AstNode *fn_ref_expr_node = ast_parse_primary_expr(pc, token_index, true);
|
||||
Token *lparen_tok = ast_eat_token(pc, token_index, TokenIdLParen);
|
||||
AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, lparen_tok);
|
||||
node->data.fn_call_expr.is_async = true;
|
||||
node->data.fn_call_expr.async_allocator = allocator_expr_node;
|
||||
node->data.fn_call_expr.fn_ref_expr = fn_ref_expr_node;
|
||||
ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params);
|
||||
|
||||
primary_expr = node;
|
||||
} else {
|
||||
primary_expr = ast_parse_primary_expr(pc, token_index, mandatory);
|
||||
if (!primary_expr)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
Token *first_token = &pc->tokens->at(*token_index);
|
||||
@ -1535,6 +1560,24 @@ static AstNode *ast_parse_break_expr(ParseContext *pc, size_t *token_index) {
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
CancelExpression = "cancel" Expression;
|
||||
*/
|
||||
static AstNode *ast_parse_cancel_expr(ParseContext *pc, size_t *token_index) {
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
|
||||
if (token->id != TokenIdKeywordCancel) {
|
||||
return nullptr;
|
||||
}
|
||||
*token_index += 1;
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeCancel, token);
|
||||
|
||||
node->data.cancel_expr.expr = ast_parse_expression(pc, token_index, false);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
Defer(body) = ("defer" | "errdefer") body
|
||||
*/
|
||||
@ -2159,7 +2202,7 @@ static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_in
|
||||
}
|
||||
|
||||
/*
|
||||
Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression
|
||||
Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression
|
||||
*/
|
||||
static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) {
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
@ -2176,6 +2219,10 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool
|
||||
if (break_expr)
|
||||
return break_expr;
|
||||
|
||||
AstNode *cancel_expr = ast_parse_cancel_expr(pc, token_index);
|
||||
if (cancel_expr)
|
||||
return cancel_expr;
|
||||
|
||||
AstNode *ass_expr = ast_parse_ass_expr(pc, token_index, false);
|
||||
if (ass_expr)
|
||||
return ass_expr;
|
||||
@ -2809,6 +2856,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
||||
case NodeTypeFnCallExpr:
|
||||
visit_field(&node->data.fn_call_expr.fn_ref_expr, visit, context);
|
||||
visit_node_list(&node->data.fn_call_expr.params, visit, context);
|
||||
visit_field(&node->data.fn_call_expr.async_allocator, visit, context);
|
||||
break;
|
||||
case NodeTypeArrayAccessExpr:
|
||||
visit_field(&node->data.array_access_expr.array_ref_expr, visit, context);
|
||||
@ -2931,5 +2979,8 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
||||
case NodeTypeErrorSetDecl:
|
||||
visit_node_list(&node->data.err_set_decl.decls, visit, context);
|
||||
break;
|
||||
case NodeTypeCancel:
|
||||
visit_field(&node->data.cancel_expr.expr, visit, context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
16
std/mem.zig
16
std/mem.zig
@ -116,6 +116,22 @@ pub const Allocator = struct {
|
||||
const non_const_ptr = @intToPtr(&u8, @ptrToInt(bytes.ptr));
|
||||
self.freeFn(self, non_const_ptr[0..bytes.len]);
|
||||
}
|
||||
|
||||
pub const AsyncAllocator = struct {
|
||||
allocator: &Allocator,
|
||||
|
||||
fn alloc(self: &const AsyncAllocator, byte_count: usize, alignment: u29) Error![]u8 {
|
||||
return self.allocator.allocFn(self.allocator, byte_count, alignment);
|
||||
}
|
||||
|
||||
fn free(self: &const AsyncAllocator, old_mem: []u8) {
|
||||
return self.allocator.freeFn(self.allocator, old_mem);
|
||||
}
|
||||
};
|
||||
|
||||
fn toAsync(self: &Allocator) AsyncAllocator {
|
||||
return AsyncAllocator { .allocator = self };
|
||||
}
|
||||
};
|
||||
|
||||
/// Copy all of source into dest at position 0.
|
||||
|
Loading…
x
Reference in New Issue
Block a user