| author | |
| committer | |
| log | f1aaf1353e12aa39bd6f89588852a1c70e8424b3 |
| tree | 38d2f72517dc257ef4f8eb09ff4ae84be0819201 |
| parent | 6494cf208e8045c58e8ab79fb76e360cec077263 |
8 files changed, 52 insertions(+), 2 deletions(-)
README.md+3-1| ... | @@ -163,11 +163,13 @@ FnCallExpression : PrimaryExpression token(LParen) list(Expression, token(Comma) | ... | @@ -163,11 +163,13 @@ FnCallExpression : PrimaryExpression token(LParen) list(Expression, token(Comma) |
| 163 | 163 | ||
| 164 | PrefixOp : token(Not) | token(Dash) | token(Tilde) | 164 | PrefixOp : token(Not) | token(Dash) | token(Tilde) |
| 165 | 165 | ||
| 166 | PrimaryExpression : token(Number) | token(String) | token(Unreachable) | GroupedExpression | token(Symbol) | Goto | 166 | PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | token(Symbol) | Goto |
| 167 | 167 | ||
| 168 | Goto: token(Goto) token(Symbol) | 168 | Goto: token(Goto) token(Symbol) |
| 169 | 169 | ||
| 170 | GroupedExpression : token(LParen) Expression token(RParen) | 170 | GroupedExpression : token(LParen) Expression token(RParen) |
| 171 | |||
| 172 | KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) | ||
| 171 | ``` | 173 | ``` |
| 172 | 174 | ||
| 173 | ### Operator Precedence | 175 | ### Operator Precedence |
example/expressions/expressions.zig+7-1| ... | @@ -4,6 +4,12 @@ extern { | ... | @@ -4,6 +4,12 @@ extern { |
| 4 | fn exit(code: i32) -> unreachable; | 4 | fn exit(code: i32) -> unreachable; |
| 5 | } | 5 | } |
| 6 | 6 | ||
| 7 | fn other_exit() -> unreachable { | ||
| 8 | if (true) { exit(0); } | ||
| 9 | // the unreachable statement is the programmer assuring the compiler that this code is impossible to execute. | ||
| 10 | unreachable; | ||
| 11 | } | ||
| 12 | |||
| 7 | export fn _start() -> unreachable { | 13 | export fn _start() -> unreachable { |
| 8 | let a : i32 = 1; | 14 | let a : i32 = 1; |
| 9 | let b = 2; | 15 | let b = 2; |
| ... | @@ -19,5 +25,5 @@ export fn _start() -> unreachable { | ... | @@ -19,5 +25,5 @@ export fn _start() -> unreachable { |
| 19 | no_conflict | 25 | no_conflict |
| 20 | }; | 26 | }; |
| 21 | if (c == 10) { puts("OK 2"); } | 27 | if (c == 10) { puts("OK 2"); } |
| 22 | exit(0); | 28 | other_exit(); |
| 23 | } | 29 | } |
src/analyze.cpp+6| ... | @@ -297,6 +297,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, | ... | @@ -297,6 +297,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 297 | case NodeTypeStringLiteral: | 297 | case NodeTypeStringLiteral: |
| 298 | case NodeTypeUnreachable: | 298 | case NodeTypeUnreachable: |
| 299 | case NodeTypeVoid: | 299 | case NodeTypeVoid: |
| 300 | case NodeTypeBoolLiteral: | ||
| 300 | case NodeTypeSymbol: | 301 | case NodeTypeSymbol: |
| 301 | case NodeTypeCastExpr: | 302 | case NodeTypeCastExpr: |
| 302 | case NodeTypePrefixOpExpr: | 303 | case NodeTypePrefixOpExpr: |
| ... | @@ -592,6 +593,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -592,6 +593,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 592 | return_type = g->builtin_types.entry_void; | 593 | return_type = g->builtin_types.entry_void; |
| 593 | break; | 594 | break; |
| 594 | 595 | ||
| 596 | case NodeTypeBoolLiteral: | ||
| 597 | return_type = g->builtin_types.entry_bool; | ||
| 598 | break; | ||
| 599 | |||
| 595 | case NodeTypeSymbol: | 600 | case NodeTypeSymbol: |
| 596 | { | 601 | { |
| 597 | Buf *symbol_name = &node->data.symbol; | 602 | Buf *symbol_name = &node->data.symbol; |
| ... | @@ -766,6 +771,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, | ... | @@ -766,6 +771,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 766 | case NodeTypeStringLiteral: | 771 | case NodeTypeStringLiteral: |
| 767 | case NodeTypeUnreachable: | 772 | case NodeTypeUnreachable: |
| 768 | case NodeTypeVoid: | 773 | case NodeTypeVoid: |
| 774 | case NodeTypeBoolLiteral: | ||
| 769 | case NodeTypeSymbol: | 775 | case NodeTypeSymbol: |
| 770 | case NodeTypeCastExpr: | 776 | case NodeTypeCastExpr: |
| 771 | case NodeTypePrefixOpExpr: | 777 | case NodeTypePrefixOpExpr: |
src/codegen.cpp+5| ... | @@ -487,6 +487,11 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { | ... | @@ -487,6 +487,11 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 487 | return LLVMBuildUnreachable(g->builder); | 487 | return LLVMBuildUnreachable(g->builder); |
| 488 | case NodeTypeVoid: | 488 | case NodeTypeVoid: |
| 489 | return nullptr; | 489 | return nullptr; |
| 490 | case NodeTypeBoolLiteral: | ||
| 491 | if (node->data.bool_literal) | ||
| 492 | return LLVMConstAllOnes(LLVMInt1Type()); | ||
| 493 | else | ||
| 494 | return LLVMConstNull(LLVMInt1Type()); | ||
| 490 | case NodeTypeIfExpr: | 495 | case NodeTypeIfExpr: |
| 491 | return gen_if_expr(g, node); | 496 | return gen_if_expr(g, node); |
| 492 | case NodeTypeNumberLiteral: | 497 | case NodeTypeNumberLiteral: |
src/parser.cpp+21| ... | @@ -93,6 +93,8 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -93,6 +93,8 @@ const char *node_type_str(NodeType node_type) { |
| 93 | return "Use"; | 93 | return "Use"; |
| 94 | case NodeTypeVoid: | 94 | case NodeTypeVoid: |
| 95 | return "Void"; | 95 | return "Void"; |
| 96 | case NodeTypeBoolLiteral: | ||
| 97 | return "BoolLiteral"; | ||
| 96 | case NodeTypeIfExpr: | 98 | case NodeTypeIfExpr: |
| 97 | return "IfExpr"; | 99 | return "IfExpr"; |
| 98 | case NodeTypeLabel: | 100 | case NodeTypeLabel: |
| ... | @@ -256,6 +258,9 @@ void ast_print(AstNode *node, int indent) { | ... | @@ -256,6 +258,9 @@ void ast_print(AstNode *node, int indent) { |
| 256 | case NodeTypeVoid: | 258 | case NodeTypeVoid: |
| 257 | fprintf(stderr, "%s\n", node_type_str(node->type)); | 259 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| 258 | break; | 260 | break; |
| 261 | case NodeTypeBoolLiteral: | ||
| 262 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), node->data.bool_literal ? "true" : "false"); | ||
| 263 | break; | ||
| 259 | case NodeTypeIfExpr: | 264 | case NodeTypeIfExpr: |
| 260 | fprintf(stderr, "%s\n", node_type_str(node->type)); | 265 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| 261 | if (node->data.if_expr.condition) | 266 | if (node->data.if_expr.condition) |
| ... | @@ -457,6 +462,12 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token | ... | @@ -457,6 +462,12 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token |
| 457 | } else if (token->id == TokenIdKeywordVoid) { | 462 | } else if (token->id == TokenIdKeywordVoid) { |
| 458 | node->data.type.type = AstNodeTypeTypePrimitive; | 463 | node->data.type.type = AstNodeTypeTypePrimitive; |
| 459 | buf_init_from_str(&node->data.type.primitive_name, "void"); | 464 | buf_init_from_str(&node->data.type.primitive_name, "void"); |
| 465 | } else if (token->id == TokenIdKeywordTrue) { | ||
| 466 | node->data.type.type = AstNodeTypeTypePrimitive; | ||
| 467 | buf_init_from_str(&node->data.type.primitive_name, "true"); | ||
| 468 | } else if (token->id == TokenIdKeywordFalse) { | ||
| 469 | node->data.type.type = AstNodeTypeTypePrimitive; | ||
| 470 | buf_init_from_str(&node->data.type.primitive_name, "false"); | ||
| 460 | } else if (token->id == TokenIdSymbol) { | 471 | } else if (token->id == TokenIdSymbol) { |
| 461 | node->data.type.type = AstNodeTypeTypePrimitive; | 472 | node->data.type.type = AstNodeTypeTypePrimitive; |
| 462 | ast_buf_from_token(pc, token, &node->data.type.primitive_name); | 473 | ast_buf_from_token(pc, token, &node->data.type.primitive_name); |
| ... | @@ -614,6 +625,16 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool | ... | @@ -614,6 +625,16 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 614 | AstNode *node = ast_create_node(pc, NodeTypeVoid, token); | 625 | AstNode *node = ast_create_node(pc, NodeTypeVoid, token); |
| 615 | *token_index += 1; | 626 | *token_index += 1; |
| 616 | return node; | 627 | return node; |
| 628 | } else if (token->id == TokenIdKeywordTrue) { | ||
| 629 | AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token); | ||
| 630 | node->data.bool_literal = true; | ||
| 631 | *token_index += 1; | ||
| 632 | return node; | ||
| 633 | } else if (token->id == TokenIdKeywordFalse) { | ||
| 634 | AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token); | ||
| 635 | node->data.bool_literal = false; | ||
| 636 | *token_index += 1; | ||
| 637 | return node; | ||
| 617 | } else if (token->id == TokenIdSymbol) { | 638 | } else if (token->id == TokenIdSymbol) { |
| 618 | AstNode *node = ast_create_node(pc, NodeTypeSymbol, token); | 639 | AstNode *node = ast_create_node(pc, NodeTypeSymbol, token); |
| 619 | ast_buf_from_token(pc, token, &node->data.symbol); | 640 | ast_buf_from_token(pc, token, &node->data.symbol); |
src/parser.hpp+2| ... | @@ -40,6 +40,7 @@ enum NodeType { | ... | @@ -40,6 +40,7 @@ enum NodeType { |
| 40 | NodeTypeFnCallExpr, | 40 | NodeTypeFnCallExpr, |
| 41 | NodeTypeUse, | 41 | NodeTypeUse, |
| 42 | NodeTypeVoid, | 42 | NodeTypeVoid, |
| 43 | NodeTypeBoolLiteral, | ||
| 43 | NodeTypeIfExpr, | 44 | NodeTypeIfExpr, |
| 44 | NodeTypeLabel, | 45 | NodeTypeLabel, |
| 45 | NodeTypeGoto, | 46 | NodeTypeGoto, |
| ... | @@ -222,6 +223,7 @@ struct AstNode { | ... | @@ -222,6 +223,7 @@ struct AstNode { |
| 222 | Buf number; | 223 | Buf number; |
| 223 | Buf string; | 224 | Buf string; |
| 224 | Buf symbol; | 225 | Buf symbol; |
| 226 | bool bool_literal; | ||
| 225 | } data; | 227 | } data; |
| 226 | }; | 228 | }; |
| 227 | 229 |
src/tokenizer.cpp+6| ... | @@ -185,6 +185,10 @@ static void end_token(Tokenize *t) { | ... | @@ -185,6 +185,10 @@ static void end_token(Tokenize *t) { |
| 185 | t->cur_tok->id = TokenIdKeywordUse; | 185 | t->cur_tok->id = TokenIdKeywordUse; |
| 186 | } else if (mem_eql_str(token_mem, token_len, "void")) { | 186 | } else if (mem_eql_str(token_mem, token_len, "void")) { |
| 187 | t->cur_tok->id = TokenIdKeywordVoid; | 187 | t->cur_tok->id = TokenIdKeywordVoid; |
| 188 | } else if (mem_eql_str(token_mem, token_len, "true")) { | ||
| 189 | t->cur_tok->id = TokenIdKeywordTrue; | ||
| 190 | } else if (mem_eql_str(token_mem, token_len, "false")) { | ||
| 191 | t->cur_tok->id = TokenIdKeywordFalse; | ||
| 188 | } else if (mem_eql_str(token_mem, token_len, "if")) { | 192 | } else if (mem_eql_str(token_mem, token_len, "if")) { |
| 189 | t->cur_tok->id = TokenIdKeywordIf; | 193 | t->cur_tok->id = TokenIdKeywordIf; |
| 190 | } else if (mem_eql_str(token_mem, token_len, "else")) { | 194 | } else if (mem_eql_str(token_mem, token_len, "else")) { |
| ... | @@ -586,6 +590,8 @@ static const char * token_name(Token *token) { | ... | @@ -586,6 +590,8 @@ static const char * token_name(Token *token) { |
| 586 | case TokenIdKeywordAs: return "As"; | 590 | case TokenIdKeywordAs: return "As"; |
| 587 | case TokenIdKeywordUse: return "Use"; | 591 | case TokenIdKeywordUse: return "Use"; |
| 588 | case TokenIdKeywordVoid: return "Void"; | 592 | case TokenIdKeywordVoid: return "Void"; |
| 593 | case TokenIdKeywordTrue: return "True"; | ||
| 594 | case TokenIdKeywordFalse: return "False"; | ||
| 589 | case TokenIdKeywordIf: return "If"; | 595 | case TokenIdKeywordIf: return "If"; |
| 590 | case TokenIdKeywordElse: return "Else"; | 596 | case TokenIdKeywordElse: return "Else"; |
| 591 | case TokenIdKeywordGoto: return "Goto"; | 597 | case TokenIdKeywordGoto: return "Goto"; |
src/tokenizer.hpp+2| ... | @@ -25,6 +25,8 @@ enum TokenId { | ... | @@ -25,6 +25,8 @@ enum TokenId { |
| 25 | TokenIdKeywordAs, | 25 | TokenIdKeywordAs, |
| 26 | TokenIdKeywordUse, | 26 | TokenIdKeywordUse, |
| 27 | TokenIdKeywordVoid, | 27 | TokenIdKeywordVoid, |
| 28 | TokenIdKeywordTrue, | ||
| 29 | TokenIdKeywordFalse, | ||
| 28 | TokenIdKeywordIf, | 30 | TokenIdKeywordIf, |
| 29 | TokenIdKeywordElse, | 31 | TokenIdKeywordElse, |
| 30 | TokenIdKeywordGoto, | 32 | TokenIdKeywordGoto, |