| author | |
| committer | |
| log | 8552d7fd19836f3350b7303f9bd897708b966805 |
| tree | 0189be7c4bc284bfb693db3eb007844bd168b213 |
| parent | 3eb5afd245d8e2059a8cf4b8aa4e201ec0613535 |
instead of wrapping integer types
closes #15915 files changed, 370 insertions(+), 261 deletions(-)
doc/langref.md+15-27| ... | ... | @@ -69,7 +69,7 @@ UnwrapError = "%%" option("|" "Symbol" "|") Expression |
| 69 | 69 | |
| 70 | 70 | AssignmentExpression = UnwrapExpression AssignmentOperator UnwrapExpression | UnwrapExpression |
| 71 | 71 | |
| 72 | AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "&&=" | "||=" | |
| 72 | AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "&&=" | "||=" | "*%=" | "+%=" | "-%=" | "<<%=" | |
| 73 | 73 | |
| 74 | 74 | BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression |
| 75 | 75 | |
| ... | ... | @@ -111,17 +111,17 @@ BinaryAndExpression = BitShiftExpression "&" BinaryAndExpression | BitShiftExpre |
| 111 | 111 | |
| 112 | 112 | BitShiftExpression = AdditionExpression BitShiftOperator BitShiftExpression | AdditionExpression |
| 113 | 113 | |
| 114 | BitShiftOperator = "<<" | ">>" | |
| 114 | BitShiftOperator = "<<" | ">>" | "<<%" | |
| 115 | 115 | |
| 116 | 116 | AdditionExpression = MultiplyExpression AdditionOperator AdditionExpression | MultiplyExpression |
| 117 | 117 | |
| 118 | AdditionOperator = "+" | "-" | "++" | |
| 118 | AdditionOperator = "+" | "-" | "++" | "+%" | "-%" | |
| 119 | 119 | |
| 120 | 120 | MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression | CurlySuffixExpression |
| 121 | 121 | |
| 122 | 122 | CurlySuffixExpression = TypeExpr option(ContainerInitExpression) |
| 123 | 123 | |
| 124 | MultiplyOperator = "*" | "/" | "%" | "**" | |
| 124 | MultiplyOperator = "*" | "/" | "%" | "**" | "*%" | |
| 125 | 125 | |
| 126 | 126 | PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression |
| 127 | 127 | |
| ... | ... | @@ -141,7 +141,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",") |
| 141 | 141 | |
| 142 | 142 | StructLiteralField = "." "Symbol" "=" Expression |
| 143 | 143 | |
| 144 | PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | "??" | |
| 144 | PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | "??" | "-%" | |
| 145 | 145 | |
| 146 | 146 | PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." "Symbol") |
| 147 | 147 | |
| ... | ... | @@ -181,26 +181,15 @@ x{} |
| 181 | 181 | Type name C equivalent Description |
| 182 | 182 | |
| 183 | 183 | i8 int8_t signed 8-bit integer |
| 184 | u8 (none) unsigned 8-bit integer | |
| 184 | u8 uint8_t unsigned 8-bit integer | |
| 185 | 185 | i16 int16_t signed 16-bit integer |
| 186 | u16 (none) unsigned 16-bit integer | |
| 186 | u16 uint16_t unsigned 16-bit integer | |
| 187 | 187 | i32 int32_t signed 32-bit integer |
| 188 | u32 (none) unsigned 32-bit integer | |
| 188 | u32 uint32_t unsigned 32-bit integer | |
| 189 | 189 | i64 int64_t signed 64-bit integer |
| 190 | u64 (none) unsigned 64-bit integer | |
| 190 | u64 uint64_t unsigned 64-bit integer | |
| 191 | 191 | isize intptr_t signed pointer sized integer |
| 192 | usize (none) unsigned pointer sized integer | |
| 193 | ||
| 194 | i8w (none) wrapping signed 8-bit integer | |
| 195 | u8w uint8_t wrapping unsigned 8-bit integer | |
| 196 | i16w (none) wrapping signed 16-bit integer | |
| 197 | u16w uint16_t wrapping unsigned 16-bit integer | |
| 198 | i32w (none) wrapping signed 32-bit integer | |
| 199 | u32w uint32_t wrapping unsigned 32-bit integer | |
| 200 | i64w (none) wrapping signed 64-bit integer | |
| 201 | u64w uint64_t wrapping unsigned 64-bit integer | |
| 202 | isizew (none) wrapping signed pointer sized integer | |
| 203 | usizew uintptr_t wrapping unsigned pointer sized integer | |
| 192 | usize uintptr_t unsigned pointer sized integer | |
| 204 | 193 | |
| 205 | 194 | c_short short for ABI compatibility with C |
| 206 | 195 | c_ushort unsigned short for ABI compatibility with C |
| ... | ... | @@ -213,8 +202,8 @@ c_ulonglong unsigned long long for ABI compatibility with C |
| 213 | 202 | c_long_double long double for ABI compatibility with C |
| 214 | 203 | c_void void for ABI compatibility with C |
| 215 | 204 | |
| 216 | f32 float 32-bit IEE754 floating point | |
| 217 | f64 double 64-bit IEE754 floating point | |
| 205 | f32 float 32-bit floating point | |
| 206 | f64 double 64-bit floating point | |
| 218 | 207 | ``` |
| 219 | 208 | |
| 220 | 209 | ### Boolean Type |
| ... | ... | @@ -595,9 +584,8 @@ const b: u8 = @truncate(u8, a); |
| 595 | 584 | This function, when semantically analyzed, causes a compile error with the message `msg`. |
| 596 | 585 | |
| 597 | 586 | There are several ways that code avoids being semantically checked, such as using `if` |
| 598 | or `switch` with compile variables, and inline functions. | |
| 587 | or `switch` with compile time constants, and inline functions. | |
| 599 | 588 | |
| 600 | ### @int_type(inline is_signed: bool, inline bit_count: u8, inline is_wrapping: bool) -> type | |
| 589 | ### @int_type(inline is_signed: bool, inline bit_count: u8) -> type | |
| 601 | 590 | |
| 602 | This function returns an integer type with the given signness, bit count, and | |
| 603 | wrapping behavior. | |
| 591 | This function returns an integer type with the given signness and bit count. |
doc/vim/syntax/zig.vim-1| ... | ... | @@ -17,7 +17,6 @@ syn keyword zigConstant null undefined |
| 17 | 17 | syn keyword zigKeyword fn use |
| 18 | 18 | syn keyword zigType bool f32 f64 void unreachable type error |
| 19 | 19 | syn keyword zigType i8 u8 i16 u16 i32 u32 i64 u64 isize usize |
| 20 | syn keyword zigType i8w u8w i16w u16w i32w u32w i64w u64w isizew usizew | |
| 21 | 20 | syn keyword zigType c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong |
| 22 | 21 | |
| 23 | 22 | syn keyword zigBoolean true false |
src/all_types.hpp+10-2| ... | ... | @@ -315,11 +315,15 @@ enum BinOpType { |
| 315 | 315 | BinOpTypeInvalid, |
| 316 | 316 | BinOpTypeAssign, |
| 317 | 317 | BinOpTypeAssignTimes, |
| 318 | BinOpTypeAssignTimesWrap, | |
| 318 | 319 | BinOpTypeAssignDiv, |
| 319 | 320 | BinOpTypeAssignMod, |
| 320 | 321 | BinOpTypeAssignPlus, |
| 322 | BinOpTypeAssignPlusWrap, | |
| 321 | 323 | BinOpTypeAssignMinus, |
| 324 | BinOpTypeAssignMinusWrap, | |
| 322 | 325 | BinOpTypeAssignBitShiftLeft, |
| 326 | BinOpTypeAssignBitShiftLeftWrap, | |
| 323 | 327 | BinOpTypeAssignBitShiftRight, |
| 324 | 328 | BinOpTypeAssignBitAnd, |
| 325 | 329 | BinOpTypeAssignBitXor, |
| ... | ... | @@ -338,10 +342,14 @@ enum BinOpType { |
| 338 | 342 | BinOpTypeBinXor, |
| 339 | 343 | BinOpTypeBinAnd, |
| 340 | 344 | BinOpTypeBitShiftLeft, |
| 345 | BinOpTypeBitShiftLeftWrap, | |
| 341 | 346 | BinOpTypeBitShiftRight, |
| 342 | 347 | BinOpTypeAdd, |
| 348 | BinOpTypeAddWrap, | |
| 343 | 349 | BinOpTypeSub, |
| 350 | BinOpTypeSubWrap, | |
| 344 | 351 | BinOpTypeMult, |
| 352 | BinOpTypeMultWrap, | |
| 345 | 353 | BinOpTypeDiv, |
| 346 | 354 | BinOpTypeMod, |
| 347 | 355 | BinOpTypeUnwrapMaybe, |
| ... | ... | @@ -449,6 +457,7 @@ enum PrefixOp { |
| 449 | 457 | PrefixOpBoolNot, |
| 450 | 458 | PrefixOpBinNot, |
| 451 | 459 | PrefixOpNegation, |
| 460 | PrefixOpNegationWrap, | |
| 452 | 461 | PrefixOpAddressOf, |
| 453 | 462 | PrefixOpConstAddressOf, |
| 454 | 463 | PrefixOpDereference, |
| ... | ... | @@ -860,7 +869,6 @@ struct TypeTableEntryPointer { |
| 860 | 869 | struct TypeTableEntryInt { |
| 861 | 870 | int bit_count; |
| 862 | 871 | bool is_signed; |
| 863 | bool is_wrapping; | |
| 864 | 872 | }; |
| 865 | 873 | |
| 866 | 874 | struct TypeTableEntryFloat { |
| ... | ... | @@ -1185,7 +1193,7 @@ struct CodeGen { |
| 1185 | 1193 | |
| 1186 | 1194 | struct { |
| 1187 | 1195 | TypeTableEntry *entry_bool; |
| 1188 | TypeTableEntry *entry_int[2][2][4]; // [signed,unsigned][wrapping,nonwrapping][8,16,32,64] | |
| 1196 | TypeTableEntry *entry_int[2][4]; // [signed,unsigned][8,16,32,64] | |
| 1189 | 1197 | TypeTableEntry *entry_c_int[CIntTypeCount]; |
| 1190 | 1198 | TypeTableEntry *entry_c_long_double; |
| 1191 | 1199 | TypeTableEntry *entry_c_void; |
src/analyze.cpp+49-35| ... | ... | @@ -245,7 +245,7 @@ static bool is_slice(TypeTableEntry *type) { |
| 245 | 245 | } |
| 246 | 246 | |
| 247 | 247 | TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { |
| 248 | return get_int_type(g, false, false, bits_needed_for_unsigned(x)); | |
| 248 | return get_int_type(g, false, bits_needed_for_unsigned(x)); | |
| 249 | 249 | } |
| 250 | 250 | |
| 251 | 251 | static TypeTableEntry *get_generic_fn_type(CodeGen *g, AstNode *decl_node) { |
| ... | ... | @@ -2037,25 +2037,13 @@ static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *pa |
| 2037 | 2037 | continue; |
| 2038 | 2038 | } else if (prev_type->id == TypeTableEntryIdInt && |
| 2039 | 2039 | cur_type->id == TypeTableEntryIdInt && |
| 2040 | prev_type->data.integral.is_signed == cur_type->data.integral.is_signed && | |
| 2041 | (cur_type->data.integral.bit_count >= prev_type->data.integral.bit_count && | |
| 2042 | (cur_type->data.integral.is_wrapping || !prev_type->data.integral.is_wrapping))) | |
| 2040 | prev_type->data.integral.is_signed == cur_type->data.integral.is_signed) | |
| 2043 | 2041 | { |
| 2044 | 2042 | if (cur_type->data.integral.bit_count > prev_type->data.integral.bit_count) { |
| 2045 | 2043 | prev_type = cur_type; |
| 2046 | 2044 | prev_node = cur_node; |
| 2047 | } else if (cur_type->data.integral.is_wrapping && !prev_type->data.integral.is_wrapping) { | |
| 2048 | prev_type = cur_type; | |
| 2049 | prev_node = cur_node; | |
| 2050 | 2045 | } |
| 2051 | 2046 | continue; |
| 2052 | } else if (prev_type->id == TypeTableEntryIdInt && | |
| 2053 | cur_type->id == TypeTableEntryIdInt && | |
| 2054 | prev_type->data.integral.is_signed == cur_type->data.integral.is_signed && | |
| 2055 | (prev_type->data.integral.bit_count >= cur_type->data.integral.bit_count && | |
| 2056 | (prev_type->data.integral.is_wrapping || !cur_type->data.integral.is_wrapping))) | |
| 2057 | { | |
| 2058 | continue; | |
| 2059 | 2047 | } else if (prev_type->id == TypeTableEntryIdFloat && |
| 2060 | 2048 | cur_type->id == TypeTableEntryIdFloat) |
| 2061 | 2049 | { |
| ... | ... | @@ -2726,9 +2714,6 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 2726 | 2714 | } else if (buf_eql_str(field_name, "is_signed")) { |
| 2727 | 2715 | return resolve_expr_const_val_as_bool(g, node, child_type->data.integral.is_signed, |
| 2728 | 2716 | depends_on_compile_var); |
| 2729 | } else if (buf_eql_str(field_name, "is_wrapping")) { | |
| 2730 | return resolve_expr_const_val_as_bool(g, node, child_type->data.integral.is_wrapping, | |
| 2731 | depends_on_compile_var); | |
| 2732 | 2717 | } else { |
| 2733 | 2718 | add_node_error(g, node, |
| 2734 | 2719 | buf_sprintf("type '%s' has no member called '%s'", |
| ... | ... | @@ -3122,15 +3107,19 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) { |
| 3122 | 3107 | case BinOpTypeAssign: |
| 3123 | 3108 | return true; |
| 3124 | 3109 | case BinOpTypeAssignTimes: |
| 3110 | case BinOpTypeAssignTimesWrap: | |
| 3125 | 3111 | case BinOpTypeAssignDiv: |
| 3126 | 3112 | case BinOpTypeAssignMod: |
| 3127 | 3113 | return type->id == TypeTableEntryIdInt || type->id == TypeTableEntryIdFloat; |
| 3128 | 3114 | case BinOpTypeAssignPlus: |
| 3115 | case BinOpTypeAssignPlusWrap: | |
| 3129 | 3116 | case BinOpTypeAssignMinus: |
| 3117 | case BinOpTypeAssignMinusWrap: | |
| 3130 | 3118 | return type->id == TypeTableEntryIdInt || |
| 3131 | 3119 | type->id == TypeTableEntryIdFloat || |
| 3132 | 3120 | type->id == TypeTableEntryIdPointer; |
| 3133 | 3121 | case BinOpTypeAssignBitShiftLeft: |
| 3122 | case BinOpTypeAssignBitShiftLeftWrap: | |
| 3134 | 3123 | case BinOpTypeAssignBitShiftRight: |
| 3135 | 3124 | case BinOpTypeAssignBitAnd: |
| 3136 | 3125 | case BinOpTypeAssignBitXor: |
| ... | ... | @@ -3153,10 +3142,14 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) { |
| 3153 | 3142 | case BinOpTypeBinXor: |
| 3154 | 3143 | case BinOpTypeBinAnd: |
| 3155 | 3144 | case BinOpTypeBitShiftLeft: |
| 3145 | case BinOpTypeBitShiftLeftWrap: | |
| 3156 | 3146 | case BinOpTypeBitShiftRight: |
| 3157 | 3147 | case BinOpTypeAdd: |
| 3148 | case BinOpTypeAddWrap: | |
| 3158 | 3149 | case BinOpTypeSub: |
| 3150 | case BinOpTypeSubWrap: | |
| 3159 | 3151 | case BinOpTypeMult: |
| 3152 | case BinOpTypeMultWrap: | |
| 3160 | 3153 | case BinOpTypeDiv: |
| 3161 | 3154 | case BinOpTypeMod: |
| 3162 | 3155 | case BinOpTypeUnwrapMaybe: |
| ... | ... | @@ -3437,11 +3430,15 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 3437 | 3430 | switch (bin_op_type) { |
| 3438 | 3431 | case BinOpTypeAssign: |
| 3439 | 3432 | case BinOpTypeAssignTimes: |
| 3433 | case BinOpTypeAssignTimesWrap: | |
| 3440 | 3434 | case BinOpTypeAssignDiv: |
| 3441 | 3435 | case BinOpTypeAssignMod: |
| 3442 | 3436 | case BinOpTypeAssignPlus: |
| 3437 | case BinOpTypeAssignPlusWrap: | |
| 3443 | 3438 | case BinOpTypeAssignMinus: |
| 3439 | case BinOpTypeAssignMinusWrap: | |
| 3444 | 3440 | case BinOpTypeAssignBitShiftLeft: |
| 3441 | case BinOpTypeAssignBitShiftLeftWrap: | |
| 3445 | 3442 | case BinOpTypeAssignBitShiftRight: |
| 3446 | 3443 | case BinOpTypeAssignBitAnd: |
| 3447 | 3444 | case BinOpTypeAssignBitXor: |
| ... | ... | @@ -3481,10 +3478,14 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 3481 | 3478 | case BinOpTypeBinXor: |
| 3482 | 3479 | case BinOpTypeBinAnd: |
| 3483 | 3480 | case BinOpTypeBitShiftLeft: |
| 3481 | case BinOpTypeBitShiftLeftWrap: | |
| 3484 | 3482 | case BinOpTypeBitShiftRight: |
| 3485 | 3483 | case BinOpTypeAdd: |
| 3484 | case BinOpTypeAddWrap: | |
| 3486 | 3485 | case BinOpTypeSub: |
| 3486 | case BinOpTypeSubWrap: | |
| 3487 | 3487 | case BinOpTypeMult: |
| 3488 | case BinOpTypeMultWrap: | |
| 3488 | 3489 | case BinOpTypeDiv: |
| 3489 | 3490 | case BinOpTypeMod: |
| 3490 | 3491 | { |
| ... | ... | @@ -4911,42 +4912,35 @@ static TypeTableEntry *analyze_int_type(CodeGen *g, ImportTableEntry *import, |
| 4911 | 4912 | { |
| 4912 | 4913 | AstNode **is_signed_node = &node->data.fn_call_expr.params.at(0); |
| 4913 | 4914 | AstNode **bit_count_node = &node->data.fn_call_expr.params.at(1); |
| 4914 | AstNode **is_wrap_node = &node->data.fn_call_expr.params.at(2); | |
| 4915 | 4915 | |
| 4916 | 4916 | TypeTableEntry *bool_type = g->builtin_types.entry_bool; |
| 4917 | 4917 | TypeTableEntry *usize_type = g->builtin_types.entry_usize; |
| 4918 | 4918 | TypeTableEntry *is_signed_type = analyze_expression(g, import, context, bool_type, *is_signed_node); |
| 4919 | 4919 | TypeTableEntry *bit_count_type = analyze_expression(g, import, context, usize_type, *bit_count_node); |
| 4920 | TypeTableEntry *is_wrap_type = analyze_expression(g, import, context, bool_type, *is_wrap_node); | |
| 4921 | 4920 | |
| 4922 | 4921 | if (is_signed_type->id == TypeTableEntryIdInvalid || |
| 4923 | bit_count_type->id == TypeTableEntryIdInvalid || | |
| 4924 | is_wrap_type->id == TypeTableEntryIdInvalid) | |
| 4922 | bit_count_type->id == TypeTableEntryIdInvalid) | |
| 4925 | 4923 | { |
| 4926 | 4924 | return g->builtin_types.entry_invalid; |
| 4927 | 4925 | } |
| 4928 | 4926 | |
| 4929 | 4927 | ConstExprValue *is_signed_val = &get_resolved_expr(*is_signed_node)->const_val; |
| 4930 | 4928 | ConstExprValue *bit_count_val = &get_resolved_expr(*bit_count_node)->const_val; |
| 4931 | ConstExprValue *is_wrap_val = &get_resolved_expr(*is_wrap_node)->const_val; | |
| 4932 | 4929 | |
| 4933 | 4930 | AstNode *bad_node = nullptr; |
| 4934 | 4931 | if (!is_signed_val->ok) { |
| 4935 | 4932 | bad_node = *is_signed_node; |
| 4936 | 4933 | } else if (!bit_count_val->ok) { |
| 4937 | 4934 | bad_node = *bit_count_node; |
| 4938 | } else if (!is_wrap_val->ok) { | |
| 4939 | bad_node = *is_wrap_node; | |
| 4940 | 4935 | } |
| 4941 | 4936 | if (bad_node) { |
| 4942 | 4937 | add_node_error(g, bad_node, buf_sprintf("unable to evaluate constant expression")); |
| 4943 | 4938 | return g->builtin_types.entry_invalid; |
| 4944 | 4939 | } |
| 4945 | 4940 | |
| 4946 | bool depends_on_compile_var = is_signed_val->depends_on_compile_var || | |
| 4947 | bit_count_val->depends_on_compile_var || is_wrap_val->depends_on_compile_var; | |
| 4941 | bool depends_on_compile_var = is_signed_val->depends_on_compile_var || bit_count_val->depends_on_compile_var; | |
| 4948 | 4942 | |
| 4949 | TypeTableEntry *int_type = get_int_type(g, is_signed_val->data.x_bool, is_wrap_val->data.x_bool, | |
| 4943 | TypeTableEntry *int_type = get_int_type(g, is_signed_val->data.x_bool, | |
| 4950 | 4944 | bit_count_val->data.x_bignum.data.x_uint); |
| 4951 | 4945 | return resolve_expr_const_val_as_type(g, node, int_type, depends_on_compile_var); |
| 4952 | 4946 | |
| ... | ... | @@ -5727,15 +5721,17 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo |
| 5727 | 5721 | // TODO const expr eval |
| 5728 | 5722 | } |
| 5729 | 5723 | case PrefixOpNegation: |
| 5724 | case PrefixOpNegationWrap: | |
| 5730 | 5725 | { |
| 5731 | 5726 | TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node); |
| 5732 | 5727 | if (expr_type->id == TypeTableEntryIdInvalid) { |
| 5733 | 5728 | return expr_type; |
| 5734 | 5729 | } else if ((expr_type->id == TypeTableEntryIdInt && |
| 5735 | 5730 | expr_type->data.integral.is_signed) || |
| 5736 | expr_type->id == TypeTableEntryIdFloat || | |
| 5737 | 5731 | expr_type->id == TypeTableEntryIdNumLitInt || |
| 5738 | expr_type->id == TypeTableEntryIdNumLitFloat) | |
| 5732 | ((expr_type->id == TypeTableEntryIdFloat || | |
| 5733 | expr_type->id == TypeTableEntryIdNumLitFloat) && | |
| 5734 | prefix_op != PrefixOpNegationWrap)) | |
| 5739 | 5735 | { |
| 5740 | 5736 | ConstExprValue *target_const_val = &get_resolved_expr(*expr_node)->const_val; |
| 5741 | 5737 | if (!target_const_val->ok) { |
| ... | ... | @@ -5745,10 +5741,28 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo |
| 5745 | 5741 | const_val->ok = true; |
| 5746 | 5742 | const_val->depends_on_compile_var = target_const_val->depends_on_compile_var; |
| 5747 | 5743 | bignum_negate(&const_val->data.x_bignum, &target_const_val->data.x_bignum); |
| 5744 | if (expr_type->id == TypeTableEntryIdFloat || | |
| 5745 | expr_type->id == TypeTableEntryIdNumLitFloat || | |
| 5746 | expr_type->id == TypeTableEntryIdNumLitInt) | |
| 5747 | { | |
| 5748 | return expr_type; | |
| 5749 | } | |
| 5750 | ||
| 5751 | bool overflow = !bignum_fits_in_bits(&const_val->data.x_bignum, | |
| 5752 | expr_type->data.integral.bit_count, expr_type->data.integral.is_signed); | |
| 5753 | if (prefix_op == PrefixOpNegationWrap) { | |
| 5754 | if (overflow) { | |
| 5755 | const_val->data.x_bignum.is_negative = true; | |
| 5756 | } | |
| 5757 | } else if (overflow) { | |
| 5758 | add_node_error(g, *expr_node, buf_sprintf("negation caused overflow")); | |
| 5759 | return g->builtin_types.entry_invalid; | |
| 5760 | } | |
| 5748 | 5761 | return expr_type; |
| 5749 | 5762 | } else { |
| 5750 | add_node_error(g, node, buf_sprintf("invalid negation type: '%s'", | |
| 5751 | buf_ptr(&expr_type->name))); | |
| 5763 | const char *fmt = (prefix_op == PrefixOpNegationWrap) ? | |
| 5764 | "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'"; | |
| 5765 | add_node_error(g, node, buf_sprintf(fmt, buf_ptr(&expr_type->name))); | |
| 5752 | 5766 | return g->builtin_types.entry_invalid; |
| 5753 | 5767 | } |
| 5754 | 5768 | } |
| ... | ... | @@ -7059,7 +7073,7 @@ bool is_node_void_expr(AstNode *node) { |
| 7059 | 7073 | return false; |
| 7060 | 7074 | } |
| 7061 | 7075 | |
| 7062 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, bool is_wrapping, int size_in_bits) { | |
| 7076 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits) { | |
| 7063 | 7077 | int index; |
| 7064 | 7078 | if (size_in_bits == 8) { |
| 7065 | 7079 | index = 0; |
| ... | ... | @@ -7072,11 +7086,11 @@ TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, bool is_wrapping, |
| 7072 | 7086 | } else { |
| 7073 | 7087 | zig_unreachable(); |
| 7074 | 7088 | } |
| 7075 | return &g->builtin_types.entry_int[is_signed ? 0 : 1][is_wrapping ? 0 : 1][index]; | |
| 7089 | return &g->builtin_types.entry_int[is_signed ? 0 : 1][index]; | |
| 7076 | 7090 | } |
| 7077 | 7091 | |
| 7078 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, bool is_wrapping, int size_in_bits) { | |
| 7079 | return *get_int_type_ptr(g, is_signed, is_wrapping, size_in_bits); | |
| 7092 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits) { | |
| 7093 | return *get_int_type_ptr(g, is_signed, size_in_bits); | |
| 7080 | 7094 | } |
| 7081 | 7095 | |
| 7082 | 7096 | TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) { |
src/analyze.hpp+2-2| ... | ... | @@ -19,8 +19,8 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent); |
| 19 | 19 | Expr *get_resolved_expr(AstNode *node); |
| 20 | 20 | bool is_node_void_expr(AstNode *node); |
| 21 | 21 | uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry); |
| 22 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, bool is_wrapping, int size_in_bits); | |
| 23 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, bool is_wrapping, int size_in_bits); | |
| 22 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits); | |
| 23 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits); | |
| 24 | 24 | TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type); |
| 25 | 25 | TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type); |
| 26 | 26 | TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *child_type); |
src/ast_render.cpp+44-35| ... | ... | @@ -4,41 +4,49 @@ |
| 4 | 4 | |
| 5 | 5 | static const char *bin_op_str(BinOpType bin_op) { |
| 6 | 6 | switch (bin_op) { |
| 7 | case BinOpTypeInvalid: return "(invalid)"; | |
| 8 | case BinOpTypeBoolOr: return "||"; | |
| 9 | case BinOpTypeBoolAnd: return "&&"; | |
| 10 | case BinOpTypeCmpEq: return "=="; | |
| 11 | case BinOpTypeCmpNotEq: return "!="; | |
| 12 | case BinOpTypeCmpLessThan: return "<"; | |
| 13 | case BinOpTypeCmpGreaterThan: return ">"; | |
| 14 | case BinOpTypeCmpLessOrEq: return "<="; | |
| 15 | case BinOpTypeCmpGreaterOrEq: return ">="; | |
| 16 | case BinOpTypeBinOr: return "|"; | |
| 17 | case BinOpTypeBinXor: return "^"; | |
| 18 | case BinOpTypeBinAnd: return "&"; | |
| 19 | case BinOpTypeBitShiftLeft: return "<<"; | |
| 20 | case BinOpTypeBitShiftRight: return ">>"; | |
| 21 | case BinOpTypeAdd: return "+"; | |
| 22 | case BinOpTypeSub: return "-"; | |
| 23 | case BinOpTypeMult: return "*"; | |
| 24 | case BinOpTypeDiv: return "/"; | |
| 25 | case BinOpTypeMod: return "%"; | |
| 26 | case BinOpTypeAssign: return "="; | |
| 27 | case BinOpTypeAssignTimes: return "*="; | |
| 28 | case BinOpTypeAssignDiv: return "/="; | |
| 29 | case BinOpTypeAssignMod: return "%="; | |
| 30 | case BinOpTypeAssignPlus: return "+="; | |
| 31 | case BinOpTypeAssignMinus: return "-="; | |
| 32 | case BinOpTypeAssignBitShiftLeft: return "<<="; | |
| 33 | case BinOpTypeAssignBitShiftRight: return ">>="; | |
| 34 | case BinOpTypeAssignBitAnd: return "&="; | |
| 35 | case BinOpTypeAssignBitXor: return "^="; | |
| 36 | case BinOpTypeAssignBitOr: return "|="; | |
| 37 | case BinOpTypeAssignBoolAnd: return "&&="; | |
| 38 | case BinOpTypeAssignBoolOr: return "||="; | |
| 39 | case BinOpTypeUnwrapMaybe: return "??"; | |
| 40 | case BinOpTypeArrayCat: return "++"; | |
| 41 | case BinOpTypeArrayMult: return "**"; | |
| 7 | case BinOpTypeInvalid: return "(invalid)"; | |
| 8 | case BinOpTypeBoolOr: return "||"; | |
| 9 | case BinOpTypeBoolAnd: return "&&"; | |
| 10 | case BinOpTypeCmpEq: return "=="; | |
| 11 | case BinOpTypeCmpNotEq: return "!="; | |
| 12 | case BinOpTypeCmpLessThan: return "<"; | |
| 13 | case BinOpTypeCmpGreaterThan: return ">"; | |
| 14 | case BinOpTypeCmpLessOrEq: return "<="; | |
| 15 | case BinOpTypeCmpGreaterOrEq: return ">="; | |
| 16 | case BinOpTypeBinOr: return "|"; | |
| 17 | case BinOpTypeBinXor: return "^"; | |
| 18 | case BinOpTypeBinAnd: return "&"; | |
| 19 | case BinOpTypeBitShiftLeft: return "<<"; | |
| 20 | case BinOpTypeBitShiftLeftWrap: return "<<%"; | |
| 21 | case BinOpTypeBitShiftRight: return ">>"; | |
| 22 | case BinOpTypeAdd: return "+"; | |
| 23 | case BinOpTypeAddWrap: return "+%"; | |
| 24 | case BinOpTypeSub: return "-"; | |
| 25 | case BinOpTypeSubWrap: return "-%"; | |
| 26 | case BinOpTypeMult: return "*"; | |
| 27 | case BinOpTypeMultWrap: return "*%"; | |
| 28 | case BinOpTypeDiv: return "/"; | |
| 29 | case BinOpTypeMod: return "%"; | |
| 30 | case BinOpTypeAssign: return "="; | |
| 31 | case BinOpTypeAssignTimes: return "*="; | |
| 32 | case BinOpTypeAssignTimesWrap: return "*%="; | |
| 33 | case BinOpTypeAssignDiv: return "/="; | |
| 34 | case BinOpTypeAssignMod: return "%="; | |
| 35 | case BinOpTypeAssignPlus: return "+="; | |
| 36 | case BinOpTypeAssignPlusWrap: return "+%="; | |
| 37 | case BinOpTypeAssignMinus: return "-="; | |
| 38 | case BinOpTypeAssignMinusWrap: return "-%="; | |
| 39 | case BinOpTypeAssignBitShiftLeft: return "<<="; | |
| 40 | case BinOpTypeAssignBitShiftLeftWrap: return "<<%="; | |
| 41 | case BinOpTypeAssignBitShiftRight: return ">>="; | |
| 42 | case BinOpTypeAssignBitAnd: return "&="; | |
| 43 | case BinOpTypeAssignBitXor: return "^="; | |
| 44 | case BinOpTypeAssignBitOr: return "|="; | |
| 45 | case BinOpTypeAssignBoolAnd: return "&&="; | |
| 46 | case BinOpTypeAssignBoolOr: return "||="; | |
| 47 | case BinOpTypeUnwrapMaybe: return "??"; | |
| 48 | case BinOpTypeArrayCat: return "++"; | |
| 49 | case BinOpTypeArrayMult: return "**"; | |
| 42 | 50 | } |
| 43 | 51 | zig_unreachable(); |
| 44 | 52 | } |
| ... | ... | @@ -47,6 +55,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) { |
| 47 | 55 | switch (prefix_op) { |
| 48 | 56 | case PrefixOpInvalid: return "(invalid)"; |
| 49 | 57 | case PrefixOpNegation: return "-"; |
| 58 | case PrefixOpNegationWrap: return "-%"; | |
| 50 | 59 | case PrefixOpBoolNot: return "!"; |
| 51 | 60 | case PrefixOpBinNot: return "~"; |
| 52 | 61 | case PrefixOpAddressOf: return "&"; |
src/codegen.cpp+60-51| ... | ... | @@ -1564,17 +1564,20 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { |
| 1564 | 1564 | AstNode *expr_node = node->data.prefix_op_expr.primary_expr; |
| 1565 | 1565 | TypeTableEntry *expr_type = get_expr_type(expr_node); |
| 1566 | 1566 | |
| 1567 | switch (node->data.prefix_op_expr.prefix_op) { | |
| 1567 | PrefixOp op = node->data.prefix_op_expr.prefix_op; | |
| 1568 | ||
| 1569 | switch (op) { | |
| 1568 | 1570 | case PrefixOpInvalid: |
| 1569 | 1571 | zig_unreachable(); |
| 1570 | 1572 | case PrefixOpNegation: |
| 1573 | case PrefixOpNegationWrap: | |
| 1571 | 1574 | { |
| 1572 | 1575 | LLVMValueRef expr = gen_expr(g, expr_node); |
| 1573 | 1576 | set_debug_source_node(g, node); |
| 1574 | 1577 | if (expr_type->id == TypeTableEntryIdFloat) { |
| 1575 | 1578 | return LLVMBuildFNeg(g->builder, expr, ""); |
| 1576 | 1579 | } else if (expr_type->id == TypeTableEntryIdInt) { |
| 1577 | if (expr_type->data.integral.is_wrapping) { | |
| 1580 | if (op == PrefixOpNegationWrap) { | |
| 1578 | 1581 | return LLVMBuildNeg(g->builder, expr, ""); |
| 1579 | 1582 | } else if (want_debug_safety(g, expr_node)) { |
| 1580 | 1583 | LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(expr)); |
| ... | ... | @@ -1796,17 +1799,23 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node, |
| 1796 | 1799 | set_debug_source_node(g, source_node); |
| 1797 | 1800 | return LLVMBuildAnd(g->builder, val1, val2, ""); |
| 1798 | 1801 | case BinOpTypeBitShiftLeft: |
| 1802 | case BinOpTypeBitShiftLeftWrap: | |
| 1799 | 1803 | case BinOpTypeAssignBitShiftLeft: |
| 1800 | set_debug_source_node(g, source_node); | |
| 1801 | assert(op1_type->id == TypeTableEntryIdInt); | |
| 1802 | if (op1_type->data.integral.is_wrapping) { | |
| 1803 | return LLVMBuildShl(g->builder, val1, val2, ""); | |
| 1804 | } else if (want_debug_safety(g, source_node)) { | |
| 1805 | return gen_overflow_shl_op(g, op1_type, val1, val2); | |
| 1806 | } else if (op1_type->data.integral.is_signed) { | |
| 1807 | return ZigLLVMBuildNSWShl(g->builder, val1, val2, ""); | |
| 1808 | } else { | |
| 1809 | return ZigLLVMBuildNUWShl(g->builder, val1, val2, ""); | |
| 1804 | case BinOpTypeAssignBitShiftLeftWrap: | |
| 1805 | { | |
| 1806 | set_debug_source_node(g, source_node); | |
| 1807 | assert(op1_type->id == TypeTableEntryIdInt); | |
| 1808 | bool is_wrapping = (bin_op == BinOpTypeBitShiftLeftWrap) || | |
| 1809 | (bin_op == BinOpTypeAssignBitShiftLeftWrap); | |
| 1810 | if (is_wrapping) { | |
| 1811 | return LLVMBuildShl(g->builder, val1, val2, ""); | |
| 1812 | } else if (want_debug_safety(g, source_node)) { | |
| 1813 | return gen_overflow_shl_op(g, op1_type, val1, val2); | |
| 1814 | } else if (op1_type->data.integral.is_signed) { | |
| 1815 | return ZigLLVMBuildNSWShl(g->builder, val1, val2, ""); | |
| 1816 | } else { | |
| 1817 | return ZigLLVMBuildNUWShl(g->builder, val1, val2, ""); | |
| 1818 | } | |
| 1810 | 1819 | } |
| 1811 | 1820 | case BinOpTypeBitShiftRight: |
| 1812 | 1821 | case BinOpTypeAssignBitShiftRight: |
| ... | ... | @@ -1820,12 +1829,15 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node, |
| 1820 | 1829 | return LLVMBuildLShr(g->builder, val1, val2, ""); |
| 1821 | 1830 | } |
| 1822 | 1831 | case BinOpTypeAdd: |
| 1832 | case BinOpTypeAddWrap: | |
| 1823 | 1833 | case BinOpTypeAssignPlus: |
| 1834 | case BinOpTypeAssignPlusWrap: | |
| 1824 | 1835 | set_debug_source_node(g, source_node); |
| 1825 | 1836 | if (op1_type->id == TypeTableEntryIdFloat) { |
| 1826 | 1837 | return LLVMBuildFAdd(g->builder, val1, val2, ""); |
| 1827 | 1838 | } else if (op1_type->id == TypeTableEntryIdInt) { |
| 1828 | if (op1_type->data.integral.is_wrapping) { | |
| 1839 | bool is_wrapping = (bin_op == BinOpTypeAddWrap) || (bin_op == BinOpTypeAssignPlusWrap); | |
| 1840 | if (is_wrapping) { | |
| 1829 | 1841 | return LLVMBuildAdd(g->builder, val1, val2, ""); |
| 1830 | 1842 | } else if (want_debug_safety(g, source_node)) { |
| 1831 | 1843 | return gen_overflow_op(g, op1_type, AddSubMulAdd, val1, val2); |
| ... | ... | @@ -1838,12 +1850,15 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node, |
| 1838 | 1850 | zig_unreachable(); |
| 1839 | 1851 | } |
| 1840 | 1852 | case BinOpTypeSub: |
| 1853 | case BinOpTypeSubWrap: | |
| 1841 | 1854 | case BinOpTypeAssignMinus: |
| 1855 | case BinOpTypeAssignMinusWrap: | |
| 1842 | 1856 | set_debug_source_node(g, source_node); |
| 1843 | 1857 | if (op1_type->id == TypeTableEntryIdFloat) { |
| 1844 | 1858 | return LLVMBuildFSub(g->builder, val1, val2, ""); |
| 1845 | 1859 | } else if (op1_type->id == TypeTableEntryIdInt) { |
| 1846 | if (op1_type->data.integral.is_wrapping) { | |
| 1860 | bool is_wrapping = (bin_op == BinOpTypeSubWrap || bin_op == BinOpTypeAssignMinusWrap); | |
| 1861 | if (is_wrapping) { | |
| 1847 | 1862 | return LLVMBuildSub(g->builder, val1, val2, ""); |
| 1848 | 1863 | } else if (want_debug_safety(g, source_node)) { |
| 1849 | 1864 | return gen_overflow_op(g, op1_type, AddSubMulSub, val1, val2); |
| ... | ... | @@ -1856,12 +1871,15 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node, |
| 1856 | 1871 | zig_unreachable(); |
| 1857 | 1872 | } |
| 1858 | 1873 | case BinOpTypeMult: |
| 1874 | case BinOpTypeMultWrap: | |
| 1859 | 1875 | case BinOpTypeAssignTimes: |
| 1876 | case BinOpTypeAssignTimesWrap: | |
| 1860 | 1877 | set_debug_source_node(g, source_node); |
| 1861 | 1878 | if (op1_type->id == TypeTableEntryIdFloat) { |
| 1862 | 1879 | return LLVMBuildFMul(g->builder, val1, val2, ""); |
| 1863 | 1880 | } else if (op1_type->id == TypeTableEntryIdInt) { |
| 1864 | if (op1_type->data.integral.is_wrapping) { | |
| 1881 | bool is_wrapping = (bin_op == BinOpTypeMultWrap || bin_op == BinOpTypeAssignTimesWrap); | |
| 1882 | if (is_wrapping) { | |
| 1865 | 1883 | return LLVMBuildMul(g->builder, val1, val2, ""); |
| 1866 | 1884 | } else if (want_debug_safety(g, source_node)) { |
| 1867 | 1885 | return gen_overflow_op(g, op1_type, AddSubMulMul, val1, val2); |
| ... | ... | @@ -2214,11 +2232,15 @@ static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) { |
| 2214 | 2232 | zig_unreachable(); |
| 2215 | 2233 | case BinOpTypeAssign: |
| 2216 | 2234 | case BinOpTypeAssignTimes: |
| 2235 | case BinOpTypeAssignTimesWrap: | |
| 2217 | 2236 | case BinOpTypeAssignDiv: |
| 2218 | 2237 | case BinOpTypeAssignMod: |
| 2219 | 2238 | case BinOpTypeAssignPlus: |
| 2239 | case BinOpTypeAssignPlusWrap: | |
| 2220 | 2240 | case BinOpTypeAssignMinus: |
| 2241 | case BinOpTypeAssignMinusWrap: | |
| 2221 | 2242 | case BinOpTypeAssignBitShiftLeft: |
| 2243 | case BinOpTypeAssignBitShiftLeftWrap: | |
| 2222 | 2244 | case BinOpTypeAssignBitShiftRight: |
| 2223 | 2245 | case BinOpTypeAssignBitAnd: |
| 2224 | 2246 | case BinOpTypeAssignBitXor: |
| ... | ... | @@ -2243,10 +2265,14 @@ static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) { |
| 2243 | 2265 | case BinOpTypeBinXor: |
| 2244 | 2266 | case BinOpTypeBinAnd: |
| 2245 | 2267 | case BinOpTypeBitShiftLeft: |
| 2268 | case BinOpTypeBitShiftLeftWrap: | |
| 2246 | 2269 | case BinOpTypeBitShiftRight: |
| 2247 | 2270 | case BinOpTypeAdd: |
| 2271 | case BinOpTypeAddWrap: | |
| 2248 | 2272 | case BinOpTypeSub: |
| 2273 | case BinOpTypeSubWrap: | |
| 2249 | 2274 | case BinOpTypeMult: |
| 2275 | case BinOpTypeMultWrap: | |
| 2250 | 2276 | case BinOpTypeDiv: |
| 2251 | 2277 | case BinOpTypeMod: |
| 2252 | 2278 | return gen_arithmetic_bin_op_expr(g, node); |
| ... | ... | @@ -4188,17 +4214,7 @@ static const CIntTypeInfo c_int_type_infos[] = { |
| 4188 | 4214 | {CIntTypeULongLong, "c_ulonglong", false}, |
| 4189 | 4215 | }; |
| 4190 | 4216 | |
| 4191 | struct SignWrap { | |
| 4192 | bool is_signed; | |
| 4193 | bool is_wrapping; | |
| 4194 | }; | |
| 4195 | ||
| 4196 | static const SignWrap sign_wrap_list[] = { | |
| 4197 | {false, false}, | |
| 4198 | {false, true}, | |
| 4199 | {true, false}, | |
| 4200 | {true, true}, | |
| 4201 | }; | |
| 4217 | static const bool is_signed_list[] = { false, true, }; | |
| 4202 | 4218 | |
| 4203 | 4219 | static void define_builtin_types(CodeGen *g) { |
| 4204 | 4220 | { |
| ... | ... | @@ -4238,18 +4254,16 @@ static void define_builtin_types(CodeGen *g) { |
| 4238 | 4254 | |
| 4239 | 4255 | for (int int_size_i = 0; int_size_i < array_length(int_sizes_in_bits); int_size_i += 1) { |
| 4240 | 4256 | int size_in_bits = int_sizes_in_bits[int_size_i]; |
| 4241 | for (int sign_wrap_i = 0; sign_wrap_i < array_length(sign_wrap_list); sign_wrap_i += 1) { | |
| 4242 | bool is_signed = sign_wrap_list[sign_wrap_i].is_signed; | |
| 4243 | bool is_wrapping = sign_wrap_list[sign_wrap_i].is_wrapping; | |
| 4257 | for (int is_sign_i = 0; is_sign_i < array_length(is_signed_list); is_sign_i += 1) { | |
| 4258 | bool is_signed = is_signed_list[is_sign_i]; | |
| 4244 | 4259 | |
| 4245 | 4260 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); |
| 4246 | 4261 | entry->type_ref = LLVMIntType(size_in_bits); |
| 4247 | 4262 | entry->deep_const = true; |
| 4248 | 4263 | |
| 4249 | 4264 | const char u_or_i = is_signed ? 'i' : 'u'; |
| 4250 | const char *w_or_none = is_wrapping ? "w" : ""; | |
| 4251 | 4265 | buf_resize(&entry->name, 0); |
| 4252 | buf_appendf(&entry->name, "%c%d%s", u_or_i, size_in_bits, w_or_none); | |
| 4266 | buf_appendf(&entry->name, "%c%d", u_or_i, size_in_bits); | |
| 4253 | 4267 | |
| 4254 | 4268 | unsigned dwarf_tag; |
| 4255 | 4269 | if (is_signed) { |
| ... | ... | @@ -4271,11 +4285,10 @@ static void define_builtin_types(CodeGen *g) { |
| 4271 | 4285 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), |
| 4272 | 4286 | debug_size_in_bits, debug_align_in_bits, dwarf_tag); |
| 4273 | 4287 | entry->data.integral.is_signed = is_signed; |
| 4274 | entry->data.integral.is_wrapping = is_wrapping; | |
| 4275 | 4288 | entry->data.integral.bit_count = size_in_bits; |
| 4276 | 4289 | g->primitive_type_table.put(&entry->name, entry); |
| 4277 | 4290 | |
| 4278 | get_int_type_ptr(g, is_signed, is_wrapping, size_in_bits)[0] = entry; | |
| 4291 | get_int_type_ptr(g, is_signed, size_in_bits)[0] = entry; | |
| 4279 | 4292 | } |
| 4280 | 4293 | } |
| 4281 | 4294 | |
| ... | ... | @@ -4297,7 +4310,6 @@ static void define_builtin_types(CodeGen *g) { |
| 4297 | 4310 | debug_align_in_bits, |
| 4298 | 4311 | is_signed ? LLVMZigEncoding_DW_ATE_signed() : LLVMZigEncoding_DW_ATE_unsigned()); |
| 4299 | 4312 | entry->data.integral.is_signed = is_signed; |
| 4300 | entry->data.integral.is_wrapping = !is_signed; | |
| 4301 | 4313 | entry->data.integral.bit_count = size_in_bits; |
| 4302 | 4314 | g->primitive_type_table.put(&entry->name, entry); |
| 4303 | 4315 | |
| ... | ... | @@ -4319,21 +4331,18 @@ static void define_builtin_types(CodeGen *g) { |
| 4319 | 4331 | g->primitive_type_table.put(&entry->name, entry); |
| 4320 | 4332 | } |
| 4321 | 4333 | |
| 4322 | for (int sign_wrap_i = 0; sign_wrap_i < array_length(sign_wrap_list); sign_wrap_i += 1) { | |
| 4323 | bool is_signed = sign_wrap_list[sign_wrap_i].is_signed; | |
| 4324 | bool is_wrapping = sign_wrap_list[sign_wrap_i].is_wrapping; | |
| 4334 | for (int sign_i = 0; sign_i < array_length(is_signed_list); sign_i += 1) { | |
| 4335 | bool is_signed = is_signed_list[sign_i]; | |
| 4325 | 4336 | |
| 4326 | 4337 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); |
| 4327 | 4338 | entry->deep_const = true; |
| 4328 | 4339 | entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8); |
| 4329 | 4340 | |
| 4330 | 4341 | const char u_or_i = is_signed ? 'i' : 'u'; |
| 4331 | const char *w_or_none = is_wrapping ? "w" : ""; | |
| 4332 | 4342 | buf_resize(&entry->name, 0); |
| 4333 | buf_appendf(&entry->name, "%csize%s", u_or_i, w_or_none); | |
| 4343 | buf_appendf(&entry->name, "%csize", u_or_i); | |
| 4334 | 4344 | |
| 4335 | 4345 | entry->data.integral.is_signed = is_signed; |
| 4336 | entry->data.integral.is_wrapping = is_wrapping; | |
| 4337 | 4346 | entry->data.integral.bit_count = g->pointer_size_bytes * 8; |
| 4338 | 4347 | |
| 4339 | 4348 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); |
| ... | ... | @@ -4344,9 +4353,9 @@ static void define_builtin_types(CodeGen *g) { |
| 4344 | 4353 | is_signed ? LLVMZigEncoding_DW_ATE_signed() : LLVMZigEncoding_DW_ATE_unsigned()); |
| 4345 | 4354 | g->primitive_type_table.put(&entry->name, entry); |
| 4346 | 4355 | |
| 4347 | if (is_signed && !is_wrapping) { | |
| 4356 | if (is_signed) { | |
| 4348 | 4357 | g->builtin_types.entry_isize = entry; |
| 4349 | } else if (!is_signed && !is_wrapping) { | |
| 4358 | } else { | |
| 4350 | 4359 | g->builtin_types.entry_usize = entry; |
| 4351 | 4360 | } |
| 4352 | 4361 | } |
| ... | ... | @@ -4430,14 +4439,14 @@ static void define_builtin_types(CodeGen *g) { |
| 4430 | 4439 | g->primitive_type_table.put(&entry->name, entry); |
| 4431 | 4440 | } |
| 4432 | 4441 | |
| 4433 | g->builtin_types.entry_u8 = get_int_type(g, false, false, 8); | |
| 4434 | g->builtin_types.entry_u16 = get_int_type(g, false, false, 16); | |
| 4435 | g->builtin_types.entry_u32 = get_int_type(g, false, false, 32); | |
| 4436 | g->builtin_types.entry_u64 = get_int_type(g, false, false, 64); | |
| 4437 | g->builtin_types.entry_i8 = get_int_type(g, true, false, 8); | |
| 4438 | g->builtin_types.entry_i16 = get_int_type(g, true, false, 16); | |
| 4439 | g->builtin_types.entry_i32 = get_int_type(g, true, false, 32); | |
| 4440 | g->builtin_types.entry_i64 = get_int_type(g, true, false, 64); | |
| 4442 | g->builtin_types.entry_u8 = get_int_type(g, false, 8); | |
| 4443 | g->builtin_types.entry_u16 = get_int_type(g, false, 16); | |
| 4444 | g->builtin_types.entry_u32 = get_int_type(g, false, 32); | |
| 4445 | g->builtin_types.entry_u64 = get_int_type(g, false, 64); | |
| 4446 | g->builtin_types.entry_i8 = get_int_type(g, true, 8); | |
| 4447 | g->builtin_types.entry_i16 = get_int_type(g, true, 16); | |
| 4448 | g->builtin_types.entry_i32 = get_int_type(g, true, 32); | |
| 4449 | g->builtin_types.entry_i64 = get_int_type(g, true, 64); | |
| 4441 | 4450 | |
| 4442 | 4451 | { |
| 4443 | 4452 | g->builtin_types.entry_c_void = get_typedecl_type(g, "c_void", g->builtin_types.entry_u8); |
| ... | ... | @@ -4703,7 +4712,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 4703 | 4712 | create_builtin_fn_with_arg_count(g, BuiltinFnIdDivExact, "div_exact", 2); |
| 4704 | 4713 | create_builtin_fn_with_arg_count(g, BuiltinFnIdTruncate, "truncate", 2); |
| 4705 | 4714 | create_builtin_fn_with_arg_count(g, BuiltinFnIdCompileErr, "compile_err", 1); |
| 4706 | create_builtin_fn_with_arg_count(g, BuiltinFnIdIntType, "int_type", 3); | |
| 4715 | create_builtin_fn_with_arg_count(g, BuiltinFnIdIntType, "int_type", 2); | |
| 4707 | 4716 | } |
| 4708 | 4717 | |
| 4709 | 4718 | static void init(CodeGen *g, Buf *source_path) { |
src/eval.cpp+34-13| ... | ... | @@ -146,7 +146,7 @@ static int64_t min_signed_val(TypeTableEntry *type_entry) { |
| 146 | 146 | |
| 147 | 147 | static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val, |
| 148 | 148 | ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *), |
| 149 | TypeTableEntry *type) | |
| 149 | TypeTableEntry *type, bool wrapping_op) | |
| 150 | 150 | { |
| 151 | 151 | bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum); |
| 152 | 152 | if (overflow) { |
| ... | ... | @@ -156,7 +156,7 @@ static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue |
| 156 | 156 | if (type->id == TypeTableEntryIdInt && !bignum_fits_in_bits(&out_val->data.x_bignum, |
| 157 | 157 | type->data.integral.bit_count, type->data.integral.is_signed)) |
| 158 | 158 | { |
| 159 | if (type->data.integral.is_wrapping) { | |
| 159 | if (wrapping_op) { | |
| 160 | 160 | if (type->data.integral.is_signed) { |
| 161 | 161 | out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1; |
| 162 | 162 | out_val->data.x_bignum.is_negative = !out_val->data.x_bignum.is_negative; |
| ... | ... | @@ -187,11 +187,15 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, |
| 187 | 187 | switch (bin_op) { |
| 188 | 188 | case BinOpTypeAssign: |
| 189 | 189 | case BinOpTypeAssignTimes: |
| 190 | case BinOpTypeAssignTimesWrap: | |
| 190 | 191 | case BinOpTypeAssignDiv: |
| 191 | 192 | case BinOpTypeAssignMod: |
| 192 | 193 | case BinOpTypeAssignPlus: |
| 194 | case BinOpTypeAssignPlusWrap: | |
| 193 | 195 | case BinOpTypeAssignMinus: |
| 196 | case BinOpTypeAssignMinusWrap: | |
| 194 | 197 | case BinOpTypeAssignBitShiftLeft: |
| 198 | case BinOpTypeAssignBitShiftLeftWrap: | |
| 195 | 199 | case BinOpTypeAssignBitShiftRight: |
| 196 | 200 | case BinOpTypeAssignBitAnd: |
| 197 | 201 | case BinOpTypeAssignBitXor: |
| ... | ... | @@ -256,21 +260,29 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, |
| 256 | 260 | return 0; |
| 257 | 261 | } |
| 258 | 262 | case BinOpTypeAdd: |
| 259 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type); | |
| 263 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, false); | |
| 264 | case BinOpTypeAddWrap: | |
| 265 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, true); | |
| 260 | 266 | case BinOpTypeBinOr: |
| 261 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or, op1_type); | |
| 267 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or, op1_type, false); | |
| 262 | 268 | case BinOpTypeBinXor: |
| 263 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type); | |
| 269 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type, false); | |
| 264 | 270 | case BinOpTypeBinAnd: |
| 265 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and, op1_type); | |
| 271 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and, op1_type, false); | |
| 266 | 272 | case BinOpTypeBitShiftLeft: |
| 267 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type); | |
| 273 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, false); | |
| 274 | case BinOpTypeBitShiftLeftWrap: | |
| 275 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, true); | |
| 268 | 276 | case BinOpTypeBitShiftRight: |
| 269 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type); | |
| 277 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type, false); | |
| 270 | 278 | case BinOpTypeSub: |
| 271 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type); | |
| 279 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, false); | |
| 280 | case BinOpTypeSubWrap: | |
| 281 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, true); | |
| 272 | 282 | case BinOpTypeMult: |
| 273 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type); | |
| 283 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, false); | |
| 284 | case BinOpTypeMultWrap: | |
| 285 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, true); | |
| 274 | 286 | case BinOpTypeDiv: |
| 275 | 287 | { |
| 276 | 288 | bool is_int = false; |
| ... | ... | @@ -289,11 +301,11 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, |
| 289 | 301 | { |
| 290 | 302 | return ErrorDivByZero; |
| 291 | 303 | } else { |
| 292 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div, op1_type); | |
| 304 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div, op1_type, false); | |
| 293 | 305 | } |
| 294 | 306 | } |
| 295 | 307 | case BinOpTypeMod: |
| 296 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type); | |
| 308 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type, false); | |
| 297 | 309 | case BinOpTypeUnwrapMaybe: |
| 298 | 310 | zig_panic("TODO"); |
| 299 | 311 | case BinOpTypeArrayCat: |
| ... | ... | @@ -314,11 +326,15 @@ static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) |
| 314 | 326 | switch (bin_op) { |
| 315 | 327 | case BinOpTypeAssign: |
| 316 | 328 | case BinOpTypeAssignTimes: |
| 329 | case BinOpTypeAssignTimesWrap: | |
| 317 | 330 | case BinOpTypeAssignDiv: |
| 318 | 331 | case BinOpTypeAssignMod: |
| 319 | 332 | case BinOpTypeAssignPlus: |
| 333 | case BinOpTypeAssignPlusWrap: | |
| 320 | 334 | case BinOpTypeAssignMinus: |
| 335 | case BinOpTypeAssignMinusWrap: | |
| 321 | 336 | case BinOpTypeAssignBitShiftLeft: |
| 337 | case BinOpTypeAssignBitShiftLeftWrap: | |
| 322 | 338 | case BinOpTypeAssignBitShiftRight: |
| 323 | 339 | case BinOpTypeAssignBitAnd: |
| 324 | 340 | case BinOpTypeAssignBitXor: |
| ... | ... | @@ -338,10 +354,14 @@ static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) |
| 338 | 354 | case BinOpTypeBinXor: |
| 339 | 355 | case BinOpTypeBinAnd: |
| 340 | 356 | case BinOpTypeBitShiftLeft: |
| 357 | case BinOpTypeBitShiftLeftWrap: | |
| 341 | 358 | case BinOpTypeBitShiftRight: |
| 342 | 359 | case BinOpTypeAdd: |
| 360 | case BinOpTypeAddWrap: | |
| 343 | 361 | case BinOpTypeSub: |
| 362 | case BinOpTypeSubWrap: | |
| 344 | 363 | case BinOpTypeMult: |
| 364 | case BinOpTypeMultWrap: | |
| 345 | 365 | case BinOpTypeDiv: |
| 346 | 366 | case BinOpTypeMod: |
| 347 | 367 | case BinOpTypeUnwrapMaybe: |
| ... | ... | @@ -1098,13 +1118,14 @@ static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_v |
| 1098 | 1118 | break; |
| 1099 | 1119 | } |
| 1100 | 1120 | case PrefixOpNegation: |
| 1121 | case PrefixOpNegationWrap: | |
| 1101 | 1122 | if (expr_type->id == TypeTableEntryIdInt) { |
| 1102 | 1123 | assert(expr_type->data.integral.is_signed); |
| 1103 | 1124 | bignum_negate(&out_val->data.x_bignum, &expr_val.data.x_bignum); |
| 1104 | 1125 | out_val->ok = true; |
| 1105 | 1126 | bool overflow = !bignum_fits_in_bits(&out_val->data.x_bignum, |
| 1106 | 1127 | expr_type->data.integral.bit_count, expr_type->data.integral.is_signed); |
| 1107 | if (expr_type->data.integral.is_wrapping) { | |
| 1128 | if (prefix_op == PrefixOpNegationWrap) { | |
| 1108 | 1129 | if (overflow) { |
| 1109 | 1130 | out_val->data.x_bignum.is_negative = true; |
| 1110 | 1131 | } |
src/parser.cpp+25-16| ... | ... | @@ -1384,6 +1384,7 @@ static PrefixOp tok_to_prefix_op(Token *token) { |
| 1384 | 1384 | switch (token->id) { |
| 1385 | 1385 | case TokenIdBang: return PrefixOpBoolNot; |
| 1386 | 1386 | case TokenIdDash: return PrefixOpNegation; |
| 1387 | case TokenIdMinusPercent: return PrefixOpNegationWrap; | |
| 1387 | 1388 | case TokenIdTilde: return PrefixOpBinNot; |
| 1388 | 1389 | case TokenIdAmpersand: return PrefixOpAddressOf; |
| 1389 | 1390 | case TokenIdStar: return PrefixOpDereference; |
| ... | ... | @@ -1399,7 +1400,7 @@ static PrefixOp tok_to_prefix_op(Token *token) { |
| 1399 | 1400 | |
| 1400 | 1401 | /* |
| 1401 | 1402 | PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression |
| 1402 | PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const))) | |
| 1403 | PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | "??" | "-%" | |
| 1403 | 1404 | */ |
| 1404 | 1405 | static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1405 | 1406 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -1458,16 +1459,17 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo |
| 1458 | 1459 | |
| 1459 | 1460 | static BinOpType tok_to_mult_op(Token *token) { |
| 1460 | 1461 | switch (token->id) { |
| 1461 | case TokenIdStar: return BinOpTypeMult; | |
| 1462 | case TokenIdStarStar: return BinOpTypeArrayMult; | |
| 1463 | case TokenIdSlash: return BinOpTypeDiv; | |
| 1464 | case TokenIdPercent: return BinOpTypeMod; | |
| 1465 | default: return BinOpTypeInvalid; | |
| 1462 | case TokenIdStar: return BinOpTypeMult; | |
| 1463 | case TokenIdTimesPercent: return BinOpTypeMultWrap; | |
| 1464 | case TokenIdStarStar: return BinOpTypeArrayMult; | |
| 1465 | case TokenIdSlash: return BinOpTypeDiv; | |
| 1466 | case TokenIdPercent: return BinOpTypeMod; | |
| 1467 | default: return BinOpTypeInvalid; | |
| 1466 | 1468 | } |
| 1467 | 1469 | } |
| 1468 | 1470 | |
| 1469 | 1471 | /* |
| 1470 | MultiplyOperator = "*" | "/" | "%" | "**" | |
| 1472 | MultiplyOperator = "*" | "/" | "%" | "**" | "*%" | |
| 1471 | 1473 | */ |
| 1472 | 1474 | static BinOpType ast_parse_mult_op(ParseContext *pc, int *token_index, bool mandatory) { |
| 1473 | 1475 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -1511,15 +1513,17 @@ static AstNode *ast_parse_mult_expr(ParseContext *pc, int *token_index, bool man |
| 1511 | 1513 | |
| 1512 | 1514 | static BinOpType tok_to_add_op(Token *token) { |
| 1513 | 1515 | switch (token->id) { |
| 1514 | case TokenIdPlus: return BinOpTypeAdd; | |
| 1515 | case TokenIdDash: return BinOpTypeSub; | |
| 1516 | case TokenIdPlusPlus: return BinOpTypeArrayCat; | |
| 1517 | default: return BinOpTypeInvalid; | |
| 1516 | case TokenIdPlus: return BinOpTypeAdd; | |
| 1517 | case TokenIdPlusPercent: return BinOpTypeAddWrap; | |
| 1518 | case TokenIdDash: return BinOpTypeSub; | |
| 1519 | case TokenIdMinusPercent: return BinOpTypeSubWrap; | |
| 1520 | case TokenIdPlusPlus: return BinOpTypeArrayCat; | |
| 1521 | default: return BinOpTypeInvalid; | |
| 1518 | 1522 | } |
| 1519 | 1523 | } |
| 1520 | 1524 | |
| 1521 | 1525 | /* |
| 1522 | AdditionOperator : "+" | "-" | "++" | |
| 1526 | AdditionOperator = "+" | "-" | "++" | "+%" | "-%" | |
| 1523 | 1527 | */ |
| 1524 | 1528 | static BinOpType ast_parse_add_op(ParseContext *pc, int *token_index, bool mandatory) { |
| 1525 | 1529 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -1563,14 +1567,15 @@ static AstNode *ast_parse_add_expr(ParseContext *pc, int *token_index, bool mand |
| 1563 | 1567 | |
| 1564 | 1568 | static BinOpType tok_to_bit_shift_op(Token *token) { |
| 1565 | 1569 | switch (token->id) { |
| 1566 | case TokenIdBitShiftLeft: return BinOpTypeBitShiftLeft; | |
| 1567 | case TokenIdBitShiftRight: return BinOpTypeBitShiftRight; | |
| 1570 | case TokenIdBitShiftLeft: return BinOpTypeBitShiftLeft; | |
| 1571 | case TokenIdBitShiftLeftPercent: return BinOpTypeBitShiftLeftWrap; | |
| 1572 | case TokenIdBitShiftRight: return BinOpTypeBitShiftRight; | |
| 1568 | 1573 | default: return BinOpTypeInvalid; |
| 1569 | 1574 | } |
| 1570 | 1575 | } |
| 1571 | 1576 | |
| 1572 | 1577 | /* |
| 1573 | BitShiftOperator : token(BitShiftLeft) | token(BitShiftRight) | |
| 1578 | BitShiftOperator = "<<" | ">>" | "<<%" | |
| 1574 | 1579 | */ |
| 1575 | 1580 | static BinOpType ast_parse_bit_shift_op(ParseContext *pc, int *token_index, bool mandatory) { |
| 1576 | 1581 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -2230,11 +2235,15 @@ static BinOpType tok_to_ass_op(Token *token) { |
| 2230 | 2235 | switch (token->id) { |
| 2231 | 2236 | case TokenIdEq: return BinOpTypeAssign; |
| 2232 | 2237 | case TokenIdTimesEq: return BinOpTypeAssignTimes; |
| 2238 | case TokenIdTimesPercentEq: return BinOpTypeAssignTimesWrap; | |
| 2233 | 2239 | case TokenIdDivEq: return BinOpTypeAssignDiv; |
| 2234 | 2240 | case TokenIdModEq: return BinOpTypeAssignMod; |
| 2235 | 2241 | case TokenIdPlusEq: return BinOpTypeAssignPlus; |
| 2242 | case TokenIdPlusPercentEq: return BinOpTypeAssignPlusWrap; | |
| 2236 | 2243 | case TokenIdMinusEq: return BinOpTypeAssignMinus; |
| 2244 | case TokenIdMinusPercentEq: return BinOpTypeAssignMinusWrap; | |
| 2237 | 2245 | case TokenIdBitShiftLeftEq: return BinOpTypeAssignBitShiftLeft; |
| 2246 | case TokenIdBitShiftLeftPercentEq: return BinOpTypeAssignBitShiftLeftWrap; | |
| 2238 | 2247 | case TokenIdBitShiftRightEq: return BinOpTypeAssignBitShiftRight; |
| 2239 | 2248 | case TokenIdBitAndEq: return BinOpTypeAssignBitAnd; |
| 2240 | 2249 | case TokenIdBitXorEq: return BinOpTypeAssignBitXor; |
| ... | ... | @@ -2246,7 +2255,7 @@ static BinOpType tok_to_ass_op(Token *token) { |
| 2246 | 2255 | } |
| 2247 | 2256 | |
| 2248 | 2257 | /* |
| 2249 | AssignmentOperator : token(Eq) | token(TimesEq) | token(DivEq) | token(ModEq) | token(PlusEq) | token(MinusEq) | token(BitShiftLeftEq) | token(BitShiftRightEq) | token(BitAndEq) | token(BitXorEq) | token(BitOrEq) | token(BoolAndEq) | token(BoolOrEq) | |
| 2258 | AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "&&=" | "||=" | "*%=" | "+%=" | "-%=" | "<<%=" | |
| 2250 | 2259 | */ |
| 2251 | 2260 | static BinOpType ast_parse_ass_op(ParseContext *pc, int *token_index, bool mandatory) { |
| 2252 | 2261 | Token *token = &pc->tokens->at(*token_index); |
src/tokenizer.cpp+88| ... | ... | @@ -154,10 +154,13 @@ enum TokenizeState { |
| 154 | 154 | TokenizeStateCharLiteral, |
| 155 | 155 | TokenizeStateCharLiteralEnd, |
| 156 | 156 | TokenizeStateSawStar, |
| 157 | TokenizeStateSawStarPercent, | |
| 157 | 158 | TokenizeStateSawSlash, |
| 158 | 159 | TokenizeStateSawPercent, |
| 159 | 160 | TokenizeStateSawPlus, |
| 161 | TokenizeStateSawPlusPercent, | |
| 160 | 162 | TokenizeStateSawDash, |
| 163 | TokenizeStateSawMinusPercent, | |
| 161 | 164 | TokenizeStateSawAmpersand, |
| 162 | 165 | TokenizeStateSawAmpersandAmpersand, |
| 163 | 166 | TokenizeStateSawCaret, |
| ... | ... | @@ -171,6 +174,7 @@ enum TokenizeState { |
| 171 | 174 | TokenizeStateSawBang, |
| 172 | 175 | TokenizeStateSawLessThan, |
| 173 | 176 | TokenizeStateSawLessThanLessThan, |
| 177 | TokenizeStateSawShiftLeftPercent, | |
| 174 | 178 | TokenizeStateSawGreaterThan, |
| 175 | 179 | TokenizeStateSawGreaterThanGreaterThan, |
| 176 | 180 | TokenizeStateSawDot, |
| ... | ... | @@ -596,6 +600,24 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 596 | 600 | end_token(&t); |
| 597 | 601 | t.state = TokenizeStateStart; |
| 598 | 602 | break; |
| 603 | case '%': | |
| 604 | t.cur_tok->id = TokenIdBitShiftLeftPercent; | |
| 605 | t.state = TokenizeStateSawShiftLeftPercent; | |
| 606 | break; | |
| 607 | default: | |
| 608 | t.pos -= 1; | |
| 609 | end_token(&t); | |
| 610 | t.state = TokenizeStateStart; | |
| 611 | continue; | |
| 612 | } | |
| 613 | break; | |
| 614 | case TokenizeStateSawShiftLeftPercent: | |
| 615 | switch (c) { | |
| 616 | case '=': | |
| 617 | t.cur_tok->id = TokenIdBitShiftLeftPercentEq; | |
| 618 | end_token(&t); | |
| 619 | t.state = TokenizeStateStart; | |
| 620 | break; | |
| 599 | 621 | default: |
| 600 | 622 | t.pos -= 1; |
| 601 | 623 | end_token(&t); |
| ... | ... | @@ -648,6 +670,24 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 648 | 670 | end_token(&t); |
| 649 | 671 | t.state = TokenizeStateStart; |
| 650 | 672 | break; |
| 673 | case '%': | |
| 674 | t.cur_tok->id = TokenIdTimesPercent; | |
| 675 | t.state = TokenizeStateSawStarPercent; | |
| 676 | break; | |
| 677 | default: | |
| 678 | t.pos -= 1; | |
| 679 | end_token(&t); | |
| 680 | t.state = TokenizeStateStart; | |
| 681 | continue; | |
| 682 | } | |
| 683 | break; | |
| 684 | case TokenizeStateSawStarPercent: | |
| 685 | switch (c) { | |
| 686 | case '=': | |
| 687 | t.cur_tok->id = TokenIdTimesPercentEq; | |
| 688 | end_token(&t); | |
| 689 | t.state = TokenizeStateStart; | |
| 690 | break; | |
| 651 | 691 | default: |
| 652 | 692 | t.pos -= 1; |
| 653 | 693 | end_token(&t); |
| ... | ... | @@ -691,6 +731,24 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 691 | 731 | end_token(&t); |
| 692 | 732 | t.state = TokenizeStateStart; |
| 693 | 733 | break; |
| 734 | case '%': | |
| 735 | t.cur_tok->id = TokenIdPlusPercent; | |
| 736 | t.state = TokenizeStateSawPlusPercent; | |
| 737 | break; | |
| 738 | default: | |
| 739 | t.pos -= 1; | |
| 740 | end_token(&t); | |
| 741 | t.state = TokenizeStateStart; | |
| 742 | continue; | |
| 743 | } | |
| 744 | break; | |
| 745 | case TokenizeStateSawPlusPercent: | |
| 746 | switch (c) { | |
| 747 | case '=': | |
| 748 | t.cur_tok->id = TokenIdPlusPercentEq; | |
| 749 | end_token(&t); | |
| 750 | t.state = TokenizeStateStart; | |
| 751 | break; | |
| 694 | 752 | default: |
| 695 | 753 | t.pos -= 1; |
| 696 | 754 | end_token(&t); |
| ... | ... | @@ -1181,6 +1239,24 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1181 | 1239 | end_token(&t); |
| 1182 | 1240 | t.state = TokenizeStateStart; |
| 1183 | 1241 | break; |
| 1242 | case '%': | |
| 1243 | t.cur_tok->id = TokenIdMinusPercent; | |
| 1244 | t.state = TokenizeStateSawMinusPercent; | |
| 1245 | break; | |
| 1246 | default: | |
| 1247 | t.pos -= 1; | |
| 1248 | end_token(&t); | |
| 1249 | t.state = TokenizeStateStart; | |
| 1250 | continue; | |
| 1251 | } | |
| 1252 | break; | |
| 1253 | case TokenizeStateSawMinusPercent: | |
| 1254 | switch (c) { | |
| 1255 | case '=': | |
| 1256 | t.cur_tok->id = TokenIdMinusPercentEq; | |
| 1257 | end_token(&t); | |
| 1258 | t.state = TokenizeStateStart; | |
| 1259 | break; | |
| 1184 | 1260 | default: |
| 1185 | 1261 | t.pos -= 1; |
| 1186 | 1262 | end_token(&t); |
| ... | ... | @@ -1252,6 +1328,10 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1252 | 1328 | case TokenizeStateSawDot: |
| 1253 | 1329 | case TokenizeStateSawQuestionMark: |
| 1254 | 1330 | case TokenizeStateSawAtSign: |
| 1331 | case TokenizeStateSawStarPercent: | |
| 1332 | case TokenizeStateSawPlusPercent: | |
| 1333 | case TokenizeStateSawMinusPercent: | |
| 1334 | case TokenizeStateSawShiftLeftPercent: | |
| 1255 | 1335 | end_token(&t); |
| 1256 | 1336 | break; |
| 1257 | 1337 | case TokenizeStateSawDotDot: |
| ... | ... | @@ -1372,6 +1452,14 @@ const char * token_name(TokenId id) { |
| 1372 | 1452 | case TokenIdMaybeAssign: return "?="; |
| 1373 | 1453 | case TokenIdAtSign: return "@"; |
| 1374 | 1454 | case TokenIdPercentDot: return "%."; |
| 1455 | case TokenIdTimesPercent: return "*%"; | |
| 1456 | case TokenIdTimesPercentEq: return "*%="; | |
| 1457 | case TokenIdPlusPercent: return "+%"; | |
| 1458 | case TokenIdPlusPercentEq: return "+%="; | |
| 1459 | case TokenIdMinusPercent: return "-%"; | |
| 1460 | case TokenIdMinusPercentEq: return "-%="; | |
| 1461 | case TokenIdBitShiftLeftPercent: return "<<%"; | |
| 1462 | case TokenIdBitShiftLeftPercentEq: return "<<%="; | |
| 1375 | 1463 | } |
| 1376 | 1464 | return "(invalid token)"; |
| 1377 | 1465 | } |
src/tokenizer.hpp+8| ... | ... | @@ -70,11 +70,19 @@ enum TokenId { |
| 70 | 70 | TokenIdBinXor, |
| 71 | 71 | TokenIdEq, |
| 72 | 72 | TokenIdTimesEq, |
| 73 | TokenIdTimesPercent, | |
| 74 | TokenIdTimesPercentEq, | |
| 73 | 75 | TokenIdDivEq, |
| 74 | 76 | TokenIdModEq, |
| 75 | 77 | TokenIdPlusEq, |
| 78 | TokenIdPlusPercent, | |
| 79 | TokenIdPlusPercentEq, | |
| 76 | 80 | TokenIdMinusEq, |
| 81 | TokenIdMinusPercent, | |
| 82 | TokenIdMinusPercentEq, | |
| 77 | 83 | TokenIdBitShiftLeftEq, |
| 84 | TokenIdBitShiftLeftPercent, | |
| 85 | TokenIdBitShiftLeftPercentEq, | |
| 78 | 86 | TokenIdBitShiftRightEq, |
| 79 | 87 | TokenIdBitAndEq, |
| 80 | 88 | TokenIdBitXorEq, |
std/io.zig+1-1| ... | ... | @@ -235,7 +235,7 @@ fn char_to_digit(c: u8, radix: u8) -> %u8 { |
| 235 | 235 | } |
| 236 | 236 | |
| 237 | 237 | pub fn buf_print_signed(inline T: type, out_buf: []u8, x: T) -> usize { |
| 238 | const uint = @int_type(false, T.bit_count, false); | |
| 238 | const uint = @int_type(false, T.bit_count); | |
| 239 | 239 | if (x < 0) { |
| 240 | 240 | out_buf[0] = '-'; |
| 241 | 241 | return 1 + buf_print_unsigned(uint, out_buf[1...], uint(-(x + 1)) + 1); |
std/rand.zig+5-6| ... | ... | @@ -77,7 +77,7 @@ pub struct Rand { |
| 77 | 77 | |
| 78 | 78 | /// Get a floating point value in the range 0.0..1.0. |
| 79 | 79 | pub fn float(r: &Rand, inline T: type) -> T { |
| 80 | const int_type = @int_type(false, @sizeof(T) * 8, false); | |
| 80 | const int_type = @int_type(false, @sizeof(T) * 8); | |
| 81 | 81 | // TODO switch statement for constant values |
| 82 | 82 | const precision = if (T == f32) { |
| 83 | 83 | 16777216 |
| ... | ... | @@ -99,7 +99,6 @@ struct MersenneTwister( |
| 99 | 99 | l: int, f: int) |
| 100 | 100 | { |
| 101 | 101 | const Self = MersenneTwister(int, n, m, r, a, u, d, s, b, t, c, l, f); |
| 102 | const intw = @int_type(int.is_signed, int.bit_count, true); | |
| 103 | 102 | |
| 104 | 103 | array: [n]int, |
| 105 | 104 | index: usize, |
| ... | ... | @@ -113,7 +112,7 @@ struct MersenneTwister( |
| 113 | 112 | var prev_value = seed; |
| 114 | 113 | mt.array[0] = prev_value; |
| 115 | 114 | {var i: usize = 1; while (i < n; i += 1) { |
| 116 | prev_value = intw(i) + intw(f) * intw(prev_value ^ (prev_value >> (int.bit_count - 2))); | |
| 115 | prev_value = int(i) +% f *% (prev_value ^ (prev_value >> (int.bit_count - 2))); | |
| 117 | 116 | mt.array[i] = prev_value; |
| 118 | 117 | }}; |
| 119 | 118 | |
| ... | ... | @@ -152,12 +151,12 @@ struct MersenneTwister( |
| 152 | 151 | mt.index = 0; |
| 153 | 152 | } |
| 154 | 153 | |
| 155 | var x: intw = mt.array[mt.index]; | |
| 154 | var x = mt.array[mt.index]; | |
| 156 | 155 | mt.index += 1; |
| 157 | 156 | |
| 158 | 157 | x ^= ((x >> u) & d); |
| 159 | x ^= ((x << s) & b); | |
| 160 | x ^= ((x << t) & c); | |
| 158 | x ^= ((x <<% s) & b); | |
| 159 | x ^= ((x <<% t) & c); | |
| 161 | 160 | x ^= (x >> l); |
| 162 | 161 | |
| 163 | 162 | return x; |
test/run_tests.cpp-6| ... | ... | @@ -1362,12 +1362,6 @@ fn mul(a: u16, b: u16) -> u16 { |
| 1362 | 1362 | ".tmp_source.zig:3:18: note: called from here", |
| 1363 | 1363 | ".tmp_source.zig:6:7: note: overflow occurred here"); |
| 1364 | 1364 | |
| 1365 | add_compile_fail_case("add incompatible int types", R"SOURCE( | |
| 1366 | fn add(x: i8w, y: i32) { | |
| 1367 | const z = x + y; | |
| 1368 | } | |
| 1369 | )SOURCE", 1, ".tmp_source.zig:3:17: error: incompatible types: 'i8w' and 'i32'"); | |
| 1370 | ||
| 1371 | 1365 | add_compile_fail_case("truncate sign mismatch", R"SOURCE( |
| 1372 | 1366 | fn f() { |
| 1373 | 1367 | const x: u32 = 10; |
test/self_hosted.zig+29-66| ... | ... | @@ -1458,17 +1458,17 @@ fn unsigned_wrapping() { |
| 1458 | 1458 | test_unsigned_wrapping_eval(@max_value(u32)); |
| 1459 | 1459 | test_unsigned_wrapping_noeval(@max_value(u32)); |
| 1460 | 1460 | } |
| 1461 | fn test_unsigned_wrapping_eval(x: u32w) { | |
| 1462 | const zero = x + 1; | |
| 1461 | fn test_unsigned_wrapping_eval(x: u32) { | |
| 1462 | const zero = x +% 1; | |
| 1463 | 1463 | assert(zero == 0); |
| 1464 | const orig = zero - 1; | |
| 1464 | const orig = zero -% 1; | |
| 1465 | 1465 | assert(orig == @max_value(u32)); |
| 1466 | 1466 | } |
| 1467 | 1467 | #static_eval_enable(false) |
| 1468 | fn test_unsigned_wrapping_noeval(x: u32w) { | |
| 1469 | const zero = x + 1; | |
| 1468 | fn test_unsigned_wrapping_noeval(x: u32) { | |
| 1469 | const zero = x +% 1; | |
| 1470 | 1470 | assert(zero == 0); |
| 1471 | const orig = zero - 1; | |
| 1471 | const orig = zero -% 1; | |
| 1472 | 1472 | assert(orig == @max_value(u32)); |
| 1473 | 1473 | } |
| 1474 | 1474 | |
| ... | ... | @@ -1477,17 +1477,17 @@ fn signed_wrapping() { |
| 1477 | 1477 | test_signed_wrapping_eval(@max_value(i32)); |
| 1478 | 1478 | test_signed_wrapping_noeval(@max_value(i32)); |
| 1479 | 1479 | } |
| 1480 | fn test_signed_wrapping_eval(x: i32w) { | |
| 1481 | const min_val = x + 1; | |
| 1480 | fn test_signed_wrapping_eval(x: i32) { | |
| 1481 | const min_val = x +% 1; | |
| 1482 | 1482 | assert(min_val == @min_value(i32)); |
| 1483 | const max_val = min_val - 1; | |
| 1483 | const max_val = min_val -% 1; | |
| 1484 | 1484 | assert(max_val == @max_value(i32)); |
| 1485 | 1485 | } |
| 1486 | 1486 | #static_eval_enable(false) |
| 1487 | fn test_signed_wrapping_noeval(x: i32w) { | |
| 1488 | const min_val = x + 1; | |
| 1487 | fn test_signed_wrapping_noeval(x: i32) { | |
| 1488 | const min_val = x +% 1; | |
| 1489 | 1489 | assert(min_val == @min_value(i32)); |
| 1490 | const max_val = min_val - 1; | |
| 1490 | const max_val = min_val -% 1; | |
| 1491 | 1491 | assert(max_val == @max_value(i32)); |
| 1492 | 1492 | } |
| 1493 | 1493 | |
| ... | ... | @@ -1496,15 +1496,15 @@ fn negation_wrapping() { |
| 1496 | 1496 | test_negation_wrapping_eval(@min_value(i16)); |
| 1497 | 1497 | test_negation_wrapping_noeval(@min_value(i16)); |
| 1498 | 1498 | } |
| 1499 | fn test_negation_wrapping_eval(x: i16w) { | |
| 1499 | fn test_negation_wrapping_eval(x: i16) { | |
| 1500 | 1500 | assert(x == -32768); |
| 1501 | const neg = -x; | |
| 1501 | const neg = -%x; | |
| 1502 | 1502 | assert(neg == -32768); |
| 1503 | 1503 | } |
| 1504 | 1504 | #static_eval_enable(false) |
| 1505 | fn test_negation_wrapping_noeval(x: i16w) { | |
| 1505 | fn test_negation_wrapping_noeval(x: i16) { | |
| 1506 | 1506 | assert(x == -32768); |
| 1507 | const neg = -x; | |
| 1507 | const neg = -%x; | |
| 1508 | 1508 | assert(neg == -32768); |
| 1509 | 1509 | } |
| 1510 | 1510 | |
| ... | ... | @@ -1513,13 +1513,13 @@ fn shl_wrapping() { |
| 1513 | 1513 | test_shl_wrapping_eval(@max_value(u16)); |
| 1514 | 1514 | test_shl_wrapping_noeval(@max_value(u16)); |
| 1515 | 1515 | } |
| 1516 | fn test_shl_wrapping_eval(x: u16w) { | |
| 1517 | const shifted = x << 1; | |
| 1516 | fn test_shl_wrapping_eval(x: u16) { | |
| 1517 | const shifted = x <<% 1; | |
| 1518 | 1518 | assert(shifted == 65534); |
| 1519 | 1519 | } |
| 1520 | 1520 | #static_eval_enable(false) |
| 1521 | fn test_shl_wrapping_noeval(x: u16w) { | |
| 1522 | const shifted = x << 1; | |
| 1521 | fn test_shl_wrapping_noeval(x: u16) { | |
| 1522 | const shifted = x <<% 1; | |
| 1523 | 1523 | assert(shifted == 65534); |
| 1524 | 1524 | } |
| 1525 | 1525 | |
| ... | ... | @@ -1531,23 +1531,6 @@ fn shl_with_overflow() { |
| 1531 | 1531 | assert(result == 0b1011111111111100); |
| 1532 | 1532 | } |
| 1533 | 1533 | |
| 1534 | #attribute("test") | |
| 1535 | fn combine_non_wrap_with_wrap() { | |
| 1536 | const x: i32 = 123; | |
| 1537 | const y: i32w = 456; | |
| 1538 | const z = x + y; | |
| 1539 | const z2 = y + x; | |
| 1540 | assert(@typeof(z) == i32w); | |
| 1541 | assert(@typeof(z2) == i32w); | |
| 1542 | ||
| 1543 | const a: i8 = 123; | |
| 1544 | const b: i32w = 456; | |
| 1545 | const c = b + a; | |
| 1546 | const d = a + b; | |
| 1547 | assert(@typeof(c) == i32w); | |
| 1548 | assert(@typeof(d) == i32w); | |
| 1549 | } | |
| 1550 | ||
| 1551 | 1534 | #attribute("test") |
| 1552 | 1535 | fn c_string_concatenation() { |
| 1553 | 1536 | const a = c"OK" ++ c" IT " ++ c"WORKED"; |
| ... | ... | @@ -1687,41 +1670,21 @@ struct DivResult { |
| 1687 | 1670 | |
| 1688 | 1671 | #attribute("test") |
| 1689 | 1672 | fn int_type_builtin() { |
| 1690 | assert(@int_type(true, 8, false) == i8); | |
| 1691 | assert(@int_type(true, 16, false) == i16); | |
| 1692 | assert(@int_type(true, 32, false) == i32); | |
| 1693 | assert(@int_type(true, 64, false) == i64); | |
| 1694 | ||
| 1695 | assert(@int_type(false, 8, false) == u8); | |
| 1696 | assert(@int_type(false, 16, false) == u16); | |
| 1697 | assert(@int_type(false, 32, false) == u32); | |
| 1698 | assert(@int_type(false, 64, false) == u64); | |
| 1699 | ||
| 1700 | assert(@int_type(true, 8, true) == i8w); | |
| 1701 | assert(@int_type(true, 16, true) == i16w); | |
| 1702 | assert(@int_type(true, 32, true) == i32w); | |
| 1703 | assert(@int_type(true, 64, true) == i64w); | |
| 1704 | ||
| 1705 | assert(@int_type(false, 8, true) == u8w); | |
| 1706 | assert(@int_type(false, 16, true) == u16w); | |
| 1707 | assert(@int_type(false, 32, true) == u32w); | |
| 1708 | assert(@int_type(false, 64, true) == u64w); | |
| 1673 | assert(@int_type(true, 8) == i8); | |
| 1674 | assert(@int_type(true, 16) == i16); | |
| 1675 | assert(@int_type(true, 32) == i32); | |
| 1676 | assert(@int_type(true, 64) == i64); | |
| 1677 | ||
| 1678 | assert(@int_type(false, 8) == u8); | |
| 1679 | assert(@int_type(false, 16) == u16); | |
| 1680 | assert(@int_type(false, 32) == u32); | |
| 1681 | assert(@int_type(false, 64) == u64); | |
| 1709 | 1682 | |
| 1710 | 1683 | assert(i8.bit_count == 8); |
| 1711 | 1684 | assert(i16.bit_count == 16); |
| 1712 | 1685 | assert(i32.bit_count == 32); |
| 1713 | 1686 | assert(i64.bit_count == 64); |
| 1714 | 1687 | |
| 1715 | assert(!i8.is_wrapping); | |
| 1716 | assert(!i16.is_wrapping); | |
| 1717 | assert(!i32.is_wrapping); | |
| 1718 | assert(!i64.is_wrapping); | |
| 1719 | ||
| 1720 | assert(i8w.is_wrapping); | |
| 1721 | assert(i16w.is_wrapping); | |
| 1722 | assert(i32w.is_wrapping); | |
| 1723 | assert(i64w.is_wrapping); | |
| 1724 | ||
| 1725 | 1688 | assert(i8.is_signed); |
| 1726 | 1689 | assert(i16.is_signed); |
| 1727 | 1690 | assert(i32.is_signed); |