From 179443bd61c85c7d808304dc334bb407aa793988 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 1 Feb 2016 02:11:46 -0700 Subject: [PATCH] add ?? prefix operator --- doc/langref.md | 2 +- src/all_types.hpp | 1 + src/analyze.cpp | 14 ++++++++++++++ src/ast_render.cpp | 4 +++- src/codegen.cpp | 7 +++++++ src/parseh.cpp | 24 +----------------------- src/parser.cpp | 1 + test/run_tests.cpp | 2 +- 8 files changed, 29 insertions(+), 26 deletions(-) diff --git a/doc/langref.md b/doc/langref.md index 73f46a146d..1a36202099 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -143,7 +143,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",") StructLiteralField = "." "Symbol" "=" Expression -PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" +PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | "??" PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." "Symbol") diff --git a/src/all_types.hpp b/src/all_types.hpp index 68a9b080ed..1f6160728d 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -418,6 +418,7 @@ enum PrefixOp { PrefixOpMaybe, PrefixOpError, PrefixOpUnwrapError, + PrefixOpUnwrapMaybe, }; struct AstNodePrefixOpExpr { diff --git a/src/analyze.cpp b/src/analyze.cpp index e71c762669..6e3abdac35 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4207,6 +4207,20 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo return g->builtin_types.entry_invalid; } } + case PrefixOpUnwrapMaybe: + { + TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node); + + if (type_entry->id == TypeTableEntryIdInvalid) { + return type_entry; + } else if (type_entry->id == TypeTableEntryIdMaybe) { + return type_entry->data.maybe.child_type; + } else { + add_node_error(g, expr_node, + buf_sprintf("expected maybe type, got '%s'", buf_ptr(&type_entry->name))); + return g->builtin_types.entry_invalid; + } + } } zig_unreachable(); } diff --git a/src/ast_render.cpp b/src/ast_render.cpp index a09b4c52be..beacd823d6 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -53,6 +53,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) { case PrefixOpMaybe: return "?"; case PrefixOpError: return "%"; case PrefixOpUnwrapError: return "%%"; + case PrefixOpUnwrapMaybe: return "??"; } } @@ -696,8 +697,9 @@ static void render_node(AstRender *ar, AstNode *node) { if (node->data.fn_call_expr.is_builtin) { fprintf(ar->f, "@"); } - render_node(ar, node->data.fn_call_expr.fn_ref_expr); fprintf(ar->f, "("); + render_node(ar, node->data.fn_call_expr.fn_ref_expr); + fprintf(ar->f, ")("); for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { AstNode *param = node->data.fn_call_expr.params.at(i); if (i != 0) { diff --git a/src/codegen.cpp b/src/codegen.cpp index ef910bbba7..c82b337c50 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -85,6 +85,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op, LLVMValueRef target_ref, LLVMValueRef value, TypeTableEntry *op1_type, TypeTableEntry *op2_type); +static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref); static TypeTableEntry *get_type_for_type_node(AstNode *node) { Expr *expr = get_resolved_expr(node); @@ -1005,6 +1006,12 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { return nullptr; } } + case PrefixOpUnwrapMaybe: + { + LLVMValueRef expr_val = gen_expr(g, expr_node); + // TODO in debug mode, put a panic here if null + return gen_unwrap_maybe(g, expr_node, expr_val); + } } zig_unreachable(); } diff --git a/src/parseh.cpp b/src/parseh.cpp index 271fb318dc..1e1bcacaee 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -249,33 +249,11 @@ static AstNode *create_one_statement_block(Context *c, AstNode *statement) { return node; } -static AstNode *create_container_init_node(Context *c, AstNode *type_node) { - AstNode *node = create_node(c, NodeTypeContainerInitExpr); - node->data.container_init_expr.kind = ContainerInitKindArray; - node->data.container_init_expr.type = type_node; - - normalize_parent_ptrs(node); - return node; -} - -static AstNode *create_bin_op_node(Context *c, AstNode *lhs, BinOpType op, AstNode *rhs) { - AstNode *node = create_node(c, NodeTypeBinOpExpr); - node->data.bin_op_expr.op1 = lhs; - node->data.bin_op_expr.bin_op = op; - node->data.bin_op_expr.op2 = rhs; - - normalize_parent_ptrs(node); - return node; -} - static AstNode *create_inline_fn_node(Context *c, Buf *fn_name, Buf *var_name, TypeTableEntry *fn_type) { AstNode *node = create_node(c, NodeTypeFnDef); node->data.fn_def.fn_proto = create_fn_proto_node(c, fn_name, fn_type); - AstNode *unreach_type_node = make_type_node(c, c->codegen->builtin_types.entry_unreachable); - AstNode *unreach_node = create_container_init_node(c, unreach_type_node); - AstNode *unwrap_node = create_bin_op_node(c, create_symbol_node(c, buf_ptr(var_name)), - BinOpTypeUnwrapMaybe, unreach_node); + AstNode *unwrap_node = create_prefix_node(c, PrefixOpUnwrapMaybe, create_symbol_node(c, buf_ptr(var_name))); AstNode *fn_call_node = create_node(c, NodeTypeFnCallExpr); fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node; diff --git a/src/parser.cpp b/src/parser.cpp index de18a57ff6..7e7f073722 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1206,6 +1206,7 @@ static PrefixOp tok_to_prefix_op(Token *token) { case TokenIdMaybe: return PrefixOpMaybe; case TokenIdPercent: return PrefixOpError; case TokenIdPercentPercent: return PrefixOpUnwrapError; + case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe; case TokenIdBoolAnd: return PrefixOpAddressOf; default: return PrefixOpInvalid; } diff --git a/test/run_tests.cpp b/test/run_tests.cpp index b244e9ab8a..83fb14c12a 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -2116,7 +2116,7 @@ extern void (*fn_ptr)(void); "pub extern var fn_ptr: ?extern fn();", R"SOURCE(#attribute("inline") pub fn foo() { - (fn_ptr ?? (unreachable){})() + (??fn_ptr)() })SOURCE"); }