| 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,7 +138,11 @@ MultiplyExpression : CastExpression MultiplyOperator CastExpression | CastExpres |
| 138 | 138 | ||
| 139 | MultiplyOperator : token(Star) | token(Slash) | token(Percent) | 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 | PrimaryExpression : token(Number) | token(String) | token(Unreachable) | FnCall | GroupedExpression | Block | 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,9 +153,11 @@ FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen |
| 149 | Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen) | 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 | as | 161 | as |
| 156 | * / % | 162 | * / % |
| 157 | + - | 163 | + - |
src/codegen.cpp+32-1| ... | @@ -317,6 +317,7 @@ static void find_declarations(CodeGen *g, AstNode *node) { | ... | @@ -317,6 +317,7 @@ static void find_declarations(CodeGen *g, AstNode *node) { |
| 317 | case NodeTypeAddExpr: | 317 | case NodeTypeAddExpr: |
| 318 | case NodeTypeMultExpr: | 318 | case NodeTypeMultExpr: |
| 319 | case NodeTypeCastExpr: | 319 | case NodeTypeCastExpr: |
| 320 | case NodeTypeUnaryExpr: | ||
| 320 | case NodeTypePrimaryExpr: | 321 | case NodeTypePrimaryExpr: |
| 321 | case NodeTypeGroupedExpr: | 322 | case NodeTypeGroupedExpr: |
| 322 | zig_unreachable(); | 323 | zig_unreachable(); |
| ... | @@ -542,6 +543,9 @@ static void analyze_node(CodeGen *g, AstNode *node) { | ... | @@ -542,6 +543,9 @@ static void analyze_node(CodeGen *g, AstNode *node) { |
| 542 | case NodeTypeCastExpr: | 543 | case NodeTypeCastExpr: |
| 543 | zig_panic("TODO"); | 544 | zig_panic("TODO"); |
| 544 | break; | 545 | break; |
| 546 | case NodeTypeUnaryExpr: | ||
| 547 | zig_panic("TODO"); | ||
| 548 | break; | ||
| 545 | case NodeTypePrimaryExpr: | 549 | case NodeTypePrimaryExpr: |
| 546 | switch (node->data.primary_expr.type) { | 550 | switch (node->data.primary_expr.type) { |
| 547 | case PrimaryExprTypeNumber: | 551 | case PrimaryExprTypeNumber: |
| ... | @@ -740,10 +744,35 @@ static LLVMValueRef gen_primary_expr(CodeGen *g, AstNode *node) { | ... | @@ -740,10 +744,35 @@ static LLVMValueRef gen_primary_expr(CodeGen *g, AstNode *node) { |
| 740 | zig_unreachable(); | 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 | static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { | 772 | static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { |
| 744 | assert(node->type == NodeTypeCastExpr); | 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 | if (!node->data.cast_expr.type) | 777 | if (!node->data.cast_expr.type) |
| 749 | return expr; | 778 | return expr; |
| ... | @@ -997,6 +1026,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { | ... | @@ -997,6 +1026,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 997 | return gen_bool_or_expr(g, node); | 1026 | return gen_bool_or_expr(g, node); |
| 998 | case NodeTypeReturnExpr: | 1027 | case NodeTypeReturnExpr: |
| 999 | return gen_return_expr(g, node); | 1028 | return gen_return_expr(g, node); |
| 1029 | case NodeTypeUnaryExpr: | ||
| 1030 | return gen_unary_expr(g, node); | ||
| 1000 | case NodeTypeRoot: | 1031 | case NodeTypeRoot: |
| 1001 | case NodeTypeRootExportDecl: | 1032 | case NodeTypeRootExportDecl: |
| 1002 | case NodeTypeFnProto: | 1033 | case NodeTypeFnProto: |
src/parser.cpp+67-6| ... | @@ -10,6 +10,16 @@ | ... | @@ -10,6 +10,16 @@ |
| 10 | #include <stdarg.h> | 10 | #include <stdarg.h> |
| 11 | #include <stdio.h> | 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 | static const char *mult_op_str(MultOp mult_op) { | 23 | static const char *mult_op_str(MultOp mult_op) { |
| 14 | switch (mult_op) { | 24 | switch (mult_op) { |
| 15 | case MultOpInvalid: return "(invalid)"; | 25 | case MultOpInvalid: return "(invalid)"; |
| ... | @@ -116,6 +126,8 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -116,6 +126,8 @@ const char *node_type_str(NodeType node_type) { |
| 116 | return "PrimaryExpr"; | 126 | return "PrimaryExpr"; |
| 117 | case NodeTypeGroupedExpr: | 127 | case NodeTypeGroupedExpr: |
| 118 | return "GroupedExpr"; | 128 | return "GroupedExpr"; |
| 129 | case NodeTypeUnaryExpr: | ||
| 130 | return "UnaryExpr"; | ||
| 119 | } | 131 | } |
| 120 | zig_unreachable(); | 132 | zig_unreachable(); |
| 121 | } | 133 | } |
| ... | @@ -284,10 +296,15 @@ void ast_print(AstNode *node, int indent) { | ... | @@ -284,10 +296,15 @@ void ast_print(AstNode *node, int indent) { |
| 284 | break; | 296 | break; |
| 285 | case NodeTypeCastExpr: | 297 | case NodeTypeCastExpr: |
| 286 | fprintf(stderr, "%s\n", node_type_str(node->type)); | 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 | if (node->data.cast_expr.type) | 300 | if (node->data.cast_expr.type) |
| 289 | ast_print(node->data.cast_expr.type, indent + 2); | 301 | ast_print(node->data.cast_expr.type, indent + 2); |
| 290 | break; | 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 | case NodeTypePrimaryExpr: | 308 | case NodeTypePrimaryExpr: |
| 292 | switch (node->data.primary_expr.type) { | 309 | switch (node->data.primary_expr.type) { |
| 293 | case PrimaryExprTypeNumber: | 310 | case PrimaryExprTypeNumber: |
| ... | @@ -688,21 +705,65 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool | ... | @@ -688,21 +705,65 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 688 | ast_invalid_token_error(pc, token); | 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 | static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bool mandatory) { | 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); | 756 | AstNode *unary_expr = ast_parse_unary_expr(pc, token_index, mandatory); |
| 696 | if (!primary_expr) | 757 | if (!unary_expr) |
| 697 | return nullptr; | 758 | return nullptr; |
| 698 | 759 | ||
| 699 | Token *as_kw = &pc->tokens->at(*token_index); | 760 | Token *as_kw = &pc->tokens->at(*token_index); |
| 700 | if (as_kw->id != TokenIdKeywordAs) | 761 | if (as_kw->id != TokenIdKeywordAs) |
| 701 | return primary_expr; | 762 | return unary_expr; |
| 702 | *token_index += 1; | 763 | *token_index += 1; |
| 703 | 764 | ||
| 704 | AstNode *node = ast_create_node(NodeTypeCastExpr, as_kw); | 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 | node->data.cast_expr.type = ast_parse_type(pc, *token_index, token_index); | 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,6 +40,7 @@ enum NodeType { |
| 40 | NodeTypeCastExpr, | 40 | NodeTypeCastExpr, |
| 41 | NodeTypePrimaryExpr, | 41 | NodeTypePrimaryExpr, |
| 42 | NodeTypeGroupedExpr, | 42 | NodeTypeGroupedExpr, |
| 43 | NodeTypeUnaryExpr, | ||
| 43 | }; | 44 | }; |
| 44 | 45 | ||
| 45 | struct AstNodeRoot { | 46 | struct AstNodeRoot { |
| ... | @@ -204,7 +205,7 @@ struct AstNodeMultExpr { | ... | @@ -204,7 +205,7 @@ struct AstNodeMultExpr { |
| 204 | }; | 205 | }; |
| 205 | 206 | ||
| 206 | struct AstNodeCastExpr { | 207 | struct AstNodeCastExpr { |
| 207 | AstNode *primary_expr; | 208 | AstNode *unary_expr; |
| 208 | // if type is non-null, do cast, otherwise nothing | 209 | // if type is non-null, do cast, otherwise nothing |
| 209 | AstNode *type; | 210 | AstNode *type; |
| 210 | }; | 211 | }; |
| ... | @@ -233,6 +234,18 @@ struct AstNodeGroupedExpr { | ... | @@ -233,6 +234,18 @@ struct AstNodeGroupedExpr { |
| 233 | AstNode *expr; | 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 | struct AstNode { | 249 | struct AstNode { |
| 237 | enum NodeType type; | 250 | enum NodeType type; |
| 238 | AstNode *parent; | 251 | AstNode *parent; |
| ... | @@ -264,6 +277,7 @@ struct AstNode { | ... | @@ -264,6 +277,7 @@ struct AstNode { |
| 264 | AstNodeCastExpr cast_expr; | 277 | AstNodeCastExpr cast_expr; |
| 265 | AstNodePrimaryExpr primary_expr; | 278 | AstNodePrimaryExpr primary_expr; |
| 266 | AstNodeGroupedExpr grouped_expr; | 279 | AstNodeGroupedExpr grouped_expr; |
| 280 | AstNodeUnaryExpr unary_expr; | ||
| 267 | } data; | 281 | } data; |
| 268 | }; | 282 | }; |
| 269 | 283 |
src/tokenizer.cpp+7-2| ... | @@ -249,6 +249,10 @@ ZigList<Token> *tokenize(Buf *buf) { | ... | @@ -249,6 +249,10 @@ ZigList<Token> *tokenize(Buf *buf) { |
| 249 | begin_token(&t, TokenIdPlus); | 249 | begin_token(&t, TokenIdPlus); |
| 250 | end_token(&t); | 250 | end_token(&t); |
| 251 | break; | 251 | break; |
| 252 | case '~': | ||
| 253 | begin_token(&t, TokenIdTilde); | ||
| 254 | end_token(&t); | ||
| 255 | break; | ||
| 252 | case '-': | 256 | case '-': |
| 253 | begin_token(&t, TokenIdDash); | 257 | begin_token(&t, TokenIdDash); |
| 254 | t.state = TokenizeStateSawDash; | 258 | t.state = TokenizeStateSawDash; |
| ... | @@ -278,7 +282,7 @@ ZigList<Token> *tokenize(Buf *buf) { | ... | @@ -278,7 +282,7 @@ ZigList<Token> *tokenize(Buf *buf) { |
| 278 | t.state = TokenizeStateEq; | 282 | t.state = TokenizeStateEq; |
| 279 | break; | 283 | break; |
| 280 | case '!': | 284 | case '!': |
| 281 | begin_token(&t, TokenIdNot); | 285 | begin_token(&t, TokenIdBang); |
| 282 | t.state = TokenizeStateBang; | 286 | t.state = TokenizeStateBang; |
| 283 | break; | 287 | break; |
| 284 | case '<': | 288 | case '<': |
| ... | @@ -578,7 +582,8 @@ static const char * token_name(Token *token) { | ... | @@ -578,7 +582,8 @@ static const char * token_name(Token *token) { |
| 578 | case TokenIdBoolOr: return "BoolOr"; | 582 | case TokenIdBoolOr: return "BoolOr"; |
| 579 | case TokenIdBoolAnd: return "BoolAnd"; | 583 | case TokenIdBoolAnd: return "BoolAnd"; |
| 580 | case TokenIdEq: return "Eq"; | 584 | case TokenIdEq: return "Eq"; |
| 581 | case TokenIdNot: return "Not"; | 585 | case TokenIdBang: return "Bang"; |
| 586 | case TokenIdTilde: return "Tilde"; | ||
| 582 | case TokenIdCmpEq: return "CmpEq"; | 587 | case TokenIdCmpEq: return "CmpEq"; |
| 583 | case TokenIdCmpNotEq: return "CmpNotEq"; | 588 | case TokenIdCmpNotEq: return "CmpNotEq"; |
| 584 | case TokenIdCmpLessThan: return "CmpLessThan"; | 589 | case TokenIdCmpLessThan: return "CmpLessThan"; |
src/tokenizer.hpp+2-1| ... | @@ -43,7 +43,8 @@ enum TokenId { | ... | @@ -43,7 +43,8 @@ enum TokenId { |
| 43 | TokenIdBinXor, | 43 | TokenIdBinXor, |
| 44 | TokenIdEq, | 44 | TokenIdEq, |
| 45 | TokenIdCmpEq, | 45 | TokenIdCmpEq, |
| 46 | TokenIdNot, | 46 | TokenIdBang, |
| 47 | TokenIdTilde, | ||
| 47 | TokenIdCmpNotEq, | 48 | TokenIdCmpNotEq, |
| 48 | TokenIdCmpLessThan, | 49 | TokenIdCmpLessThan, |
| 49 | TokenIdCmpGreaterThan, | 50 | TokenIdCmpGreaterThan, |