add while loop

This commit is contained in:
Andrew Kelley 2015-12-24 14:37:43 -07:00
parent 2e74889c3c
commit a030b60aeb
7 changed files with 99 additions and 2 deletions

View File

@ -94,7 +94,9 @@ AssignmentExpression : BoolOrExpression AssignmentOperator BoolOrExpression | Bo
AssignmentOperator : token(Eq) | token(TimesEq) | token(DivEq) | token(ModEq) | token(PlusEq) | token(MinusEq) | token(BitShiftLeftEq) | token(BitShiftRightEq) | token(BitAndEq) | token(BitXorEq) | token(BitOrEq) | token(BoolAndEq) | token(BoolOrEq) AssignmentOperator : token(Eq) | token(TimesEq) | token(DivEq) | token(ModEq) | token(PlusEq) | token(MinusEq) | token(BitShiftLeftEq) | token(BitShiftRightEq) | token(BitAndEq) | token(BitXorEq) | token(BitOrEq) | token(BoolAndEq) | token(BoolOrEq)
BlockExpression : IfExpression | Block BlockExpression : IfExpression | Block | WhileExpression
WhileExpression : token(While) Expression Block
BoolOrExpression : BoolAndExpression token(BoolOr) BoolOrExpression | BoolAndExpression BoolOrExpression : BoolAndExpression token(BoolOr) BoolOrExpression | BoolAndExpression

View File

@ -54,6 +54,7 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeStructField: case NodeTypeStructField:
case NodeTypeStructValueExpr: case NodeTypeStructValueExpr:
case NodeTypeStructValueField: case NodeTypeStructValueField:
case NodeTypeWhileExpr:
return node; return node;
} }
zig_panic("unreachable"); zig_panic("unreachable");
@ -526,6 +527,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
case NodeTypeCastExpr: case NodeTypeCastExpr:
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
case NodeTypeIfExpr: case NodeTypeIfExpr:
case NodeTypeWhileExpr:
case NodeTypeLabel: case NodeTypeLabel:
case NodeTypeGoto: case NodeTypeGoto:
case NodeTypeAsmExpr: case NodeTypeAsmExpr:
@ -593,6 +595,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
case NodeTypeCastExpr: case NodeTypeCastExpr:
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
case NodeTypeIfExpr: case NodeTypeIfExpr:
case NodeTypeWhileExpr:
case NodeTypeLabel: case NodeTypeLabel:
case NodeTypeGoto: case NodeTypeGoto:
case NodeTypeAsmExpr: case NodeTypeAsmExpr:
@ -1349,6 +1352,14 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp
return type_entry; return type_entry;
} }
static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.while_expr.condition);
analyze_expression(g, import, context, g->builtin_types.entry_void, node->data.while_expr.body);
return g->builtin_types.entry_void;
}
static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node) TypeTableEntry *expected_type, AstNode *node)
{ {
@ -1625,6 +1636,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
} }
break; break;
} }
case NodeTypeWhileExpr:
return_type = analyze_while_expr(g, import, context, expected_type, node);
break;
case NodeTypeStructValueExpr: case NodeTypeStructValueExpr:
return_type = analyze_struct_val_expr(g, import, context, expected_type, node); return_type = analyze_struct_val_expr(g, import, context, expected_type, node);
break; break;
@ -1775,6 +1789,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
case NodeTypeCastExpr: case NodeTypeCastExpr:
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
case NodeTypeIfExpr: case NodeTypeIfExpr:
case NodeTypeWhileExpr:
case NodeTypeLabel: case NodeTypeLabel:
case NodeTypeGoto: case NodeTypeGoto:
case NodeTypeAsmExpr: case NodeTypeAsmExpr:

View File

