| 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,7 +114,7 @@ Statement : NonBlockExpression token(Semicolon) | BlockExpression |
| 114 | 114 | ||
| 115 | Expression : BlockExpression | NonBlockExpression | 115 | Expression : BlockExpression | NonBlockExpression |
| 116 | 116 | ||
| 117 | NonBlockExpression : BoolOrExpression | ReturnExpression | 117 | NonBlockExpression : ReturnExpression | VariableDeclaration | BoolOrExpression |
| 118 | 118 | ||
| 119 | BlockExpression : IfExpression | Block | 119 | BlockExpression : IfExpression | Block |
| 120 | 120 | ||
| ... | @@ -122,6 +122,8 @@ BoolOrExpression : BoolAndExpression token(BoolOr) BoolAndExpression | BoolAndEx | ... | @@ -122,6 +122,8 @@ BoolOrExpression : BoolAndExpression token(BoolOr) BoolAndExpression | BoolAndEx |
| 122 | 122 | ||
| 123 | ReturnExpression : token(Return) option(Expression) | 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 | IfExpression : token(If) Expression Block option(Else | ElseIf) | 127 | IfExpression : token(If) Expression Block option(Else | ElseIf) |
| 126 | 128 | ||
| 127 | ElseIf : token(Else) IfExpression | 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,6 +277,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 277 | case NodeTypeType: | 277 | case NodeTypeType: |
| 278 | case NodeTypeFnDecl: | 278 | case NodeTypeFnDecl: |
| 279 | case NodeTypeReturnExpr: | 279 | case NodeTypeReturnExpr: |
| 280 | case NodeTypeVariableDeclaration: | ||
| 280 | case NodeTypeRoot: | 281 | case NodeTypeRoot: |
| 281 | case NodeTypeBlock: | 282 | case NodeTypeBlock: |
| 282 | case NodeTypeBinOpExpr: | 283 | case NodeTypeBinOpExpr: |
| ... | @@ -373,6 +374,14 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -373,6 +374,14 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 373 | break; | 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 | case NodeTypeBinOpExpr: | 385 | case NodeTypeBinOpExpr: |
| 377 | { | 386 | { |
| 378 | switch (node->data.bin_op_expr.bin_op) { | 387 | switch (node->data.bin_op_expr.bin_op) { |
| ... | @@ -630,6 +639,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, | ... | @@ -630,6 +639,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 630 | case NodeTypeType: | 639 | case NodeTypeType: |
| 631 | case NodeTypeFnDecl: | 640 | case NodeTypeFnDecl: |
| 632 | case NodeTypeReturnExpr: | 641 | case NodeTypeReturnExpr: |
| 642 | case NodeTypeVariableDeclaration: | ||
| 633 | case NodeTypeRoot: | 643 | case NodeTypeRoot: |
| 634 | case NodeTypeBlock: | 644 | case NodeTypeBlock: |
| 635 | case NodeTypeBinOpExpr: | 645 | case NodeTypeBinOpExpr: |
src/codegen.cpp+2| ... | @@ -477,6 +477,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { | ... | @@ -477,6 +477,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 477 | return gen_bin_op_expr(g, node); | 477 | return gen_bin_op_expr(g, node); |
| 478 | case NodeTypeReturnExpr: | 478 | case NodeTypeReturnExpr: |
| 479 | return gen_return_expr(g, node); | 479 | return gen_return_expr(g, node); |
| 480 | case NodeTypeVariableDeclaration: | ||
| 481 | zig_panic("TODO: variable declaration code gen"); | ||
| 480 | case NodeTypeCastExpr: | 482 | case NodeTypeCastExpr: |
| 481 | return gen_cast_expr(g, node); | 483 | return gen_cast_expr(g, node); |
| 482 | case NodeTypePrefixOpExpr: | 484 | case NodeTypePrefixOpExpr: |
src/parser.cpp+60-5| ... | @@ -75,6 +75,8 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -75,6 +75,8 @@ const char *node_type_str(NodeType node_type) { |
| 75 | return "Directive"; | 75 | return "Directive"; |
| 76 | case NodeTypeReturnExpr: | 76 | case NodeTypeReturnExpr: |
| 77 | return "ReturnExpr"; | 77 | return "ReturnExpr"; |
| 78 | case NodeTypeVariableDeclaration: | ||
| 79 | return "VariableDeclaration"; | ||
| 78 | case NodeTypeCastExpr: | 80 | case NodeTypeCastExpr: |
| 79 | return "CastExpr"; | 81 | return "CastExpr"; |
| 80 | case NodeTypeNumberLiteral: | 82 | case NodeTypeNumberLiteral: |
| ... | @@ -178,6 +180,16 @@ void ast_print(AstNode *node, int indent) { | ... | @@ -178,6 +180,16 @@ void ast_print(AstNode *node, int indent) { |
| 178 | if (node->data.return_expr.expr) | 180 | if (node->data.return_expr.expr) |
| 179 | ast_print(node->data.return_expr.expr, indent + 2); | 181 | ast_print(node->data.return_expr.expr, indent + 2); |
| 180 | break; | 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 | case NodeTypeExternBlock: | 193 | case NodeTypeExternBlock: |
| 182 | { | 194 | { |
| 183 | fprintf(stderr, "%s\n", node_type_str(node->type)); | 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,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 | BoolOrExpression : BoolAndExpression token(BoolOr) BoolAndExpression | BoolAndExpression | 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,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 | static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, bool mandatory) { | 1142 | static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1092 | Token *token = &pc->tokens->at(*token_index); | 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 | AstNode *return_expr = ast_parse_return_expr(pc, token_index, false); | 1145 | AstNode *return_expr = ast_parse_return_expr(pc, token_index, false); |
| 1099 | if (return_expr) | 1146 | if (return_expr) |
| 1100 | return return_expr; | 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 | if (mandatory) | 1157 | if (mandatory) |
| 1103 | ast_invalid_token_error(pc, token); | 1158 | ast_invalid_token_error(pc, token); |
| 1104 | 1159 |
src/parser.hpp+9| ... | @@ -29,6 +29,7 @@ enum NodeType { | ... | @@ -29,6 +29,7 @@ enum NodeType { |
| 29 | NodeTypeExternBlock, | 29 | NodeTypeExternBlock, |
| 30 | NodeTypeDirective, | 30 | NodeTypeDirective, |
| 31 | NodeTypeReturnExpr, | 31 | NodeTypeReturnExpr, |
| 32 | NodeTypeVariableDeclaration, | ||
| 32 | NodeTypeBinOpExpr, | 33 | NodeTypeBinOpExpr, |
| 33 | NodeTypeCastExpr, | 34 | NodeTypeCastExpr, |
| 34 | NodeTypeNumberLiteral, | 35 | NodeTypeNumberLiteral, |
| ... | @@ -95,6 +96,13 @@ struct AstNodeReturnExpr { | ... | @@ -95,6 +96,13 @@ struct AstNodeReturnExpr { |
| 95 | AstNode *expr; | 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 | enum BinOpType { | 106 | enum BinOpType { |
| 99 | BinOpTypeInvalid, | 107 | BinOpTypeInvalid, |
| 100 | // TODO: include assignment? | 108 | // TODO: include assignment? |
| ... | @@ -190,6 +198,7 @@ struct AstNode { | ... | @@ -190,6 +198,7 @@ struct AstNode { |
| 190 | AstNodeParamDecl param_decl; | 198 | AstNodeParamDecl param_decl; |
| 191 | AstNodeBlock block; | 199 | AstNodeBlock block; |
| 192 | AstNodeReturnExpr return_expr; | 200 | AstNodeReturnExpr return_expr; |
| 201 | AstNodeVariableDeclaration variable_declaration; | ||
| 193 | AstNodeBinOpExpr bin_op_expr; | 202 | AstNodeBinOpExpr bin_op_expr; |
| 194 | AstNodeExternBlock extern_block; | 203 | AstNodeExternBlock extern_block; |
| 195 | AstNodeDirective directive; | 204 | AstNodeDirective directive; |
src/tokenizer.cpp+3| ... | @@ -165,6 +165,8 @@ static void end_token(Tokenize *t) { | ... | @@ -165,6 +165,8 @@ static void end_token(Tokenize *t) { |
| 165 | t->cur_tok->id = TokenIdKeywordFn; | 165 | t->cur_tok->id = TokenIdKeywordFn; |
| 166 | } else if (mem_eql_str(token_mem, token_len, "return")) { | 166 | } else if (mem_eql_str(token_mem, token_len, "return")) { |
| 167 | t->cur_tok->id = TokenIdKeywordReturn; | 167 | t->cur_tok->id = TokenIdKeywordReturn; |
| 168 | } else if (mem_eql_str(token_mem, token_len, "let")) { | ||
| 169 | t->cur_tok->id = TokenIdKeywordLet; | ||
| 168 | } else if (mem_eql_str(token_mem, token_len, "mut")) { | 170 | } else if (mem_eql_str(token_mem, token_len, "mut")) { |
| 169 | t->cur_tok->id = TokenIdKeywordMut; | 171 | t->cur_tok->id = TokenIdKeywordMut; |
| 170 | } else if (mem_eql_str(token_mem, token_len, "const")) { | 172 | } else if (mem_eql_str(token_mem, token_len, "const")) { |
| ... | @@ -574,6 +576,7 @@ static const char * token_name(Token *token) { | ... | @@ -574,6 +576,7 @@ static const char * token_name(Token *token) { |
| 574 | case TokenIdKeywordConst: return "Const"; | 576 | case TokenIdKeywordConst: return "Const"; |
| 575 | case TokenIdKeywordMut: return "Mut"; | 577 | case TokenIdKeywordMut: return "Mut"; |
| 576 | case TokenIdKeywordReturn: return "Return"; | 578 | case TokenIdKeywordReturn: return "Return"; |
| 579 | case TokenIdKeywordLet: return "Let"; | ||
| 577 | case TokenIdKeywordExtern: return "Extern"; | 580 | case TokenIdKeywordExtern: return "Extern"; |
| 578 | case TokenIdKeywordUnreachable: return "Unreachable"; | 581 | case TokenIdKeywordUnreachable: return "Unreachable"; |
| 579 | case TokenIdKeywordPub: return "Pub"; | 582 | case TokenIdKeywordPub: return "Pub"; |
src/tokenizer.hpp+1| ... | @@ -15,6 +15,7 @@ enum TokenId { | ... | @@ -15,6 +15,7 @@ enum TokenId { |
| 15 | TokenIdSymbol, | 15 | TokenIdSymbol, |
| 16 | TokenIdKeywordFn, | 16 | TokenIdKeywordFn, |
| 17 | TokenIdKeywordReturn, | 17 | TokenIdKeywordReturn, |
| 18 | TokenIdKeywordLet, | ||
| 18 | TokenIdKeywordMut, | 19 | TokenIdKeywordMut, |
| 19 | TokenIdKeywordConst, | 20 | TokenIdKeywordConst, |
| 20 | TokenIdKeywordExtern, | 21 | TokenIdKeywordExtern, |