Skip to content

Commit

Permalink
simple unconditional defer support
Browse files Browse the repository at this point in the history
See #110
  • Loading branch information
andrewrk committed Feb 6, 2016
1 parent 6a2ede5 commit ec33e5a
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 75 deletions.
6 changes: 3 additions & 3 deletions doc/langref.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ ParamDecl = option("noalias") option("Symbol" ":") TypeExpr | "..."
Block = "{" list(option(Statement), ";") "}"
Statement = Label | VariableDeclaration ";" | NonBlockExpression ";" | BlockExpression
Statement = Label | VariableDeclaration ";" | Defer ";" | NonBlockExpression ";" | BlockExpression
Label = "Symbol" ":"
Expression = BlockExpression | NonBlockExpression
TypeExpr = PrefixOpExpression
NonBlockExpression = ReturnExpression | AssignmentExpression | DeferExpression
NonBlockExpression = ReturnExpression | AssignmentExpression
AsmExpression = "asm" option("volatile") "(" "String" option(AsmOutput) ")"
Expand Down Expand Up @@ -91,7 +91,7 @@ BoolOrExpression = BoolAndExpression "||" BoolOrExpression | BoolAndExpression
ReturnExpression = option("%" | "?") "return" option(Expression)
DeferExpression = option("%" | "?") "defer" option(Expression)
Defer = option("%" | "?") "defer" option(Expression)
IfExpression = IfVarExpression | IfBoolExpression
Expand Down
1 change: 0 additions & 1 deletion example/cat/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import "std.zig";

// Things to do to make this work:
// * var args printing
// * defer
// * cast err type to string
// * string equality

