| author | |
| committer | |
| log | c89f77dd8e5005e60e8fb223c6c68b50566ac1ed |
| tree | 8512500c908ac8d95595e44af6eb9bc06bd03c06 |
| parent | ffc2c9225ff78b282e06486ce5465c91186bb48d |
8 files changed, 102 insertions(+), 6 deletions(-)
README.md+3-1| ... | ... | @@ -114,7 +114,7 @@ Statement : NonBlockExpression token(Semicolon) | BlockExpression |
| 114 | 114 | |
| 115 | 115 | Expression : BlockExpression | NonBlockExpression |
| 116 | 116 | |
| 117 | NonBlockExpression : BoolOrExpression | ReturnExpression | |
| 117 | NonBlockExpression : ReturnExpression | VariableDeclaration | BoolOrExpression | |
| 118 | 118 | |
| 119 | 119 | BlockExpression : IfExpression | Block |
| 120 | 120 | |
| ... | ... | @@ -122,6 +122,8 @@ BoolOrExpression : BoolAndExpression token(BoolOr) BoolAndExpression | BoolAndEx |
| 122 | 122 | |
| 123 | 123 | ReturnExpression : token(Return) option(Expression) |
| 124 | 124 | |
| 125 | VariableDeclaration : token(Let) token(Symbole) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) | |
| 126 | ||
| 125 | 127 | IfExpression : token(If) Expression Block option(Else | ElseIf) |
| 126 | 128 | |
| 127 | 129 | ElseIf : token(Else) IfExpression |
example/expressions/expressions.zig created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | #link("c") | |
| 2 | extern { | |
| 3 | fn puts(s: *const u8) -> i32; | |
| 4 | fn exit(code: i32) -> unreachable; | |
| 5 | } | |
| 6 | ||
| 7 | export fn _start() -> unreachable { | |
| 8 | let a : i32 = 1; | |
| 9 | let b = 2; | |
| 10 | let c : i32; | |
| 11 | // let d; // compile error | |
| 12 | puts("Hello, world!"); | |
| 13 | exit(a + b); | |
| 14 | } |
src/analyze.cpp+10| ... | ... | @@ -277,6 +277,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 277 | 277 | case NodeTypeType: |
| 278 | 278 | case NodeTypeFnDecl: |
| 279 | 279 | case NodeTypeReturnExpr: |
| 280 | case NodeTypeVariableDeclaration: | |
| 280 | 281 | case NodeTypeRoot: |
| 281 | 282 | case NodeTypeBlock: |
| 282 | 283 | case NodeTypeBinOpExpr: |
| ... | ... | @@ -373,6 +374,14 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 373 | 374 | break; |
| 374 | 375 | } |
| 375 | 376 | |
| 377 | case NodeTypeVariableDeclaration: | |
| 378 | { | |
| 379 | zig_panic("TODO: analyze variable declaration"); | |
| 380 | ||
| 381 | return_type = g->builtin_types.entry_void; | |
| 382 | break; | |
| 383 | } | |
| 384 | ||
| 376 | 385 | case NodeTypeBinOpExpr: |
| 377 | 386 | { |
| 378 | 387 | switch (node->data.bin_op_expr.bin_op) { |
| ... | ... | @@ -630,6 +639,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 630 | 639 | case NodeTypeType: |
| 631 | 640 | case NodeTypeFnDecl: |
| 632 | 641 | case NodeTypeReturnExpr: |
| 642 | case NodeTypeVariableDeclaration: | |
| 633 | 643 | case NodeTypeRoot: |
| 634 | 644 | case NodeTypeBlock: |
| 635 | 645 | case NodeTypeBinOpExpr: |
src/codegen.cpp+2| ... | ... | @@ -477,6 +477,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 477 | 477 | return gen_bin_op_expr(g, node); |
| 478 | 478 | case NodeTypeReturnExpr: |
| 479 | 479 | return gen_return_expr(g, node); |
| 480 | case NodeTypeVariableDeclaration: | |
| 481 | zig_panic("TODO: variable declaration code gen"); | |
| 480 | 482 | case NodeTypeCastExpr: |
| 481 | 483 | return gen_cast_expr(g, node); |
| 482 | 484 | case NodeTypePrefixOpExpr: |
src/parser.cpp+60-5| ... | ... | @@ -75,6 +75,8 @@ const char *node_type_str(NodeType node_type) { |
| 75 | 75 | return "Directive"; |
| 76 | 76 | case NodeTypeReturnExpr: |
| 77 | 77 | return "ReturnExpr"; |
| 78 | case NodeTypeVariableDeclaration: | |
| 79 | return "VariableDeclaration"; | |
| 78 | 80 | case NodeTypeCastExpr: |
| 79 | 81 | return "CastExpr"; |
| 80 | 82 | case NodeTypeNumberLiteral: |
| ... | ... | @@ -178,6 +180,16 @@ void ast_print(AstNode *node, int indent) { |
| 178 | 180 | if (node->data.return_expr.expr) |
| 179 | 181 | ast_print(node->data.return_expr.expr, indent + 2); |
| 180 | 182 | break; |
| 183 | case NodeTypeVariableDeclaration: | |
| 184 | { | |
| 185 | Buf *name_buf = &node->data.variable_declaration.symbol; | |
| 186 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf)); | |
| 187 | if (node->data.variable_declaration.type) | |
| 188 | ast_print(node->data.variable_declaration.type, indent + 2); | |
| 189 | if (node->data.variable_declaration.expr) | |
| 190 | ast_print(node->data.variable_declaration.expr, indent + 2); | |
| 191 | break; | |
| 192 | } | |
| 181 | 193 | case NodeTypeExternBlock: |
| 182 | 194 | { |
| 183 | 195 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| ... | ... | @@ -1042,6 +1054,45 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m |
| 1042 | 1054 | } |
| 1043 | 1055 | } |
| 1044 | 1056 | |
| 1057 | /* | |
| 1058 | VariableDeclaration : token(Let) token(Symbole) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression)) | |
| 1059 | */ | |
| 1060 | static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory) { | |
| 1061 | Token *let_tok = &pc->tokens->at(*token_index); | |
| 1062 | if (let_tok->id == TokenIdKeywordLet) { | |
| 1063 | *token_index += 1; | |
| 1064 | AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, let_tok); | |
| 1065 | ||
| 1066 | Token *name_token = &pc->tokens->at(*token_index); | |
| 1067 | *token_index += 1; | |
| 1068 | ast_expect_token(pc, name_token, TokenIdSymbol); | |
| 1069 | ast_buf_from_token(pc, name_token, &node->data.variable_declaration.symbol); | |
| 1070 | ||
| 1071 | Token *eq_or_colon = &pc->tokens->at(*token_index); | |
| 1072 | *token_index += 1; | |
| 1073 | if (eq_or_colon->id == TokenIdEq) { | |
| 1074 | node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); | |
| 1075 | return node; | |
| 1076 | } else if (eq_or_colon->id == TokenIdColon) { | |
| 1077 | node->data.variable_declaration.type = ast_parse_type(pc, *token_index, token_index); | |
| 1078 | ||
| 1079 | Token *eq_token = &pc->tokens->at(*token_index); | |
| 1080 | if (eq_token->id == TokenIdEq) { | |
| 1081 | *token_index += 1; | |
| 1082 | ||
| 1083 | node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); | |
| 1084 | } | |
| 1085 | return node; | |
| 1086 | } else { | |
| 1087 | ast_invalid_token_error(pc, eq_or_colon); | |
| 1088 | } | |
| 1089 | } else if (mandatory) { | |
| 1090 | ast_invalid_token_error(pc, let_tok); | |
| 1091 | } else { | |
| 1092 | return nullptr; | |
| 1093 | } | |
| 1094 | } | |
| 1095 | ||
| 1045 | 1096 | /* |
| 1046 | 1097 | BoolOrExpression : BoolAndExpression token(BoolOr) BoolAndExpression | BoolAndExpression |
| 1047 | 1098 | */ |
| ... | ... | @@ -1086,19 +1137,23 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma |
| 1086 | 1137 | } |
| 1087 | 1138 | |
| 1088 | 1139 | /* |
| 1089 | NonBlockExpression : BoolOrExpression | ReturnExpression | |
| 1140 | NonBlockExpression : ReturnExpression | VariableDeclaration | BoolOrExpression | |
| 1090 | 1141 | */ |
| 1091 | 1142 | static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1092 | 1143 | Token *token = &pc->tokens->at(*token_index); |
| 1093 | 1144 | |
| 1094 | AstNode *bool_or_expr = ast_parse_bool_or_expr(pc, token_index, false); | |
| 1095 | if (bool_or_expr) | |
| 1096 | return bool_or_expr; | |
| 1097 | ||
| 1098 | 1145 | AstNode *return_expr = ast_parse_return_expr(pc, token_index, false); |
| 1099 | 1146 | if (return_expr) |
| 1100 | 1147 | return return_expr; |
| 1101 | 1148 | |
| 1149 | AstNode *variable_declaration_expr = ast_parse_variable_declaration_expr(pc, token_index, false); | |
| 1150 | if (variable_declaration_expr) | |
| 1151 | return variable_declaration_expr; | |
| 1152 | ||
| 1153 | AstNode *bool_or_expr = ast_parse_bool_or_expr(pc, token_index, false); | |
| 1154 | if (bool_or_expr) | |
| 1155 | return bool_or_expr; | |
| 1156 | ||
| 1102 | 1157 | if (mandatory) |
| 1103 | 1158 | ast_invalid_token_error(pc, token); |
| 1104 | 1159 |
src/parser.hpp+9| ... | ... | @@ -29,6 +29,7 @@ enum NodeType { |
| 29 | 29 | NodeTypeExternBlock, |
| 30 | 30 | NodeTypeDirective, |
| 31 | 31 | NodeTypeReturnExpr, |
| 32 | NodeTypeVariableDeclaration, | |
| 32 | 33 | NodeTypeBinOpExpr, |
| 33 | 34 | NodeTypeCastExpr, |
| 34 | 35 | NodeTypeNumberLiteral, |
| ... | ... | @@ -95,6 +96,13 @@ struct AstNodeReturnExpr { |
| 95 | 96 | AstNode *expr; |
| 96 | 97 | }; |
| 97 | 98 | |
| 99 | struct AstNodeVariableDeclaration { | |
| 100 | Buf symbol; | |
| 101 | // one or both of type and expr will be non null | |
| 102 | AstNode *type; | |
| 103 | AstNode *expr; | |
| 104 | }; | |
| 105 | ||
| 98 | 106 | enum BinOpType { |
| 99 | 107 | BinOpTypeInvalid, |
| 100 | 108 | // TODO: include assignment? |
| ... | ... | @@ -190,6 +198,7 @@ struct AstNode { |
| 190 | 198 | AstNodeParamDecl param_decl; |
| 191 | 199 | AstNodeBlock block; |
| 192 | 200 | AstNodeReturnExpr return_expr; |
| 201 | AstNodeVariableDeclaration variable_declaration; | |
| 193 | 202 | AstNodeBinOpExpr bin_op_expr; |
| 194 | 203 | AstNodeExternBlock extern_block; |
| 195 | 204 | AstNodeDirective directive; |
src/tokenizer.cpp+3| ... | ... | @@ -165,6 +165,8 @@ static void end_token(Tokenize *t) { |
| 165 | 165 | t->cur_tok->id = TokenIdKeywordFn; |
| 166 | 166 | } else if (mem_eql_str(token_mem, token_len, "return")) { |
| 167 | 167 | t->cur_tok->id = TokenIdKeywordReturn; |
| 168 | } else if (mem_eql_str(token_mem, token_len, "let")) { | |
| 169 | t->cur_tok->id = TokenIdKeywordLet; | |
| 168 | 170 | } else if (mem_eql_str(token_mem, token_len, "mut")) { |
| 169 | 171 | t->cur_tok->id = TokenIdKeywordMut; |
| 170 | 172 | } else if (mem_eql_str(token_mem, token_len, "const")) { |
| ... | ... | @@ -574,6 +576,7 @@ static const char * token_name(Token *token) { |
| 574 | 576 | case TokenIdKeywordConst: return "Const"; |
| 575 | 577 | case TokenIdKeywordMut: return "Mut"; |
| 576 | 578 | case TokenIdKeywordReturn: return "Return"; |
| 579 | case TokenIdKeywordLet: return "Let"; | |
| 577 | 580 | case TokenIdKeywordExtern: return "Extern"; |
| 578 | 581 | case TokenIdKeywordUnreachable: return "Unreachable"; |
| 579 | 582 | case TokenIdKeywordPub: return "Pub"; |
src/tokenizer.hpp+1| ... | ... | @@ -15,6 +15,7 @@ enum TokenId { |
| 15 | 15 | TokenIdSymbol, |
| 16 | 16 | TokenIdKeywordFn, |
| 17 | 17 | TokenIdKeywordReturn, |
| 18 | TokenIdKeywordLet, | |
| 18 | 19 | TokenIdKeywordMut, |
| 19 | 20 | TokenIdKeywordConst, |
| 20 | 21 | TokenIdKeywordExtern, |