add ?? prefix operator

This commit is contained in:
Andrew Kelley 2016-02-01 02:11:46 -07:00
parent b3459f64e7
commit 179443bd61
8 changed files with 29 additions and 26 deletions

View File

@ -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")

View File

@ -418,6 +418,7 @@ enum PrefixOp {
PrefixOpMaybe,
PrefixOpError,
PrefixOpUnwrapError,
PrefixOpUnwrapMaybe,
};
struct AstNodePrefixOpExpr {

View File

@ -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();
}

View File

@ -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) {

View File

@ -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();
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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");
}