| author | |
| committer | |
| log | 579856e502eab87ea8a73a76dc63a2108e5a8cc8 |
| tree | feb34b0985b29f45073ac81e21982a368e0a3542 |
| parent | 5a479720ec5786145dac6c85deae4e322bd5972e |
| parent | fcedc35551cc6b14756499414e47c33004de3be4 |
15 files changed, 1693 insertions(+), 469 deletions(-)
CMakeLists.txt+1| ... | @@ -41,6 +41,7 @@ set(ZIG_SOURCES | ... | @@ -41,6 +41,7 @@ set(ZIG_SOURCES |
| 41 | "${CMAKE_SOURCE_DIR}/src/bignum.cpp" | 41 | "${CMAKE_SOURCE_DIR}/src/bignum.cpp" |
| 42 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" | 42 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" |
| 43 | "${CMAKE_SOURCE_DIR}/src/parser.cpp" | 43 | "${CMAKE_SOURCE_DIR}/src/parser.cpp" |
| 44 | "${CMAKE_SOURCE_DIR}/src/eval.cpp" | ||
| 44 | "${CMAKE_SOURCE_DIR}/src/analyze.cpp" | 45 | "${CMAKE_SOURCE_DIR}/src/analyze.cpp" |
| 45 | "${CMAKE_SOURCE_DIR}/src/codegen.cpp" | 46 | "${CMAKE_SOURCE_DIR}/src/codegen.cpp" |
| 46 | "${CMAKE_SOURCE_DIR}/src/buffer.cpp" | 47 | "${CMAKE_SOURCE_DIR}/src/buffer.cpp" |
src/all_types.hpp+38-1| ... | @@ -496,8 +496,8 @@ struct AstNodeWhileExpr { | ... | @@ -496,8 +496,8 @@ struct AstNodeWhileExpr { |
| 496 | }; | 496 | }; |
| 497 | 497 | ||
| 498 | struct AstNodeForExpr { | 498 | struct AstNodeForExpr { |
| 499 | AstNode *elem_node; // always a symbol | ||
| 500 | AstNode *array_expr; | 499 | AstNode *array_expr; |
| 500 | AstNode *elem_node; // always a symbol | ||
| 501 | AstNode *index_node; // always a symbol, might be null | 501 | AstNode *index_node; // always a symbol, might be null |
| 502 | AstNode *body; | 502 | AstNode *body; |
| 503 | 503 | ||
| ... | @@ -960,6 +960,7 @@ struct TypeTableEntry { | ... | @@ -960,6 +960,7 @@ struct TypeTableEntry { |
| 960 | LLVMZigDIType *di_type; | 960 | LLVMZigDIType *di_type; |
| 961 | 961 | ||
| 962 | bool zero_bits; | 962 | bool zero_bits; |
| 963 | bool deep_const; | ||
| 963 | 964 | ||
| 964 | union { | 965 | union { |
| 965 | TypeTableEntryPointer pointer; | 966 | TypeTableEntryPointer pointer; |
| ... | @@ -1005,6 +1006,13 @@ struct ImportTableEntry { | ... | @@ -1005,6 +1006,13 @@ struct ImportTableEntry { |
| 1005 | ZigList<AstNode *> use_decls; | 1006 | ZigList<AstNode *> use_decls; |
| 1006 | }; | 1007 | }; |
| 1007 | 1008 | ||
| 1009 | enum FnAnalState { | ||
| 1010 | FnAnalStateReady, | ||
| 1011 | FnAnalStateProbing, | ||
| 1012 | FnAnalStateComplete, | ||
| 1013 | FnAnalStateSkipped, | ||
| 1014 | }; | ||
| 1015 | |||
| 1008 | struct FnTableEntry { | 1016 | struct FnTableEntry { |
| 1009 | LLVMValueRef fn_value; | 1017 | LLVMValueRef fn_value; |
| 1010 | AstNode *proto_node; | 1018 | AstNode *proto_node; |
| ... | @@ -1019,7 +1027,9 @@ struct FnTableEntry { | ... | @@ -1019,7 +1027,9 @@ struct FnTableEntry { |
| 1019 | bool internal_linkage; | 1027 | bool internal_linkage; |
| 1020 | bool is_extern; | 1028 | bool is_extern; |
| 1021 | bool is_test; | 1029 | bool is_test; |
| 1030 | bool is_pure; | ||
| 1022 | BlockContext *parent_block_context; | 1031 | BlockContext *parent_block_context; |
| 1032 | FnAnalState anal_state; | ||
| 1023 | 1033 | ||
| 1024 | ZigList<AstNode *> cast_alloca_list; | 1034 | ZigList<AstNode *> cast_alloca_list; |
| 1025 | ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list; | 1035 | ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list; |
| ... | @@ -1027,6 +1037,33 @@ struct FnTableEntry { | ... | @@ -1027,6 +1037,33 @@ struct FnTableEntry { |
| 1027 | ZigList<AstNode *> goto_list; | 1037 | ZigList<AstNode *> goto_list; |
| 1028 | }; | 1038 | }; |
| 1029 | 1039 | ||
| 1040 | struct EvalVar { | ||
| 1041 | Buf *name; | ||
| 1042 | ConstExprValue value; | ||
| 1043 | }; | ||
| 1044 | |||
| 1045 | struct EvalScope { | ||
| 1046 | BlockContext *block_context; | ||
| 1047 | ZigList<EvalVar> vars; | ||
| 1048 | }; | ||
| 1049 | |||
| 1050 | struct EvalFnRoot { | ||
| 1051 | CodeGen *codegen; | ||
| 1052 | FnTableEntry *fn; | ||
| 1053 | AstNode *call_node; | ||
| 1054 | int branch_quota; | ||
| 1055 | int branches_used; | ||
| 1056 | AstNode *exceeded_quota_node; | ||
| 1057 | bool abort; | ||
| 1058 | }; | ||
| 1059 | |||
| 1060 | struct EvalFn { | ||
| 1061 | EvalFnRoot *root; | ||
| 1062 | FnTableEntry *fn; | ||
| 1063 | ConstExprValue *return_expr; | ||
| 1064 | ZigList<EvalScope*> scope_stack; | ||
| 1065 | }; | ||
| 1066 | |||
| 1030 | enum BuiltinFnId { | 1067 | enum BuiltinFnId { |
| 1031 | BuiltinFnIdInvalid, | 1068 | BuiltinFnIdInvalid, |
| 1032 | BuiltinFnIdMemcpy, | 1069 | BuiltinFnIdMemcpy, |
src/analyze.cpp+176-321| ... | @@ -13,6 +13,7 @@ | ... | @@ -13,6 +13,7 @@ |
| 13 | #include "parseh.hpp" | 13 | #include "parseh.hpp" |
| 14 | #include "config.h" | 14 | #include "config.h" |
| 15 | #include "ast_render.hpp" | 15 | #include "ast_render.hpp" |
| 16 | #include "eval.hpp" | ||
| 16 | 17 | ||
| 17 | static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 18 | static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 18 | TypeTableEntry *expected_type, AstNode *node); | 19 | TypeTableEntry *expected_type, AstNode *node); |
| ... | @@ -34,7 +35,8 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, | ... | @@ -34,7 +35,8 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, |
| 34 | static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node, | 35 | static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node, |
| 35 | TypeTableEntry *expected_type, uint64_t x); | 36 | TypeTableEntry *expected_type, uint64_t x); |
| 36 | static AstNode *find_decl(BlockContext *context, Buf *name); | 37 | static AstNode *find_decl(BlockContext *context, Buf *name); |
| 37 | static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node, bool pointer_only); | 38 | static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node, |
| 39 | bool pointer_only, BlockContext *block_context); | ||
| 38 | static TopLevelDecl *get_as_top_level_decl(AstNode *node); | 40 | static TopLevelDecl *get_as_top_level_decl(AstNode *node); |
| 39 | static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import, | 41 | static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import, |
| 40 | BlockContext *context, AstNode *source_node, | 42 | BlockContext *context, AstNode *source_node, |
| ... | @@ -206,6 +208,7 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { | ... | @@ -206,6 +208,7 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { |
| 206 | static TypeTableEntry *get_generic_fn_type(CodeGen *g, AstNode *decl_node) { | 208 | static TypeTableEntry *get_generic_fn_type(CodeGen *g, AstNode *decl_node) { |
| 207 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdGenericFn); | 209 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdGenericFn); |
| 208 | buf_init_from_str(&entry->name, "(generic function)"); | 210 | buf_init_from_str(&entry->name, "(generic function)"); |
| 211 | entry->deep_const = true; | ||
| 209 | entry->zero_bits = true; | 212 | entry->zero_bits = true; |
| 210 | entry->data.generic_fn.decl_node = decl_node; | 213 | entry->data.generic_fn.decl_node = decl_node; |
| 211 | return entry; | 214 | return entry; |
| ... | @@ -219,6 +222,8 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool | ... | @@ -219,6 +222,8 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool |
| 219 | } else { | 222 | } else { |
| 220 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer); | 223 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer); |
| 221 | 224 | ||
| 225 | entry->deep_const = is_const && child_type->deep_const; | ||
| 226 | |||
| 222 | const char *const_str = is_const ? "const " : ""; | 227 | const char *const_str = is_const ? "const " : ""; |
| 223 | buf_resize(&entry->name, 0); | 228 | buf_resize(&entry->name, 0); |
| 224 | buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name)); | 229 | buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name)); |
| ... | @@ -260,6 +265,8 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) { | ... | @@ -260,6 +265,8 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) { |
| 260 | assert(child_type->type_ref); | 265 | assert(child_type->type_ref); |
| 261 | assert(child_type->di_type); | 266 | assert(child_type->di_type); |
| 262 | 267 | ||
| 268 | entry->deep_const = child_type->deep_const; | ||
| 269 | |||
| 263 | buf_resize(&entry->name, 0); | 270 | buf_resize(&entry->name, 0); |
| 264 | buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name)); | 271 | buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name)); |
| 265 | 272 | ||
| ... | @@ -343,6 +350,8 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { | ... | @@ -343,6 +350,8 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { |
| 343 | 350 | ||
| 344 | entry->data.error.child_type = child_type; | 351 | entry->data.error.child_type = child_type; |
| 345 | 352 | ||
| 353 | entry->deep_const = child_type->deep_const; | ||
| 354 | |||
| 346 | if (!type_has_bits(child_type)) { | 355 | if (!type_has_bits(child_type)) { |
| 347 | entry->type_ref = g->err_tag_type->type_ref; | 356 | entry->type_ref = g->err_tag_type->type_ref; |
| 348 | entry->di_type = g->err_tag_type->di_type; | 357 | entry->di_type = g->err_tag_type->di_type; |
| ... | @@ -414,6 +423,7 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t | ... | @@ -414,6 +423,7 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t |
| 414 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray); | 423 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray); |
| 415 | entry->type_ref = LLVMArrayType(child_type->type_ref, array_size); | 424 | entry->type_ref = LLVMArrayType(child_type->type_ref, array_size); |
| 416 | entry->zero_bits = (array_size == 0) || child_type->zero_bits; | 425 | entry->zero_bits = (array_size == 0) || child_type->zero_bits; |
| 426 | entry->deep_const = child_type->deep_const; | ||
| 417 | 427 | ||
| 418 | buf_resize(&entry->name, 0); | 428 | buf_resize(&entry->name, 0); |
| 419 | buf_appendf(&entry->name, "[%" PRIu64 "]%s", array_size, buf_ptr(&child_type->name)); | 429 | buf_appendf(&entry->name, "[%" PRIu64 "]%s", array_size, buf_ptr(&child_type->name)); |
| ... | @@ -464,6 +474,8 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c | ... | @@ -464,6 +474,8 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c |
| 464 | TypeTableEntry *var_peer = get_slice_type(g, child_type, false); | 474 | TypeTableEntry *var_peer = get_slice_type(g, child_type, false); |
| 465 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); | 475 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); |
| 466 | 476 | ||
| 477 | entry->deep_const = child_type->deep_const; | ||
| 478 | |||
| 467 | buf_resize(&entry->name, 0); | 479 | buf_resize(&entry->name, 0); |
| 468 | buf_appendf(&entry->name, "[]const %s", buf_ptr(&child_type->name)); | 480 | buf_appendf(&entry->name, "[]const %s", buf_ptr(&child_type->name)); |
| 469 | 481 | ||
| ... | @@ -549,6 +561,7 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry * | ... | @@ -549,6 +561,7 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry * |
| 549 | 561 | ||
| 550 | buf_init_from_str(&entry->name, name); | 562 | buf_init_from_str(&entry->name, name); |
| 551 | 563 | ||
| 564 | entry->deep_const = child_type->deep_const; | ||
| 552 | entry->type_ref = child_type->type_ref; | 565 | entry->type_ref = child_type->type_ref; |
| 553 | entry->di_type = child_type->di_type; | 566 | entry->di_type = child_type->di_type; |
| 554 | entry->zero_bits = child_type->zero_bits; | 567 | entry->zero_bits = child_type->zero_bits; |
| ... | @@ -572,6 +585,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { | ... | @@ -572,6 +585,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 572 | } | 585 | } |
| 573 | 586 | ||
| 574 | TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn); | 587 | TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn); |
| 588 | fn_type->deep_const = true; | ||
| 575 | fn_type->data.fn.fn_type_id = *fn_type_id; | 589 | fn_type->data.fn.fn_type_id = *fn_type_id; |
| 576 | if (fn_type_id->param_info == &fn_type_id->prealloc_param_info[0]) { | 590 | if (fn_type_id->param_info == &fn_type_id->prealloc_param_info[0]) { |
| 577 | fn_type->data.fn.fn_type_id.param_info = &fn_type->data.fn.fn_type_id.prealloc_param_info[0]; | 591 | fn_type->data.fn.fn_type_id.param_info = &fn_type->data.fn.fn_type_id.prealloc_param_info[0]; |
| ... | @@ -944,6 +958,19 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t | ... | @@ -944,6 +958,19 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 944 | add_node_error(g, directive_node, | 958 | add_node_error(g, directive_node, |
| 945 | buf_sprintf("#condition valid only on exported symbols")); | 959 | buf_sprintf("#condition valid only on exported symbols")); |
| 946 | } | 960 | } |
| 961 | } else if (buf_eql_str(name, "static_eval_enable")) { | ||
| 962 | if (fn_table_entry->is_extern) { | ||
| 963 | add_node_error(g, directive_node, | ||
| 964 | buf_sprintf("#static_val_enable invalid on extern functions")); | ||
| 965 | } else { | ||
| 966 | bool enable; | ||
| 967 | bool ok = resolve_const_expr_bool(g, import, import->block_context, | ||
| 968 | &directive_node->data.directive.expr, &enable); | ||
| 969 | if (!enable || !ok) { | ||
| 970 | fn_table_entry->is_pure = false; | ||
| 971 | } | ||
| 972 | // TODO cause compile error if enable is true and impure fn | ||
| 973 | } | ||
| 947 | } else { | 974 | } else { |
| 948 | add_node_error(g, directive_node, | 975 | add_node_error(g, directive_node, |
| 949 | buf_sprintf("invalid directive: '%s'", buf_ptr(name))); | 976 | buf_sprintf("invalid directive: '%s'", buf_ptr(name))); |
| ... | @@ -1037,6 +1064,8 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt | ... | @@ -1037,6 +1064,8 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt |
| 1037 | 1064 | ||
| 1038 | assert(enum_type->di_type); | 1065 | assert(enum_type->di_type); |
| 1039 | 1066 | ||
| 1067 | enum_type->deep_const = true; | ||
| 1068 | |||
| 1040 | uint32_t field_count = decl_node->data.struct_decl.fields.length; | 1069 | uint32_t field_count = decl_node->data.struct_decl.fields.length; |
| 1041 | 1070 | ||
| 1042 | enum_type->data.enumeration.field_count = field_count; | 1071 | enum_type->data.enumeration.field_count = field_count; |
| ... | @@ -1064,6 +1093,10 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt | ... | @@ -1064,6 +1093,10 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt |
| 1064 | type_enum_field->type_entry = field_type; | 1093 | type_enum_field->type_entry = field_type; |
| 1065 | type_enum_field->value = i; | 1094 | type_enum_field->value = i; |
| 1066 | 1095 | ||
| 1096 | if (!field_type->deep_const) { | ||
| 1097 | enum_type->deep_const = false; | ||
| 1098 | } | ||
| 1099 | |||
| 1067 | 1100 | ||
| 1068 | di_enumerators[i] = LLVMZigCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i); | 1101 | di_enumerators[i] = LLVMZigCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i); |
| 1069 | 1102 | ||
| ... | @@ -1224,6 +1257,8 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE | ... | @@ -1224,6 +1257,8 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE |
| 1224 | 1257 | ||
| 1225 | assert(struct_type->di_type); | 1258 | assert(struct_type->di_type); |
| 1226 | 1259 | ||
| 1260 | struct_type->deep_const = true; | ||
| 1261 | |||
| 1227 | int field_count = decl_node->data.struct_decl.fields.length; | 1262 | int field_count = decl_node->data.struct_decl.fields.length; |
| 1228 | 1263 | ||
| 1229 | struct_type->data.structure.src_field_count = field_count; | 1264 | struct_type->data.structure.src_field_count = field_count; |
| ... | @@ -1247,6 +1282,10 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE | ... | @@ -1247,6 +1282,10 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE |
| 1247 | type_struct_field->src_index = i; | 1282 | type_struct_field->src_index = i; |
| 1248 | type_struct_field->gen_index = -1; | 1283 | type_struct_field->gen_index = -1; |
| 1249 | 1284 | ||
| 1285 | if (!field_type->deep_const) { | ||
| 1286 | struct_type->deep_const = false; | ||
| 1287 | } | ||
| 1288 | |||
| 1250 | if (field_type->id == TypeTableEntryIdStruct) { | 1289 | if (field_type->id == TypeTableEntryIdStruct) { |
| 1251 | resolve_struct_type(g, import, field_type); | 1290 | resolve_struct_type(g, import, field_type); |
| 1252 | } else if (field_type->id == TypeTableEntryIdEnum) { | 1291 | } else if (field_type->id == TypeTableEntryIdEnum) { |
| ... | @@ -1374,6 +1413,7 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN | ... | @@ -1374,6 +1413,7 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN |
| 1374 | fn_table_entry->proto_node = proto_node; | 1413 | fn_table_entry->proto_node = proto_node; |
| 1375 | fn_table_entry->fn_def_node = fn_def_node; | 1414 | fn_table_entry->fn_def_node = fn_def_node; |
| 1376 | fn_table_entry->is_extern = is_extern; | 1415 | fn_table_entry->is_extern = is_extern; |
| 1416 | fn_table_entry->is_pure = !is_extern; | ||
| 1377 | 1417 | ||
| 1378 | get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_'); | 1418 | get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_'); |
| 1379 | 1419 | ||
| ... | @@ -2201,9 +2241,9 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry | ... | @@ -2201,9 +2241,9 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry |
| 2201 | const_val->ok = false; | 2241 | const_val->ok = false; |
| 2202 | } | 2242 | } |
| 2203 | } | 2243 | } |
| 2204 | if (!const_val->ok) { | 2244 | } |
| 2205 | context->fn_entry->struct_val_expr_alloca_list.append(codegen); | 2245 | if (!const_val->ok) { |
| 2206 | } | 2246 | context->fn_entry->struct_val_expr_alloca_list.append(codegen); |
| 2207 | } | 2247 | } |
| 2208 | 2248 | ||
| 2209 | for (int i = 0; i < actual_field_count; i += 1) { | 2249 | for (int i = 0; i < actual_field_count; i += 1) { |
| ... | @@ -2355,7 +2395,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -2355,7 +2395,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 2355 | AstNode *decl_node = entry ? entry->value : nullptr; | 2395 | AstNode *decl_node = entry ? entry->value : nullptr; |
| 2356 | if (decl_node) { | 2396 | if (decl_node) { |
| 2357 | bool pointer_only = false; | 2397 | bool pointer_only = false; |
| 2358 | return analyze_decl_ref(g, node, decl_node, pointer_only); | 2398 | return analyze_decl_ref(g, node, decl_node, pointer_only, context); |
| 2359 | } else { | 2399 | } else { |
| 2360 | add_node_error(g, node, | 2400 | add_node_error(g, node, |
| 2361 | buf_sprintf("container '%s' has no member called '%s'", | 2401 | buf_sprintf("container '%s' has no member called '%s'", |
| ... | @@ -2382,7 +2422,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -2382,7 +2422,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 2382 | add_error_note(g, msg, decl_node, buf_sprintf("declared here")); | 2422 | add_error_note(g, msg, decl_node, buf_sprintf("declared here")); |
| 2383 | } | 2423 | } |
| 2384 | bool pointer_only = false; | 2424 | bool pointer_only = false; |
| 2385 | return analyze_decl_ref(g, node, decl_node, pointer_only); | 2425 | return analyze_decl_ref(g, node, decl_node, pointer_only, context); |
| 2386 | } else { | 2426 | } else { |
| 2387 | const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)"; | 2427 | const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)"; |
| 2388 | add_node_error(g, node, | 2428 | add_node_error(g, node, |
| ... | @@ -2443,6 +2483,12 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -2443,6 +2483,12 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, |
| 2443 | return return_type; | 2483 | return return_type; |
| 2444 | } | 2484 | } |
| 2445 | 2485 | ||
| 2486 | static void mark_impure_fn(BlockContext *context) { | ||
| 2487 | if (context->fn_entry) { | ||
| 2488 | context->fn_entry->is_pure = false; | ||
| 2489 | } | ||
| 2490 | } | ||
| 2491 | |||
| 2446 | static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2492 | static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2447 | AstNode *node) | 2493 | AstNode *node) |
| 2448 | { | 2494 | { |
| ... | @@ -2607,26 +2653,6 @@ static TypeTableEntry *resolve_expr_const_val_as_float_num_lit(CodeGen *g, AstNo | ... | @@ -2607,26 +2653,6 @@ static TypeTableEntry *resolve_expr_const_val_as_float_num_lit(CodeGen *g, AstNo |
| 2607 | return g->builtin_types.entry_num_lit_float; | 2653 | return g->builtin_types.entry_num_lit_float; |
| 2608 | } | 2654 | } |
| 2609 | 2655 | ||
| 2610 | static TypeTableEntry *resolve_expr_const_val_as_bignum_op(CodeGen *g, AstNode *node, | ||
| 2611 | bool (*bignum_fn)(BigNum *, BigNum *, BigNum *), AstNode *op1, AstNode *op2, | ||
| 2612 | TypeTableEntry *resolved_type) | ||
| 2613 | { | ||
| 2614 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; | ||
| 2615 | ConstExprValue *op1_val = &get_resolved_expr(op1)->const_val; | ||
| 2616 | ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val; | ||
| 2617 | |||
| 2618 | const_val->ok = true; | ||
| 2619 | |||
| 2620 | if (bignum_fn(&const_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum)) { | ||
| 2621 | add_node_error(g, node, | ||
| 2622 | buf_sprintf("value cannot be represented in any integer type")); | ||
| 2623 | } else { | ||
| 2624 | num_lit_fits_in_other_type(g, node, resolved_type); | ||
| 2625 | } | ||
| 2626 | |||
| 2627 | return resolved_type; | ||
| 2628 | } | ||
| 2629 | |||
| 2630 | static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import, | 2656 | static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import, |
| 2631 | BlockContext *context, AstNode *node, Buf *err_name) | 2657 | BlockContext *context, AstNode *node, Buf *err_name) |
| 2632 | { | 2658 | { |
| ... | @@ -2642,8 +2668,21 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry * | ... | @@ -2642,8 +2668,21 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry * |
| 2642 | return g->builtin_types.entry_invalid; | 2668 | return g->builtin_types.entry_invalid; |
| 2643 | } | 2669 | } |
| 2644 | 2670 | ||
| 2645 | static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var) { | 2671 | static bool var_is_pure(VariableTableEntry *var, BlockContext *context) { |
| 2672 | if (var->block_context->fn_entry == context->fn_entry) { | ||
| 2673 | // variable was declared in the current function, so it's OK. | ||
| 2674 | return true; | ||
| 2675 | } | ||
| 2676 | return var->is_const && var->type->deep_const; | ||
| 2677 | } | ||
| 2678 | |||
| 2679 | static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var, | ||
| 2680 | BlockContext *context) | ||
| 2681 | { | ||
| 2646 | get_resolved_expr(source_node)->variable = var; | 2682 | get_resolved_expr(source_node)->variable = var; |
| 2683 | if (!var_is_pure(var, context)) { | ||
| 2684 | mark_impure_fn(context); | ||
| 2685 | } | ||
| 2647 | if (var->is_const && var->val_node) { | 2686 | if (var->is_const && var->val_node) { |
| 2648 | ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val; | 2687 | ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val; |
| 2649 | if (other_const_val->ok) { | 2688 | if (other_const_val->ok) { |
| ... | @@ -2654,7 +2693,7 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl | ... | @@ -2654,7 +2693,7 @@ static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, Variabl |
| 2654 | } | 2693 | } |
| 2655 | 2694 | ||
| 2656 | static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node, | 2695 | static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node, |
| 2657 | bool pointer_only) | 2696 | bool pointer_only, BlockContext *block_context) |
| 2658 | { | 2697 | { |
| 2659 | resolve_top_level_decl(g, decl_node, pointer_only); | 2698 | resolve_top_level_decl(g, decl_node, pointer_only); |
| 2660 | TopLevelDecl *tld = get_as_top_level_decl(decl_node); | 2699 | TopLevelDecl *tld = get_as_top_level_decl(decl_node); |
| ... | @@ -2664,7 +2703,7 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod | ... | @@ -2664,7 +2703,7 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod |
| 2664 | 2703 | ||
| 2665 | if (decl_node->type == NodeTypeVariableDeclaration) { | 2704 | if (decl_node->type == NodeTypeVariableDeclaration) { |
| 2666 | VariableTableEntry *var = decl_node->data.variable_declaration.variable; | 2705 | VariableTableEntry *var = decl_node->data.variable_declaration.variable; |
| 2667 | return analyze_var_ref(g, source_node, var); | 2706 | return analyze_var_ref(g, source_node, var, block_context); |
| 2668 | } else if (decl_node->type == NodeTypeFnProto) { | 2707 | } else if (decl_node->type == NodeTypeFnProto) { |
| 2669 | if (decl_node->data.fn_proto.generic_params.length > 0) { | 2708 | if (decl_node->data.fn_proto.generic_params.length > 0) { |
| 2670 | TypeTableEntry *type_entry = decl_node->data.fn_proto.generic_fn_type; | 2709 | TypeTableEntry *type_entry = decl_node->data.fn_proto.generic_fn_type; |
| ... | @@ -2700,12 +2739,13 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -2700,12 +2739,13 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, |
| 2700 | 2739 | ||
| 2701 | VariableTableEntry *var = find_variable(g, context, variable_name); | 2740 | VariableTableEntry *var = find_variable(g, context, variable_name); |
| 2702 | if (var) { | 2741 | if (var) { |
| 2703 | return analyze_var_ref(g, node, var); | 2742 | TypeTableEntry *var_type = analyze_var_ref(g, node, var, context); |
| 2743 | return var_type; | ||
| 2704 | } | 2744 | } |
| 2705 | 2745 | ||
| 2706 | AstNode *decl_node = find_decl(context, variable_name); | 2746 | AstNode *decl_node = find_decl(context, variable_name); |
| 2707 | if (decl_node) { | 2747 | if (decl_node) { |
| 2708 | return analyze_decl_ref(g, node, decl_node, pointer_only); | 2748 | return analyze_decl_ref(g, node, decl_node, pointer_only, context); |
| 2709 | } | 2749 | } |
| 2710 | 2750 | ||
| 2711 | if (import->any_imports_failed) { | 2751 | if (import->any_imports_failed) { |
| ... | @@ -2840,71 +2880,6 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc | ... | @@ -2840,71 +2880,6 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc |
| 2840 | return expected_rhs_type; | 2880 | return expected_rhs_type; |
| 2841 | } | 2881 | } |
| 2842 | 2882 | ||
| 2843 | static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) { | ||
| 2844 | if (bin_op == BinOpTypeBoolOr) { | ||
| 2845 | return a || b; | ||
| 2846 | } else if (bin_op == BinOpTypeBoolAnd) { | ||
| 2847 | return a && b; | ||
| 2848 | } else { | ||
| 2849 | zig_unreachable(); | ||
| 2850 | } | ||
| 2851 | } | ||
| 2852 | |||
| 2853 | static bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) { | ||
| 2854 | switch (type_entry->id) { | ||
| 2855 | case TypeTableEntryIdEnum: | ||
| 2856 | { | ||
| 2857 | ConstEnumValue *enum1 = &a->data.x_enum; | ||
| 2858 | ConstEnumValue *enum2 = &b->data.x_enum; | ||
| 2859 | if (enum1->tag == enum2->tag) { | ||
| 2860 | TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum1->tag]; | ||
| 2861 | if (type_has_bits(enum_field->type_entry)) { | ||
| 2862 | zig_panic("TODO const expr analyze enum special value for equality"); | ||
| 2863 | } else { | ||
| 2864 | return true; | ||
| 2865 | } | ||
| 2866 | } | ||
| 2867 | return false; | ||
| 2868 | } | ||
| 2869 | case TypeTableEntryIdMetaType: | ||
| 2870 | return a->data.x_type == b->data.x_type; | ||
| 2871 | case TypeTableEntryIdVoid: | ||
| 2872 | return true; | ||
| 2873 | case TypeTableEntryIdPureError: | ||
| 2874 | return a->data.x_err.err == b->data.x_err.err; | ||
| 2875 | case TypeTableEntryIdFn: | ||
| 2876 | return a->data.x_fn == b->data.x_fn; | ||
| 2877 | case TypeTableEntryIdBool: | ||
| 2878 | return a->data.x_bool == b->data.x_bool; | ||
| 2879 | case TypeTableEntryIdInt: | ||
| 2880 | case TypeTableEntryIdFloat: | ||
| 2881 | case TypeTableEntryIdNumLitFloat: | ||
| 2882 | case TypeTableEntryIdNumLitInt: | ||
| 2883 | return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum); | ||
| 2884 | case TypeTableEntryIdPointer: | ||
| 2885 | zig_panic("TODO"); | ||
| 2886 | case TypeTableEntryIdArray: | ||
| 2887 | zig_panic("TODO"); | ||
| 2888 | case TypeTableEntryIdStruct: | ||
| 2889 | zig_panic("TODO"); | ||
| 2890 | case TypeTableEntryIdUndefLit: | ||
| 2891 | zig_panic("TODO"); | ||
| 2892 | case TypeTableEntryIdMaybe: | ||
| 2893 | zig_panic("TODO"); | ||
| 2894 | case TypeTableEntryIdErrorUnion: | ||
| 2895 | zig_panic("TODO"); | ||
| 2896 | case TypeTableEntryIdTypeDecl: | ||
| 2897 | zig_panic("TODO"); | ||
| 2898 | case TypeTableEntryIdNamespace: | ||
| 2899 | zig_panic("TODO"); | ||
| 2900 | case TypeTableEntryIdGenericFn: | ||
| 2901 | case TypeTableEntryIdInvalid: | ||
| 2902 | case TypeTableEntryIdUnreachable: | ||
| 2903 | zig_unreachable(); | ||
| 2904 | } | ||
| 2905 | zig_unreachable(); | ||
| 2906 | } | ||
| 2907 | |||
| 2908 | static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2883 | static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2909 | AstNode *node) | 2884 | AstNode *node) |
| 2910 | { | 2885 | { |
| ... | @@ -2944,39 +2919,11 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im | ... | @@ -2944,39 +2919,11 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im |
| 2944 | return g->builtin_types.entry_bool; | 2919 | return g->builtin_types.entry_bool; |
| 2945 | } | 2920 | } |
| 2946 | 2921 | ||
| 2947 | bool answer; | ||
| 2948 | if (type_can_gt_lt_cmp) { | ||
| 2949 | bool (*bignum_cmp)(BigNum *, BigNum *); | ||
| 2950 | if (bin_op_type == BinOpTypeCmpEq) { | ||
| 2951 | bignum_cmp = bignum_cmp_eq; | ||
| 2952 | } else if (bin_op_type == BinOpTypeCmpNotEq) { | ||
| 2953 | bignum_cmp = bignum_cmp_neq; | ||
| 2954 | } else if (bin_op_type == BinOpTypeCmpLessThan) { | ||
| 2955 | bignum_cmp = bignum_cmp_lt; | ||
| 2956 | } else if (bin_op_type == BinOpTypeCmpGreaterThan) { | ||
| 2957 | bignum_cmp = bignum_cmp_gt; | ||
| 2958 | } else if (bin_op_type == BinOpTypeCmpLessOrEq) { | ||
| 2959 | bignum_cmp = bignum_cmp_lte; | ||
| 2960 | } else if (bin_op_type == BinOpTypeCmpGreaterOrEq) { | ||
| 2961 | bignum_cmp = bignum_cmp_gte; | ||
| 2962 | } else { | ||
| 2963 | zig_unreachable(); | ||
| 2964 | } | ||
| 2965 | 2922 | ||
| 2966 | answer = bignum_cmp(&op1_val->data.x_bignum, &op2_val->data.x_bignum); | 2923 | ConstExprValue *out_val = &get_resolved_expr(node)->const_val; |
| 2967 | } else { | 2924 | eval_const_expr_bin_op(op1_val, op1_type, bin_op_type, op2_val, op2_type, out_val); |
| 2968 | bool are_equal = const_values_equal(op1_val, op2_val, resolved_type); | 2925 | return g->builtin_types.entry_bool; |
| 2969 | if (bin_op_type == BinOpTypeCmpEq) { | ||
| 2970 | answer = are_equal; | ||
| 2971 | } else if (bin_op_type == BinOpTypeCmpNotEq) { | ||
| 2972 | answer = !are_equal; | ||
| 2973 | } else { | ||
| 2974 | zig_unreachable(); | ||
| 2975 | } | ||
| 2976 | } | ||
| 2977 | 2926 | ||
| 2978 | bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; | ||
| 2979 | return resolve_expr_const_val_as_bool(g, node, answer, depends_on_compile_var); | ||
| 2980 | } | 2927 | } |
| 2981 | 2928 | ||
| 2982 | static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2929 | static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| ... | @@ -3002,9 +2949,9 @@ static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -3002,9 +2949,9 @@ static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *i |
| 3002 | return g->builtin_types.entry_bool; | 2949 | return g->builtin_types.entry_bool; |
| 3003 | } | 2950 | } |
| 3004 | 2951 | ||
| 3005 | bool answer = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op_type, op2_val->data.x_bool); | 2952 | ConstExprValue *out_val = &get_resolved_expr(node)->const_val; |
| 3006 | bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; | 2953 | eval_const_expr_bin_op(op1_val, op1_type, bin_op_type, op2_val, op2_type, out_val); |
| 3007 | return resolve_expr_const_val_as_bool(g, node, answer, depends_on_compile_var); | 2954 | return g->builtin_types.entry_bool; |
| 3008 | } | 2955 | } |
| 3009 | 2956 | ||
| 3010 | static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2957 | static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| ... | @@ -3041,6 +2988,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -3041,6 +2988,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 3041 | } | 2988 | } |
| 3042 | 2989 | ||
| 3043 | analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2); | 2990 | analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2); |
| 2991 | // not const ok because expression has side effects | ||
| 3044 | return g->builtin_types.entry_void; | 2992 | return g->builtin_types.entry_void; |
| 3045 | } | 2993 | } |
| 3046 | case BinOpTypeBoolOr: | 2994 | case BinOpTypeBoolOr: |
| ... | @@ -3106,37 +3054,23 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -3106,37 +3054,23 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 3106 | return resolved_type; | 3054 | return resolved_type; |
| 3107 | } | 3055 | } |
| 3108 | 3056 | ||
| 3109 | if (bin_op_type == BinOpTypeAdd) { | 3057 | ConstExprValue *out_val = &get_resolved_expr(node)->const_val; |
| 3110 | return resolve_expr_const_val_as_bignum_op(g, node, bignum_add, *op1, *op2, resolved_type); | 3058 | int err; |
| 3111 | } else if (bin_op_type == BinOpTypeSub) { | 3059 | if ((err = eval_const_expr_bin_op(op1_val, resolved_type, bin_op_type, |
| 3112 | return resolve_expr_const_val_as_bignum_op(g, node, bignum_sub, *op1, *op2, resolved_type); | 3060 | op2_val, resolved_type, out_val))) |
| 3113 | } else if (bin_op_type == BinOpTypeMult) { | 3061 | { |
| 3114 | return resolve_expr_const_val_as_bignum_op(g, node, bignum_mul, *op1, *op2, resolved_type); | 3062 | if (err == ErrorDivByZero) { |
| 3115 | } else if (bin_op_type == BinOpTypeDiv) { | ||
| 3116 | ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val; | ||
| 3117 | if ((is_int && op2_val->data.x_bignum.data.x_uint == 0) || | ||
| 3118 | (is_float && op2_val->data.x_bignum.data.x_float == 0.0)) | ||
| 3119 | { | ||
| 3120 | add_node_error(g, node, buf_sprintf("division by zero is undefined")); | 3063 | add_node_error(g, node, buf_sprintf("division by zero is undefined")); |
| 3121 | return g->builtin_types.entry_invalid; | 3064 | return g->builtin_types.entry_invalid; |
| 3122 | } else { | 3065 | } else if (err == ErrorOverflow) { |
| 3123 | return resolve_expr_const_val_as_bignum_op(g, node, bignum_div, *op1, *op2, resolved_type); | 3066 | add_node_error(g, node, buf_sprintf("value cannot be represented in any integer type")); |
| 3067 | return g->builtin_types.entry_invalid; | ||
| 3124 | } | 3068 | } |
| 3125 | } else if (bin_op_type == BinOpTypeMod) { | 3069 | return g->builtin_types.entry_invalid; |
| 3126 | return resolve_expr_const_val_as_bignum_op(g, node, bignum_mod, *op1, *op2, resolved_type); | ||
| 3127 | } else if (bin_op_type == BinOpTypeBinOr) { | ||
| 3128 | return resolve_expr_const_val_as_bignum_op(g, node, bignum_or, *op1, *op2, resolved_type); | ||
| 3129 | } else if (bin_op_type == BinOpTypeBinAnd) { | ||
| 3130 | return resolve_expr_const_val_as_bignum_op(g, node, bignum_and, *op1, *op2, resolved_type); | ||
| 3131 | } else if (bin_op_type == BinOpTypeBinXor) { | ||
| 3132 | return resolve_expr_const_val_as_bignum_op(g, node, bignum_xor, *op1, *op2, resolved_type); | ||
| 3133 | } else if (bin_op_type == BinOpTypeBitShiftLeft) { | ||
| 3134 | return resolve_expr_const_val_as_bignum_op(g, node, bignum_shl, *op1, *op2, resolved_type); | ||
| 3135 | } else if (bin_op_type == BinOpTypeBitShiftRight) { | ||
| 3136 | return resolve_expr_const_val_as_bignum_op(g, node, bignum_shr, *op1, *op2, resolved_type); | ||
| 3137 | } else { | ||
| 3138 | zig_unreachable(); | ||
| 3139 | } | 3070 | } |
| 3071 | |||
| 3072 | num_lit_fits_in_other_type(g, node, resolved_type); | ||
| 3073 | return resolved_type; | ||
| 3140 | } | 3074 | } |
| 3141 | case BinOpTypeUnwrapMaybe: | 3075 | case BinOpTypeUnwrapMaybe: |
| 3142 | { | 3076 | { |
| ... | @@ -3720,6 +3654,10 @@ static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import | ... | @@ -3720,6 +3654,10 @@ static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import |
| 3720 | } | 3654 | } |
| 3721 | 3655 | ||
| 3722 | ConstExprValue *cond_val = &get_resolved_expr(*cond)->const_val; | 3656 | ConstExprValue *cond_val = &get_resolved_expr(*cond)->const_val; |
| 3657 | if (cond_val->undef) { | ||
| 3658 | add_node_error(g, first_executing_node(*cond), buf_sprintf("branch on undefined value")); | ||
| 3659 | return cond_type; | ||
| 3660 | } | ||
| 3723 | if (cond_val->ok && !cond_val->depends_on_compile_var) { | 3661 | if (cond_val->ok && !cond_val->depends_on_compile_var) { |
| 3724 | const char *str_val = cond_val->data.x_bool ? "true" : "false"; | 3662 | const char *str_val = cond_val->data.x_bool ? "true" : "false"; |
| 3725 | add_node_error(g, first_executing_node(*cond), | 3663 | add_node_error(g, first_executing_node(*cond), |
| ... | @@ -3762,17 +3700,6 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -3762,17 +3700,6 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, |
| 3762 | node, then_node, else_node, cond_is_const, cond_bool_val); | 3700 | node, then_node, else_node, cond_is_const, cond_bool_val); |
| 3763 | } | 3701 | } |
| 3764 | 3702 | ||
| 3765 | static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) { | ||
| 3766 | assert(int_type->id == TypeTableEntryIdInt); | ||
| 3767 | |||
| 3768 | for (int i = 0; i < CIntTypeCount; i += 1) { | ||
| 3769 | if (int_type == g->builtin_types.entry_c_int[i]) { | ||
| 3770 | return true; | ||
| 3771 | } | ||
| 3772 | } | ||
| 3773 | return false; | ||
| 3774 | } | ||
| 3775 | |||
| 3776 | static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 3703 | static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 3777 | AstNode *node, const char *err_format, bool is_max) | 3704 | AstNode *node, const char *err_format, bool is_max) |
| 3778 | { | 3705 | { |
| ... | @@ -3781,67 +3708,15 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor | ... | @@ -3781,67 +3708,15 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor |
| 3781 | 3708 | ||
| 3782 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | 3709 | AstNode *type_node = node->data.fn_call_expr.params.at(0); |
| 3783 | TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); | 3710 | TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); |
| 3711 | |||
| 3784 | if (type_entry->id == TypeTableEntryIdInvalid) { | 3712 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 3785 | return g->builtin_types.entry_invalid; | 3713 | return g->builtin_types.entry_invalid; |
| 3786 | } else if (type_entry->id == TypeTableEntryIdInt) { | 3714 | } else if (type_entry->id == TypeTableEntryIdInt || |
| 3787 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; | 3715 | type_entry->id == TypeTableEntryIdFloat || |
| 3788 | const_val->ok = true; | 3716 | type_entry->id == TypeTableEntryIdBool) |
| 3789 | const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry); | 3717 | { |
| 3790 | if (is_max) { | 3718 | eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max); |
| 3791 | if (type_entry->data.integral.is_signed) { | ||
| 3792 | int64_t val; | ||
| 3793 | if (type_entry->data.integral.bit_count == 64) { | ||
| 3794 | val = INT64_MAX; | ||
| 3795 | } else if (type_entry->data.integral.bit_count == 32) { | ||
| 3796 | val = INT32_MAX; | ||
| 3797 | } else if (type_entry->data.integral.bit_count == 16) { | ||
| 3798 | val = INT16_MAX; | ||
| 3799 | } else if (type_entry->data.integral.bit_count == 8) { | ||
| 3800 | val = INT8_MAX; | ||
| 3801 | } else { | ||
| 3802 | zig_unreachable(); | ||
| 3803 | } | ||
| 3804 | bignum_init_signed(&const_val->data.x_bignum, val); | ||
| 3805 | } else { | ||
| 3806 | uint64_t val; | ||
| 3807 | if (type_entry->data.integral.bit_count == 64) { | ||
| 3808 | val = UINT64_MAX; | ||
| 3809 | } else if (type_entry->data.integral.bit_count == 32) { | ||
| 3810 | val = UINT32_MAX; | ||
| 3811 | } else if (type_entry->data.integral.bit_count == 16) { | ||
| 3812 | val = UINT16_MAX; | ||
| 3813 | } else if (type_entry->data.integral.bit_count == 8) { | ||
| 3814 | val = UINT8_MAX; | ||
| 3815 | } else { | ||
| 3816 | zig_unreachable(); | ||
| 3817 | } | ||
| 3818 | bignum_init_unsigned(&const_val->data.x_bignum, val); | ||
| 3819 | } | ||
| 3820 | } else { | ||
| 3821 | if (type_entry->data.integral.is_signed) { | ||
| 3822 | int64_t val; | ||
| 3823 | if (type_entry->data.integral.bit_count == 64) { | ||
| 3824 | val = INT64_MIN; | ||
| 3825 | } else if (type_entry->data.integral.bit_count == 32) { | ||
| 3826 | val = INT32_MIN; | ||
| 3827 | } else if (type_entry->data.integral.bit_count == 16) { | ||
| 3828 | val = INT16_MIN; | ||
| 3829 | } else if (type_entry->data.integral.bit_count == 8) { | ||
| 3830 | val = INT8_MIN; | ||
| 3831 | } else { | ||
| 3832 | zig_unreachable(); | ||
| 3833 | } | ||
| 3834 | bignum_init_signed(&const_val->data.x_bignum, val); | ||
| 3835 | } else { | ||
| 3836 | bignum_init_unsigned(&const_val->data.x_bignum, 0); | ||
| 3837 | } | ||
| 3838 | } | ||
| 3839 | return type_entry; | ||
| 3840 | } else if (type_entry->id == TypeTableEntryIdFloat) { | ||
| 3841 | zig_panic("TODO analyze_min_max_value float"); | ||
| 3842 | return type_entry; | 3719 | return type_entry; |
| 3843 | } else if (type_entry->id == TypeTableEntryIdBool) { | ||
| 3844 | return resolve_expr_const_val_as_bool(g, node, is_max, false); | ||
| 3845 | } else { | 3720 | } else { |
| 3846 | add_node_error(g, node, | 3721 | add_node_error(g, node, |
| 3847 | buf_sprintf(err_format, buf_ptr(&type_entry->name))); | 3722 | buf_sprintf(err_format, buf_ptr(&type_entry->name))); |
| ... | @@ -3849,92 +3724,19 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor | ... | @@ -3849,92 +3724,19 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor |
| 3849 | } | 3724 | } |
| 3850 | } | 3725 | } |
| 3851 | 3726 | ||
| 3852 | static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *expr_node) { | ||
| 3853 | assert(node->type == NodeTypeFnCallExpr); | ||
| 3854 | ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val; | ||
| 3855 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; | ||
| 3856 | if (!other_val->ok) { | ||
| 3857 | return; | ||
| 3858 | } | ||
| 3859 | const_val->depends_on_compile_var = other_val->depends_on_compile_var; | ||
| 3860 | const_val->undef = other_val->undef; | ||
| 3861 | |||
| 3862 | assert(other_val != const_val); | ||
| 3863 | switch (node->data.fn_call_expr.cast_op) { | ||
| 3864 | case CastOpNoCast: | ||
| 3865 | zig_unreachable(); | ||
| 3866 | case CastOpNoop: | ||
| 3867 | case CastOpWidenOrShorten: | ||
| 3868 | case CastOpPointerReinterpret: | ||
| 3869 | *const_val = *other_val; | ||
| 3870 | break; | ||
| 3871 | case CastOpPtrToInt: | ||
| 3872 | case CastOpIntToPtr: | ||
| 3873 | // can't do it | ||
| 3874 | break; | ||
| 3875 | case CastOpToUnknownSizeArray: | ||
| 3876 | { | ||
| 3877 | TypeTableEntry *other_type = get_resolved_expr(expr_node)->type_entry; | ||
| 3878 | assert(other_type->id == TypeTableEntryIdArray); | ||
| 3879 | |||
| 3880 | ConstExprValue *all_fields = allocate<ConstExprValue>(2); | ||
| 3881 | ConstExprValue *ptr_field = &all_fields[0]; | ||
| 3882 | ConstExprValue *len_field = &all_fields[1]; | ||
| 3883 | |||
| 3884 | const_val->data.x_struct.fields = allocate<ConstExprValue*>(2); | ||
| 3885 | const_val->data.x_struct.fields[0] = ptr_field; | ||
| 3886 | const_val->data.x_struct.fields[1] = len_field; | ||
| 3887 | |||
| 3888 | ptr_field->ok = true; | ||
| 3889 | ptr_field->data.x_ptr.ptr = other_val->data.x_array.fields; | ||
| 3890 | ptr_field->data.x_ptr.len = other_type->data.array.len; | ||
| 3891 | |||
| 3892 | len_field->ok = true; | ||
| 3893 | bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len); | ||
| 3894 | |||
| 3895 | const_val->ok = true; | ||
| 3896 | break; | ||
| 3897 | } | ||
| 3898 | case CastOpMaybeWrap: | ||
| 3899 | const_val->data.x_maybe = other_val; | ||
| 3900 | const_val->ok = true; | ||
| 3901 | break; | ||
| 3902 | case CastOpErrorWrap: | ||
| 3903 | const_val->data.x_err.err = nullptr; | ||
| 3904 | const_val->data.x_err.payload = other_val; | ||
| 3905 | const_val->ok = true; | ||
| 3906 | break; | ||
| 3907 | case CastOpPureErrorWrap: | ||
| 3908 | const_val->data.x_err.err = other_val->data.x_err.err; | ||
| 3909 | const_val->ok = true; | ||
| 3910 | break; | ||
| 3911 | case CastOpErrToInt: | ||
| 3912 | { | ||
| 3913 | uint64_t value = other_val->data.x_err.err ? other_val->data.x_err.err->value : 0; | ||
| 3914 | bignum_init_unsigned(&const_val->data.x_bignum, value); | ||
| 3915 | const_val->ok = true; | ||
| 3916 | break; | ||
| 3917 | } | ||
| 3918 | case CastOpIntToFloat: | ||
| 3919 | bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum); | ||
| 3920 | const_val->ok = true; | ||
| 3921 | break; | ||
| 3922 | case CastOpFloatToInt: | ||
| 3923 | bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum); | ||
| 3924 | const_val->ok = true; | ||
| 3925 | break; | ||
| 3926 | case CastOpBoolToInt: | ||
| 3927 | bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0); | ||
| 3928 | const_val->ok = true; | ||
| 3929 | break; | ||
| 3930 | } | ||
| 3931 | } | ||
| 3932 | |||
| 3933 | static TypeTableEntry *resolve_cast(CodeGen *g, BlockContext *context, AstNode *node, | 3727 | static TypeTableEntry *resolve_cast(CodeGen *g, BlockContext *context, AstNode *node, |
| 3934 | AstNode *expr_node, TypeTableEntry *wanted_type, CastOp op, bool need_alloca) | 3728 | AstNode *expr_node, TypeTableEntry *wanted_type, CastOp op, bool need_alloca) |
| 3935 | { | 3729 | { |
| 3936 | node->data.fn_call_expr.cast_op = op; | 3730 | node->data.fn_call_expr.cast_op = op; |
| 3937 | eval_const_expr_implicit_cast(g, node, expr_node); | 3731 | |
| 3732 | ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val; | ||
| 3733 | TypeTableEntry *other_type = get_resolved_expr(expr_node)->type_entry; | ||
| 3734 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; | ||
| 3735 | if (other_val->ok) { | ||
| 3736 | eval_const_expr_implicit_cast(node->data.fn_call_expr.cast_op, other_val, other_type, | ||
| 3737 | const_val, wanted_type); | ||
| 3738 | } | ||
| 3739 | |||
| 3938 | if (need_alloca) { | 3740 | if (need_alloca) { |
| 3939 | if (context->fn_entry) { | 3741 | if (context->fn_entry) { |
| 3940 | context->fn_entry->cast_alloca_list.append(node); | 3742 | context->fn_entry->cast_alloca_list.append(node); |
| ... | @@ -4630,13 +4432,15 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry | ... | @@ -4630,13 +4432,15 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 4630 | case BuiltinFnIdErrName: | 4432 | case BuiltinFnIdErrName: |
| 4631 | return analyze_err_name(g, import, context, node); | 4433 | return analyze_err_name(g, import, context, node); |
| 4632 | case BuiltinFnIdBreakpoint: | 4434 | case BuiltinFnIdBreakpoint: |
| 4435 | mark_impure_fn(context); | ||
| 4633 | return g->builtin_types.entry_void; | 4436 | return g->builtin_types.entry_void; |
| 4634 | } | 4437 | } |
| 4635 | zig_unreachable(); | 4438 | zig_unreachable(); |
| 4636 | } | 4439 | } |
| 4637 | 4440 | ||
| 4638 | static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 4441 | static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 4639 | TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *fn_type, TypeTableEntry *struct_type) | 4442 | TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *fn_type, |
| 4443 | AstNode *struct_node) | ||
| 4640 | { | 4444 | { |
| 4641 | assert(node->type == NodeTypeFnCallExpr); | 4445 | assert(node->type == NodeTypeFnCallExpr); |
| 4642 | 4446 | ||
| ... | @@ -4648,31 +4452,49 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, | ... | @@ -4648,31 +4452,49 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 4648 | int src_param_count = fn_type->data.fn.fn_type_id.param_count; | 4452 | int src_param_count = fn_type->data.fn.fn_type_id.param_count; |
| 4649 | int actual_param_count = node->data.fn_call_expr.params.length; | 4453 | int actual_param_count = node->data.fn_call_expr.params.length; |
| 4650 | 4454 | ||
| 4651 | if (struct_type) { | 4455 | if (struct_node) { |
| 4652 | actual_param_count += 1; | 4456 | actual_param_count += 1; |
| 4653 | } | 4457 | } |
| 4654 | 4458 | ||
| 4459 | bool ok_invocation = true; | ||
| 4460 | |||
| 4655 | if (fn_type->data.fn.fn_type_id.is_var_args) { | 4461 | if (fn_type->data.fn.fn_type_id.is_var_args) { |
| 4656 | if (actual_param_count < src_param_count) { | 4462 | if (actual_param_count < src_param_count) { |
| 4463 | ok_invocation = false; | ||
| 4657 | add_node_error(g, node, | 4464 | add_node_error(g, node, |
| 4658 | buf_sprintf("expected at least %d arguments, got %d", src_param_count, actual_param_count)); | 4465 | buf_sprintf("expected at least %d arguments, got %d", src_param_count, actual_param_count)); |
| 4659 | } | 4466 | } |
| 4660 | } else if (src_param_count != actual_param_count) { | 4467 | } else if (src_param_count != actual_param_count) { |
| 4468 | ok_invocation = false; | ||
| 4661 | add_node_error(g, node, | 4469 | add_node_error(g, node, |
| 4662 | buf_sprintf("expected %d arguments, got %d", src_param_count, actual_param_count)); | 4470 | buf_sprintf("expected %d arguments, got %d", src_param_count, actual_param_count)); |
| 4663 | } | 4471 | } |
| 4664 | 4472 | ||
| 4473 | bool all_args_const_expr = true; | ||
| 4474 | |||
| 4475 | if (struct_node) { | ||
| 4476 | ConstExprValue *struct_const_val = &get_resolved_expr(struct_node)->const_val; | ||
| 4477 | if (!struct_const_val->ok) { | ||
| 4478 | all_args_const_expr = false; | ||
| 4479 | } | ||
| 4480 | } | ||
| 4481 | |||
| 4665 | // analyze each parameter. in the case of a method, we already analyzed the | 4482 | // analyze each parameter. in the case of a method, we already analyzed the |
| 4666 | // first parameter in order to figure out which struct we were calling a method on. | 4483 | // first parameter in order to figure out which struct we were calling a method on. |
| 4667 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { | 4484 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { |
| 4668 | AstNode *child = node->data.fn_call_expr.params.at(i); | 4485 | AstNode **child = &node->data.fn_call_expr.params.at(i); |
| 4669 | // determine the expected type for each parameter | 4486 | // determine the expected type for each parameter |
| 4670 | TypeTableEntry *expected_param_type = nullptr; | 4487 | TypeTableEntry *expected_param_type = nullptr; |
| 4671 | int fn_proto_i = i + (struct_type ? 1 : 0); | 4488 | int fn_proto_i = i + (struct_node ? 1 : 0); |
| 4672 | if (fn_proto_i < src_param_count) { | 4489 | if (fn_proto_i < src_param_count) { |
| 4673 | expected_param_type = fn_type->data.fn.fn_type_id.param_info[fn_proto_i].type; | 4490 | expected_param_type = fn_type->data.fn.fn_type_id.param_info[fn_proto_i].type; |
| 4674 | } | 4491 | } |
| 4675 | analyze_expression(g, import, context, expected_param_type, child); | 4492 | analyze_expression(g, import, context, expected_param_type, *child); |
| 4493 | |||
| 4494 | ConstExprValue *const_arg_val = &get_resolved_expr(*child)->const_val; | ||
| 4495 | if (!const_arg_val->ok) { | ||
| 4496 | all_args_const_expr = false; | ||
| 4497 | } | ||
| 4676 | } | 4498 | } |
| 4677 | 4499 | ||
| 4678 | TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type; | 4500 | TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type; |
| ... | @@ -4681,6 +4503,27 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, | ... | @@ -4681,6 +4503,27 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 4681 | return return_type; | 4503 | return return_type; |
| 4682 | } | 4504 | } |
| 4683 | 4505 | ||
| 4506 | FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry; | ||
| 4507 | if (ok_invocation && fn_table_entry && fn_table_entry->is_pure) { | ||
| 4508 | if (fn_table_entry->anal_state == FnAnalStateReady) { | ||
| 4509 | analyze_fn_body(g, fn_table_entry); | ||
| 4510 | } | ||
| 4511 | if (all_args_const_expr) { | ||
| 4512 | if (fn_table_entry->is_pure && fn_table_entry->anal_state == FnAnalStateComplete) { | ||
| 4513 | ConstExprValue *result_val = &get_resolved_expr(node)->const_val; | ||
| 4514 | if (eval_fn(g, node, fn_table_entry, result_val, 1000, struct_node)) { | ||
| 4515 | // function evaluation generated an error | ||
| 4516 | return g->builtin_types.entry_invalid; | ||
| 4517 | } | ||
| 4518 | return return_type; | ||
| 4519 | } | ||
| 4520 | } | ||
| 4521 | } | ||
| 4522 | if (!ok_invocation || !fn_table_entry || !fn_table_entry->is_pure) { | ||
| 4523 | // calling an impure fn is impure | ||
| 4524 | mark_impure_fn(context); | ||
| 4525 | } | ||
| 4526 | |||
| 4684 | if (handle_is_ptr(return_type)) { | 4527 | if (handle_is_ptr(return_type)) { |
| 4685 | context->fn_entry->cast_alloca_list.append(node); | 4528 | context->fn_entry->cast_alloca_list.append(node); |
| 4686 | } | 4529 | } |
| ... | @@ -4689,13 +4532,13 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, | ... | @@ -4689,13 +4532,13 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, |
| 4689 | } | 4532 | } |
| 4690 | 4533 | ||
| 4691 | static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 4534 | static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 4692 | TypeTableEntry *expected_type, AstNode *node, FnTableEntry *fn_table_entry, TypeTableEntry *struct_type) | 4535 | TypeTableEntry *expected_type, AstNode *node, FnTableEntry *fn_table_entry, AstNode *struct_node) |
| 4693 | { | 4536 | { |
| 4694 | assert(node->type == NodeTypeFnCallExpr); | 4537 | assert(node->type == NodeTypeFnCallExpr); |
| 4695 | 4538 | ||
| 4696 | node->data.fn_call_expr.fn_entry = fn_table_entry; | 4539 | node->data.fn_call_expr.fn_entry = fn_table_entry; |
| 4697 | 4540 | ||
| 4698 | return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_type); | 4541 | return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_node); |
| 4699 | } | 4542 | } |
| 4700 | 4543 | ||
| 4701 | static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, | 4544 | static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, |
| ... | @@ -4721,7 +4564,7 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp | ... | @@ -4721,7 +4564,7 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp |
| 4721 | generic_fn_type_id->generic_param_count = actual_param_count; | 4564 | generic_fn_type_id->generic_param_count = actual_param_count; |
| 4722 | generic_fn_type_id->generic_params = allocate<GenericParamValue>(actual_param_count); | 4565 | generic_fn_type_id->generic_params = allocate<GenericParamValue>(actual_param_count); |
| 4723 | 4566 | ||
| 4724 | BlockContext *child_context = import->block_context; | 4567 | BlockContext *child_context = decl_node->owner->block_context; |
| 4725 | for (int i = 0; i < actual_param_count; i += 1) { | 4568 | for (int i = 0; i < actual_param_count; i += 1) { |
| 4726 | AstNode *generic_param_decl_node = decl_node->data.fn_proto.generic_params.at(i); | 4569 | AstNode *generic_param_decl_node = decl_node->data.fn_proto.generic_params.at(i); |
| 4727 | assert(generic_param_decl_node->type == NodeTypeParamDecl); | 4570 | assert(generic_param_decl_node->type == NodeTypeParamDecl); |
| ... | @@ -4861,17 +4704,17 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import | ... | @@ -4861,17 +4704,17 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 4861 | return analyze_cast_expr(g, import, context, node); | 4704 | return analyze_cast_expr(g, import, context, node); |
| 4862 | } | 4705 | } |
| 4863 | } else if (invoke_type_entry->id == TypeTableEntryIdFn) { | 4706 | } else if (invoke_type_entry->id == TypeTableEntryIdFn) { |
| 4864 | TypeTableEntry *bare_struct_type; | 4707 | AstNode *struct_node; |
| 4865 | if (fn_ref_expr->type == NodeTypeFieldAccessExpr && | 4708 | if (fn_ref_expr->type == NodeTypeFieldAccessExpr && |
| 4866 | fn_ref_expr->data.field_access_expr.is_member_fn) | 4709 | fn_ref_expr->data.field_access_expr.is_member_fn) |
| 4867 | { | 4710 | { |
| 4868 | bare_struct_type = fn_ref_expr->data.field_access_expr.bare_struct_type; | 4711 | struct_node = fn_ref_expr->data.field_access_expr.struct_expr; |
| 4869 | } else { | 4712 | } else { |
| 4870 | bare_struct_type = nullptr; | 4713 | struct_node = nullptr; |
| 4871 | } | 4714 | } |
| 4872 | 4715 | ||
| 4873 | return analyze_fn_call_raw(g, import, context, expected_type, node, | 4716 | return analyze_fn_call_raw(g, import, context, expected_type, node, |
| 4874 | const_val->data.x_fn, bare_struct_type); | 4717 | const_val->data.x_fn, struct_node); |
| 4875 | } else if (invoke_type_entry->id == TypeTableEntryIdGenericFn) { | 4718 | } else if (invoke_type_entry->id == TypeTableEntryIdGenericFn) { |
| 4876 | return analyze_generic_fn_call(g, import, context, expected_type, node, const_val->data.x_type); | 4719 | return analyze_generic_fn_call(g, import, context, expected_type, node, const_val->data.x_type); |
| 4877 | } else { | 4720 | } else { |
| ... | @@ -5421,6 +5264,8 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -5421,6 +5264,8 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, |
| 5421 | static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 5264 | static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 5422 | TypeTableEntry *expected_type, AstNode *node) | 5265 | TypeTableEntry *expected_type, AstNode *node) |
| 5423 | { | 5266 | { |
| 5267 | mark_impure_fn(context); | ||
| 5268 | |||
| 5424 | node->data.asm_expr.return_count = 0; | 5269 | node->data.asm_expr.return_count = 0; |
| 5425 | TypeTableEntry *return_type = g->builtin_types.entry_void; | 5270 | TypeTableEntry *return_type = g->builtin_types.entry_void; |
| 5426 | for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) { | 5271 | for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) { |
| ... | @@ -5641,8 +5486,10 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { | ... | @@ -5641,8 +5486,10 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 5641 | if (fn_proto_node->data.fn_proto.skip) { | 5486 | if (fn_proto_node->data.fn_proto.skip) { |
| 5642 | // we detected an error with this function definition which prevents us | 5487 | // we detected an error with this function definition which prevents us |
| 5643 | // from further analyzing it. | 5488 | // from further analyzing it. |
| 5489 | fn_table_entry->anal_state = FnAnalStateSkipped; | ||
| 5644 | return; | 5490 | return; |
| 5645 | } | 5491 | } |
| 5492 | fn_table_entry->anal_state = FnAnalStateProbing; | ||
| 5646 | 5493 | ||
| 5647 | BlockContext *context = node->data.fn_def.block_context; | 5494 | BlockContext *context = node->data.fn_def.block_context; |
| 5648 | 5495 | ||
| ... | @@ -5676,6 +5523,10 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { | ... | @@ -5676,6 +5523,10 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 5676 | param_decl_node->data.param_decl.variable = var; | 5523 | param_decl_node->data.param_decl.variable = var; |
| 5677 | 5524 | ||
| 5678 | var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index; | 5525 | var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index; |
| 5526 | |||
| 5527 | if (!type->deep_const) { | ||
| 5528 | fn_table_entry->is_pure = false; | ||
| 5529 | } | ||
| 5679 | } | 5530 | } |
| 5680 | 5531 | ||
| 5681 | TypeTableEntry *expected_type = fn_type->data.fn.fn_type_id.return_type; | 5532 | TypeTableEntry *expected_type = fn_type->data.fn.fn_type_id.return_type; |
| ... | @@ -5697,6 +5548,8 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { | ... | @@ -5697,6 +5548,8 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 5697 | buf_ptr(&label->decl_node->data.label.name))); | 5548 | buf_ptr(&label->decl_node->data.label.name))); |
| 5698 | } | 5549 | } |
| 5699 | } | 5550 | } |
| 5551 | |||
| 5552 | fn_table_entry->anal_state = FnAnalStateComplete; | ||
| 5700 | } | 5553 | } |
| 5701 | 5554 | ||
| 5702 | static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContext *block_context, | 5555 | static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContext *block_context, |
| ... | @@ -6005,7 +5858,9 @@ void semantic_analyze(CodeGen *g) { | ... | @@ -6005,7 +5858,9 @@ void semantic_analyze(CodeGen *g) { |
| 6005 | 5858 | ||
| 6006 | for (int i = 0; i < g->fn_defs.length; i += 1) { | 5859 | for (int i = 0; i < g->fn_defs.length; i += 1) { |
| 6007 | FnTableEntry *fn_entry = g->fn_defs.at(i); | 5860 | FnTableEntry *fn_entry = g->fn_defs.at(i); |
| 6008 | analyze_fn_body(g, fn_entry); | 5861 | if (fn_entry->anal_state == FnAnalStateReady) { |
| 5862 | analyze_fn_body(g, fn_entry); | ||
| 5863 | } | ||
| 6009 | } | 5864 | } |
| 6010 | } | 5865 | } |
| 6011 | 5866 |
src/ast_render.cpp+6-2| ... | @@ -326,9 +326,9 @@ static void render_node(AstRender *ar, AstNode *node) { | ... | @@ -326,9 +326,9 @@ static void render_node(AstRender *ar, AstNode *node) { |
| 326 | AstNode *statement = node->data.block.statements.at(i); | 326 | AstNode *statement = node->data.block.statements.at(i); |
| 327 | print_indent(ar); | 327 | print_indent(ar); |
| 328 | render_node(ar, statement); | 328 | render_node(ar, statement); |
| 329 | fprintf(ar->f, ";\n"); | ||
| 329 | } | 330 | } |
| 330 | ar->indent -= ar->indent_size; | 331 | ar->indent -= ar->indent_size; |
| 331 | fprintf(ar->f, "\n"); | ||
| 332 | print_indent(ar); | 332 | print_indent(ar); |
| 333 | fprintf(ar->f, "}"); | 333 | fprintf(ar->f, "}"); |
| 334 | break; | 334 | break; |
| ... | @@ -438,7 +438,11 @@ static void render_node(AstRender *ar, AstNode *node) { | ... | @@ -438,7 +438,11 @@ static void render_node(AstRender *ar, AstNode *node) { |
| 438 | fprintf(ar->f, ")"); | 438 | fprintf(ar->f, ")"); |
| 439 | break; | 439 | break; |
| 440 | case NodeTypeArrayAccessExpr: | 440 | case NodeTypeArrayAccessExpr: |
| 441 | zig_panic("TODO"); | 441 | render_node(ar, node->data.array_access_expr.array_ref_expr); |
| 442 | fprintf(ar->f, "["); | ||
| 443 | render_node(ar, node->data.array_access_expr.subscript); | ||
| 444 | fprintf(ar->f, "]"); | ||
| 445 | break; | ||
| 442 | case NodeTypeSliceExpr: | 446 | case NodeTypeSliceExpr: |
| 443 | zig_panic("TODO"); | 447 | zig_panic("TODO"); |
| 444 | case NodeTypeFieldAccessExpr: | 448 | case NodeTypeFieldAccessExpr: |
src/bignum.cpp+5| ... | @@ -71,6 +71,11 @@ bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed) { | ... | @@ -71,6 +71,11 @@ bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed) { |
| 71 | } | 71 | } |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | void bignum_truncate(BigNum *bn, int bit_count) { | ||
| 75 | assert(bn->kind == BigNumKindInt); | ||
| 76 | bn->data.x_uint &= (1LL << bit_count) - 1; | ||
| 77 | } | ||
| 78 | |||
| 74 | uint64_t bignum_to_twos_complement(BigNum *bn) { | 79 | uint64_t bignum_to_twos_complement(BigNum *bn) { |
| 75 | assert(bn->kind == BigNumKindInt); | 80 | assert(bn->kind == BigNumKindInt); |
| 76 | 81 |
src/bignum.hpp+2| ... | @@ -47,6 +47,8 @@ void bignum_negate(BigNum *dest, BigNum *op); | ... | @@ -47,6 +47,8 @@ void bignum_negate(BigNum *dest, BigNum *op); |
| 47 | void bignum_cast_to_float(BigNum *dest, BigNum *op); | 47 | void bignum_cast_to_float(BigNum *dest, BigNum *op); |
| 48 | void bignum_cast_to_int(BigNum *dest, BigNum *op); | 48 | void bignum_cast_to_int(BigNum *dest, BigNum *op); |
| 49 | 49 | ||
| 50 | void bignum_truncate(BigNum *dest, int bit_count); | ||
| 51 | |||
| 50 | // returns the result of the comparison | 52 | // returns the result of the comparison |
| 51 | bool bignum_cmp_eq(BigNum *op1, BigNum *op2); | 53 | bool bignum_cmp_eq(BigNum *op1, BigNum *op2); |
| 52 | bool bignum_cmp_neq(BigNum *op1, BigNum *op2); | 54 | bool bignum_cmp_neq(BigNum *op1, BigNum *op2); |
src/codegen.cpp+24-7| ... | @@ -1074,15 +1074,12 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lva | ... | @@ -1074,15 +1074,12 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lva |
| 1074 | 1074 | ||
| 1075 | AstNode *struct_expr = node->data.field_access_expr.struct_expr; | 1075 | AstNode *struct_expr = node->data.field_access_expr.struct_expr; |
| 1076 | TypeTableEntry *struct_type = get_expr_type(struct_expr); | 1076 | TypeTableEntry *struct_type = get_expr_type(struct_expr); |
| 1077 | Buf *name = &node->data.field_access_expr.field_name; | ||
| 1078 | 1077 | ||
| 1079 | if (struct_type->id == TypeTableEntryIdArray) { | 1078 | if (struct_type->id == TypeTableEntryIdArray) { |
| 1080 | if (buf_eql_str(name, "len")) { | 1079 | Buf *name = &node->data.field_access_expr.field_name; |
| 1081 | return LLVMConstInt(g->builtin_types.entry_isize->type_ref, | 1080 | assert(buf_eql_str(name, "len")); |
| 1082 | struct_type->data.array.len, false); | 1081 | return LLVMConstInt(g->builtin_types.entry_isize->type_ref, |
| 1083 | } else { | 1082 | struct_type->data.array.len, false); |
| 1084 | zig_panic("gen_field_access_expr bad array field"); | ||
| 1085 | } | ||
| 1086 | } else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer && | 1083 | } else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer && |
| 1087 | struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)) | 1084 | struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)) |
| 1088 | { | 1085 | { |
| ... | @@ -3036,6 +3033,7 @@ static void gen_const_globals(CodeGen *g) { | ... | @@ -3036,6 +3033,7 @@ static void gen_const_globals(CodeGen *g) { |
| 3036 | } else { | 3033 | } else { |
| 3037 | expr->const_llvm_val = gen_const_val(g, type_entry, const_val); | 3034 | expr->const_llvm_val = gen_const_val(g, type_entry, const_val); |
| 3038 | } | 3035 | } |
| 3036 | assert(expr->const_llvm_val); | ||
| 3039 | } | 3037 | } |
| 3040 | } | 3038 | } |
| 3041 | 3039 | ||
| ... | @@ -3466,23 +3464,27 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3466,23 +3464,27 @@ static void define_builtin_types(CodeGen *g) { |
| 3466 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNamespace); | 3464 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNamespace); |
| 3467 | buf_init_from_str(&entry->name, "(namespace)"); | 3465 | buf_init_from_str(&entry->name, "(namespace)"); |
| 3468 | entry->zero_bits = true; | 3466 | entry->zero_bits = true; |
| 3467 | entry->deep_const = true; | ||
| 3469 | g->builtin_types.entry_namespace = entry; | 3468 | g->builtin_types.entry_namespace = entry; |
| 3470 | } | 3469 | } |
| 3471 | { | 3470 | { |
| 3472 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitFloat); | 3471 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitFloat); |
| 3473 | buf_init_from_str(&entry->name, "(float literal)"); | 3472 | buf_init_from_str(&entry->name, "(float literal)"); |
| 3474 | entry->zero_bits = true; | 3473 | entry->zero_bits = true; |
| 3474 | entry->deep_const = true; | ||
| 3475 | g->builtin_types.entry_num_lit_float = entry; | 3475 | g->builtin_types.entry_num_lit_float = entry; |
| 3476 | } | 3476 | } |
| 3477 | { | 3477 | { |
| 3478 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitInt); | 3478 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitInt); |
| 3479 | buf_init_from_str(&entry->name, "(integer literal)"); | 3479 | buf_init_from_str(&entry->name, "(integer literal)"); |
| 3480 | entry->zero_bits = true; | 3480 | entry->zero_bits = true; |
| 3481 | entry->deep_const = true; | ||
| 3481 | g->builtin_types.entry_num_lit_int = entry; | 3482 | g->builtin_types.entry_num_lit_int = entry; |
| 3482 | } | 3483 | } |
| 3483 | { | 3484 | { |
| 3484 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUndefLit); | 3485 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUndefLit); |
| 3485 | buf_init_from_str(&entry->name, "(undefined)"); | 3486 | buf_init_from_str(&entry->name, "(undefined)"); |
| 3487 | entry->deep_const = true; | ||
| 3486 | g->builtin_types.entry_undef = entry; | 3488 | g->builtin_types.entry_undef = entry; |
| 3487 | } | 3489 | } |
| 3488 | 3490 | ||
| ... | @@ -3492,6 +3494,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3492,6 +3494,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3492 | for (;;) { | 3494 | for (;;) { |
| 3493 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); | 3495 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); |
| 3494 | entry->type_ref = LLVMIntType(size_in_bits); | 3496 | entry->type_ref = LLVMIntType(size_in_bits); |
| 3497 | entry->deep_const = true; | ||
| 3495 | 3498 | ||
| 3496 | const char u_or_i = is_signed ? 'i' : 'u'; | 3499 | const char u_or_i = is_signed ? 'i' : 'u'; |
| 3497 | buf_resize(&entry->name, 0); | 3500 | buf_resize(&entry->name, 0); |
| ... | @@ -3537,6 +3540,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3537,6 +3540,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3537 | 3540 | ||
| 3538 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); | 3541 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); |
| 3539 | entry->type_ref = LLVMIntType(size_in_bits); | 3542 | entry->type_ref = LLVMIntType(size_in_bits); |
| 3543 | entry->deep_const = true; | ||
| 3540 | 3544 | ||
| 3541 | buf_init_from_str(&entry->name, info->name); | 3545 | buf_init_from_str(&entry->name, info->name); |
| 3542 | 3546 | ||
| ... | @@ -3556,6 +3560,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3556,6 +3560,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3556 | { | 3560 | { |
| 3557 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool); | 3561 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool); |
| 3558 | entry->type_ref = LLVMInt1Type(); | 3562 | entry->type_ref = LLVMInt1Type(); |
| 3563 | entry->deep_const = true; | ||
| 3559 | buf_init_from_str(&entry->name, "bool"); | 3564 | buf_init_from_str(&entry->name, "bool"); |
| 3560 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); | 3565 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); |
| 3561 | uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref); | 3566 | uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref); |
| ... | @@ -3568,6 +3573,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3568,6 +3573,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3568 | } | 3573 | } |
| 3569 | { | 3574 | { |
| 3570 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); | 3575 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); |
| 3576 | entry->deep_const = true; | ||
| 3571 | entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8); | 3577 | entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8); |
| 3572 | buf_init_from_str(&entry->name, "isize"); | 3578 | buf_init_from_str(&entry->name, "isize"); |
| 3573 | entry->data.integral.is_signed = true; | 3579 | entry->data.integral.is_signed = true; |
| ... | @@ -3584,6 +3590,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3584,6 +3590,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3584 | } | 3590 | } |
| 3585 | { | 3591 | { |
| 3586 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); | 3592 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); |
| 3593 | entry->deep_const = true; | ||
| 3587 | entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8); | 3594 | entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8); |
| 3588 | buf_init_from_str(&entry->name, "usize"); | 3595 | buf_init_from_str(&entry->name, "usize"); |
| 3589 | entry->data.integral.is_signed = false; | 3596 | entry->data.integral.is_signed = false; |
| ... | @@ -3600,6 +3607,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3600,6 +3607,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3600 | } | 3607 | } |
| 3601 | { | 3608 | { |
| 3602 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); | 3609 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); |
| 3610 | entry->deep_const = true; | ||
| 3603 | entry->type_ref = LLVMFloatType(); | 3611 | entry->type_ref = LLVMFloatType(); |
| 3604 | buf_init_from_str(&entry->name, "f32"); | 3612 | buf_init_from_str(&entry->name, "f32"); |
| 3605 | entry->data.floating.bit_count = 32; | 3613 | entry->data.floating.bit_count = 32; |
| ... | @@ -3615,6 +3623,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3615,6 +3623,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3615 | } | 3623 | } |
| 3616 | { | 3624 | { |
| 3617 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); | 3625 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); |
| 3626 | entry->deep_const = true; | ||
| 3618 | entry->type_ref = LLVMDoubleType(); | 3627 | entry->type_ref = LLVMDoubleType(); |
| 3619 | buf_init_from_str(&entry->name, "f64"); | 3628 | buf_init_from_str(&entry->name, "f64"); |
| 3620 | entry->data.floating.bit_count = 64; | 3629 | entry->data.floating.bit_count = 64; |
| ... | @@ -3630,6 +3639,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3630,6 +3639,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3630 | } | 3639 | } |
| 3631 | { | 3640 | { |
| 3632 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); | 3641 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); |
| 3642 | entry->deep_const = true; | ||
| 3633 | entry->type_ref = LLVMX86FP80Type(); | 3643 | entry->type_ref = LLVMX86FP80Type(); |
| 3634 | buf_init_from_str(&entry->name, "c_long_double"); | 3644 | buf_init_from_str(&entry->name, "c_long_double"); |
| 3635 | entry->data.floating.bit_count = 80; | 3645 | entry->data.floating.bit_count = 80; |
| ... | @@ -3645,6 +3655,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3645,6 +3655,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3645 | } | 3655 | } |
| 3646 | { | 3656 | { |
| 3647 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid); | 3657 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid); |
| 3658 | entry->deep_const = true; | ||
| 3648 | entry->type_ref = LLVMVoidType(); | 3659 | entry->type_ref = LLVMVoidType(); |
| 3649 | entry->zero_bits = true; | 3660 | entry->zero_bits = true; |
| 3650 | buf_init_from_str(&entry->name, "void"); | 3661 | buf_init_from_str(&entry->name, "void"); |
| ... | @@ -3657,6 +3668,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3657,6 +3668,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3657 | } | 3668 | } |
| 3658 | { | 3669 | { |
| 3659 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUnreachable); | 3670 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUnreachable); |
| 3671 | entry->deep_const = true; | ||
| 3660 | entry->type_ref = LLVMVoidType(); | 3672 | entry->type_ref = LLVMVoidType(); |
| 3661 | entry->zero_bits = true; | 3673 | entry->zero_bits = true; |
| 3662 | buf_init_from_str(&entry->name, "unreachable"); | 3674 | buf_init_from_str(&entry->name, "unreachable"); |
| ... | @@ -3666,6 +3678,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3666,6 +3678,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3666 | } | 3678 | } |
| 3667 | { | 3679 | { |
| 3668 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMetaType); | 3680 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMetaType); |
| 3681 | entry->deep_const = true; | ||
| 3669 | buf_init_from_str(&entry->name, "type"); | 3682 | buf_init_from_str(&entry->name, "type"); |
| 3670 | entry->zero_bits = true; | 3683 | entry->zero_bits = true; |
| 3671 | g->builtin_types.entry_type = entry; | 3684 | g->builtin_types.entry_type = entry; |
| ... | @@ -3688,6 +3701,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3688,6 +3701,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3688 | 3701 | ||
| 3689 | { | 3702 | { |
| 3690 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError); | 3703 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError); |
| 3704 | entry->deep_const = true; | ||
| 3691 | buf_init_from_str(&entry->name, "error"); | 3705 | buf_init_from_str(&entry->name, "error"); |
| 3692 | 3706 | ||
| 3693 | // TODO allow overriding this type and keep track of max value and emit an | 3707 | // TODO allow overriding this type and keep track of max value and emit an |
| ... | @@ -3703,6 +3717,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3703,6 +3717,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3703 | 3717 | ||
| 3704 | { | 3718 | { |
| 3705 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); | 3719 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); |
| 3720 | entry->deep_const = true; | ||
| 3706 | entry->zero_bits = true; // only allowed at compile time | 3721 | entry->zero_bits = true; // only allowed at compile time |
| 3707 | buf_init_from_str(&entry->name, "@OS"); | 3722 | buf_init_from_str(&entry->name, "@OS"); |
| 3708 | uint32_t field_count = target_os_count(); | 3723 | uint32_t field_count = target_os_count(); |
| ... | @@ -3728,6 +3743,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3728,6 +3743,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3728 | 3743 | ||
| 3729 | { | 3744 | { |
| 3730 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); | 3745 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); |
| 3746 | entry->deep_const = true; | ||
| 3731 | entry->zero_bits = true; // only allowed at compile time | 3747 | entry->zero_bits = true; // only allowed at compile time |
| 3732 | buf_init_from_str(&entry->name, "@Arch"); | 3748 | buf_init_from_str(&entry->name, "@Arch"); |
| 3733 | uint32_t field_count = target_arch_count(); | 3749 | uint32_t field_count = target_arch_count(); |
| ... | @@ -3759,6 +3775,7 @@ static void define_builtin_types(CodeGen *g) { | ... | @@ -3759,6 +3775,7 @@ static void define_builtin_types(CodeGen *g) { |
| 3759 | 3775 | ||
| 3760 | { | 3776 | { |
| 3761 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); | 3777 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); |
| 3778 | entry->deep_const = true; | ||
| 3762 | entry->zero_bits = true; // only allowed at compile time | 3779 | entry->zero_bits = true; // only allowed at compile time |
| 3763 | buf_init_from_str(&entry->name, "@Environ"); | 3780 | buf_init_from_str(&entry->name, "@Environ"); |
| 3764 | uint32_t field_count = target_environ_count(); | 3781 | uint32_t field_count = target_environ_count(); |
src/error.cpp+2| ... | @@ -12,6 +12,8 @@ const char *err_str(int err) { | ... | @@ -12,6 +12,8 @@ const char *err_str(int err) { |
| 12 | case ErrorFileNotFound: return "file not found"; | 12 | case ErrorFileNotFound: return "file not found"; |
| 13 | case ErrorFileSystem: return "file system error"; | 13 | case ErrorFileSystem: return "file system error"; |
| 14 | case ErrorFileTooBig: return "file too big"; | 14 | case ErrorFileTooBig: return "file too big"; |
| 15 | case ErrorDivByZero: return "division by zero"; | ||
| 16 | case ErrorOverflow: return "overflow"; | ||
| 15 | } | 17 | } |
| 16 | return "(invalid error)"; | 18 | return "(invalid error)"; |
| 17 | } | 19 | } |
src/error.hpp+2| ... | @@ -19,6 +19,8 @@ enum Error { | ... | @@ -19,6 +19,8 @@ enum Error { |
| 19 | ErrorFileNotFound, | 19 | ErrorFileNotFound, |
| 20 | ErrorFileSystem, | 20 | ErrorFileSystem, |
| 21 | ErrorFileTooBig, | 21 | ErrorFileTooBig, |
| 22 | ErrorDivByZero, | ||
| 23 | ErrorOverflow | ||
| 22 | }; | 24 | }; |
| 23 | 25 | ||
| 24 | const char *err_str(int err); | 26 | const char *err_str(int err); |
src/eval.cpp created+1191| ... | @@ -0,0 +1,1191 @@ | ||
| 1 | #include "eval.hpp" | ||
| 2 | #include "analyze.hpp" | ||
| 3 | #include "error.hpp" | ||
| 4 | |||
| 5 | static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val); | ||
| 6 | |||
| 7 | bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) { | ||
| 8 | switch (type_entry->id) { | ||
| 9 | case TypeTableEntryIdEnum: | ||
| 10 | { | ||
| 11 | ConstEnumValue *enum1 = &a->data.x_enum; | ||
| 12 | ConstEnumValue *enum2 = &b->data.x_enum; | ||
| 13 | if (enum1->tag == enum2->tag) { | ||
| 14 | TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum1->tag]; | ||
| 15 | if (type_has_bits(enum_field->type_entry)) { | ||
| 16 | zig_panic("TODO const expr analyze enum special value for equality"); | ||
| 17 | } else { | ||
| 18 | return true; | ||
| 19 | } | ||
| 20 | } | ||
| 21 | return false; | ||
| 22 | } | ||
| 23 | case TypeTableEntryIdMetaType: | ||
| 24 | return a->data.x_type == b->data.x_type; | ||
| 25 | case TypeTableEntryIdVoid: | ||
| 26 | return true; | ||
| 27 | case TypeTableEntryIdPureError: | ||
| 28 | return a->data.x_err.err == b->data.x_err.err; | ||
| 29 | case TypeTableEntryIdFn: | ||
| 30 | return a->data.x_fn == b->data.x_fn; | ||
| 31 | case TypeTableEntryIdBool: | ||
| 32 | return a->data.x_bool == b->data.x_bool; | ||
| 33 | case TypeTableEntryIdInt: | ||
| 34 | case TypeTableEntryIdFloat: | ||
| 35 | case TypeTableEntryIdNumLitFloat: | ||
| 36 | case TypeTableEntryIdNumLitInt: | ||
| 37 | return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum); | ||
| 38 | case TypeTableEntryIdPointer: | ||
| 39 | zig_panic("TODO"); | ||
| 40 | case TypeTableEntryIdArray: | ||
| 41 | zig_panic("TODO"); | ||
| 42 | case TypeTableEntryIdStruct: | ||
| 43 | zig_panic("TODO"); | ||
| 44 | case TypeTableEntryIdUndefLit: | ||
| 45 | zig_panic("TODO"); | ||
| 46 | case TypeTableEntryIdMaybe: | ||
| 47 | zig_panic("TODO"); | ||
| 48 | case TypeTableEntryIdErrorUnion: | ||
| 49 | zig_panic("TODO"); | ||
| 50 | case TypeTableEntryIdTypeDecl: | ||
| 51 | zig_panic("TODO"); | ||
| 52 | case TypeTableEntryIdNamespace: | ||
| 53 | zig_panic("TODO"); | ||
| 54 | case TypeTableEntryIdGenericFn: | ||
| 55 | case TypeTableEntryIdInvalid: | ||
| 56 | case TypeTableEntryIdUnreachable: | ||
| 57 | zig_unreachable(); | ||
| 58 | } | ||
| 59 | zig_unreachable(); | ||
| 60 | } | ||
| 61 | |||
| 62 | |||
| 63 | static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out); | ||
| 64 | |||
| 65 | static bool eval_block(EvalFn *ef, AstNode *node, ConstExprValue *out) { | ||
| 66 | assert(node->type == NodeTypeBlock); | ||
| 67 | |||
| 68 | EvalScope *my_scope = allocate<EvalScope>(1); | ||
| 69 | my_scope->block_context = node->block_context; | ||
| 70 | ef->scope_stack.append(my_scope); | ||
| 71 | |||
| 72 | for (int i = 0; i < node->data.block.statements.length; i += 1) { | ||
| 73 | AstNode *child = node->data.block.statements.at(i); | ||
| 74 | memset(out, 0, sizeof(ConstExprValue)); | ||
| 75 | if (eval_expr(ef, child, out)) return true; | ||
| 76 | } | ||
| 77 | |||
| 78 | ef->scope_stack.pop(); | ||
| 79 | |||
| 80 | return false; | ||
| 81 | } | ||
| 82 | |||
| 83 | static bool eval_return(EvalFn *ef, AstNode *node, ConstExprValue *out) { | ||
| 84 | assert(node->type == NodeTypeReturnExpr); | ||
| 85 | |||
| 86 | eval_expr(ef, node->data.return_expr.expr, ef->return_expr); | ||
| 87 | return true; | ||
| 88 | } | ||
| 89 | |||
| 90 | static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) { | ||
| 91 | if (bin_op == BinOpTypeBoolOr) { | ||
| 92 | return a || b; | ||
| 93 | } else if (bin_op == BinOpTypeBoolAnd) { | ||
| 94 | return a && b; | ||
| 95 | } else { | ||
| 96 | zig_unreachable(); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val, | ||
| 101 | ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *)) | ||
| 102 | { | ||
| 103 | bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum); | ||
| 104 | if (overflow) { | ||
| 105 | return ErrorOverflow; | ||
| 106 | } | ||
| 107 | |||
| 108 | out_val->ok = true; | ||
| 109 | out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; | ||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | |||
| 113 | int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, | ||
| 114 | BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val) | ||
| 115 | { | ||
| 116 | assert(op1_val->ok); | ||
| 117 | assert(op2_val->ok); | ||
| 118 | |||
| 119 | switch (bin_op) { | ||
| 120 | case BinOpTypeAssign: | ||
| 121 | case BinOpTypeAssignTimes: | ||
| 122 | case BinOpTypeAssignDiv: | ||
| 123 | case BinOpTypeAssignMod: | ||
| 124 | case BinOpTypeAssignPlus: | ||
| 125 | case BinOpTypeAssignMinus: | ||
| 126 | case BinOpTypeAssignBitShiftLeft: | ||
| 127 | case BinOpTypeAssignBitShiftRight: | ||
| 128 | case BinOpTypeAssignBitAnd: | ||
| 129 | case BinOpTypeAssignBitXor: | ||
| 130 | case BinOpTypeAssignBitOr: | ||
| 131 | case BinOpTypeAssignBoolAnd: | ||
| 132 | case BinOpTypeAssignBoolOr: | ||
| 133 | out_val->ok = true; | ||
| 134 | return 0; | ||
| 135 | case BinOpTypeBoolOr: | ||
| 136 | case BinOpTypeBoolAnd: | ||
| 137 | assert(op1_type->id == TypeTableEntryIdBool); | ||
| 138 | assert(op2_type->id == TypeTableEntryIdBool); | ||
| 139 | out_val->data.x_bool = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op, op2_val->data.x_bool); | ||
| 140 | out_val->ok = true; | ||
| 141 | out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; | ||
| 142 | return 0; | ||
| 143 | case BinOpTypeCmpEq: | ||
| 144 | case BinOpTypeCmpNotEq: | ||
| 145 | case BinOpTypeCmpLessThan: | ||
| 146 | case BinOpTypeCmpGreaterThan: | ||
| 147 | case BinOpTypeCmpLessOrEq: | ||
| 148 | case BinOpTypeCmpGreaterOrEq: | ||
| 149 | { | ||
| 150 | bool type_can_gt_lt_cmp = (op1_type->id == TypeTableEntryIdNumLitFloat || | ||
| 151 | op1_type->id == TypeTableEntryIdNumLitInt || | ||
| 152 | op1_type->id == TypeTableEntryIdFloat || | ||
| 153 | op1_type->id == TypeTableEntryIdInt); | ||
| 154 | bool answer; | ||
| 155 | if (type_can_gt_lt_cmp) { | ||
| 156 | bool (*bignum_cmp)(BigNum *, BigNum *); | ||
| 157 | if (bin_op == BinOpTypeCmpEq) { | ||
| 158 | bignum_cmp = bignum_cmp_eq; | ||
| 159 | } else if (bin_op == BinOpTypeCmpNotEq) { | ||
| 160 | bignum_cmp = bignum_cmp_neq; | ||
| 161 | } else if (bin_op == BinOpTypeCmpLessThan) { | ||
| 162 | bignum_cmp = bignum_cmp_lt; | ||
| 163 | } else if (bin_op == BinOpTypeCmpGreaterThan) { | ||
| 164 | bignum_cmp = bignum_cmp_gt; | ||
| 165 | } else if (bin_op == BinOpTypeCmpLessOrEq) { | ||
| 166 | bignum_cmp = bignum_cmp_lte; | ||
| 167 | } else if (bin_op == BinOpTypeCmpGreaterOrEq) { | ||
| 168 | bignum_cmp = bignum_cmp_gte; | ||
| 169 | } else { | ||
| 170 | zig_unreachable(); | ||
| 171 | } | ||
| 172 | |||
| 173 | answer = bignum_cmp(&op1_val->data.x_bignum, &op2_val->data.x_bignum); | ||
| 174 | } else { | ||
| 175 | bool are_equal = const_values_equal(op1_val, op2_val, op1_type); | ||
| 176 | if (bin_op == BinOpTypeCmpEq) { | ||
| 177 | answer = are_equal; | ||
| 178 | } else if (bin_op == BinOpTypeCmpNotEq) { | ||
| 179 | answer = !are_equal; | ||
| 180 | } else { | ||
| 181 | zig_unreachable(); | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | out_val->depends_on_compile_var = | ||
| 186 | op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; | ||
| 187 | out_val->data.x_bool = answer; | ||
| 188 | out_val->ok = true; | ||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | case BinOpTypeAdd: | ||
| 192 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add); | ||
| 193 | case BinOpTypeBinOr: | ||
| 194 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or); | ||
| 195 | case BinOpTypeBinXor: | ||
| 196 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor); | ||
| 197 | case BinOpTypeBinAnd: | ||
| 198 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and); | ||
| 199 | case BinOpTypeBitShiftLeft: | ||
| 200 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl); | ||
| 201 | case BinOpTypeBitShiftRight: | ||
| 202 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr); | ||
| 203 | case BinOpTypeSub: | ||
| 204 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub); | ||
| 205 | case BinOpTypeMult: | ||
| 206 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul); | ||
| 207 | case BinOpTypeDiv: | ||
| 208 | { | ||
| 209 | bool is_int = false; | ||
| 210 | bool is_float = false; | ||
| 211 | if (op1_type->id == TypeTableEntryIdInt || | ||
| 212 | op1_type->id == TypeTableEntryIdNumLitInt) | ||
| 213 | { | ||
| 214 | is_int = true; | ||
| 215 | } else if (op1_type->id == TypeTableEntryIdFloat || | ||
| 216 | op1_type->id == TypeTableEntryIdNumLitFloat) | ||
| 217 | { | ||
| 218 | is_float = true; | ||
| 219 | } | ||
| 220 | if ((is_int && op2_val->data.x_bignum.data.x_uint == 0) || | ||
| 221 | (is_float && op2_val->data.x_bignum.data.x_float == 0.0)) | ||
| 222 | { | ||
| 223 | return ErrorDivByZero; | ||
| 224 | } else { | ||
| 225 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div); | ||
| 226 | } | ||
| 227 | } | ||
| 228 | case BinOpTypeMod: | ||
| 229 | return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod); | ||
| 230 | case BinOpTypeUnwrapMaybe: | ||
| 231 | zig_panic("TODO"); | ||
| 232 | case BinOpTypeStrCat: | ||
| 233 | zig_panic("TODO"); | ||
| 234 | case BinOpTypeInvalid: | ||
| 235 | zig_unreachable(); | ||
| 236 | } | ||
| 237 | zig_unreachable(); | ||
| 238 | } | ||
| 239 | |||
| 240 | static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 241 | assert(node->type == NodeTypeBinOpExpr); | ||
| 242 | |||
| 243 | AstNode *op1 = node->data.bin_op_expr.op1; | ||
| 244 | AstNode *op2 = node->data.bin_op_expr.op2; | ||
| 245 | |||
| 246 | TypeTableEntry *op1_type = get_resolved_expr(op1)->type_entry; | ||
| 247 | TypeTableEntry *op2_type = get_resolved_expr(op2)->type_entry; | ||
| 248 | |||
| 249 | ConstExprValue op1_val = {0}; | ||
| 250 | if (eval_expr(ef, op1, &op1_val)) return true; | ||
| 251 | |||
| 252 | ConstExprValue op2_val = {0}; | ||
| 253 | if (eval_expr(ef, op2, &op2_val)) return true; | ||
| 254 | |||
| 255 | BinOpType bin_op = node->data.bin_op_expr.bin_op; | ||
| 256 | |||
| 257 | int err; | ||
| 258 | if ((err = eval_const_expr_bin_op(&op1_val, op1_type, bin_op, &op2_val, op2_type, out_val))) { | ||
| 259 | ef->root->abort = true; | ||
| 260 | if (err == ErrorDivByZero) { | ||
| 261 | ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, | ||
| 262 | buf_sprintf("function evaluation caused division by zero")); | ||
| 263 | add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); | ||
| 264 | add_error_note(ef->root->codegen, msg, node, buf_sprintf("division by zero here")); | ||
| 265 | } else if (err == ErrorOverflow) { | ||
| 266 | ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, | ||
| 267 | buf_sprintf("function evaluation caused overflow")); | ||
| 268 | add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); | ||
| 269 | add_error_note(ef->root->codegen, msg, node, buf_sprintf("overflow occurred here")); | ||
| 270 | } else { | ||
| 271 | zig_unreachable(); | ||
| 272 | } | ||
| 273 | return true; | ||
| 274 | } | ||
| 275 | |||
| 276 | assert(out_val->ok); | ||
| 277 | |||
| 278 | return false; | ||
| 279 | } | ||
| 280 | |||
| 281 | static EvalVar *find_var(EvalFn *ef, Buf *name) { | ||
| 282 | int scope_index = ef->scope_stack.length - 1; | ||
| 283 | while (scope_index >= 0) { | ||
| 284 | EvalScope *scope = ef->scope_stack.at(scope_index); | ||
| 285 | for (int var_i = 0; var_i < scope->vars.length; var_i += 1) { | ||
| 286 | EvalVar *var = &scope->vars.at(var_i); | ||
| 287 | if (buf_eql_buf(var->name, name)) { | ||
| 288 | return var; | ||
| 289 | } | ||
| 290 | } | ||
| 291 | scope_index -= 1; | ||
| 292 | } | ||
| 293 | |||
| 294 | return nullptr; | ||
| 295 | } | ||
| 296 | |||
| 297 | static bool eval_symbol_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 298 | assert(node->type == NodeTypeSymbol); | ||
| 299 | |||
| 300 | Buf *name = &node->data.symbol_expr.symbol; | ||
| 301 | EvalVar *var = find_var(ef, name); | ||
| 302 | assert(var); | ||
| 303 | |||
| 304 | *out_val = var->value; | ||
| 305 | |||
| 306 | return false; | ||
| 307 | } | ||
| 308 | |||
| 309 | static TypeTableEntry *resolve_expr_type(AstNode *node) { | ||
| 310 | Expr *expr = get_resolved_expr(node); | ||
| 311 | TypeTableEntry *type_entry = expr->type_entry; | ||
| 312 | assert(type_entry->id == TypeTableEntryIdMetaType); | ||
| 313 | ConstExprValue *const_val = &expr->const_val; | ||
| 314 | assert(const_val->ok); | ||
| 315 | return const_val->data.x_type; | ||
| 316 | } | ||
| 317 | |||
| 318 | static bool eval_container_init_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 319 | assert(node->type == NodeTypeContainerInitExpr); | ||
| 320 | |||
| 321 | AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; | ||
| 322 | ContainerInitKind kind = container_init_expr->kind; | ||
| 323 | TypeTableEntry *container_type = resolve_expr_type(container_init_expr->type); | ||
| 324 | out_val->ok = true; | ||
| 325 | |||
| 326 | if (container_type->id == TypeTableEntryIdStruct && | ||
| 327 | !container_type->data.structure.is_unknown_size_array && | ||
| 328 | kind == ContainerInitKindStruct) | ||
| 329 | { | ||
| 330 | int expr_field_count = container_init_expr->entries.length; | ||
| 331 | int actual_field_count = container_type->data.structure.src_field_count; | ||
| 332 | assert(expr_field_count == actual_field_count); | ||
| 333 | |||
| 334 | out_val->data.x_struct.fields = allocate<ConstExprValue*>(actual_field_count); | ||
| 335 | |||
| 336 | for (int i = 0; i < expr_field_count; i += 1) { | ||
| 337 | AstNode *val_field_node = container_init_expr->entries.at(i); | ||
| 338 | assert(val_field_node->type == NodeTypeStructValueField); | ||
| 339 | |||
| 340 | TypeStructField *type_field = val_field_node->data.struct_val_field.type_struct_field; | ||
| 341 | int field_index = type_field->src_index; | ||
| 342 | |||
| 343 | ConstExprValue src_field_val = {0}; | ||
| 344 | if (eval_expr(ef, val_field_node->data.struct_val_field.expr, &src_field_val)) return true; | ||
| 345 | |||
| 346 | ConstExprValue *dest_field_val = allocate<ConstExprValue>(1); | ||
| 347 | *dest_field_val = src_field_val; | ||
| 348 | |||
| 349 | out_val->data.x_struct.fields[field_index] = dest_field_val; | ||
| 350 | out_val->depends_on_compile_var = out_val->depends_on_compile_var || | ||
| 351 | src_field_val.depends_on_compile_var; | ||
| 352 | } | ||
| 353 | } else if (container_type->id == TypeTableEntryIdVoid) { | ||
| 354 | return false; | ||
| 355 | } else if (container_type->id == TypeTableEntryIdUnreachable) { | ||
| 356 | ef->root->abort = true; | ||
| 357 | ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node, | ||
| 358 | buf_sprintf("function evaluation reached unreachable expression")); | ||
| 359 | add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here")); | ||
| 360 | add_error_note(ef->root->codegen, msg, node, buf_sprintf("unreachable expression here")); | ||
| 361 | return true; | ||
| 362 | } else if (container_type->id == TypeTableEntryIdStruct && | ||
| 363 | container_type->data.structure.is_unknown_size_array && | ||
| 364 | kind == ContainerInitKindArray) | ||
| 365 | { | ||
| 366 | |||
| 367 | int elem_count = container_init_expr->entries.length; | ||
| 368 | |||
| 369 | out_val->ok = true; | ||
| 370 | out_val->data.x_array.fields = allocate<ConstExprValue*>(elem_count); | ||
| 371 | |||
| 372 | for (int i = 0; i < elem_count; i += 1) { | ||
| 373 | AstNode *elem_node = container_init_expr->entries.at(i); | ||
| 374 | |||
| 375 | ConstExprValue *elem_val = allocate<ConstExprValue>(1); | ||
| 376 | if (eval_expr(ef, elem_node, elem_val)) return true; | ||
| 377 | |||
| 378 | assert(elem_val->ok); | ||
| 379 | |||
| 380 | out_val->data.x_array.fields[i] = elem_val; | ||
| 381 | out_val->depends_on_compile_var = out_val->depends_on_compile_var || | ||
| 382 | elem_val->depends_on_compile_var; | ||
| 383 | } | ||
| 384 | } else { | ||
| 385 | zig_panic("TODO"); | ||
| 386 | } | ||
| 387 | |||
| 388 | |||
| 389 | return false; | ||
| 390 | } | ||
| 391 | |||
| 392 | static bool eval_if_bool_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 393 | assert(node->type == NodeTypeIfBoolExpr); | ||
| 394 | |||
| 395 | ConstExprValue cond_val = {0}; | ||
| 396 | if (eval_expr(ef, node->data.if_bool_expr.condition, &cond_val)) return true; | ||
| 397 | |||
| 398 | AstNode *exec_node = cond_val.data.x_bool ? | ||
| 399 | node->data.if_bool_expr.then_block : node->data.if_bool_expr.else_node; | ||
| 400 | |||
| 401 | if (exec_node) { | ||
| 402 | if (eval_expr(ef, exec_node, out_val)) return true; | ||
| 403 | } | ||
| 404 | out_val->ok = true; | ||
| 405 | return false; | ||
| 406 | } | ||
| 407 | |||
| 408 | void eval_const_expr_implicit_cast(CastOp cast_op, | ||
| 409 | ConstExprValue *other_val, TypeTableEntry *other_type, | ||
| 410 | ConstExprValue *const_val, TypeTableEntry *new_type) | ||
| 411 | { | ||
| 412 | const_val->depends_on_compile_var = other_val->depends_on_compile_var; | ||
| 413 | const_val->undef = other_val->undef; | ||
| 414 | |||
| 415 | assert(other_val != const_val); | ||
| 416 | switch (cast_op) { | ||
| 417 | case CastOpNoCast: | ||
| 418 | zig_unreachable(); | ||
| 419 | case CastOpNoop: | ||
| 420 | case CastOpWidenOrShorten: | ||
| 421 | *const_val = *other_val; | ||
| 422 | break; | ||
| 423 | case CastOpPointerReinterpret: | ||
| 424 | if (other_type->id == TypeTableEntryIdPointer && | ||
| 425 | new_type->id == TypeTableEntryIdPointer) | ||
| 426 | { | ||
| 427 | TypeTableEntry *other_child_type = other_type->data.pointer.child_type; | ||
| 428 | TypeTableEntry *new_child_type = new_type->data.pointer.child_type; | ||
| 429 | |||
| 430 | if ((other_child_type->id == TypeTableEntryIdInt || | ||
| 431 | other_child_type->id == TypeTableEntryIdFloat) && | ||
| 432 | (new_child_type->id == TypeTableEntryIdInt || | ||
| 433 | new_child_type->id == TypeTableEntryIdFloat)) | ||
| 434 | { | ||
| 435 | ConstExprValue **ptr_val = allocate<ConstExprValue*>(1); | ||
| 436 | *ptr_val = other_val->data.x_ptr.ptr[0]; | ||
| 437 | const_val->data.x_ptr.ptr = ptr_val; | ||
| 438 | const_val->data.x_ptr.len = 1; | ||
| 439 | const_val->ok = true; | ||
| 440 | const_val->undef = other_val->undef; | ||
| 441 | const_val->depends_on_compile_var = other_val->depends_on_compile_var; | ||
| 442 | } else { | ||
| 443 | zig_panic("TODO"); | ||
| 444 | } | ||
| 445 | } else if (other_type->id == TypeTableEntryIdMaybe && | ||
| 446 | new_type->id == TypeTableEntryIdMaybe) | ||
| 447 | { | ||
| 448 | if (!other_val->data.x_maybe) { | ||
| 449 | *const_val = *other_val; | ||
| 450 | break; | ||
| 451 | } | ||
| 452 | |||
| 453 | TypeTableEntry *other_ptr_type = other_type->data.maybe.child_type; | ||
| 454 | TypeTableEntry *new_ptr_type = new_type->data.maybe.child_type; | ||
| 455 | |||
| 456 | if (other_ptr_type->id == TypeTableEntryIdPointer && | ||
| 457 | new_ptr_type->id == TypeTableEntryIdPointer) | ||
| 458 | { | ||
| 459 | TypeTableEntry *other_child_type = other_ptr_type->data.pointer.child_type; | ||
| 460 | TypeTableEntry *new_child_type = new_ptr_type->data.pointer.child_type; | ||
| 461 | |||
| 462 | if ((other_child_type->id == TypeTableEntryIdInt || | ||
| 463 | other_child_type->id == TypeTableEntryIdFloat) && | ||
| 464 | (new_child_type->id == TypeTableEntryIdInt || | ||
| 465 | new_child_type->id == TypeTableEntryIdFloat)) | ||
| 466 | { | ||
| 467 | ConstExprValue *ptr_parent = allocate<ConstExprValue>(1); | ||
| 468 | ConstExprValue **ptr_val = allocate<ConstExprValue*>(1); | ||
| 469 | *ptr_val = other_val->data.x_maybe->data.x_ptr.ptr[0]; | ||
| 470 | ptr_parent->data.x_ptr.ptr = ptr_val; | ||
| 471 | ptr_parent->data.x_ptr.len = 1; | ||
| 472 | ptr_parent->ok = true; | ||
| 473 | |||
| 474 | const_val->data.x_maybe = ptr_parent; | ||
| 475 | const_val->ok = true; | ||
| 476 | const_val->undef = other_val->undef; | ||
| 477 | const_val->depends_on_compile_var = other_val->depends_on_compile_var; | ||
| 478 | } else { | ||
| 479 | zig_panic("TODO"); | ||
| 480 | } | ||
| 481 | } else { | ||
| 482 | zig_panic("TODO"); | ||
| 483 | } | ||
| 484 | } | ||
| 485 | break; | ||
| 486 | case CastOpPtrToInt: | ||
| 487 | case CastOpIntToPtr: | ||
| 488 | // can't do it | ||
| 489 | break; | ||
| 490 | case CastOpToUnknownSizeArray: | ||
| 491 | { | ||
| 492 | assert(other_type->id == TypeTableEntryIdArray); | ||
| 493 | |||
| 494 | ConstExprValue *all_fields = allocate<ConstExprValue>(2); | ||
| 495 | ConstExprValue *ptr_field = &all_fields[0]; | ||
| 496 | ConstExprValue *len_field = &all_fields[1]; | ||
| 497 | |||
| 498 | const_val->data.x_struct.fields = allocate<ConstExprValue*>(2); | ||
| 499 | const_val->data.x_struct.fields[0] = ptr_field; | ||
| 500 | const_val->data.x_struct.fields[1] = len_field; | ||
| 501 | |||
| 502 | ptr_field->ok = true; | ||
| 503 | ptr_field->data.x_ptr.ptr = other_val->data.x_array.fields; | ||
| 504 | ptr_field->data.x_ptr.len = other_type->data.array.len; | ||
| 505 | |||
| 506 | len_field->ok = true; | ||
| 507 | bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len); | ||
| 508 | |||
| 509 | const_val->ok = true; | ||
| 510 | break; | ||
| 511 | } | ||
| 512 | case CastOpMaybeWrap: | ||
| 513 | const_val->data.x_maybe = other_val; | ||
| 514 | const_val->ok = true; | ||
| 515 | break; | ||
| 516 | case CastOpErrorWrap: | ||
| 517 | const_val->data.x_err.err = nullptr; | ||
| 518 | const_val->data.x_err.payload = other_val; | ||
| 519 | const_val->ok = true; | ||
| 520 | break; | ||
| 521 | case CastOpPureErrorWrap: | ||
| 522 | const_val->data.x_err.err = other_val->data.x_err.err; | ||
| 523 | const_val->ok = true; | ||
| 524 | break; | ||
| 525 | case CastOpErrToInt: | ||
| 526 | { | ||
| 527 | uint64_t value = other_val->data.x_err.err ? other_val->data.x_err.err->value : 0; | ||
| 528 | bignum_init_unsigned(&const_val->data.x_bignum, value); | ||
| 529 | const_val->ok = true; | ||
| 530 | break; | ||
| 531 | } | ||
| 532 | case CastOpIntToFloat: | ||
| 533 | bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum); | ||
| 534 | const_val->ok = true; | ||
| 535 | break; | ||
| 536 | case CastOpFloatToInt: | ||
| 537 | bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum); | ||
| 538 | const_val->ok = true; | ||
| 539 | break; | ||
| 540 | case CastOpBoolToInt: | ||
| 541 | bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0); | ||
| 542 | const_val->ok = true; | ||
| 543 | break; | ||
| 544 | } | ||
| 545 | } | ||
| 546 | |||
| 547 | static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) { | ||
| 548 | assert(int_type->id == TypeTableEntryIdInt); | ||
| 549 | |||
| 550 | for (int i = 0; i < CIntTypeCount; i += 1) { | ||
| 551 | if (int_type == g->builtin_types.entry_c_int[i]) { | ||
| 552 | return true; | ||
| 553 | } | ||
| 554 | } | ||
| 555 | return false; | ||
| 556 | } | ||
| 557 | |||
| 558 | void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max) { | ||
| 559 | if (type_entry->id == TypeTableEntryIdInt) { | ||
| 560 | const_val->ok = true; | ||
| 561 | const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry); | ||
| 562 | if (is_max) { | ||
| 563 | if (type_entry->data.integral.is_signed) { | ||
| 564 | int64_t val; | ||
| 565 | if (type_entry->data.integral.bit_count == 64) { | ||
| 566 | val = INT64_MAX; | ||
| 567 | } else if (type_entry->data.integral.bit_count == 32) { | ||
| 568 | val = INT32_MAX; | ||
| 569 | } else if (type_entry->data.integral.bit_count == 16) { | ||
| 570 | val = INT16_MAX; | ||
| 571 | } else if (type_entry->data.integral.bit_count == 8) { | ||
| 572 | val = INT8_MAX; | ||
| 573 | } else { | ||
| 574 | zig_unreachable(); | ||
| 575 | } | ||
| 576 | bignum_init_signed(&const_val->data.x_bignum, val); | ||
| 577 | } else { | ||
| 578 | uint64_t val; | ||
| 579 | if (type_entry->data.integral.bit_count == 64) { | ||
| 580 | val = UINT64_MAX; | ||
| 581 | } else if (type_entry->data.integral.bit_count == 32) { | ||
| 582 | val = UINT32_MAX; | ||
| 583 | } else if (type_entry->data.integral.bit_count == 16) { | ||
| 584 | val = UINT16_MAX; | ||
| 585 | } else if (type_entry->data.integral.bit_count == 8) { | ||
| 586 | val = UINT8_MAX; | ||
| 587 | } else { | ||
| 588 | zig_unreachable(); | ||
| 589 | } | ||
| 590 | bignum_init_unsigned(&const_val->data.x_bignum, val); | ||
| 591 | } | ||
| 592 | } else { | ||
| 593 | if (type_entry->data.integral.is_signed) { | ||
| 594 | int64_t val; | ||
| 595 | if (type_entry->data.integral.bit_count == 64) { | ||
| 596 | val = INT64_MIN; | ||
| 597 | } else if (type_entry->data.integral.bit_count == 32) { | ||
| 598 | val = INT32_MIN; | ||
| 599 | } else if (type_entry->data.integral.bit_count == 16) { | ||
| 600 | val = INT16_MIN; | ||
| 601 | } else if (type_entry->data.integral.bit_count == 8) { | ||
| 602 | val = INT8_MIN; | ||
| 603 | } else { | ||
| 604 | zig_unreachable(); | ||
| 605 | } | ||
| 606 | bignum_init_signed(&const_val->data.x_bignum, val); | ||
| 607 | } else { | ||
| 608 | bignum_init_unsigned(&const_val->data.x_bignum, 0); | ||
| 609 | } | ||
| 610 | } | ||
| 611 | } else if (type_entry->id == TypeTableEntryIdFloat) { | ||
| 612 | zig_panic("TODO analyze_min_max_value float"); | ||
| 613 | } else if (type_entry->id == TypeTableEntryIdBool) { | ||
| 614 | const_val->ok = true; | ||
| 615 | const_val->data.x_bool = is_max; | ||
| 616 | } else { | ||
| 617 | zig_unreachable(); | ||
| 618 | } | ||
| 619 | } | ||
| 620 | |||
| 621 | static bool eval_min_max(EvalFn *ef, AstNode *node, ConstExprValue *out_val, bool is_max) { | ||
| 622 | assert(node->type == NodeTypeFnCallExpr); | ||
| 623 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | ||
| 624 | TypeTableEntry *type_entry = resolve_expr_type(type_node); | ||
| 625 | eval_min_max_value(ef->root->codegen, type_entry, out_val, is_max); | ||
| 626 | return false; | ||
| 627 | } | ||
| 628 | |||
| 629 | static bool eval_fn_with_overflow(EvalFn *ef, AstNode *node, ConstExprValue *out_val, | ||
| 630 | bool (*bignum_fn)(BigNum *dest, BigNum *op1, BigNum *op2)) | ||
| 631 | { | ||
| 632 | assert(node->type == NodeTypeFnCallExpr); | ||
| 633 | |||
| 634 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | ||
| 635 | TypeTableEntry *int_type = resolve_expr_type(type_node); | ||
| 636 | assert(int_type->id == TypeTableEntryIdInt); | ||
| 637 | |||
| 638 | AstNode *op1_node = node->data.fn_call_expr.params.at(1); | ||
| 639 | AstNode *op2_node = node->data.fn_call_expr.params.at(2); | ||
| 640 | AstNode *result_node = node->data.fn_call_expr.params.at(3); | ||
| 641 | |||
| 642 | ConstExprValue op1_val = {0}; | ||
| 643 | if (eval_expr(ef, op1_node, &op1_val)) return true; | ||
| 644 | |||
| 645 | ConstExprValue op2_val = {0}; | ||
| 646 | if (eval_expr(ef, op2_node, &op2_val)) return true; | ||
| 647 | |||
| 648 | ConstExprValue result_ptr_val = {0}; | ||
| 649 | if (eval_expr(ef, result_node, &result_ptr_val)) return true; | ||
| 650 | |||
| 651 | ConstExprValue *result_val = result_ptr_val.data.x_ptr.ptr[0]; | ||
| 652 | |||
| 653 | out_val->ok = true; | ||
| 654 | bool overflow = bignum_fn(&result_val->data.x_bignum, &op1_val.data.x_bignum, &op2_val.data.x_bignum); | ||
| 655 | |||
| 656 | overflow = overflow || !bignum_fits_in_bits(&result_val->data.x_bignum, | ||
| 657 | int_type->data.integral.bit_count, int_type->data.integral.is_signed); | ||
| 658 | |||
| 659 | out_val->data.x_bool = overflow; | ||
| 660 | |||
| 661 | if (overflow) { | ||
| 662 | bignum_truncate(&result_val->data.x_bignum, int_type->data.integral.bit_count); | ||
| 663 | } | ||
| 664 | |||
| 665 | return false; | ||
| 666 | } | ||
| 667 | |||
| 668 | static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 669 | assert(node->type == NodeTypeFnCallExpr); | ||
| 670 | |||
| 671 | BuiltinFnEntry *builtin_fn = node->data.fn_call_expr.builtin_fn; | ||
| 672 | switch (builtin_fn->id) { | ||
| 673 | case BuiltinFnIdMaxValue: | ||
| 674 | return eval_min_max(ef, node, out_val, true); | ||
| 675 | case BuiltinFnIdMinValue: | ||
| 676 | return eval_min_max(ef, node, out_val, false); | ||
| 677 | case BuiltinFnIdMulWithOverflow: | ||
| 678 | return eval_fn_with_overflow(ef, node, out_val, bignum_mul); | ||
| 679 | case BuiltinFnIdAddWithOverflow: | ||
| 680 | return eval_fn_with_overflow(ef, node, out_val, bignum_add); | ||
| 681 | case BuiltinFnIdSubWithOverflow: | ||
| 682 | return eval_fn_with_overflow(ef, node, out_val, bignum_sub); | ||
| 683 | case BuiltinFnIdMemcpy: | ||
| 684 | case BuiltinFnIdMemset: | ||
| 685 | case BuiltinFnIdSizeof: | ||
| 686 | case BuiltinFnIdAlignof: | ||
| 687 | case BuiltinFnIdMemberCount: | ||
| 688 | case BuiltinFnIdTypeof: | ||
| 689 | case BuiltinFnIdCInclude: | ||
| 690 | case BuiltinFnIdCDefine: | ||
| 691 | case BuiltinFnIdCUndef: | ||
| 692 | case BuiltinFnIdCompileVar: | ||
| 693 | case BuiltinFnIdConstEval: | ||
| 694 | case BuiltinFnIdCtz: | ||
| 695 | case BuiltinFnIdClz: | ||
| 696 | case BuiltinFnIdImport: | ||
| 697 | case BuiltinFnIdCImport: | ||
| 698 | case BuiltinFnIdErrName: | ||
| 699 | zig_panic("TODO"); | ||
| 700 | case BuiltinFnIdBreakpoint: | ||
| 701 | case BuiltinFnIdInvalid: | ||
| 702 | zig_unreachable(); | ||
| 703 | } | ||
| 704 | |||
| 705 | return false; | ||
| 706 | } | ||
| 707 | |||
| 708 | static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 709 | assert(node->type == NodeTypeFnCallExpr); | ||
| 710 | |||
| 711 | AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; | ||
| 712 | CastOp cast_op = node->data.fn_call_expr.cast_op; | ||
| 713 | if (node->data.fn_call_expr.is_builtin) { | ||
| 714 | return eval_fn_call_builtin(ef, node, out_val); | ||
| 715 | } else if (cast_op != CastOpNoCast) { | ||
| 716 | TypeTableEntry *new_type = resolve_expr_type(fn_ref_expr); | ||
| 717 | AstNode *param_node = node->data.fn_call_expr.params.at(0); | ||
| 718 | TypeTableEntry *old_type = get_resolved_expr(param_node)->type_entry; | ||
| 719 | ConstExprValue param_val = {0}; | ||
| 720 | if (eval_expr(ef, param_node, &param_val)) return true; | ||
| 721 | eval_const_expr_implicit_cast(cast_op, &param_val, old_type, out_val, new_type); | ||
| 722 | return false; | ||
| 723 | } | ||
| 724 | |||
| 725 | if (node->data.fn_call_expr.enum_type) { | ||
| 726 | zig_panic("TODO"); | ||
| 727 | } | ||
| 728 | |||
| 729 | FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry; | ||
| 730 | |||
| 731 | if (fn_ref_expr->type == NodeTypeFieldAccessExpr && | ||
| 732 | fn_ref_expr->data.field_access_expr.is_member_fn) | ||
| 733 | { | ||
| 734 | zig_panic("TODO"); | ||
| 735 | } | ||
| 736 | |||
| 737 | if (!fn_table_entry) { | ||
| 738 | ConstExprValue fn_val = {0}; | ||
| 739 | if (eval_expr(ef, fn_ref_expr, &fn_val)) return true; | ||
| 740 | fn_table_entry = fn_val.data.x_fn; | ||
| 741 | } | ||
| 742 | |||
| 743 | int param_count = node->data.fn_call_expr.params.length; | ||
| 744 | ConstExprValue *args = allocate<ConstExprValue>(param_count); | ||
| 745 | for (int i = 0; i < param_count; i += 1) { | ||
| 746 | AstNode *param_expr_node = node->data.fn_call_expr.params.at(i); | ||
| 747 | ConstExprValue *param_val = &args[i]; | ||
| 748 | if (eval_expr(ef, param_expr_node, param_val)) return true; | ||
| 749 | } | ||
| 750 | |||
| 751 | ef->root->branches_used += 1; | ||
| 752 | |||
| 753 | eval_fn_args(ef->root, fn_table_entry, args, out_val); | ||
| 754 | return false; | ||
| 755 | } | ||
| 756 | |||
| 757 | static bool eval_field_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 758 | assert(node->type == NodeTypeFieldAccessExpr); | ||
| 759 | |||
| 760 | AstNode *struct_expr = node->data.field_access_expr.struct_expr; | ||
| 761 | TypeTableEntry *struct_type = get_resolved_expr(struct_expr)->type_entry; | ||
| 762 | |||
| 763 | if (struct_type->id == TypeTableEntryIdArray) { | ||
| 764 | Buf *name = &node->data.field_access_expr.field_name; | ||
| 765 | assert(buf_eql_str(name, "len")); | ||
| 766 | zig_panic("TODO"); | ||
| 767 | } else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer && | ||
| 768 | struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)) | ||
| 769 | { | ||
| 770 | TypeStructField *tsf = node->data.field_access_expr.type_struct_field; | ||
| 771 | assert(tsf); | ||
| 772 | if (struct_type->id == TypeTableEntryIdStruct) { | ||
| 773 | ConstExprValue struct_val = {0}; | ||
| 774 | if (eval_expr(ef, struct_expr, &struct_val)) return true; | ||
| 775 | ConstExprValue *field_value = struct_val.data.x_struct.fields[tsf->src_index]; | ||
| 776 | *out_val = *field_value; | ||
| 777 | assert(out_val->ok); | ||
| 778 | } else { | ||
| 779 | zig_panic("TODO"); | ||
| 780 | } | ||
| 781 | } else if (struct_type->id == TypeTableEntryIdMetaType) { | ||
| 782 | TypeTableEntry *child_type = resolve_expr_type(struct_expr); | ||
| 783 | if (child_type->id == TypeTableEntryIdPureError) { | ||
| 784 | *out_val = get_resolved_expr(node)->const_val; | ||
| 785 | } else { | ||
| 786 | zig_panic("TODO"); | ||
| 787 | } | ||
| 788 | } else if (struct_type->id == TypeTableEntryIdNamespace) { | ||
| 789 | zig_panic("TODO"); | ||
| 790 | } else { | ||
| 791 | zig_unreachable(); | ||
| 792 | } | ||
| 793 | |||
| 794 | return false; | ||
| 795 | } | ||
| 796 | |||
| 797 | static bool eval_for_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 798 | assert(node->type == NodeTypeForExpr); | ||
| 799 | |||
| 800 | AstNode *array_node = node->data.for_expr.array_expr; | ||
| 801 | AstNode *elem_node = node->data.for_expr.elem_node; | ||
| 802 | AstNode *index_node = node->data.for_expr.index_node; | ||
| 803 | AstNode *body_node = node->data.for_expr.body; | ||
| 804 | |||
| 805 | TypeTableEntry *array_type = get_resolved_expr(array_node)->type_entry; | ||
| 806 | |||
| 807 | ConstExprValue array_val = {0}; | ||
| 808 | if (eval_expr(ef, array_node, &array_val)) return true; | ||
| 809 | |||
| 810 | assert(elem_node->type == NodeTypeSymbol); | ||
| 811 | Buf *elem_var_name = &elem_node->data.symbol_expr.symbol; | ||
| 812 | |||
| 813 | Buf *index_var_name = nullptr; | ||
| 814 | if (index_node) { | ||
| 815 | assert(index_node->type == NodeTypeSymbol); | ||
| 816 | index_var_name = &index_node->data.symbol_expr.symbol; | ||
| 817 | } | ||
| 818 | |||
| 819 | uint64_t it_index = 0; | ||
| 820 | uint64_t array_len; | ||
| 821 | ConstExprValue **array_ptr_val; | ||
| 822 | if (array_type->id == TypeTableEntryIdArray) { | ||
| 823 | array_len = array_type->data.array.len; | ||
| 824 | array_ptr_val = array_val.data.x_array.fields; | ||
| 825 | } else if (array_type->id == TypeTableEntryIdStruct) { | ||
| 826 | ConstExprValue *len_field_val = array_val.data.x_struct.fields[1]; | ||
| 827 | array_len = len_field_val->data.x_bignum.data.x_uint; | ||
| 828 | array_ptr_val = array_val.data.x_struct.fields[0]->data.x_ptr.ptr; | ||
| 829 | } else { | ||
| 830 | zig_unreachable(); | ||
| 831 | } | ||
| 832 | |||
| 833 | EvalScope *my_scope = allocate<EvalScope>(1); | ||
| 834 | my_scope->block_context = body_node->block_context; | ||
| 835 | ef->scope_stack.append(my_scope); | ||
| 836 | |||
| 837 | for (; it_index < array_len; it_index += 1) { | ||
| 838 | my_scope->vars.resize(0); | ||
| 839 | |||
| 840 | if (index_var_name) { | ||
| 841 | my_scope->vars.add_one(); | ||
| 842 | EvalVar *index_var = &my_scope->vars.last(); | ||
| 843 | index_var->name = index_var_name; | ||
| 844 | memset(&index_var->value, 0, sizeof(ConstExprValue)); | ||
| 845 | index_var->value.ok = true; | ||
| 846 | bignum_init_unsigned(&index_var->value.data.x_bignum, it_index); | ||
| 847 | } | ||
| 848 | { | ||
| 849 | my_scope->vars.add_one(); | ||
| 850 | EvalVar *elem_var = &my_scope->vars.last(); | ||
| 851 | elem_var->name = elem_var_name; | ||
| 852 | elem_var->value = *array_ptr_val[it_index]; | ||
| 853 | } | ||
| 854 | |||
| 855 | ConstExprValue body_val = {0}; | ||
| 856 | if (eval_expr(ef, body_node, &body_val)) return true; | ||
| 857 | |||
| 858 | ef->root->branches_used += 1; | ||
| 859 | } | ||
| 860 | |||
| 861 | ef->scope_stack.pop(); | ||
| 862 | |||
| 863 | return false; | ||
| 864 | } | ||
| 865 | |||
| 866 | static bool eval_array_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 867 | assert(node->type == NodeTypeArrayAccessExpr); | ||
| 868 | |||
| 869 | AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr; | ||
| 870 | AstNode *index_node = node->data.array_access_expr.subscript; | ||
| 871 | |||
| 872 | TypeTableEntry *array_type = get_resolved_expr(array_ref_node)->type_entry; | ||
| 873 | |||
| 874 | ConstExprValue array_val = {0}; | ||
| 875 | if (eval_expr(ef, array_ref_node, &array_val)) return true; | ||
| 876 | |||
| 877 | ConstExprValue index_val = {0}; | ||
| 878 | if (eval_expr(ef, index_node, &index_val)) return true; | ||
| 879 | uint64_t index_int = index_val.data.x_bignum.data.x_uint; | ||
| 880 | |||
| 881 | if (array_type->id == TypeTableEntryIdPointer) { | ||
| 882 | if (index_int >= array_val.data.x_ptr.len) { | ||
| 883 | zig_panic("TODO"); | ||
| 884 | } | ||
| 885 | *out_val = *array_val.data.x_ptr.ptr[index_int]; | ||
| 886 | } else if (array_type->id == TypeTableEntryIdStruct) { | ||
| 887 | assert(array_type->data.structure.is_unknown_size_array); | ||
| 888 | |||
| 889 | ConstExprValue *len_value = array_val.data.x_struct.fields[1]; | ||
| 890 | uint64_t len_int = len_value->data.x_bignum.data.x_uint; | ||
| 891 | if (index_int >= len_int) { | ||
| 892 | zig_panic("TODO"); | ||
| 893 | } | ||
| 894 | |||
| 895 | ConstExprValue *ptr_value = array_val.data.x_struct.fields[0]; | ||
| 896 | *out_val = *ptr_value->data.x_ptr.ptr[index_int]; | ||
| 897 | } else if (array_type->id == TypeTableEntryIdArray) { | ||
| 898 | uint64_t array_len = array_type->data.array.len; | ||
| 899 | if (index_int >= array_len) { | ||
| 900 | zig_panic("TODO"); | ||
| 901 | } | ||
| 902 | *out_val = *array_val.data.x_array.fields[index_int]; | ||
| 903 | } else { | ||
| 904 | zig_unreachable(); | ||
| 905 | } | ||
| 906 | |||
| 907 | return false; | ||
| 908 | } | ||
| 909 | |||
| 910 | static bool eval_bool_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 911 | assert(node->type == NodeTypeBoolLiteral); | ||
| 912 | |||
| 913 | out_val->ok = true; | ||
| 914 | out_val->data.x_bool = node->data.bool_literal.value; | ||
| 915 | |||
| 916 | return false; | ||
| 917 | } | ||
| 918 | |||
| 919 | static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 920 | assert(node->type == NodeTypePrefixOpExpr); | ||
| 921 | |||
| 922 | PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op; | ||
| 923 | AstNode *expr_node = node->data.prefix_op_expr.primary_expr; | ||
| 924 | |||
| 925 | ConstExprValue expr_val = {0}; | ||
| 926 | if (eval_expr(ef, expr_node, &expr_val)) return true; | ||
| 927 | |||
| 928 | TypeTableEntry *expr_type = get_resolved_expr(expr_node)->type_entry; | ||
| 929 | |||
| 930 | switch (prefix_op) { | ||
| 931 | case PrefixOpBoolNot: | ||
| 932 | *out_val = expr_val; | ||
| 933 | out_val->data.x_bool = !out_val->data.x_bool; | ||
| 934 | break; | ||
| 935 | case PrefixOpDereference: | ||
| 936 | assert(expr_type->id == TypeTableEntryIdPointer); | ||
| 937 | *out_val = *expr_val.data.x_ptr.ptr[0]; | ||
| 938 | break; | ||
| 939 | case PrefixOpAddressOf: | ||
| 940 | case PrefixOpConstAddressOf: | ||
| 941 | { | ||
| 942 | ConstExprValue *child_val = allocate<ConstExprValue>(1); | ||
| 943 | *child_val = expr_val; | ||
| 944 | |||
| 945 | ConstExprValue **ptr_val = allocate<ConstExprValue*>(1); | ||
| 946 | *ptr_val = child_val; | ||
| 947 | |||
| 948 | out_val->data.x_ptr.ptr = ptr_val; | ||
| 949 | out_val->data.x_ptr.len = 1; | ||
| 950 | out_val->ok = true; | ||
| 951 | break; | ||
| 952 | } | ||
| 953 | case PrefixOpBinNot: | ||
| 954 | case PrefixOpNegation: | ||
| 955 | case PrefixOpMaybe: | ||
| 956 | case PrefixOpError: | ||
| 957 | case PrefixOpUnwrapError: | ||
| 958 | case PrefixOpUnwrapMaybe: | ||
| 959 | zig_panic("TODO"); | ||
| 960 | case PrefixOpInvalid: | ||
| 961 | zig_unreachable(); | ||
| 962 | } | ||
| 963 | |||
| 964 | return false; | ||
| 965 | } | ||
| 966 | |||
| 967 | static bool eval_var_decl_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 968 | assert(node->type == NodeTypeVariableDeclaration); | ||
| 969 | |||
| 970 | assert(node->data.variable_declaration.expr); | ||
| 971 | |||
| 972 | EvalScope *my_scope = ef->scope_stack.at(ef->scope_stack.length - 1); | ||
| 973 | |||
| 974 | my_scope->vars.add_one(); | ||
| 975 | EvalVar *var = &my_scope->vars.last(); | ||
| 976 | var->name = &node->data.variable_declaration.symbol; | ||
| 977 | |||
| 978 | if (eval_expr(ef, node->data.variable_declaration.expr, &var->value)) return true; | ||
| 979 | |||
| 980 | out_val->ok = true; | ||
| 981 | |||
| 982 | return false; | ||
| 983 | } | ||
| 984 | |||
| 985 | static bool eval_number_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 986 | assert(node->type == NodeTypeNumberLiteral); | ||
| 987 | assert(!node->data.number_literal.overflow); | ||
| 988 | |||
| 989 | out_val->ok = true; | ||
| 990 | if (node->data.number_literal.kind == NumLitUInt) { | ||
| 991 | bignum_init_unsigned(&out_val->data.x_bignum, node->data.number_literal.data.x_uint); | ||
| 992 | } else if (node->data.number_literal.kind == NumLitFloat) { | ||
| 993 | bignum_init_float(&out_val->data.x_bignum, node->data.number_literal.data.x_float); | ||
| 994 | } else { | ||
| 995 | zig_unreachable(); | ||
| 996 | } | ||
| 997 | |||
| 998 | return false; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | static bool eval_char_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 1002 | assert(node->type == NodeTypeCharLiteral); | ||
| 1003 | |||
| 1004 | out_val->ok = true; | ||
| 1005 | bignum_init_unsigned(&out_val->data.x_bignum, node->data.char_literal.value); | ||
| 1006 | |||
| 1007 | return false; | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | static bool eval_while_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) { | ||
| 1011 | assert(node->type == NodeTypeWhileExpr); | ||
| 1012 | |||
| 1013 | AstNode *cond_node = node->data.while_expr.condition; | ||
| 1014 | AstNode *body_node = node->data.while_expr.body; | ||
| 1015 | |||
| 1016 | EvalScope *my_scope = allocate<EvalScope>(1); | ||
| 1017 | my_scope->block_context = body_node->block_context; | ||
| 1018 | ef->scope_stack.append(my_scope); | ||
| 1019 | |||
| 1020 | for (;;) { | ||
| 1021 | my_scope->vars.resize(0); | ||
| 1022 | |||
| 1023 | ConstExprValue cond_val = {0}; | ||
| 1024 | if (eval_expr(ef, cond_node, &cond_val)) return true; | ||
| 1025 | |||
| 1026 | if (!cond_val.data.x_bool) break; | ||
| 1027 | |||
| 1028 | ConstExprValue body_val = {0}; | ||
| 1029 | if (eval_expr(ef, body_node, &body_val)) return true; | ||
| 1030 | |||
| 1031 | ef->root->branches_used += 1; | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | ef->scope_stack.pop(); | ||
| 1035 | |||
| 1036 | return false; | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) { | ||
| 1040 | if (ef->root->branches_used > ef->root->branch_quota) { | ||
| 1041 | ef->root->exceeded_quota_node = node; | ||
| 1042 | return true; | ||
| 1043 | } | ||
| 1044 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; | ||
| 1045 | if (const_val->ok) { | ||
| 1046 | *out = *const_val; | ||
| 1047 | return false; | ||
| 1048 | } | ||
| 1049 | switch (node->type) { | ||
| 1050 | case NodeTypeBlock: | ||
| 1051 | return eval_block(ef, node, out); | ||
| 1052 | case NodeTypeReturnExpr: | ||
| 1053 | return eval_return(ef, node, out); | ||
| 1054 | case NodeTypeBinOpExpr: | ||
| 1055 | return eval_bin_op_expr(ef, node, out); | ||
| 1056 | case NodeTypeSymbol: | ||
| 1057 | return eval_symbol_expr(ef, node, out); | ||
| 1058 | case NodeTypeContainerInitExpr: | ||
| 1059 | return eval_container_init_expr(ef, node, out); | ||
| 1060 | case NodeTypeIfBoolExpr: | ||
| 1061 | return eval_if_bool_expr(ef, node, out); | ||
| 1062 | case NodeTypeFnCallExpr: | ||
| 1063 | return eval_fn_call_expr(ef, node, out); | ||
| 1064 | case NodeTypeFieldAccessExpr: | ||
| 1065 | return eval_field_access_expr(ef, node, out); | ||
| 1066 | case NodeTypeForExpr: | ||
| 1067 | return eval_for_expr(ef, node, out); | ||
| 1068 | case NodeTypeArrayAccessExpr: | ||
| 1069 | return eval_array_access_expr(ef, node, out); | ||
| 1070 | case NodeTypeBoolLiteral: | ||
| 1071 | return eval_bool_literal_expr(ef, node, out); | ||
| 1072 | case NodeTypePrefixOpExpr: | ||
| 1073 | return eval_prefix_op_expr(ef, node, out); | ||
| 1074 | case NodeTypeVariableDeclaration: | ||
| 1075 | return eval_var_decl_expr(ef, node, out); | ||
| 1076 | case NodeTypeNumberLiteral: | ||
| 1077 | return eval_number_literal_expr(ef, node, out); | ||
| 1078 | case NodeTypeCharLiteral: | ||
| 1079 | return eval_char_literal_expr(ef, node, out); | ||
| 1080 | case NodeTypeWhileExpr: | ||
| 1081 | return eval_while_expr(ef, node, out); | ||
| 1082 | case NodeTypeDefer: | ||
| 1083 | case NodeTypeErrorValueDecl: | ||
| 1084 | case NodeTypeUnwrapErrorExpr: | ||
| 1085 | case NodeTypeStringLiteral: | ||
| 1086 | case NodeTypeSliceExpr: | ||
| 1087 | case NodeTypeNullLiteral: | ||
| 1088 | case NodeTypeUndefinedLiteral: | ||
| 1089 | case NodeTypeIfVarExpr: | ||
| 1090 | case NodeTypeSwitchExpr: | ||
| 1091 | case NodeTypeSwitchProng: | ||
| 1092 | case NodeTypeSwitchRange: | ||
| 1093 | case NodeTypeLabel: | ||
| 1094 | case NodeTypeGoto: | ||
| 1095 | case NodeTypeBreak: | ||
| 1096 | case NodeTypeContinue: | ||
| 1097 | case NodeTypeStructDecl: | ||
| 1098 | case NodeTypeStructField: | ||
| 1099 | case NodeTypeStructValueField: | ||
| 1100 | case NodeTypeArrayType: | ||
| 1101 | case NodeTypeErrorType: | ||
| 1102 | case NodeTypeTypeLiteral: | ||
| 1103 | zig_panic("TODO"); | ||
| 1104 | case NodeTypeRoot: | ||
| 1105 | case NodeTypeFnProto: | ||
| 1106 | case NodeTypeFnDef: | ||
| 1107 | case NodeTypeFnDecl: | ||
| 1108 | case NodeTypeUse: | ||
| 1109 | case NodeTypeAsmExpr: | ||
| 1110 | case NodeTypeParamDecl: | ||
| 1111 | case NodeTypeDirective: | ||
| 1112 | case NodeTypeTypeDecl: | ||
| 1113 | zig_unreachable(); | ||
| 1114 | } | ||
| 1115 | } | ||
| 1116 | |||
| 1117 | static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val) { | ||
| 1118 | EvalFn ef = {0}; | ||
| 1119 | ef.root = efr; | ||
| 1120 | ef.fn = fn; | ||
| 1121 | ef.return_expr = out_val; | ||
| 1122 | |||
| 1123 | EvalScope *root_scope = allocate<EvalScope>(1); | ||
| 1124 | root_scope->block_context = fn->fn_def_node->data.fn_def.body->block_context; | ||
| 1125 | ef.scope_stack.append(root_scope); | ||
| 1126 | |||
| 1127 | int param_count = fn->type_entry->data.fn.fn_type_id.param_count; | ||
| 1128 | for (int i = 0; i < param_count; i += 1) { | ||
| 1129 | AstNode *decl_param_node = fn->proto_node->data.fn_proto.params.at(i); | ||
| 1130 | assert(decl_param_node->type == NodeTypeParamDecl); | ||
| 1131 | |||
| 1132 | ConstExprValue *src_const_val = &args[i]; | ||
| 1133 | assert(src_const_val->ok); | ||
| 1134 | |||
| 1135 | root_scope->vars.add_one(); | ||
| 1136 | EvalVar *eval_var = &root_scope->vars.last(); | ||
| 1137 | eval_var->name = &decl_param_node->data.param_decl.name; | ||
| 1138 | eval_var->value = *src_const_val; | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | return eval_expr(&ef, fn->fn_def_node->data.fn_def.body, out_val); | ||
| 1142 | |||
| 1143 | } | ||
| 1144 | |||
| 1145 | bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_val, | ||
| 1146 | int branch_quota, AstNode *struct_node) | ||
| 1147 | { | ||
| 1148 | assert(node->type == NodeTypeFnCallExpr); | ||
| 1149 | |||
| 1150 | EvalFnRoot efr = {0}; | ||
| 1151 | efr.codegen = g; | ||
| 1152 | efr.fn = fn; | ||
| 1153 | efr.call_node = node; | ||
| 1154 | efr.branch_quota = branch_quota; | ||
| 1155 | |||
| 1156 | int call_param_count = node->data.fn_call_expr.params.length; | ||
| 1157 | int type_param_count = fn->type_entry->data.fn.fn_type_id.param_count; | ||
| 1158 | ConstExprValue *args = allocate<ConstExprValue>(type_param_count); | ||
| 1159 | int next_arg_index = 0; | ||
| 1160 | if (struct_node) { | ||
| 1161 | ConstExprValue *struct_val = &get_resolved_expr(struct_node)->const_val; | ||
| 1162 | assert(struct_val->ok); | ||
| 1163 | args[next_arg_index] = *struct_val; | ||
| 1164 | next_arg_index += 1; | ||
| 1165 | } | ||
| 1166 | for (int call_index = 0; call_index < call_param_count; call_index += 1) { | ||
| 1167 | AstNode *call_param_node = node->data.fn_call_expr.params.at(call_index); | ||
| 1168 | ConstExprValue *src_const_val = &get_resolved_expr(call_param_node)->const_val; | ||
| 1169 | assert(src_const_val->ok); | ||
| 1170 | args[next_arg_index] = *src_const_val; | ||
| 1171 | next_arg_index += 1; | ||
| 1172 | } | ||
| 1173 | eval_fn_args(&efr, fn, args, out_val); | ||
| 1174 | |||
| 1175 | if (efr.exceeded_quota_node) { | ||
| 1176 | ErrorMsg *msg = add_node_error(g, fn->fn_def_node, | ||
| 1177 | buf_sprintf("function evaluation exceeded %d branches", efr.branch_quota)); | ||
| 1178 | |||
| 1179 | add_error_note(g, msg, efr.call_node, buf_sprintf("called from here")); | ||
| 1180 | add_error_note(g, msg, efr.exceeded_quota_node, buf_sprintf("quota exceeded here")); | ||
| 1181 | return true; | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | if (efr.abort) { | ||
| 1185 | return true; | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | assert(out_val->ok); | ||
| 1189 | return false; | ||
| 1190 | } | ||
| 1191 | |||
src/eval.hpp created+26| ... | @@ -0,0 +1,26 @@ | ||
| 1 | /* | ||
| 2 | * Copyright (c) 2016 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef ZIG_EVAL_HPP | ||
| 9 | #define ZIG_EVAL_HPP | ||
| 10 | |||
| 11 | #include "all_types.hpp" | ||
| 12 | |||
| 13 | bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_val, int branch_quota, | ||
| 14 | AstNode *struct_node); | ||
| 15 | |||
| 16 | bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry); | ||
| 17 | int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, | ||
| 18 | BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val); | ||
| 19 | |||
| 20 | void eval_const_expr_implicit_cast(CastOp cast_op, | ||
| 21 | ConstExprValue *other_val, TypeTableEntry *other_type, | ||
| 22 | ConstExprValue *const_val, TypeTableEntry *new_type); | ||
| 23 | |||
| 24 | void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max); | ||
| 25 | |||
| 26 | #endif | ||
src/parser.cpp+15-7| ... | @@ -2927,6 +2927,7 @@ static void clone_subtree_list(ZigList<AstNode *> *dest, ZigList<AstNode *> *src | ... | @@ -2927,6 +2927,7 @@ static void clone_subtree_list(ZigList<AstNode *> *dest, ZigList<AstNode *> *src |
| 2927 | dest->resize(src->length); | 2927 | dest->resize(src->length); |
| 2928 | for (int i = 0; i < src->length; i += 1) { | 2928 | for (int i = 0; i < src->length; i += 1) { |
| 2929 | dest->at(i) = ast_clone_subtree(src->at(i), next_node_index); | 2929 | dest->at(i) = ast_clone_subtree(src->at(i), next_node_index); |
| 2930 | dest->at(i)->parent_field = &dest->at(i); | ||
| 2930 | } | 2931 | } |
| 2931 | } | 2932 | } |
| 2932 | 2933 | ||
| ... | @@ -2958,11 +2959,12 @@ AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) { | ... | @@ -2958,11 +2959,12 @@ AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) { |
| 2958 | memcpy(new_node, old_node, sizeof(AstNode)); | 2959 | memcpy(new_node, old_node, sizeof(AstNode)); |
| 2959 | new_node->create_index = *next_node_index; | 2960 | new_node->create_index = *next_node_index; |
| 2960 | *next_node_index += 1; | 2961 | *next_node_index += 1; |
| 2962 | new_node->parent_field = nullptr; | ||
| 2961 | 2963 | ||
| 2962 | switch (new_node->type) { | 2964 | switch (new_node->type) { |
| 2963 | case NodeTypeRoot: | 2965 | case NodeTypeRoot: |
| 2964 | clone_subtree_list(&new_node->data.root.top_level_decls, &old_node->data.root.top_level_decls, | 2966 | clone_subtree_list(&new_node->data.root.top_level_decls, |
| 2965 | next_node_index); | 2967 | &old_node->data.root.top_level_decls, next_node_index); |
| 2966 | break; | 2968 | break; |
| 2967 | case NodeTypeFnProto: | 2969 | case NodeTypeFnProto: |
| 2968 | clone_subtree_tld(&new_node->data.fn_proto.top_level_decl, &old_node->data.fn_proto.top_level_decl, | 2970 | clone_subtree_tld(&new_node->data.fn_proto.top_level_decl, &old_node->data.fn_proto.top_level_decl, |
| ... | @@ -3036,15 +3038,21 @@ AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) { | ... | @@ -3036,15 +3038,21 @@ AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) { |
| 3036 | // none | 3038 | // none |
| 3037 | break; | 3039 | break; |
| 3038 | case NodeTypePrefixOpExpr: | 3040 | case NodeTypePrefixOpExpr: |
| 3039 | clone_subtree_field(&new_node->data.prefix_op_expr.primary_expr, old_node->data.prefix_op_expr.primary_expr, next_node_index); | 3041 | clone_subtree_field(&new_node->data.prefix_op_expr.primary_expr, |
| 3042 | old_node->data.prefix_op_expr.primary_expr, next_node_index); | ||
| 3040 | break; | 3043 | break; |
| 3041 | case NodeTypeFnCallExpr: | 3044 | case NodeTypeFnCallExpr: |
| 3042 | clone_subtree_field(&new_node->data.fn_call_expr.fn_ref_expr, old_node->data.fn_call_expr.fn_ref_expr, next_node_index); | 3045 | assert(!old_node->data.fn_call_expr.resolved_expr.has_global_const); |
| 3043 | clone_subtree_list(&new_node->data.fn_call_expr.params, &old_node->data.fn_call_expr.params, next_node_index); | 3046 | clone_subtree_field(&new_node->data.fn_call_expr.fn_ref_expr, |
| 3047 | old_node->data.fn_call_expr.fn_ref_expr, next_node_index); | ||
| 3048 | clone_subtree_list(&new_node->data.fn_call_expr.params, | ||
| 3049 | &old_node->data.fn_call_expr.params, next_node_index); | ||
| 3044 | break; | 3050 | break; |
| 3045 | case NodeTypeArrayAccessExpr: | 3051 | case NodeTypeArrayAccessExpr: |
| 3046 | clone_subtree_field(&new_node->data.array_access_expr.array_ref_expr, old_node->data.array_access_expr.array_ref_expr, next_node_index); | 3052 | clone_subtree_field(&new_node->data.array_access_expr.array_ref_expr, |
| 3047 | clone_subtree_field(&new_node->data.array_access_expr.subscript, old_node->data.array_access_expr.subscript, next_node_index); | 3053 | old_node->data.array_access_expr.array_ref_expr, next_node_index); |
| 3054 | clone_subtree_field(&new_node->data.array_access_expr.subscript, | ||
| 3055 | old_node->data.array_access_expr.subscript, next_node_index); | ||
| 3048 | break; | 3056 | break; |
| 3049 | case NodeTypeSliceExpr: | 3057 | case NodeTypeSliceExpr: |
| 3050 | clone_subtree_field(&new_node->data.slice_expr.array_ref_expr, old_node->data.slice_expr.array_ref_expr, next_node_index); | 3058 | clone_subtree_field(&new_node->data.slice_expr.array_ref_expr, old_node->data.slice_expr.array_ref_expr, next_node_index); |
std/rand.zig+1| ... | @@ -7,6 +7,7 @@ pub struct Rand { | ... | @@ -7,6 +7,7 @@ pub struct Rand { |
| 7 | index: isize, | 7 | index: isize, |
| 8 | 8 | ||
| 9 | /// Initialize random state with the given seed. | 9 | /// Initialize random state with the given seed. |
| 10 | #static_eval_enable(false) | ||
| 10 | pub fn init(seed: u32) -> Rand { | 11 | pub fn init(seed: u32) -> Rand { |
| 11 | var r: Rand = undefined; | 12 | var r: Rand = undefined; |
| 12 | r.index = 0; | 13 | r.index = 0; |
test/run_tests.cpp+29-122| ... | @@ -218,6 +218,7 @@ pub fn bar_function() { | ... | @@ -218,6 +218,7 @@ pub fn bar_function() { |
| 218 | )SOURCE"); | 218 | )SOURCE"); |
| 219 | 219 | ||
| 220 | add_source_file(tc, "other.zig", R"SOURCE( | 220 | add_source_file(tc, "other.zig", R"SOURCE( |
| 221 | #static_eval_enable(false) | ||
| 221 | pub fn foo_function() -> bool { | 222 | pub fn foo_function() -> bool { |
| 222 | // this one conflicts with the one from foo | 223 | // this one conflicts with the one from foo |
| 223 | return true; | 224 | return true; |
| ... | @@ -406,20 +407,6 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -406,20 +407,6 @@ pub fn main(args: [][]u8) -> %void { |
| 406 | } | 407 | } |
| 407 | )SOURCE", "loop\nloop\nloop\nloop\n"); | 408 | )SOURCE", "loop\nloop\nloop\nloop\n"); |
| 408 | 409 | ||
| 409 | add_simple_case("implicit cast after unreachable", R"SOURCE( | ||
| 410 | const io = @import("std").io; | ||
| 411 | pub fn main(args: [][]u8) -> %void { | ||
| 412 | const x = outer(); | ||
| 413 | if (x == 1234) { | ||
| 414 | %%io.stdout.printf("OK\n"); | ||
| 415 | } | ||
| 416 | } | ||
| 417 | fn inner() -> i32 { 1234 } | ||
| 418 | fn outer() -> isize { | ||
| 419 | return inner(); | ||
| 420 | } | ||
| 421 | )SOURCE", "OK\n"); | ||
| 422 | |||
| 423 | add_simple_case("@sizeof() and @typeof()", R"SOURCE( | 410 | add_simple_case("@sizeof() and @typeof()", R"SOURCE( |
| 424 | const io = @import("std").io; | 411 | const io = @import("std").io; |
| 425 | const x: u16 = 13; | 412 | const x: u16 = 13; |
| ... | @@ -431,23 +418,6 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -431,23 +418,6 @@ pub fn main(args: [][]u8) -> %void { |
| 431 | } | 418 | } |
| 432 | )SOURCE", "2\n"); | 419 | )SOURCE", "2\n"); |
| 433 | 420 | ||
| 434 | add_simple_case("member functions", R"SOURCE( | ||
| 435 | const io = @import("std").io; | ||
| 436 | struct Rand { | ||
| 437 | seed: u32, | ||
| 438 | pub fn get_seed(r: Rand) -> u32 { | ||
| 439 | r.seed | ||
| 440 | } | ||
| 441 | } | ||
| 442 | pub fn main(args: [][]u8) -> %void { | ||
| 443 | const r = Rand {.seed = 1234}; | ||
| 444 | if (r.get_seed() != 1234) { | ||
| 445 | %%io.stdout.printf("BAD seed\n"); | ||
| 446 | } | ||
| 447 | %%io.stdout.printf("OK\n"); | ||
| 448 | } | ||
| 449 | )SOURCE", "OK\n"); | ||
| 450 | |||
| 451 | add_simple_case("pointer dereferencing", R"SOURCE( | 421 | add_simple_case("pointer dereferencing", R"SOURCE( |
| 452 | const io = @import("std").io; | 422 | const io = @import("std").io; |
| 453 | 423 | ||
| ... | @@ -565,24 +535,6 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -565,24 +535,6 @@ pub fn main(args: [][]u8) -> %void { |
| 565 | "min i64: -9223372036854775808\n"); | 535 | "min i64: -9223372036854775808\n"); |
| 566 | 536 | ||
| 567 | 537 | ||
| 568 | add_simple_case("else if expression", R"SOURCE( | ||
| 569 | const io = @import("std").io; | ||
| 570 | pub fn main(args: [][]u8) -> %void { | ||
| 571 | if (f(1) == 1) { | ||
| 572 | %%io.stdout.printf("OK\n"); | ||
| 573 | } | ||
| 574 | } | ||
| 575 | fn f(c: u8) -> u8 { | ||
| 576 | if (c == 0) { | ||
| 577 | 0 | ||
| 578 | } else if (c == 1) { | ||
| 579 | 1 | ||
| 580 | } else { | ||
| 581 | 2 | ||
| 582 | } | ||
| 583 | } | ||
| 584 | )SOURCE", "OK\n"); | ||
| 585 | |||
| 586 | add_simple_case("overflow intrinsics", R"SOURCE( | 538 | add_simple_case("overflow intrinsics", R"SOURCE( |
| 587 | const io = @import("std").io; | 539 | const io = @import("std").io; |
| 588 | pub fn main(args: [][]u8) -> %void { | 540 | pub fn main(args: [][]u8) -> %void { |
| ... | @@ -730,29 +682,6 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -730,29 +682,6 @@ pub fn main(args: [][]u8) -> %void { |
| 730 | } | 682 | } |
| 731 | )SOURCE", "OK\n"); | 683 | )SOURCE", "OK\n"); |
| 732 | 684 | ||
| 733 | add_simple_case("%% binary operator", R"SOURCE( | ||
| 734 | const io = @import("std").io; | ||
| 735 | error ItBroke; | ||
| 736 | fn g(x: bool) -> %isize { | ||
| 737 | if (x) { | ||
| 738 | error.ItBroke | ||
| 739 | } else { | ||
| 740 | 10 | ||
| 741 | } | ||
| 742 | } | ||
| 743 | pub fn main(args: [][]u8) -> %void { | ||
| 744 | const a = g(true) %% 3; | ||
| 745 | const b = g(false) %% 3; | ||
| 746 | if (a != 3) { | ||
| 747 | %%io.stdout.printf("BAD\n"); | ||
| 748 | } | ||
| 749 | if (b != 10) { | ||
| 750 | %%io.stdout.printf("BAD\n"); | ||
| 751 | } | ||
| 752 | %%io.stdout.printf("OK\n"); | ||
| 753 | } | ||
| 754 | )SOURCE", "OK\n"); | ||
| 755 | |||
| 756 | add_simple_case("string concatenation", R"SOURCE( | 685 | add_simple_case("string concatenation", R"SOURCE( |
| 757 | const io = @import("std").io; | 686 | const io = @import("std").io; |
| 758 | pub fn main(args: [][]u8) -> %void { | 687 | pub fn main(args: [][]u8) -> %void { |
| ... | @@ -808,54 +737,6 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -808,54 +737,6 @@ pub fn main(args: [][]u8) -> %void { |
| 808 | } | 737 | } |
| 809 | )SOURCE", "OK\n"); | 738 | )SOURCE", "OK\n"); |
| 810 | 739 | ||
| 811 | add_simple_case("unwrap simple value from error", R"SOURCE( | ||
| 812 | const io = @import("std").io; | ||
| 813 | fn do() -> %isize { | ||
| 814 | 13 | ||
| 815 | } | ||
| 816 | |||
| 817 | pub fn main(args: [][]u8) -> %void { | ||
| 818 | const i = %%do(); | ||
| 819 | if (i != 13) { | ||
| 820 | %%io.stdout.printf("BAD\n"); | ||
| 821 | } | ||
| 822 | %%io.stdout.printf("OK\n"); | ||
| 823 | } | ||
| 824 | )SOURCE", "OK\n"); | ||
| 825 | |||
| 826 | add_simple_case("store member function in variable", R"SOURCE( | ||
| 827 | const io = @import("std").io; | ||
| 828 | struct Foo { | ||
| 829 | x: i32, | ||
| 830 | fn member(foo: Foo) -> i32 { foo.x } | ||
| 831 | } | ||
| 832 | pub fn main(args: [][]u8) -> %void { | ||
| 833 | const instance = Foo { .x = 1234, }; | ||
| 834 | const member_fn = Foo.member; | ||
| 835 | const result = member_fn(instance); | ||
| 836 | if (result != 1234) { | ||
| 837 | %%io.stdout.printf("BAD\n"); | ||
| 838 | } | ||
| 839 | %%io.stdout.printf("OK\n"); | ||
| 840 | } | ||
| 841 | )SOURCE", "OK\n"); | ||
| 842 | |||
| 843 | add_simple_case("call member function directly", R"SOURCE( | ||
| 844 | const io = @import("std").io; | ||
| 845 | struct Foo { | ||
| 846 | x: i32, | ||
| 847 | fn member(foo: Foo) -> i32 { foo.x } | ||
| 848 | } | ||
| 849 | pub fn main(args: [][]u8) -> %void { | ||
| 850 | const instance = Foo { .x = 1234, }; | ||
| 851 | const result = Foo.member(instance); | ||
| 852 | if (result != 1234) { | ||
| 853 | %%io.stdout.printf("BAD\n"); | ||
| 854 | } | ||
| 855 | %%io.stdout.printf("OK\n"); | ||
| 856 | } | ||
| 857 | )SOURCE", "OK\n"); | ||
| 858 | |||
| 859 | add_simple_case("call result of if else expression", R"SOURCE( | 740 | add_simple_case("call result of if else expression", R"SOURCE( |
| 860 | const io = @import("std").io; | 741 | const io = @import("std").io; |
| 861 | fn a() -> []u8 { "a\n" } | 742 | fn a() -> []u8 { "a\n" } |
| ... | @@ -1496,7 +1377,8 @@ fn a(x: i32) { | ... | @@ -1496,7 +1377,8 @@ fn a(x: i32) { |
| 1496 | struct Foo { | 1377 | struct Foo { |
| 1497 | y: [get()]u8, | 1378 | y: [get()]u8, |
| 1498 | } | 1379 | } |
| 1499 | fn get() -> isize { 1 } | 1380 | var global_var: isize = 1; |
| 1381 | fn get() -> isize { global_var } | ||
| 1500 | )SOURCE", 1, ".tmp_source.zig:3:9: error: unable to evaluate constant expression"); | 1382 | )SOURCE", 1, ".tmp_source.zig:3:9: error: unable to evaluate constant expression"); |
| 1501 | 1383 | ||
| 1502 | 1384 | ||
| ... | @@ -1599,6 +1481,31 @@ fn foo() { | ... | @@ -1599,6 +1481,31 @@ fn foo() { |
| 1599 | const pointer = &array[0]; | 1481 | const pointer = &array[0]; |
| 1600 | } | 1482 | } |
| 1601 | )SOURCE", 1, ".tmp_source.zig:4:27: error: out of bounds array access"); | 1483 | )SOURCE", 1, ".tmp_source.zig:4:27: error: out of bounds array access"); |
| 1484 | |||
| 1485 | add_compile_fail_case("compile time division by zero", R"SOURCE( | ||
| 1486 | const x = foo(0); | ||
| 1487 | fn foo(x: i32) -> i32 { | ||
| 1488 | 1 / x | ||
| 1489 | } | ||
| 1490 | )SOURCE", 3, | ||
| 1491 | ".tmp_source.zig:3:1: error: function evaluation caused division by zero", | ||
| 1492 | ".tmp_source.zig:2:14: note: called from here", | ||
| 1493 | ".tmp_source.zig:4:7: note: division by zero here"); | ||
| 1494 | |||
| 1495 | add_compile_fail_case("branch on undefined value", R"SOURCE( | ||
| 1496 | const x = if (undefined) true else false; | ||
| 1497 | )SOURCE", 1, ".tmp_source.zig:2:15: error: branch on undefined value"); | ||
| 1498 | |||
| 1499 | |||
| 1500 | add_compile_fail_case("endless loop in function evaluation", R"SOURCE( | ||
| 1501 | const seventh_fib_number = fibbonaci(7); | ||
| 1502 | fn fibbonaci(x: i32) -> i32 { | ||
| 1503 | return fibbonaci(x - 1) + fibbonaci(x - 2); | ||
| 1504 | } | ||
| 1505 | )SOURCE", 3, | ||
| 1506 | ".tmp_source.zig:3:1: error: function evaluation exceeded 1000 branches", | ||
| 1507 | ".tmp_source.zig:2:37: note: called from here", | ||
| 1508 | ".tmp_source.zig:4:40: note: quota exceeded here"); | ||
| 1602 | } | 1509 | } |
| 1603 | 1510 | ||
| 1604 | ////////////////////////////////////////////////////////////////////////////// | 1511 | ////////////////////////////////////////////////////////////////////////////// |
| ... | @@ -1760,7 +1667,7 @@ extern void (*fn_ptr)(void); | ... | @@ -1760,7 +1667,7 @@ extern void (*fn_ptr)(void); |
| 1760 | )SOURCE", 2, | 1667 | )SOURCE", 2, |
| 1761 | "pub extern var fn_ptr: ?extern fn();", | 1668 | "pub extern var fn_ptr: ?extern fn();", |
| 1762 | R"SOURCE(pub inline fn foo() { | 1669 | R"SOURCE(pub inline fn foo() { |
| 1763 | (??fn_ptr)() | 1670 | (??fn_ptr)(); |
| 1764 | })SOURCE"); | 1671 | })SOURCE"); |
| 1765 | 1672 | ||
| 1766 | 1673 |
test/self_hosted.zig+175-9| ... | @@ -123,18 +123,18 @@ fn short_circuit() { | ... | @@ -123,18 +123,18 @@ fn short_circuit() { |
| 123 | var hit_3 = false; | 123 | var hit_3 = false; |
| 124 | var hit_4 = false; | 124 | var hit_4 = false; |
| 125 | 125 | ||
| 126 | if (true || { assert(false); false }) { | 126 | if (true || {assert_runtime(false); false}) { |
| 127 | hit_1 = true; | 127 | hit_1 = true; |
| 128 | } | 128 | } |
| 129 | if (false || { hit_2 = true; false }) { | 129 | if (false || { hit_2 = true; false }) { |
| 130 | assert(false); | 130 | assert_runtime(false); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | if (true && { hit_3 = true; false }) { | 133 | if (true && { hit_3 = true; false }) { |
| 134 | %%io.stdout.printf("BAD 3\n"); | 134 | assert_runtime(false); |
| 135 | } | 135 | } |
| 136 | if (false && { assert(false); false }) { | 136 | if (false && {assert_runtime(false); false}) { |
| 137 | assert(false); | 137 | assert_runtime(false); |
| 138 | } else { | 138 | } else { |
| 139 | hit_4 = true; | 139 | hit_4 = true; |
| 140 | } | 140 | } |
| ... | @@ -144,6 +144,11 @@ fn short_circuit() { | ... | @@ -144,6 +144,11 @@ fn short_circuit() { |
| 144 | assert(hit_4); | 144 | assert(hit_4); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | #static_eval_enable(false) | ||
| 148 | fn assert_runtime(b: bool) { | ||
| 149 | if (!b) unreachable{} | ||
| 150 | } | ||
| 151 | |||
| 147 | #attribute("test") | 152 | #attribute("test") |
| 148 | fn modify_operators() { | 153 | fn modify_operators() { |
| 149 | var i : i32 = 0; | 154 | var i : i32 = 0; |
| ... | @@ -410,9 +415,7 @@ error err2; | ... | @@ -410,9 +415,7 @@ error err2; |
| 410 | 415 | ||
| 411 | #attribute("test") | 416 | #attribute("test") |
| 412 | fn fn_call_of_struct_field() { | 417 | fn fn_call_of_struct_field() { |
| 413 | if (call_struct_field(Foo {.ptr = a_func,}) != 13) { | 418 | assert(call_struct_field(Foo {.ptr = a_func,}) == 13); |
| 414 | unreachable{}; | ||
| 415 | } | ||
| 416 | } | 419 | } |
| 417 | 420 | ||
| 418 | struct Foo { | 421 | struct Foo { |
| ... | @@ -509,6 +512,7 @@ enum Fruit { | ... | @@ -509,6 +512,7 @@ enum Fruit { |
| 509 | Orange, | 512 | Orange, |
| 510 | Banana, | 513 | Banana, |
| 511 | } | 514 | } |
| 515 | #static_eval_enable(false) | ||
| 512 | fn non_const_switch_on_enum(fruit: Fruit) { | 516 | fn non_const_switch_on_enum(fruit: Fruit) { |
| 513 | switch (fruit) { | 517 | switch (fruit) { |
| 514 | Apple => unreachable{}, | 518 | Apple => unreachable{}, |
| ... | @@ -521,6 +525,7 @@ fn non_const_switch_on_enum(fruit: Fruit) { | ... | @@ -521,6 +525,7 @@ fn non_const_switch_on_enum(fruit: Fruit) { |
| 521 | fn switch_statement() { | 525 | fn switch_statement() { |
| 522 | non_const_switch(SwitchStatmentFoo.C); | 526 | non_const_switch(SwitchStatmentFoo.C); |
| 523 | } | 527 | } |
| 528 | #static_eval_enable(false) | ||
| 524 | fn non_const_switch(foo: SwitchStatmentFoo) { | 529 | fn non_const_switch(foo: SwitchStatmentFoo) { |
| 525 | const val: i32 = switch (foo) { | 530 | const val: i32 = switch (foo) { |
| 526 | A => 1, | 531 | A => 1, |
| ... | @@ -549,6 +554,7 @@ enum SwitchProngWithVarEnum { | ... | @@ -549,6 +554,7 @@ enum SwitchProngWithVarEnum { |
| 549 | Two: f32, | 554 | Two: f32, |
| 550 | Meh, | 555 | Meh, |
| 551 | } | 556 | } |
| 557 | #static_eval_enable(false) | ||
| 552 | fn switch_prong_with_var_fn(a: SwitchProngWithVarEnum) { | 558 | fn switch_prong_with_var_fn(a: SwitchProngWithVarEnum) { |
| 553 | switch(a) { | 559 | switch(a) { |
| 554 | One => |x| { | 560 | One => |x| { |
| ... | @@ -569,6 +575,7 @@ fn err_return_in_assignment() { | ... | @@ -569,6 +575,7 @@ fn err_return_in_assignment() { |
| 569 | %%do_err_return_in_assignment(); | 575 | %%do_err_return_in_assignment(); |
| 570 | } | 576 | } |
| 571 | 577 | ||
| 578 | #static_eval_enable(false) | ||
| 572 | fn do_err_return_in_assignment() -> %void { | 579 | fn do_err_return_in_assignment() -> %void { |
| 573 | var x : i32 = undefined; | 580 | var x : i32 = undefined; |
| 574 | x = %return make_a_non_err(); | 581 | x = %return make_a_non_err(); |
| ... | @@ -608,7 +615,7 @@ fn explicit_cast_maybe_pointers() { | ... | @@ -608,7 +615,7 @@ fn explicit_cast_maybe_pointers() { |
| 608 | 615 | ||
| 609 | #attribute("test") | 616 | #attribute("test") |
| 610 | fn const_expr_eval_on_single_expr_blocks() { | 617 | fn const_expr_eval_on_single_expr_blocks() { |
| 611 | if (const_expr_eval_on_single_expr_blocks_fn(1, true) != 3) unreachable{} | 618 | assert(const_expr_eval_on_single_expr_blocks_fn(1, true) == 3); |
| 612 | } | 619 | } |
| 613 | 620 | ||
| 614 | fn const_expr_eval_on_single_expr_blocks_fn(x: i32, b: bool) -> i32 { | 621 | fn const_expr_eval_on_single_expr_blocks_fn(x: i32, b: bool) -> i32 { |
| ... | @@ -736,6 +743,7 @@ fn generic_malloc_free() { | ... | @@ -736,6 +743,7 @@ fn generic_malloc_free() { |
| 736 | mem_free(u8)(a); | 743 | mem_free(u8)(a); |
| 737 | } | 744 | } |
| 738 | const some_mem : [100]u8 = undefined; | 745 | const some_mem : [100]u8 = undefined; |
| 746 | #static_eval_enable(false) | ||
| 739 | fn mem_alloc(T: type)(n: isize) -> %[]T { | 747 | fn mem_alloc(T: type)(n: isize) -> %[]T { |
| 740 | return (&T)(&some_mem[0])[0...n]; | 748 | return (&T)(&some_mem[0])[0...n]; |
| 741 | } | 749 | } |
| ... | @@ -789,6 +797,7 @@ var goto_counter: i32 = 0; | ... | @@ -789,6 +797,7 @@ var goto_counter: i32 = 0; |
| 789 | fn goto_leave_defer_scope() { | 797 | fn goto_leave_defer_scope() { |
| 790 | test_goto_leave_defer_scope(true); | 798 | test_goto_leave_defer_scope(true); |
| 791 | } | 799 | } |
| 800 | #static_eval_enable(false) | ||
| 792 | fn test_goto_leave_defer_scope(b: bool) { | 801 | fn test_goto_leave_defer_scope(b: bool) { |
| 793 | var it_worked = false; | 802 | var it_worked = false; |
| 794 | 803 | ||
| ... | @@ -820,3 +829,160 @@ fn cast_small_unsigned_to_larger_signed() { | ... | @@ -820,3 +829,160 @@ fn cast_small_unsigned_to_larger_signed() { |
| 820 | } | 829 | } |
| 821 | fn cast_small_unsigned_to_larger_signed_1(x: u8) -> i16 { x } | 830 | fn cast_small_unsigned_to_larger_signed_1(x: u8) -> i16 { x } |
| 822 | fn cast_small_unsigned_to_larger_signed_2(x: u16) -> isize { x } | 831 | fn cast_small_unsigned_to_larger_signed_2(x: u16) -> isize { x } |
| 832 | |||
| 833 | |||
| 834 | #attribute("test") | ||
| 835 | fn implicit_cast_after_unreachable() { | ||
| 836 | assert(outer() == 1234); | ||
| 837 | } | ||
| 838 | fn inner() -> i32 { 1234 } | ||
| 839 | fn outer() -> isize { | ||
| 840 | return inner(); | ||
| 841 | } | ||
| 842 | |||
| 843 | |||
| 844 | #attribute("test") | ||
| 845 | fn else_if_expression() { | ||
| 846 | assert(else_if_expression_f(1) == 1); | ||
| 847 | } | ||
| 848 | fn else_if_expression_f(c: u8) -> u8 { | ||
| 849 | if (c == 0) { | ||
| 850 | 0 | ||
| 851 | } else if (c == 1) { | ||
| 852 | 1 | ||
| 853 | } else { | ||
| 854 | 2 | ||
| 855 | } | ||
| 856 | } | ||
| 857 | |||
| 858 | #attribute("test") | ||
| 859 | fn err_binary_operator() { | ||
| 860 | const a = err_binary_operator_g(true) %% 3; | ||
| 861 | const b = err_binary_operator_g(false) %% 3; | ||
| 862 | assert(a == 3); | ||
| 863 | assert(b == 10); | ||
| 864 | } | ||
| 865 | error ItBroke; | ||
| 866 | fn err_binary_operator_g(x: bool) -> %isize { | ||
| 867 | if (x) { | ||
| 868 | error.ItBroke | ||
| 869 | } else { | ||
| 870 | 10 | ||
| 871 | } | ||
| 872 | } | ||
| 873 | |||
| 874 | #attribute("test") | ||
| 875 | fn unwrap_simple_value_from_error() { | ||
| 876 | const i = %%unwrap_simple_value_from_error_do(); | ||
| 877 | assert(i == 13); | ||
| 878 | } | ||
| 879 | fn unwrap_simple_value_from_error_do() -> %isize { 13 } | ||
| 880 | |||
| 881 | |||
| 882 | #attribute("test") | ||
| 883 | fn store_member_function_in_variable() { | ||
| 884 | const instance = MemberFnTestFoo { .x = 1234, }; | ||
| 885 | const member_fn = MemberFnTestFoo.member; | ||
| 886 | const result = member_fn(instance); | ||
| 887 | assert(result == 1234); | ||
| 888 | } | ||
| 889 | struct MemberFnTestFoo { | ||
| 890 | x: i32, | ||
| 891 | fn member(foo: MemberFnTestFoo) -> i32 { foo.x } | ||
| 892 | } | ||
| 893 | |||
| 894 | #attribute("test") | ||
| 895 | fn call_member_function_directly() { | ||
| 896 | const instance = MemberFnTestFoo { .x = 1234, }; | ||
| 897 | const result = MemberFnTestFoo.member(instance); | ||
| 898 | assert(result == 1234); | ||
| 899 | } | ||
| 900 | |||
| 901 | #attribute("test") | ||
| 902 | fn member_functions() { | ||
| 903 | const r = MemberFnRand {.seed = 1234}; | ||
| 904 | assert(r.get_seed() == 1234); | ||
| 905 | } | ||
| 906 | struct MemberFnRand { | ||
| 907 | seed: u32, | ||
| 908 | pub fn get_seed(r: MemberFnRand) -> u32 { | ||
| 909 | r.seed | ||
| 910 | } | ||
| 911 | } | ||
| 912 | |||
| 913 | #attribute("test") | ||
| 914 | fn static_function_evaluation() { | ||
| 915 | assert(statically_added_number == 3); | ||
| 916 | } | ||
| 917 | const statically_added_number = static_add(1, 2); | ||
| 918 | fn static_add(a: i32, b: i32) -> i32 { a + b } | ||
| 919 | |||
| 920 | |||
| 921 | #attribute("test") | ||
| 922 | fn statically_initalized_list() { | ||
| 923 | assert(static_point_list[0].x == 1); | ||
| 924 | assert(static_point_list[0].y == 2); | ||
| 925 | assert(static_point_list[1].x == 3); | ||
| 926 | assert(static_point_list[1].y == 4); | ||
| 927 | } | ||
| 928 | struct Point { | ||
| 929 | x: i32, | ||
| 930 | y: i32, | ||
| 931 | } | ||
| 932 | const static_point_list = []Point { make_point(1, 2), make_point(3, 4) }; | ||
| 933 | fn make_point(x: i32, y: i32) -> Point { | ||
| 934 | return Point { | ||
| 935 | .x = x, | ||
| 936 | .y = y, | ||
| 937 | }; | ||
| 938 | } | ||
| 939 | |||
| 940 | |||
| 941 | #attribute("test") | ||
| 942 | fn static_eval_recursive() { | ||
| 943 | assert(seventh_fib_number == 21); | ||
| 944 | } | ||
| 945 | const seventh_fib_number = fibbonaci(7); | ||
| 946 | fn fibbonaci(x: i32) -> i32 { | ||
| 947 | if (x <= 1) return 1; | ||
| 948 | return fibbonaci(x - 1) + fibbonaci(x - 2); | ||
| 949 | } | ||
| 950 | |||
| 951 | #attribute("test") | ||
| 952 | fn static_eval_while() { | ||
| 953 | assert(static_eval_while_number == 1); | ||
| 954 | } | ||
| 955 | const static_eval_while_number = static_while_loop_1(); | ||
| 956 | fn static_while_loop_1() -> i32 { | ||
| 957 | return while_loop_2(); | ||
| 958 | } | ||
| 959 | fn static_while_loop_2() -> i32 { | ||
| 960 | while (true) { | ||
| 961 | return 1; | ||
| 962 | } | ||
| 963 | } | ||
| 964 | |||
| 965 | #attribute("test") | ||
| 966 | fn static_eval_list_init() { | ||
| 967 | assert(static_vec3.data[2] == 1.0); | ||
| 968 | } | ||
| 969 | const static_vec3 = vec3(0.0, 0.0, 1.0); | ||
| 970 | pub struct Vec3 { | ||
| 971 | data: [3]f32, | ||
| 972 | } | ||
| 973 | pub fn vec3(x: f32, y: f32, z: f32) -> Vec3 { | ||
| 974 | Vec3 { | ||
| 975 | .data = []f32 { x, y, z, }, | ||
| 976 | } | ||
| 977 | } | ||
| 978 | |||
| 979 | |||
| 980 | #attribute("test") | ||
| 981 | fn generic_fn_with_implicit_cast() { | ||
| 982 | assert(get_first_byte(u8)([]u8 {13}) == 13); | ||
| 983 | assert(get_first_byte(u16)([]u16 {0, 13}) == 0); | ||
| 984 | } | ||
| 985 | fn get_byte(ptr: ?&u8) -> u8 {*??ptr} | ||
| 986 | fn get_first_byte(T: type)(mem: []T) -> u8 { | ||
| 987 | get_byte((&u8)(&mem[0])) | ||
| 988 | } |