Expand Down
20 changes: 14 additions & 6 deletions src/all_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ enum NodeType {
NodeTypeBlock,
NodeTypeDirective,
NodeTypeReturnExpr,
NodeTypeDeferExpr,
NodeTypeDefer,
NodeTypeVariableDeclaration,
NodeTypeTypeDecl,
NodeTypeErrorValueDecl,
Expand Down Expand Up @@ -216,7 +216,12 @@ struct AstNodeBlock {
ZigList<AstNode *> statements;

// populated by semantic analyzer
BlockContext *block_context;
// this one is the scope that the block itself introduces
BlockContext *child_block;
// this is the innermost scope created by defers and var decls.
// you can follow its parents up to child_block. it will equal
// child_block if there are no defers or var decls in the block.
BlockContext *nested_block;
Expr resolved_expr;
};

Expand All @@ -235,14 +240,15 @@ struct AstNodeReturnExpr {
Expr resolved_expr;
};

struct AstNodeDeferExpr {
struct AstNodeDefer {
ReturnKind kind;
AstNode *expr;

// populated by semantic analyzer:
Expr resolved_expr;
int index_in_block;
LLVMBasicBlockRef basic_block;
BlockContext *child_block;
};

struct AstNodeVariableDeclaration {
Expand Down Expand Up @@ -739,7 +745,7 @@ struct AstNode {
AstNodeParamDecl param_decl;
AstNodeBlock block;
AstNodeReturnExpr return_expr;
AstNodeDeferExpr defer_expr;
AstNodeDefer defer;
AstNodeVariableDeclaration variable_declaration;
AstNodeTypeDecl type_decl;
AstNodeErrorValueDecl error_value_decl;
Expand Down Expand Up @@ -1157,10 +1163,12 @@ enum BlockExitPath {
BlockExitPathFallthrough,
BlockExitPathReturn,
BlockExitPathGoto,

BlockExitPathCount,
};

struct BlockContext {
// One of: NodeTypeFnDef, NodeTypeBlock, NodeTypeRoot, NodeTypeDeferExpr, NodeTypeVariableDeclaration
// One of: NodeTypeFnDef, NodeTypeBlock, NodeTypeRoot, NodeTypeDefer, NodeTypeVariableDeclaration
AstNode *node;

// any variables that are introduced by this scope
Expand All @@ -1178,7 +1186,7 @@ struct BlockContext {

LLVMZigDIScope *di_scope;
Buf *c_import_buf;
bool block_exit_paths[3]; // one for each BlockExitPath
bool block_exit_paths[BlockExitPathCount];
};

enum CIntType {
Expand Down
66 changes: 35 additions & 31 deletions src/analyze.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeBlock:
case NodeTypeDirective:
case NodeTypeReturnExpr:
case NodeTypeDeferExpr:
case NodeTypeDefer:
case NodeTypeVariableDeclaration:
case NodeTypeTypeDecl:
case NodeTypeErrorValueDecl:
Expand Down Expand Up @@ -1456,7 +1456,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeParamDecl:
case NodeTypeFnDecl:
case NodeTypeReturnExpr:
case NodeTypeDeferExpr:
case NodeTypeDefer:
case NodeTypeRoot:
case NodeTypeBlock:
case NodeTypeBinOpExpr:
Expand Down Expand Up @@ -4590,56 +4590,54 @@ static void validate_voided_expr(CodeGen *g, AstNode *source_node, TypeTableEntr
}
}

static TypeTableEntry *analyze_defer_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
static TypeTableEntry *analyze_defer(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
TypeTableEntry *expected_type, AstNode *node)
{
if (!context->fn_entry) {
if (!parent_context->fn_entry) {
add_node_error(g, node, buf_sprintf("defer expression outside function definition"));
return g->builtin_types.entry_invalid;
}

if (!node->data.defer_expr.expr) {
if (!node->data.defer.expr) {
add_node_error(g, node, buf_sprintf("defer expects an expression"));
return g->builtin_types.entry_void;
}

node->data.defer.child_block = new_block_context(node, parent_context);

switch (node->data.defer_expr.kind) {
switch (node->data.defer.kind) {
case ReturnKindUnconditional:
{
TypeTableEntry *resolved_type = analyze_expression(g, import, context, nullptr,
node->data.defer_expr.expr);
validate_voided_expr(g, node->data.defer_expr.expr, resolved_type);
zig_panic("TODO");
TypeTableEntry *resolved_type = analyze_expression(g, import, parent_context, nullptr,
node->data.defer.expr);
validate_voided_expr(g, node->data.defer.expr, resolved_type);

//node->data.defer_expr.index_in_block = context->defer_list.length;
//context->defer_list.append(node);
return g->builtin_types.entry_void;
}
case ReturnKindError:
{
TypeTableEntry *resolved_type = analyze_expression(g, import, context, nullptr,
node->data.defer_expr.expr);
TypeTableEntry *resolved_type = analyze_expression(g, import, parent_context, nullptr,
node->data.defer.expr);
if (resolved_type->id == TypeTableEntryIdInvalid) {
// OK
} else if (resolved_type->id == TypeTableEntryIdErrorUnion) {
// OK
} else {
add_node_error(g, node->data.defer_expr.expr,
add_node_error(g, node->data.defer.expr,
buf_sprintf("expected error type, got '%s'", buf_ptr(&resolved_type->name)));
}
return g->builtin_types.entry_void;
}
case ReturnKindMaybe:
{
TypeTableEntry *resolved_type = analyze_expression(g, import, context, nullptr,
node->data.defer_expr.expr);
TypeTableEntry *resolved_type = analyze_expression(g, import, parent_context, nullptr,
node->data.defer.expr);
if (resolved_type->id == TypeTableEntryIdInvalid) {
// OK
} else if (resolved_type->id == TypeTableEntryIdMaybe) {
// OK
} else {
add_node_error(g, node->data.defer_expr.expr,
add_node_error(g, node->data.defer.expr,
buf_sprintf("expected maybe type, got '%s'", buf_ptr(&resolved_type->name)));
}
return g->builtin_types.entry_void;
Expand All @@ -4657,11 +4655,11 @@ static TypeTableEntry *analyze_string_literal_expr(CodeGen *g, ImportTableEntry
}
}

static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
TypeTableEntry *expected_type, AstNode *node)
{
BlockContext *child_context = new_block_context(node, context);
node->data.block.block_context = child_context;
BlockContext *child_context = new_block_context(node, parent_context);
node->data.block.child_block = child_context;
TypeTableEntry *return_type = g->builtin_types.entry_void;

for (int i = 0; i < node->data.block.statements.length; i += 1) {
Expand All @@ -4676,7 +4674,7 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import,
if (is_node_void_expr(child)) {
// {unreachable;void;void} is allowed.
// ignore void statements once we enter unreachable land.
analyze_expression(g, import, context, g->builtin_types.entry_void, child);
analyze_expression(g, import, child_context, g->builtin_types.entry_void, child);
continue;
}
add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code"));
Expand All @@ -4685,10 +4683,16 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import,
bool is_last = (i == node->data.block.statements.length - 1);
TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr;
return_type = analyze_expression(g, import, child_context, passed_expected_type, child);
if (child->type == NodeTypeDefer && return_type->id != TypeTableEntryIdInvalid) {
// defer starts a new block context
child_context = child->data.defer.child_block;
assert(child_context);
}
if (!is_last) {
validate_voided_expr(g, child, return_type);
}
}
node->data.block.nested_block = child_context;
return return_type;
}

Expand Down Expand Up @@ -4750,8 +4754,8 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeReturnExpr:
return_type = analyze_return_expr(g, import, context, expected_type, node);
break;
case NodeTypeDeferExpr:
return_type = analyze_defer_expr(g, import, context, expected_type, node);
case NodeTypeDefer:
return_type = analyze_defer(g, import, context, expected_type, node);
break;
case NodeTypeVariableDeclaration:
analyze_variable_declaration(g, import, context, expected_type, node);
Expand Down Expand Up @@ -4956,7 +4960,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeParamDecl:
case NodeTypeFnDecl:
case NodeTypeReturnExpr:
case NodeTypeDeferExpr:
case NodeTypeDefer:
case NodeTypeRoot:
case NodeTypeBlock:
case NodeTypeBinOpExpr:
Expand Down Expand Up @@ -5039,8 +5043,8 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeReturnExpr:
collect_expr_decl_deps(g, import, node->data.return_expr.expr, decl_node);
break;
case NodeTypeDeferExpr:
collect_expr_decl_deps(g, import, node->data.defer_expr.expr, decl_node);
case NodeTypeDefer:
collect_expr_decl_deps(g, import, node->data.defer.expr, decl_node);
break;
case NodeTypePrefixOpExpr:
collect_expr_decl_deps(g, import, node->data.prefix_op_expr.primary_expr, decl_node);
Expand Down Expand Up @@ -5361,7 +5365,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
case NodeTypeParamDecl:
case NodeTypeFnDecl:
case NodeTypeReturnExpr:
case NodeTypeDeferExpr:
case NodeTypeDefer:
case NodeTypeBlock:
case NodeTypeBinOpExpr:
case NodeTypeUnwrapErrorExpr:
Expand Down Expand Up @@ -5552,8 +5556,8 @@ Expr *get_resolved_expr(AstNode *node) {
switch (node->type) {
case NodeTypeReturnExpr:
return &node->data.return_expr.resolved_expr;
case NodeTypeDeferExpr:
return &node->data.defer_expr.resolved_expr;
case NodeTypeDefer:
return &node->data.defer.resolved_expr;
case NodeTypeBinOpExpr:
return &node->data.bin_op_expr.resolved_expr;
case NodeTypeUnwrapErrorExpr:
Expand Down Expand Up @@ -5652,7 +5656,7 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
return &node->data.type_decl.top_level_decl;
case NodeTypeNumberLiteral:
case NodeTypeReturnExpr:
case NodeTypeDeferExpr:
case NodeTypeDefer:
case NodeTypeBinOpExpr:
case NodeTypeUnwrapErrorExpr:
case NodeTypePrefixOpExpr:
Expand Down
14 changes: 7 additions & 7 deletions src/ast_render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ static const char *node_type_str(NodeType node_type) {
return "Directive";
case NodeTypeReturnExpr:
return "ReturnExpr";
case NodeTypeDeferExpr:
return "DeferExpr";
case NodeTypeDefer:
return "Defer";
case NodeTypeVariableDeclaration:
return "VariableDeclaration";
case NodeTypeTypeDecl:
Expand Down Expand Up @@ -261,12 +261,12 @@ void ast_print(FILE *f, AstNode *node, int indent) {
ast_print(f, node->data.return_expr.expr, indent + 2);
break;
}
case NodeTypeDeferExpr:
case NodeTypeDefer:
{
const char *prefix_str = return_prefix_str(node->data.defer_expr.kind);
const char *prefix_str = return_prefix_str(node->data.defer.kind);
fprintf(f, "%s%s\n", prefix_str, node_type_str(node->type));
if (node->data.defer_expr.expr)
ast_print(f, node->data.defer_expr.expr, indent + 2);
if (node->data.defer.expr)
ast_print(f, node->data.defer.expr, indent + 2);
break;
}
case NodeTypeVariableDeclaration:
Expand Down Expand Up @@ -630,7 +630,7 @@ static void render_node(AstRender *ar, AstNode *node) {
break;
case NodeTypeReturnExpr:
zig_panic("TODO");
case NodeTypeDeferExpr:
case NodeTypeDefer:
zig_panic("TODO");
case NodeTypeVariableDeclaration:
{
Expand Down
Loading

0 comments on commit ec33e5a

Please sign in to comment.