@ -1006,6 +1006,31 @@ static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) {
return tmp_struct_ptr; return tmp_struct_ptr;
} }
static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeWhileExpr);
assert(node->data.while_expr.condition);
assert(node->data.while_expr.body);
LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileCond");
LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody");
LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd");
add_debug_source_node(g, node);
LLVMBuildBr(g->builder, cond_block);
LLVMPositionBuilderAtEnd(g->builder, cond_block);
LLVMValueRef cond_val = gen_expr(g, node->data.while_expr.condition);
add_debug_source_node(g, node->data.while_expr.condition);
LLVMBuildCondBr(g->builder, cond_val, body_block, end_block);
LLVMPositionBuilderAtEnd(g->builder, body_block);
gen_expr(g, node->data.while_expr.body);
LLVMBuildBr(g->builder, cond_block);
LLVMPositionBuilderAtEnd(g->builder, end_block);
return nullptr;
}
static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
switch (node->type) { switch (node->type) {
case NodeTypeBinOpExpr: case NodeTypeBinOpExpr:
@ -1067,6 +1092,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
return LLVMConstNull(LLVMInt1Type()); return LLVMConstNull(LLVMInt1Type());
case NodeTypeIfExpr: case NodeTypeIfExpr:
return gen_if_expr(g, node); return gen_if_expr(g, node);
case NodeTypeWhileExpr:
return gen_while_expr(g, node);
case NodeTypeAsmExpr: case NodeTypeAsmExpr:
return gen_asm_expr(g, node); return gen_asm_expr(g, node);
case NodeTypeNumberLiteral: case NodeTypeNumberLiteral:

View File

@ -116,6 +116,8 @@ const char *node_type_str(NodeType node_type) {
return "BoolLiteral"; return "BoolLiteral";
case NodeTypeIfExpr: case NodeTypeIfExpr:
return "IfExpr"; return "IfExpr";
case NodeTypeWhileExpr:
return "WhileExpr";
case NodeTypeLabel: case NodeTypeLabel:
return "Label"; return "Label";
case NodeTypeGoto: case NodeTypeGoto:
@ -323,6 +325,11 @@ void ast_print(AstNode *node, int indent) {
if (node->data.if_expr.else_node) if (node->data.if_expr.else_node)
ast_print(node->data.if_expr.else_node, indent + 2); ast_print(node->data.if_expr.else_node, indent + 2);
break; break;
case NodeTypeWhileExpr:
fprintf(stderr, "%s\n", node_type_str(node->type));
ast_print(node->data.while_expr.condition, indent + 2);
ast_print(node->data.while_expr.body, indent + 2);
break;
case NodeTypeLabel: case NodeTypeLabel:
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name)); fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name));
break; break;
@ -1727,7 +1734,30 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool
} }
/* /*
BlockExpression : IfExpression | Block WhileExpression : token(While) Expression Block
*/
static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
if (token->id != TokenIdKeywordWhile) {
if (mandatory) {
ast_invalid_token_error(pc, token);
} else {
return nullptr;
}
}
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeWhileExpr, token);
node->data.while_expr.condition = ast_parse_expression(pc, token_index, true);
node->data.while_expr.body = ast_parse_block(pc, token_index, true);
return node;
}
/*
BlockExpression : IfExpression | Block | WhileExpression
*/ */
static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory) { static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index); Token *token = &pc->tokens->at(*token_index);
@ -1740,6 +1770,10 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma
if (block) if (block)
return block; return block;
AstNode *while_expr = ast_parse_while_expr(pc, token_index, false);
if (while_expr)
return while_expr;
if (mandatory) if (mandatory)
ast_invalid_token_error(pc, token); ast_invalid_token_error(pc, token);

View File

@ -45,6 +45,7 @@ enum NodeType {
NodeTypeVoid, NodeTypeVoid,
NodeTypeBoolLiteral, NodeTypeBoolLiteral,
NodeTypeIfExpr, NodeTypeIfExpr,
NodeTypeWhileExpr,
NodeTypeLabel, NodeTypeLabel,
NodeTypeGoto, NodeTypeGoto,
NodeTypeAsmExpr, NodeTypeAsmExpr,
@ -220,6 +221,11 @@ struct AstNodeIfExpr {
AstNode *else_node; // null, block node, or other if expr node AstNode *else_node; // null, block node, or other if expr node
}; };
struct AstNodeWhileExpr {
AstNode *condition;
AstNode *body;
};
struct AstNodeLabel { struct AstNodeLabel {
Buf name; Buf name;
}; };
@ -334,6 +340,7 @@ struct AstNode {
AstNodeArrayAccessExpr array_access_expr; AstNodeArrayAccessExpr array_access_expr;
AstNodeUse use; AstNodeUse use;
AstNodeIfExpr if_expr; AstNodeIfExpr if_expr;
AstNodeWhileExpr while_expr;
AstNodeLabel label; AstNodeLabel label;
AstNodeGoto go_to; AstNodeGoto go_to;
AstNodeAsmExpr asm_expr; AstNodeAsmExpr asm_expr;

View File

@ -233,6 +233,12 @@ static void end_token(Tokenize *t) {
t->cur_tok->id = TokenIdKeywordAsm; t->cur_tok->id = TokenIdKeywordAsm;
} else if (mem_eql_str(token_mem, token_len, "struct")) { } else if (mem_eql_str(token_mem, token_len, "struct")) {
t->cur_tok->id = TokenIdKeywordStruct; t->cur_tok->id = TokenIdKeywordStruct;
} else if (mem_eql_str(token_mem, token_len, "while")) {
t->cur_tok->id = TokenIdKeywordWhile;
} else if (mem_eql_str(token_mem, token_len, "continue")) {
t->cur_tok->id = TokenIdKeywordContinue;
} else if (mem_eql_str(token_mem, token_len, "break")) {
t->cur_tok->id = TokenIdKeywordBreak;
} }
t->cur_tok = nullptr; t->cur_tok = nullptr;
@ -955,6 +961,9 @@ static const char * token_name(Token *token) {
case TokenIdKeywordVolatile: return "Volatile"; case TokenIdKeywordVolatile: return "Volatile";
case TokenIdKeywordAsm: return "Asm"; case TokenIdKeywordAsm: return "Asm";
case TokenIdKeywordStruct: return "Struct"; case TokenIdKeywordStruct: return "Struct";
case TokenIdKeywordWhile: return "While";
case TokenIdKeywordContinue: return "Continue";
case TokenIdKeywordBreak: return "Break";
case TokenIdLParen: return "LParen"; case TokenIdLParen: return "LParen";
case TokenIdRParen: return "RParen"; case TokenIdRParen: return "RParen";
case TokenIdComma: return "Comma"; case TokenIdComma: return "Comma";

View File

@ -32,6 +32,9 @@ enum TokenId {
TokenIdKeywordAsm, TokenIdKeywordAsm,
TokenIdKeywordVolatile, TokenIdKeywordVolatile,
TokenIdKeywordStruct, TokenIdKeywordStruct,
TokenIdKeywordWhile,
TokenIdKeywordContinue,
TokenIdKeywordBreak,
TokenIdLParen, TokenIdLParen,
TokenIdRParen, TokenIdRParen,
TokenIdComma, TokenIdComma,