diff --git a/README.md b/README.md index 49f9135a50..0cddf8dad1 100644 --- a/README.md +++ b/README.md @@ -163,11 +163,13 @@ FnCallExpression : PrimaryExpression token(LParen) list(Expression, token(Comma) PrefixOp : token(Not) | token(Dash) | token(Tilde) -PrimaryExpression : token(Number) | token(String) | token(Unreachable) | GroupedExpression | token(Symbol) | Goto +PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | token(Symbol) | Goto Goto: token(Goto) token(Symbol) GroupedExpression : token(LParen) Expression token(RParen) + +KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) ``` ### Operator Precedence diff --git a/example/expressions/expressions.zig b/example/expressions/expressions.zig index e4b7703080..aabf23acff 100644 --- a/example/expressions/expressions.zig +++ b/example/expressions/expressions.zig @@ -4,6 +4,12 @@ extern { fn exit(code: i32) -> unreachable; } +fn other_exit() -> unreachable { + if (true) { exit(0); } + // the unreachable statement is the programmer assuring the compiler that this code is impossible to execute. + unreachable; +} + export fn _start() -> unreachable { let a : i32 = 1; let b = 2; @@ -19,5 +25,5 @@ export fn _start() -> unreachable { no_conflict }; if (c == 10) { puts("OK 2"); } - exit(0); + other_exit(); } diff --git a/src/analyze.cpp b/src/analyze.cpp index 614b80052c..be2a181713 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -297,6 +297,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, case NodeTypeStringLiteral: case NodeTypeUnreachable: case NodeTypeVoid: + case NodeTypeBoolLiteral: case NodeTypeSymbol: case NodeTypeCastExpr: case NodeTypePrefixOpExpr: @@ -592,6 +593,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, return_type = g->builtin_types.entry_void; break; + case NodeTypeBoolLiteral: + return_type = g->builtin_types.entry_bool; + break; + case NodeTypeSymbol: { Buf *symbol_name = &node->data.symbol; @@ -766,6 +771,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, case NodeTypeStringLiteral: case NodeTypeUnreachable: case NodeTypeVoid: + case NodeTypeBoolLiteral: case NodeTypeSymbol: case NodeTypeCastExpr: case NodeTypePrefixOpExpr: diff --git a/src/codegen.cpp b/src/codegen.cpp index eac6267888..ced5bbbdf5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -487,6 +487,11 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { return LLVMBuildUnreachable(g->builder); case NodeTypeVoid: return nullptr; + case NodeTypeBoolLiteral: + if (node->data.bool_literal) + return LLVMConstAllOnes(LLVMInt1Type()); + else + return LLVMConstNull(LLVMInt1Type()); case NodeTypeIfExpr: return gen_if_expr(g, node); case NodeTypeNumberLiteral: diff --git a/src/parser.cpp b/src/parser.cpp index 24b7cc7790..da58b354a5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -93,6 +93,8 @@ const char *node_type_str(NodeType node_type) { return "Use"; case NodeTypeVoid: return "Void"; + case NodeTypeBoolLiteral: + return "BoolLiteral"; case NodeTypeIfExpr: return "IfExpr"; case NodeTypeLabel: @@ -256,6 +258,9 @@ void ast_print(AstNode *node, int indent) { case NodeTypeVoid: fprintf(stderr, "%s\n", node_type_str(node->type)); break; + case NodeTypeBoolLiteral: + fprintf(stderr, "%s '%s'\n", node_type_str(node->type), node->data.bool_literal ? "true" : "false"); + break; case NodeTypeIfExpr: fprintf(stderr, "%s\n", node_type_str(node->type)); if (node->data.if_expr.condition) @@ -457,6 +462,12 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token } else if (token->id == TokenIdKeywordVoid) { node->data.type.type = AstNodeTypeTypePrimitive; buf_init_from_str(&node->data.type.primitive_name, "void"); + } else if (token->id == TokenIdKeywordTrue) { + node->data.type.type = AstNodeTypeTypePrimitive; + buf_init_from_str(&node->data.type.primitive_name, "true"); + } else if (token->id == TokenIdKeywordFalse) { + node->data.type.type = AstNodeTypeTypePrimitive; + buf_init_from_str(&node->data.type.primitive_name, "false"); } else if (token->id == TokenIdSymbol) { node->data.type.type = AstNodeTypeTypePrimitive; 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 AstNode *node = ast_create_node(pc, NodeTypeVoid, token); *token_index += 1; return node; + } else if (token->id == TokenIdKeywordTrue) { + AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token); + node->data.bool_literal = true; + *token_index += 1; + return node; + } else if (token->id == TokenIdKeywordFalse) { + AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token); + node->data.bool_literal = false; + *token_index += 1; + return node; } else if (token->id == TokenIdSymbol) { AstNode *node = ast_create_node(pc, NodeTypeSymbol, token); ast_buf_from_token(pc, token, &node->data.symbol); diff --git a/src/parser.hpp b/src/parser.hpp index ed80988dbe..90e0eb1744 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -40,6 +40,7 @@ enum NodeType { NodeTypeFnCallExpr, NodeTypeUse, NodeTypeVoid, + NodeTypeBoolLiteral, NodeTypeIfExpr, NodeTypeLabel, NodeTypeGoto, @@ -222,6 +223,7 @@ struct AstNode { Buf number; Buf string; Buf symbol; + bool bool_literal; } data; }; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index cae237f203..c98078fdf9 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -185,6 +185,10 @@ static void end_token(Tokenize *t) { t->cur_tok->id = TokenIdKeywordUse; } else if (mem_eql_str(token_mem, token_len, "void")) { t->cur_tok->id = TokenIdKeywordVoid; + } else if (mem_eql_str(token_mem, token_len, "true")) { + t->cur_tok->id = TokenIdKeywordTrue; + } else if (mem_eql_str(token_mem, token_len, "false")) { + t->cur_tok->id = TokenIdKeywordFalse; } else if (mem_eql_str(token_mem, token_len, "if")) { t->cur_tok->id = TokenIdKeywordIf; } else if (mem_eql_str(token_mem, token_len, "else")) { @@ -586,6 +590,8 @@ static const char * token_name(Token *token) { case TokenIdKeywordAs: return "As"; case TokenIdKeywordUse: return "Use"; case TokenIdKeywordVoid: return "Void"; + case TokenIdKeywordTrue: return "True"; + case TokenIdKeywordFalse: return "False"; case TokenIdKeywordIf: return "If"; case TokenIdKeywordElse: return "Else"; case TokenIdKeywordGoto: return "Goto"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 527f74e9eb..d6cd120bd8 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -25,6 +25,8 @@ enum TokenId { TokenIdKeywordAs, TokenIdKeywordUse, TokenIdKeywordVoid, + TokenIdKeywordTrue, + TokenIdKeywordFalse, TokenIdKeywordIf, TokenIdKeywordElse, TokenIdKeywordGoto,