authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-24 13:37:14-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-24 13:37:14-07:00
log925c805d4b2431b1c3140ba9c9dd7fc81de8a7d7
treee443118694e1705665a9f251a031e26dd5e732d6
parentc2e5d50027779468c66608f445f3ab0f77d34c15

add unreachable expression

now creating .o file from hello.zig correctly

8 files changed, 95 insertions(+), 41 deletions(-)

README.md+2-4
...@@ -40,8 +40,6 @@ readable, safe, optimal, and concise code to solve any computing problem....@@ -40,8 +40,6 @@ readable, safe, optimal, and concise code to solve any computing problem.
4040
41## Roadmap41## Roadmap
4242
43 * Hello, world.
44 - Produce .o file.
45 * Produce executable file instead of .o file.43 * Produce executable file instead of .o file.
46 * Add debugging symbols.44 * Add debugging symbols.
47 * Debug/Release mode.45 * Debug/Release mode.
...@@ -87,7 +85,7 @@ ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)...@@ -87,7 +85,7 @@ ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)
8785
88ParamDecl : token(Symbol) token(Colon) Type86ParamDecl : token(Symbol) token(Colon) Type
8987
90Type : token(Symbol) | PointerType88Type : token(Symbol) | PointerType | token(Unreachable)
9189
92PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type90PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type
9391
...@@ -99,7 +97,7 @@ ExpressionStatement : Expression token(Semicolon)...@@ -99,7 +97,7 @@ ExpressionStatement : Expression token(Semicolon)
9997
100ReturnStatement : token(Return) Expression token(Semicolon)98ReturnStatement : token(Return) Expression token(Semicolon)
10199
102Expression : token(Number) | token(String) | FnCall100Expression : token(Number) | token(String) | token(Unreachable) | FnCall
103101
104FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen)102FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen)
105```103```
src/codegen.cpp+69-30
...@@ -26,9 +26,14 @@ struct CodeGen {...@@ -26,9 +26,14 @@ struct CodeGen {
26 HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;26 HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
27};27};
2828
29struct TypeNode {
30 LLVMTypeRef type_ref;
31 bool is_unreachable;
32};
33
29struct CodeGenNode {34struct CodeGenNode {
30 union {35 union {
31 LLVMTypeRef type_ref; // for NodeTypeType36 TypeNode type_node; // for NodeTypeType
32 } data;37 } data;
33};38};
3439
...@@ -54,9 +59,16 @@ static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {...@@ -54,9 +59,16 @@ static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
54static LLVMTypeRef to_llvm_type(AstNode *type_node) {59static LLVMTypeRef to_llvm_type(AstNode *type_node) {
55 assert(type_node->type == NodeTypeType);60 assert(type_node->type == NodeTypeType);
56 assert(type_node->codegen_node);61 assert(type_node->codegen_node);
57 assert(type_node->codegen_node->data.type_ref);62 assert(type_node->codegen_node->data.type_node.type_ref);
5863
59 return type_node->codegen_node->data.type_ref;64 return type_node->codegen_node->data.type_node.type_ref;
65}
66
67
68static bool type_is_unreachable(AstNode *type_node) {
69 assert(type_node->type == NodeTypeType);
70 return type_node->data.type.type == AstNodeTypeTypePrimitive &&
71 buf_eql_str(&type_node->data.type.primitive_name, "unreachable");
60}72}
6173
62static void analyze_node(CodeGen *g, AstNode *node) {74static void analyze_node(CodeGen *g, AstNode *node) {
...@@ -83,13 +95,18 @@ static void analyze_node(CodeGen *g, AstNode *node) {...@@ -83,13 +95,18 @@ static void analyze_node(CodeGen *g, AstNode *node) {
83 AstNode *param_type = param_node->data.param_decl.type;95 AstNode *param_type = param_node->data.param_decl.type;
84 fn_param_values[param_i] = to_llvm_type(param_type);96 fn_param_values[param_i] = to_llvm_type(param_type);
85 }97 }
86 LLVMTypeRef return_type = to_llvm_type(fn_proto->data.fn_proto.return_type);98 AstNode *return_type_node = fn_proto->data.fn_proto.return_type;
99 LLVMTypeRef return_type = to_llvm_type(return_type_node);
87100
88 LLVMTypeRef fn_type = LLVMFunctionType(return_type, fn_param_values, params->length, 0);101 LLVMTypeRef fn_type = LLVMFunctionType(return_type, fn_param_values, params->length, 0);
89 LLVMValueRef fn_val = LLVMAddFunction(g->mod, buf_ptr(name), fn_type);102 LLVMValueRef fn_val = LLVMAddFunction(g->mod, buf_ptr(name), fn_type);
90 LLVMSetLinkage(fn_val, LLVMExternalLinkage);103 LLVMSetLinkage(fn_val, LLVMExternalLinkage);
91 LLVMSetFunctionCallConv(fn_val, LLVMCCallConv);104 LLVMSetFunctionCallConv(fn_val, LLVMCCallConv);
92105
106 if (type_is_unreachable(return_type_node)) {
107 LLVMAddFunctionAttr(fn_val, LLVMNoReturnAttribute);
108 }
109
93 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);110 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
94 fn_table_entry->fn_value = fn_val;111 fn_table_entry->fn_value = fn_val;
95 fn_table_entry->proto_node = fn_proto;112 fn_table_entry->proto_node = fn_proto;
...@@ -131,33 +148,43 @@ static void analyze_node(CodeGen *g, AstNode *node) {...@@ -131,33 +148,43 @@ static void analyze_node(CodeGen *g, AstNode *node) {
131 analyze_node(g, node->data.param_decl.type);148 analyze_node(g, node->data.param_decl.type);
132 break;149 break;
133 case NodeTypeType:150 case NodeTypeType:
134 node->codegen_node = allocate<CodeGenNode>(1);151 {
135 switch (node->data.type.type) {152 node->codegen_node = allocate<CodeGenNode>(1);
136 case AstNodeTypeTypePrimitive:153 TypeNode *type_node = &node->codegen_node->data.type_node;
137 {154 switch (node->data.type.type) {
138 Buf *name = &node->data.type.primitive_name;155 case AstNodeTypeTypePrimitive:
139 if (buf_eql_str(name, "u8")) {156 {
140 node->codegen_node->data.type_ref = LLVMInt8Type();157 Buf *name = &node->data.type.primitive_name;
141 } else if (buf_eql_str(name, "i32")) {158 if (buf_eql_str(name, "u8")) {
142 node->codegen_node->data.type_ref = LLVMInt32Type();159 type_node->type_ref = LLVMInt8Type();
143 } else if (buf_eql_str(name, "void")) {160 } else if (buf_eql_str(name, "i32")) {
144 node->codegen_node->data.type_ref = LLVMVoidType();161 type_node->type_ref = LLVMInt32Type();
145 } else {162 } else if (buf_eql_str(name, "void")) {
146 add_node_error(g, node,163 type_node->type_ref = LLVMVoidType();
147 buf_sprintf("invalid type name: '%s'", buf_ptr(name)));164 } else if (buf_eql_str(name, "unreachable")) {
148 node->codegen_node->data.type_ref = LLVMInt8Type();165 type_node->type_ref = LLVMVoidType();
166 type_node->is_unreachable = true;
167 } else {
168 add_node_error(g, node,
169 buf_sprintf("invalid type name: '%s'", buf_ptr(name)));
170 type_node->type_ref = LLVMVoidType();
171 }
172 break;
149 }173 }
150 break;174 case AstNodeTypeTypePointer:
151 }175 {
152 case AstNodeTypeTypePointer:176 analyze_node(g, node->data.type.child_type);
153 {177 TypeNode *child_type_node = &node->data.type.child_type->codegen_node->data.type_node;
154 analyze_node(g, node->data.type.child_type);178 if (child_type_node->is_unreachable) {
155 node->codegen_node->data.type_ref = LLVMPointerType(179 add_node_error(g, node,
156 node->data.type.child_type->codegen_node->data.type_ref, 0);180 buf_create_from_str("pointer to unreachable not allowed"));
157 break;181 }
158 }182 type_node->type_ref = LLVMPointerType(child_type_node->type_ref, 0);
183 break;
184 }
185 }
186 break;
159 }187 }
160 break;
161 case NodeTypeBlock:188 case NodeTypeBlock:
162 for (int i = 0; i < node->data.block.statements.length; i += 1) {189 for (int i = 0; i < node->data.block.statements.length; i += 1) {
163 AstNode *child = node->data.block.statements.at(i);190 AstNode *child = node->data.block.statements.at(i);
...@@ -183,6 +210,8 @@ static void analyze_node(CodeGen *g, AstNode *node) {...@@ -183,6 +210,8 @@ static void analyze_node(CodeGen *g, AstNode *node) {
183 case AstNodeExpressionTypeFnCall:210 case AstNodeExpressionTypeFnCall:
184 analyze_node(g, node->data.expression.data.fn_call);211 analyze_node(g, node->data.expression.data.fn_call);
185 break;212 break;
213 case AstNodeExpressionTypeUnreachable:
214 break;
186 }215 }
187 break;216 break;
188 case NodeTypeFnCall:217 case NodeTypeFnCall:
...@@ -235,7 +264,11 @@ static LLVMValueRef gen_fn_call(CodeGen *g, AstNode *fn_call_node) {...@@ -235,7 +264,11 @@ static LLVMValueRef gen_fn_call(CodeGen *g, AstNode *fn_call_node) {
235 LLVMValueRef result = LLVMBuildCall(g->builder, fn_table_entry->fn_value,264 LLVMValueRef result = LLVMBuildCall(g->builder, fn_table_entry->fn_value,
236 param_values, actual_param_count, "");265 param_values, actual_param_count, "");
237266
238 return result;267 if (type_is_unreachable(fn_table_entry->proto_node->data.fn_proto.return_type)) {
268 return LLVMBuildUnreachable(g->builder);
269 } else {
270 return result;
271 }
239}272}
240273
241static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) {274static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) {
...@@ -280,6 +313,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node) {...@@ -280,6 +313,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node) {
280 }313 }
281 case AstNodeExpressionTypeFnCall:314 case AstNodeExpressionTypeFnCall:
282 return gen_fn_call(g, expr_node->data.expression.data.fn_call);315 return gen_fn_call(g, expr_node->data.expression.data.fn_call);
316 case AstNodeExpressionTypeUnreachable:
317 return LLVMBuildUnreachable(g->builder);
283 }318 }
284 zig_unreachable();319 zig_unreachable();
285}320}
...@@ -333,6 +368,10 @@ void code_gen(CodeGen *g) {...@@ -333,6 +368,10 @@ void code_gen(CodeGen *g) {
333 LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, fn_proto->params.length, 0);368 LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, fn_proto->params.length, 0);
334 LLVMValueRef fn = LLVMAddFunction(g->mod, buf_ptr(&fn_proto->name), function_type);369 LLVMValueRef fn = LLVMAddFunction(g->mod, buf_ptr(&fn_proto->name), function_type);
335370
371 if (type_is_unreachable(fn_proto->return_type)) {
372 LLVMAddFunctionAttr(fn, LLVMNoReturnAttribute);
373 }
374
336 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn, "entry");375 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn, "entry");
337 LLVMPositionBuilderAtEnd(g->builder, entry_block);376 LLVMPositionBuilderAtEnd(g->builder, entry_block);
338377
src/main.cpp+3-1
...@@ -102,7 +102,8 @@ static int build(const char *arg0, const char *in_file, const char *out_file, Zi...@@ -102,7 +102,8 @@ static int build(const char *arg0, const char *in_file, const char *out_file, Zi
102 } else {102 } else {
103 for (int i = 0; i < errors->length; i += 1) {103 for (int i = 0; i < errors->length; i += 1) {
104 ErrorMsg *err = &errors->at(i);104 ErrorMsg *err = &errors->at(i);
105 fprintf(stderr, "Error: Line %d, column %d: %s\n", err->line_start, err->column_start,105 fprintf(stderr, "Error: Line %d, column %d: %s\n",
106 err->line_start + 1, err->column_start + 1,
106 buf_ptr(err->msg));107 buf_ptr(err->msg));
107 }108 }
108 return 1;109 return 1;
...@@ -115,6 +116,7 @@ static int build(const char *arg0, const char *in_file, const char *out_file, Zi...@@ -115,6 +116,7 @@ static int build(const char *arg0, const char *in_file, const char *out_file, Zi
115 fprintf(stderr, "\nLink:\n");116 fprintf(stderr, "\nLink:\n");
116 fprintf(stderr, "------------------\n");117 fprintf(stderr, "------------------\n");
117 code_gen_link(codegen, false, out_file);118 code_gen_link(codegen, false, out_file);
119 fprintf(stderr, "OK\n");
118120
119 return 0;121 return 0;
120}122}
src/parser.cpp+14-4
...@@ -236,7 +236,7 @@ static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {...@@ -236,7 +236,7 @@ static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
236}236}
237237
238/*238/*
239Type : token(Symbol) | PointerType;239Type : token(Symbol) | PointerType | token(Unreachable)
240PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type;240PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type;
241*/241*/
242static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token_index) {242static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token_index) {
...@@ -245,7 +245,10 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token...@@ -245,7 +245,10 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token
245245
246 AstNode *node = ast_create_node(NodeTypeType, token);246 AstNode *node = ast_create_node(NodeTypeType, token);
247247
248 if (token->id == TokenIdSymbol) {248 if (token->id == TokenIdKeywordUnreachable) {
249 node->data.type.type = AstNodeTypeTypePrimitive;
250 buf_init_from_str(&node->data.type.primitive_name, "unreachable");
251 } else if (token->id == TokenIdSymbol) {
249 node->data.type.type = AstNodeTypeTypePrimitive;252 node->data.type.type = AstNodeTypeTypePrimitive;
250 ast_buf_from_token(pc, token, &node->data.type.primitive_name);253 ast_buf_from_token(pc, token, &node->data.type.primitive_name);
251 } else if (token->id == TokenIdStar) {254 } else if (token->id == TokenIdStar) {
...@@ -373,10 +376,16 @@ static AstNode *ast_parse_fn_call(ParseContext *pc, int token_index, int *new_to...@@ -373,10 +376,16 @@ static AstNode *ast_parse_fn_call(ParseContext *pc, int token_index, int *new_to
373 return node;376 return node;
374}377}
375378
379/*
380Expression : token(Number) | token(String) | token(Unreachable) | FnCall
381*/
376static AstNode *ast_parse_expression(ParseContext *pc, int token_index, int *new_token_index) {382static AstNode *ast_parse_expression(ParseContext *pc, int token_index, int *new_token_index) {
377 Token *token = &pc->tokens->at(token_index);383 Token *token = &pc->tokens->at(token_index);
378 AstNode *node = ast_create_node(NodeTypeExpression, token);384 AstNode *node = ast_create_node(NodeTypeExpression, token);
379 if (token->id == TokenIdSymbol) {385 if (token->id == TokenIdKeywordUnreachable) {
386 node->data.expression.type = AstNodeExpressionTypeUnreachable;
387 token_index += 1;
388 } else if (token->id == TokenIdSymbol) {
380 node->data.expression.type = AstNodeExpressionTypeFnCall;389 node->data.expression.type = AstNodeExpressionTypeFnCall;
381 node->data.expression.data.fn_call = ast_parse_fn_call(pc, token_index, &token_index);390 node->data.expression.data.fn_call = ast_parse_fn_call(pc, token_index, &token_index);
382 } else if (token->id == TokenIdNumberLiteral) {391 } else if (token->id == TokenIdNumberLiteral) {
...@@ -402,7 +411,7 @@ ExpressionStatement : Expression token(Semicolon) ;...@@ -402,7 +411,7 @@ ExpressionStatement : Expression token(Semicolon) ;
402411
403ReturnStatement : token(Return) Expression token(Semicolon) ;412ReturnStatement : token(Return) Expression token(Semicolon) ;
404413
405Expression : token(Number) | token(String) | FnCall ;414Expression : token(Number) | token(String) | token(Unreachable) | FnCall
406415
407FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) ;416FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) ;
408*/417*/
...@@ -420,6 +429,7 @@ static AstNode *ast_parse_statement(ParseContext *pc, int token_index, int *new_...@@ -420,6 +429,7 @@ static AstNode *ast_parse_statement(ParseContext *pc, int token_index, int *new_
420 ast_expect_token(pc, semicolon, TokenIdSemicolon);429 ast_expect_token(pc, semicolon, TokenIdSemicolon);
421 } else if (token->id == TokenIdSymbol ||430 } else if (token->id == TokenIdSymbol ||
422 token->id == TokenIdStringLiteral ||431 token->id == TokenIdStringLiteral ||
432 token->id == TokenIdKeywordUnreachable ||
423 token->id == TokenIdNumberLiteral)433 token->id == TokenIdNumberLiteral)
424 {434 {
425 node->data.statement.type = AstNodeStatementTypeExpression;435 node->data.statement.type = AstNodeStatementTypeExpression;
src/parser.hpp+1
...@@ -94,6 +94,7 @@ enum AstNodeExpressionType {...@@ -94,6 +94,7 @@ enum AstNodeExpressionType {
94 AstNodeExpressionTypeNumber,94 AstNodeExpressionTypeNumber,
95 AstNodeExpressionTypeString,95 AstNodeExpressionTypeString,
96 AstNodeExpressionTypeFnCall,96 AstNodeExpressionTypeFnCall,
97 AstNodeExpressionTypeUnreachable,
97};98};
9899
99struct AstNodeExpression {100struct AstNodeExpression {
src/tokenizer.cpp+3
...@@ -152,6 +152,8 @@ static void end_token(Tokenize *t) {...@@ -152,6 +152,8 @@ static void end_token(Tokenize *t) {
152 t->cur_tok->id = TokenIdKeywordConst;152 t->cur_tok->id = TokenIdKeywordConst;
153 } else if (mem_eql_str(token_mem, token_len, "extern")) {153 } else if (mem_eql_str(token_mem, token_len, "extern")) {
154 t->cur_tok->id = TokenIdKeywordExtern;154 t->cur_tok->id = TokenIdKeywordExtern;
155 } else if (mem_eql_str(token_mem, token_len, "unreachable")) {
156 t->cur_tok->id = TokenIdKeywordUnreachable;
155 }157 }
156158
157 t->cur_tok = nullptr;159 t->cur_tok = nullptr;
...@@ -311,6 +313,7 @@ static const char * token_name(Token *token) {...@@ -311,6 +313,7 @@ static const char * token_name(Token *token) {
311 case TokenIdKeywordMut: return "Mut";313 case TokenIdKeywordMut: return "Mut";
312 case TokenIdKeywordReturn: return "Return";314 case TokenIdKeywordReturn: return "Return";
313 case TokenIdKeywordExtern: return "Extern";315 case TokenIdKeywordExtern: return "Extern";
316 case TokenIdKeywordUnreachable: return "Unreachable";
314 case TokenIdLParen: return "LParen";317 case TokenIdLParen: return "LParen";
315 case TokenIdRParen: return "RParen";318 case TokenIdRParen: return "RParen";
316 case TokenIdComma: return "Comma";319 case TokenIdComma: return "Comma";
src/tokenizer.hpp+1
...@@ -18,6 +18,7 @@ enum TokenId {...@@ -18,6 +18,7 @@ enum TokenId {
18 TokenIdKeywordMut,18 TokenIdKeywordMut,
19 TokenIdKeywordConst,19 TokenIdKeywordConst,
20 TokenIdKeywordExtern,20 TokenIdKeywordExtern,
21 TokenIdKeywordUnreachable,
21 TokenIdLParen,22 TokenIdLParen,
22 TokenIdRParen,23 TokenIdRParen,
23 TokenIdComma,24 TokenIdComma,
test/hello.zig+2-2
...@@ -1,9 +1,9 @@...@@ -1,9 +1,9 @@
1extern {1extern {
2 fn puts(s: *mut u8) -> i32;2 fn puts(s: *mut u8) -> i32;
3 fn exit(code: i32);3 fn exit(code: i32) -> unreachable;
4}4}
55
6fn _start() {6fn _start() -> unreachable {
7 puts("Hello, world!");7 puts("Hello, world!");
8 exit(0);8 exit(0);
9}9}