| author | |
| committer | |
| log | a7555c58d97480e439d1543cc0d4e001b23e4dd1 |
| tree | e7b65fe96a9c78a2f139a7699361e2ea1be4e1b9 |
| parent | 4466a4533c0f1ba33143bfead7ba99910d331531 |
6 files changed, 131 insertions(+), 13 deletions(-)
README.md+8-2| ... | ... | @@ -138,7 +138,11 @@ MultiplyExpression : CastExpression MultiplyOperator CastExpression | CastExpres |
| 138 | 138 | |
| 139 | 139 | MultiplyOperator : token(Star) | token(Slash) | token(Percent) |
| 140 | 140 | |
| 141 | CastExpression : PrimaryExpression token(as) Type | PrimaryExpression | |
| 141 | CastExpression : UnaryExpression token(as) Type | UnaryExpression | |
| 142 | ||
| 143 | UnaryExpression : UnaryOp PrimaryExpression | PrimaryExpression | |
| 144 | ||
| 145 | UnaryOp : token(Not) | token(Dash) | token(Tilde) | |
| 142 | 146 | |
| 143 | 147 | PrimaryExpression : token(Number) | token(String) | token(Unreachable) | FnCall | GroupedExpression | Block |
| 144 | 148 | |
| ... | ... | @@ -149,9 +153,11 @@ FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen |
| 149 | 153 | Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen) |
| 150 | 154 | ``` |
| 151 | 155 | |
| 152 | ### Binary Operator Precedence | |
| 156 | ### Operator Precedence | |
| 153 | 157 | |
| 154 | 158 | ``` |
| 159 | x() | |
| 160 | !x -x ~x | |
| 155 | 161 | as |
| 156 | 162 | * / % |
| 157 | 163 | + - |
src/codegen.cpp+32-1| ... | ... | @@ -317,6 +317,7 @@ static void find_declarations(CodeGen *g, AstNode *node) { |
| 317 | 317 | case NodeTypeAddExpr: |
| 318 | 318 | case NodeTypeMultExpr: |
| 319 | 319 | case NodeTypeCastExpr: |
| 320 | case NodeTypeUnaryExpr: | |
| 320 | 321 | case NodeTypePrimaryExpr: |
| 321 | 322 | case NodeTypeGroupedExpr: |
| 322 | 323 | zig_unreachable(); |
| ... | ... | @@ -542,6 +543,9 @@ static void analyze_node(CodeGen *g, AstNode *node) { |
| 542 | 543 | case NodeTypeCastExpr: |
| 543 | 544 | zig_panic("TODO"); |
| 544 | 545 | break; |
| 546 | case NodeTypeUnaryExpr: | |
| 547 | zig_panic("TODO"); | |
| 548 | break; | |
| 545 | 549 | case NodeTypePrimaryExpr: |
| 546 | 550 | switch (node->data.primary_expr.type) { |
| 547 | 551 | case PrimaryExprTypeNumber: |
| ... | ... | @@ -740,10 +744,35 @@ static LLVMValueRef gen_primary_expr(CodeGen *g, AstNode *node) { |
| 740 | 744 | zig_unreachable(); |
| 741 | 745 | } |
| 742 | 746 | |
| 747 | static LLVMValueRef gen_unary_expr(CodeGen *g, AstNode *node) { | |
| 748 | assert(node->type == NodeTypeUnaryExpr); | |
| 749 | assert(node->data.unary_expr.primary_expr); | |
| 750 | ||
| 751 | LLVMValueRef expr = gen_expr(g, node->data.unary_expr.primary_expr); | |
| 752 | ||
| 753 | switch (node->data.unary_expr.unary_op) { | |
| 754 | case UnaryOpNegation: | |
| 755 | add_debug_source_node(g, node); | |
| 756 | return LLVMBuildNeg(g->builder, expr, ""); | |
| 757 | case UnaryOpBoolNot: | |
| 758 | { | |
| 759 | LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(expr)); | |
| 760 | add_debug_source_node(g, node); | |
| 761 | return LLVMBuildICmp(g->builder, LLVMIntEQ, expr, zero, ""); | |
| 762 | } | |
| 763 | case UnaryOpBinNot: | |
| 764 | add_debug_source_node(g, node); | |
| 765 | return LLVMBuildNot(g->builder, expr, ""); | |
| 766 | case UnaryOpInvalid: | |
| 767 | zig_unreachable(); | |
| 768 | } | |
| 769 | ||
| 770 | } | |
| 771 | ||
| 743 | 772 | static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { |
| 744 | 773 | assert(node->type == NodeTypeCastExpr); |
| 745 | 774 | |
| 746 | LLVMValueRef expr = gen_primary_expr(g, node->data.cast_expr.primary_expr); | |
| 775 | LLVMValueRef expr = gen_expr(g, node->data.cast_expr.unary_expr); | |
| 747 | 776 | |
| 748 | 777 | if (!node->data.cast_expr.type) |
| 749 | 778 | return expr; |
| ... | ... | @@ -997,6 +1026,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 997 | 1026 | return gen_bool_or_expr(g, node); |
| 998 | 1027 | case NodeTypeReturnExpr: |
| 999 | 1028 | return gen_return_expr(g, node); |
| 1029 | case NodeTypeUnaryExpr: | |
| 1030 | return gen_unary_expr(g, node); | |
| 1000 | 1031 | case NodeTypeRoot: |
| 1001 | 1032 | case NodeTypeRootExportDecl: |
| 1002 | 1033 | case NodeTypeFnProto: |
src/parser.cpp+67-6| ... | ... | @@ -10,6 +10,16 @@ |
| 10 | 10 | #include <stdarg.h> |
| 11 | 11 | #include <stdio.h> |
| 12 | 12 | |
| 13 | static const char *unary_op_str(UnaryOp unary_op) { | |
| 14 | switch (unary_op) { | |
| 15 | case UnaryOpInvalid: return "(invalid)"; | |
| 16 | case UnaryOpNegation: return "-"; | |
| 17 | case UnaryOpBoolNot: return "!"; | |
| 18 | case UnaryOpBinNot: return "~"; | |
| 19 | } | |
| 20 | zig_unreachable(); | |
| 21 | } | |
| 22 | ||
| 13 | 23 | static const char *mult_op_str(MultOp mult_op) { |
| 14 | 24 | switch (mult_op) { |
| 15 | 25 | case MultOpInvalid: return "(invalid)"; |
| ... | ... | @@ -116,6 +126,8 @@ const char *node_type_str(NodeType node_type) { |
| 116 | 126 | return "PrimaryExpr"; |
| 117 | 127 | case NodeTypeGroupedExpr: |
| 118 | 128 | return "GroupedExpr"; |
| 129 | case NodeTypeUnaryExpr: | |
| 130 | return "UnaryExpr"; | |
| 119 | 131 | } |
| 120 | 132 | zig_unreachable(); |
| 121 | 133 | } |
| ... | ... | @@ -284,10 +296,15 @@ void ast_print(AstNode *node, int indent) { |
| 284 | 296 | break; |
| 285 | 297 | case NodeTypeCastExpr: |
| 286 | 298 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| 287 | ast_print(node->data.cast_expr.primary_expr, indent + 2); | |
| 299 | ast_print(node->data.cast_expr.unary_expr, indent + 2); | |
| 288 | 300 | if (node->data.cast_expr.type) |
| 289 | 301 | ast_print(node->data.cast_expr.type, indent + 2); |
| 290 | 302 | break; |
| 303 | case NodeTypeUnaryExpr: | |
| 304 | fprintf(stderr, "%s %s\n", node_type_str(node->type), | |
| 305 | unary_op_str(node->data.unary_expr.unary_op)); | |
| 306 | ast_print(node->data.unary_expr.primary_expr, indent + 2); | |
| 307 | break; | |
| 291 | 308 | case NodeTypePrimaryExpr: |
| 292 | 309 | switch (node->data.primary_expr.type) { |
| 293 | 310 | case PrimaryExprTypeNumber: |
| ... | ... | @@ -688,21 +705,65 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 688 | 705 | ast_invalid_token_error(pc, token); |
| 689 | 706 | } |
| 690 | 707 | |
| 708 | static UnaryOp tok_to_unary_op(Token *token) { | |
| 709 | switch (token->id) { | |
| 710 | case TokenIdBang: return UnaryOpBoolNot; | |
| 711 | case TokenIdDash: return UnaryOpNegation; | |
| 712 | case TokenIdTilde: return UnaryOpBinNot; | |
| 713 | default: return UnaryOpInvalid; | |
| 714 | } | |
| 715 | } | |
| 716 | ||
| 717 | /* | |
| 718 | UnaryOp : token(Not) | token(Dash) | token(Tilde) | |
| 719 | */ | |
| 720 | static UnaryOp ast_parse_unary_op(ParseContext *pc, int *token_index, bool mandatory) { | |
| 721 | Token *token = &pc->tokens->at(*token_index); | |
| 722 | UnaryOp result = tok_to_unary_op(token); | |
| 723 | if (result == UnaryOpInvalid) { | |
| 724 | if (mandatory) { | |
| 725 | ast_invalid_token_error(pc, token); | |
| 726 | } else { | |
| 727 | return UnaryOpInvalid; | |
| 728 | } | |
| 729 | } | |
| 730 | *token_index += 1; | |
| 731 | return result; | |
| 732 | } | |
| 733 | ||
| 734 | /* | |
| 735 | UnaryExpression : UnaryOp PrimaryExpression | PrimaryExpression | |
| 736 | */ | |
| 737 | static AstNode *ast_parse_unary_expr(ParseContext *pc, int *token_index, bool mandatory) { | |
| 738 | Token *token = &pc->tokens->at(*token_index); | |
| 739 | UnaryOp unary_op = ast_parse_unary_op(pc, token_index, false); | |
| 740 | if (unary_op == UnaryOpInvalid) | |
| 741 | return ast_parse_primary_expr(pc, token_index, mandatory); | |
| 742 | ||
| 743 | AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, true); | |
| 744 | AstNode *node = ast_create_node(NodeTypeUnaryExpr, token); | |
| 745 | node->data.unary_expr.primary_expr = primary_expr; | |
| 746 | node->data.unary_expr.unary_op = unary_op; | |
| 747 | ||
| 748 | return node; | |
| 749 | } | |
| 750 | ||
| 751 | ||
| 691 | 752 | /* |
| 692 | CastExpression : PrimaryExpression token(As) Type | PrimaryExpression | |
| 753 | CastExpression : UnaryExpression token(as) Type | UnaryExpression | |
| 693 | 754 | */ |
| 694 | 755 | static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bool mandatory) { |
| 695 | AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory); | |
| 696 | if (!primary_expr) | |
| 756 | AstNode *unary_expr = ast_parse_unary_expr(pc, token_index, mandatory); | |
| 757 | if (!unary_expr) | |
| 697 | 758 | return nullptr; |
| 698 | 759 | |
| 699 | 760 | Token *as_kw = &pc->tokens->at(*token_index); |
| 700 | 761 | if (as_kw->id != TokenIdKeywordAs) |
| 701 | return primary_expr; | |
| 762 | return unary_expr; | |
| 702 | 763 | *token_index += 1; |
| 703 | 764 | |
| 704 | 765 | AstNode *node = ast_create_node(NodeTypeCastExpr, as_kw); |
| 705 | node->data.cast_expr.primary_expr = primary_expr; | |
| 766 | node->data.cast_expr.unary_expr = unary_expr; | |
| 706 | 767 | |
| 707 | 768 | node->data.cast_expr.type = ast_parse_type(pc, *token_index, token_index); |
| 708 | 769 |
src/parser.hpp+15-1| ... | ... | @@ -40,6 +40,7 @@ enum NodeType { |
| 40 | 40 | NodeTypeCastExpr, |
| 41 | 41 | NodeTypePrimaryExpr, |
| 42 | 42 | NodeTypeGroupedExpr, |
| 43 | NodeTypeUnaryExpr, | |
| 43 | 44 | }; |
| 44 | 45 | |
| 45 | 46 | struct AstNodeRoot { |
| ... | ... | @@ -204,7 +205,7 @@ struct AstNodeMultExpr { |
| 204 | 205 | }; |
| 205 | 206 | |
| 206 | 207 | struct AstNodeCastExpr { |
| 207 | AstNode *primary_expr; | |
| 208 | AstNode *unary_expr; | |
| 208 | 209 | // if type is non-null, do cast, otherwise nothing |
| 209 | 210 | AstNode *type; |
| 210 | 211 | }; |
| ... | ... | @@ -233,6 +234,18 @@ struct AstNodeGroupedExpr { |
| 233 | 234 | AstNode *expr; |
| 234 | 235 | }; |
| 235 | 236 | |
| 237 | enum UnaryOp { | |
| 238 | UnaryOpInvalid, | |
| 239 | UnaryOpBoolNot, | |
| 240 | UnaryOpBinNot, | |
| 241 | UnaryOpNegation, | |
| 242 | }; | |
| 243 | ||
| 244 | struct AstNodeUnaryExpr { | |
| 245 | UnaryOp unary_op; | |
| 246 | AstNode *primary_expr; | |
| 247 | }; | |
| 248 | ||
| 236 | 249 | struct AstNode { |
| 237 | 250 | enum NodeType type; |
| 238 | 251 | AstNode *parent; |
| ... | ... | @@ -264,6 +277,7 @@ struct AstNode { |
| 264 | 277 | AstNodeCastExpr cast_expr; |
| 265 | 278 | AstNodePrimaryExpr primary_expr; |
| 266 | 279 | AstNodeGroupedExpr grouped_expr; |
| 280 | AstNodeUnaryExpr unary_expr; | |
| 267 | 281 | } data; |
| 268 | 282 | }; |
| 269 | 283 |
src/tokenizer.cpp+7-2| ... | ... | @@ -249,6 +249,10 @@ ZigList<Token> *tokenize(Buf *buf) { |
| 249 | 249 | begin_token(&t, TokenIdPlus); |
| 250 | 250 | end_token(&t); |
| 251 | 251 | break; |
| 252 | case '~': | |
| 253 | begin_token(&t, TokenIdTilde); | |
| 254 | end_token(&t); | |
| 255 | break; | |
| 252 | 256 | case '-': |
| 253 | 257 | begin_token(&t, TokenIdDash); |
| 254 | 258 | t.state = TokenizeStateSawDash; |
| ... | ... | @@ -278,7 +282,7 @@ ZigList<Token> *tokenize(Buf *buf) { |
| 278 | 282 | t.state = TokenizeStateEq; |
| 279 | 283 | break; |
| 280 | 284 | case '!': |
| 281 | begin_token(&t, TokenIdNot); | |
| 285 | begin_token(&t, TokenIdBang); | |
| 282 | 286 | t.state = TokenizeStateBang; |
| 283 | 287 | break; |
| 284 | 288 | case '<': |
| ... | ... | @@ -578,7 +582,8 @@ static const char * token_name(Token *token) { |
| 578 | 582 | case TokenIdBoolOr: return "BoolOr"; |
| 579 | 583 | case TokenIdBoolAnd: return "BoolAnd"; |
| 580 | 584 | case TokenIdEq: return "Eq"; |
| 581 | case TokenIdNot: return "Not"; | |
| 585 | case TokenIdBang: return "Bang"; | |
| 586 | case TokenIdTilde: return "Tilde"; | |
| 582 | 587 | case TokenIdCmpEq: return "CmpEq"; |
| 583 | 588 | case TokenIdCmpNotEq: return "CmpNotEq"; |
| 584 | 589 | case TokenIdCmpLessThan: return "CmpLessThan"; |
src/tokenizer.hpp+2-1| ... | ... | @@ -43,7 +43,8 @@ enum TokenId { |
| 43 | 43 | TokenIdBinXor, |
| 44 | 44 | TokenIdEq, |
| 45 | 45 | TokenIdCmpEq, |
| 46 | TokenIdNot, | |
| 46 | TokenIdBang, | |
| 47 | TokenIdTilde, | |
| 47 | 48 | TokenIdCmpNotEq, |
| 48 | 49 | TokenIdCmpLessThan, |
| 49 | 50 | TokenIdCmpGreaterThan, |