| author | |
| committer | |
| log | 925c805d4b2431b1c3140ba9c9dd7fc81de8a7d7 |
| tree | e443118694e1705665a9f251a031e26dd5e732d6 |
| parent | c2e5d50027779468c66608f445f3ab0f77d34c15 |
now creating .o file from hello.zig correctly8 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. |
| 40 | 40 | ||
| 41 | ## Roadmap | 41 | ## Roadmap |
| 42 | 42 | ||
| 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) |
| 87 | 85 | ||
| 88 | ParamDecl : token(Symbol) token(Colon) Type | 86 | ParamDecl : token(Symbol) token(Colon) Type |
| 89 | 87 | ||
| 90 | Type : token(Symbol) | PointerType | 88 | Type : token(Symbol) | PointerType | token(Unreachable) |
| 91 | 89 | ||
| 92 | PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type | 90 | PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type |
| 93 | 91 | ||
| ... | @@ -99,7 +97,7 @@ ExpressionStatement : Expression token(Semicolon) | ... | @@ -99,7 +97,7 @@ ExpressionStatement : Expression token(Semicolon) |
| 99 | 97 | ||
| 100 | ReturnStatement : token(Return) Expression token(Semicolon) | 98 | ReturnStatement : token(Return) Expression token(Semicolon) |
| 101 | 99 | ||
| 102 | Expression : token(Number) | token(String) | FnCall | 100 | Expression : token(Number) | token(String) | token(Unreachable) | FnCall |
| 103 | 101 | ||
| 104 | FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) | 102 | FnCall : 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 | }; |
| 28 | 28 | ||
| 29 | struct TypeNode { | ||
| 30 | LLVMTypeRef type_ref; | ||
| 31 | bool is_unreachable; | ||
| 32 | }; | ||
| 33 | |||
| 29 | struct CodeGenNode { | 34 | struct CodeGenNode { |
| 30 | union { | 35 | union { |
| 31 | LLVMTypeRef type_ref; // for NodeTypeType | 36 | TypeNode type_node; // for NodeTypeType |
| 32 | } data; | 37 | } data; |
| 33 | }; | 38 | }; |
| 34 | 39 | ||
| ... | @@ -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) { |
| 54 | static LLVMTypeRef to_llvm_type(AstNode *type_node) { | 59 | static 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); |
| 58 | 63 | ||
| 59 | return type_node->codegen_node->data.type_ref; | 64 | return type_node->codegen_node->data.type_node.type_ref; |
| 65 | } | ||
| 66 | |||
| 67 | |||
| 68 | static 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 | } |
| 61 | 73 | ||
| 62 | static void analyze_node(CodeGen *g, AstNode *node) { | 74 | static 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); | ||
| 87 | 100 | ||
| 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); |
| 92 | 105 | ||
| 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, ""); |
| 237 | 266 | ||
| 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 | } |
| 240 | 273 | ||
| 241 | static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str) { | 274 | static 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); |
| 335 | 370 | ||
| 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); |
| 338 | 377 |
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"); | ||
| 118 | 120 | ||
| 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 | } |
| 237 | 237 | ||
| 238 | /* | 238 | /* |
| 239 | Type : token(Symbol) | PointerType; | 239 | Type : token(Symbol) | PointerType | token(Unreachable) |
| 240 | PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type; | 240 | PointerType : token(Star) token(Const) Type | token(Star) token(Mut) Type; |
| 241 | */ | 241 | */ |
| 242 | static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token_index) { | 242 | static 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 |
| 245 | 245 | ||
| 246 | AstNode *node = ast_create_node(NodeTypeType, token); | 246 | AstNode *node = ast_create_node(NodeTypeType, token); |
| 247 | 247 | ||
| 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 | } |
| 375 | 378 | ||
| 379 | /* | ||
| 380 | Expression : token(Number) | token(String) | token(Unreachable) | FnCall | ||
| 381 | */ | ||
| 376 | static AstNode *ast_parse_expression(ParseContext *pc, int token_index, int *new_token_index) { | 382 | static 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) ; |
| 402 | 411 | ||
| 403 | ReturnStatement : token(Return) Expression token(Semicolon) ; | 412 | ReturnStatement : token(Return) Expression token(Semicolon) ; |
| 404 | 413 | ||
| 405 | Expression : token(Number) | token(String) | FnCall ; | 414 | Expression : token(Number) | token(String) | token(Unreachable) | FnCall |
| 406 | 415 | ||
| 407 | FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen) ; | 416 | FnCall : 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 | }; |
| 98 | 99 | ||
| 99 | struct AstNodeExpression { | 100 | struct 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 | } |
| 156 | 158 | ||
| 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 @@ |
| 1 | extern { | 1 | extern { |
| 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 | } |
| 5 | 5 | ||
| 6 | fn _start() { | 6 | fn _start() -> unreachable { |
| 7 | puts("Hello, world!"); | 7 | puts("Hello, world!"); |
| 8 | exit(0); | 8 | exit(0); |
| 9 | } | 9 | } |