authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-11 15:32:08-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-12 09:35:33-07:00
loga177e305342c25e83d6b65e24561c27e3c2e4c91
tree7ee80acc0b39dd50bc8e52263776d043f768ecb0
parent5a479720ec5786145dac6c85deae4e322bd5972e

compile-time function evaluation of pure functions


5 files changed, 793 insertions(+), 195 deletions(-)

CMakeLists.txt+1
......@@ -41,6 +41,7 @@ set(ZIG_SOURCES
4141 "${CMAKE_SOURCE_DIR}/src/bignum.cpp"
4242 "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp"
4343 "${CMAKE_SOURCE_DIR}/src/parser.cpp"
44 "${CMAKE_SOURCE_DIR}/src/eval.cpp"
4445 "${CMAKE_SOURCE_DIR}/src/analyze.cpp"
4546 "${CMAKE_SOURCE_DIR}/src/codegen.cpp"
4647 "${CMAKE_SOURCE_DIR}/src/buffer.cpp"
src/all_types.hpp+36
......@@ -65,6 +65,7 @@ struct ConstExprValue {
6565 bool ok; // true if constant expression evalution worked
6666 bool depends_on_compile_var;
6767 bool undef;
68 bool deep_const;
6869
6970 union {
7071 BigNum x_bignum;
......@@ -1005,6 +1006,13 @@ struct ImportTableEntry {
10051006 ZigList<AstNode *> use_decls;
10061007};
10071008
1009enum FnAnalState {
1010 FnAnalStateReady,
1011 FnAnalStateProbing,
1012 FnAnalStateComplete,
1013 FnAnalStateSkipped,
1014};
1015
10081016struct FnTableEntry {
10091017 LLVMValueRef fn_value;
10101018 AstNode *proto_node;
......@@ -1019,7 +1027,9 @@ struct FnTableEntry {
10191027 bool internal_linkage;
10201028 bool is_extern;
10211029 bool is_test;
1030 bool is_pure;
10221031 BlockContext *parent_block_context;
1032 FnAnalState anal_state;
10231033
10241034 ZigList<AstNode *> cast_alloca_list;
10251035 ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;
......@@ -1027,6 +1037,32 @@ struct FnTableEntry {
10271037 ZigList<AstNode *> goto_list;
10281038};
10291039
1040struct EvalVar {
1041 Buf *name;
1042 ConstExprValue value;
1043};
1044
1045struct EvalScope {
1046 BlockContext *block_context;
1047 ZigList<EvalVar> vars;
1048};
1049
1050struct 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};
1058
1059struct EvalFn {
1060 EvalFnRoot *root;
1061 FnTableEntry *fn;
1062 ConstExprValue *return_expr;
1063 ZigList<EvalScope*> scope_stack;
1064};
1065
10301066enum BuiltinFnId {
10311067 BuiltinFnIdInvalid,
10321068 BuiltinFnIdMemcpy,
src/analyze.cpp+125-195
......@@ -13,6 +13,7 @@
1313#include "parseh.hpp"
1414#include "config.h"
1515#include "ast_render.hpp"
16#include "eval.hpp"
1617
1718static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1819 TypeTableEntry *expected_type, AstNode *node);
......@@ -1374,6 +1375,7 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
13741375 fn_table_entry->proto_node = proto_node;
13751376 fn_table_entry->fn_def_node = fn_def_node;
13761377 fn_table_entry->is_extern = is_extern;
1378 fn_table_entry->is_pure = !is_extern;
13771379
13781380 get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_');
13791381
......@@ -2443,6 +2445,12 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import,
24432445 return return_type;
24442446}
24452447
2448static void mark_impure_fn(BlockContext *context) {
2449 if (context->fn_entry) {
2450 context->fn_entry->is_pure = false;
2451 }
2452}
2453
24462454static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
24472455 AstNode *node)
24482456{
......@@ -2478,6 +2486,7 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i
24782486static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node) {
24792487 Expr *expr = get_resolved_expr(node);
24802488 expr->const_val.ok = true;
2489 expr->const_val.deep_const = true;
24812490 return g->builtin_types.entry_void;
24822491}
24832492
......@@ -2485,6 +2494,7 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node,
24852494 Expr *expr = get_resolved_expr(node);
24862495 expr->const_val.ok = true;
24872496 expr->const_val.data.x_type = type;
2497 expr->const_val.deep_const = true;
24882498 return g->builtin_types.entry_type;
24892499}
24902500
......@@ -2499,6 +2509,7 @@ static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, F
24992509 Expr *expr = get_resolved_expr(node);
25002510 expr->const_val.ok = true;
25012511 expr->const_val.data.x_fn = fn;
2512 expr->const_val.deep_const = true;
25022513 return fn->type_entry;
25032514}
25042515
......@@ -2508,6 +2519,7 @@ static TypeTableEntry *resolve_expr_const_val_as_generic_fn(CodeGen *g, AstNode
25082519 Expr *expr = get_resolved_expr(node);
25092520 expr->const_val.ok = true;
25102521 expr->const_val.data.x_type = type_entry;
2522 expr->const_val.deep_const = true;
25112523 return type_entry;
25122524}
25132525
......@@ -2515,6 +2527,7 @@ static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node,
25152527 Expr *expr = get_resolved_expr(node);
25162528 expr->const_val.ok = true;
25172529 expr->const_val.data.x_err.err = err;
2530 expr->const_val.deep_const = true;
25182531 return g->builtin_types.entry_pure_error;
25192532}
25202533
......@@ -2525,6 +2538,7 @@ static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node,
25252538 expr->const_val.ok = true;
25262539 expr->const_val.depends_on_compile_var = depends_on_compile_var;
25272540 expr->const_val.data.x_bool = value;
2541 expr->const_val.deep_const = true;
25282542 return g->builtin_types.entry_bool;
25292543}
25302544
......@@ -2532,6 +2546,7 @@ static TypeTableEntry *resolve_expr_const_val_as_null(CodeGen *g, AstNode *node,
25322546 Expr *expr = get_resolved_expr(node);
25332547 expr->const_val.ok = true;
25342548 expr->const_val.data.x_maybe = nullptr;
2549 expr->const_val.deep_const = true;
25352550 return type;
25362551}
25372552
......@@ -2542,12 +2557,14 @@ static TypeTableEntry *resolve_expr_const_val_as_non_null(CodeGen *g, AstNode *n
25422557 Expr *expr = get_resolved_expr(node);
25432558 expr->const_val.ok = true;
25442559 expr->const_val.data.x_maybe = other_val;
2560 expr->const_val.deep_const = other_val->deep_const;
25452561 return type;
25462562}
25472563
25482564static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNode *node, Buf *str) {
25492565 Expr *expr = get_resolved_expr(node);
25502566 expr->const_val.ok = true;
2567 expr->const_val.deep_const = true;
25512568
25522569 int len_with_null = buf_len(str) + 1;
25532570 expr->const_val.data.x_ptr.ptr = allocate<ConstExprValue*>(len_with_null);
......@@ -2557,12 +2574,14 @@ static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNod
25572574 for (int i = 0; i < buf_len(str); i += 1) {
25582575 ConstExprValue *this_char = &all_chars[i];
25592576 this_char->ok = true;
2577 this_char->deep_const = true;
25602578 bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
25612579 expr->const_val.data.x_ptr.ptr[i] = this_char;
25622580 }
25632581
25642582 ConstExprValue *null_char = &all_chars[len_with_null - 1];
25652583 null_char->ok = true;
2584 null_char->deep_const = true;
25662585 bignum_init_unsigned(&null_char->data.x_bignum, 0);
25672586 expr->const_val.data.x_ptr.ptr[len_with_null - 1] = null_char;
25682587
......@@ -2572,12 +2591,14 @@ static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNod
25722591static TypeTableEntry *resolve_expr_const_val_as_string_lit(CodeGen *g, AstNode *node, Buf *str) {
25732592 Expr *expr = get_resolved_expr(node);
25742593 expr->const_val.ok = true;
2594 expr->const_val.deep_const = true;
25752595 expr->const_val.data.x_array.fields = allocate<ConstExprValue*>(buf_len(str));
25762596
25772597 ConstExprValue *all_chars = allocate<ConstExprValue>(buf_len(str));
25782598 for (int i = 0; i < buf_len(str); i += 1) {
25792599 ConstExprValue *this_char = &all_chars[i];
25802600 this_char->ok = true;
2601 this_char->deep_const = true;
25812602 bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
25822603 expr->const_val.data.x_array.fields[i] = this_char;
25832604 }
......@@ -2590,6 +2611,7 @@ static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, As
25902611{
25912612 Expr *expr = get_resolved_expr(node);
25922613 expr->const_val.ok = true;
2614 expr->const_val.deep_const = true;
25932615
25942616 bignum_init_unsigned(&expr->const_val.data.x_bignum, x);
25952617
......@@ -2601,6 +2623,7 @@ static TypeTableEntry *resolve_expr_const_val_as_float_num_lit(CodeGen *g, AstNo
26012623{
26022624 Expr *expr = get_resolved_expr(node);
26032625 expr->const_val.ok = true;
2626 expr->const_val.deep_const = true;
26042627
26052628 bignum_init_float(&expr->const_val.data.x_bignum, x);
26062629
......@@ -2616,6 +2639,7 @@ static TypeTableEntry *resolve_expr_const_val_as_bignum_op(CodeGen *g, AstNode *
26162639 ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val;
26172640
26182641 const_val->ok = true;
2642 const_val->deep_const = true;
26192643
26202644 if (bignum_fn(&const_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum)) {
26212645 add_node_error(g, node,
......@@ -2684,6 +2708,19 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod
26842708 }
26852709}
26862710
2711static bool var_is_pure(VariableTableEntry *var, TypeTableEntry *var_type, BlockContext *context) {
2712 if (var->block_context->fn_entry == context->fn_entry) {
2713 // variable was declared in the current function, so it's OK.
2714 return true;
2715 }
2716 if (!var->is_const) {
2717 return false;
2718 }
2719
2720 ConstExprValue *const_val = &get_resolved_expr(var->val_node)->const_val;
2721 return const_val->deep_const;
2722}
2723
26872724static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
26882725 TypeTableEntry *expected_type, AstNode *node, bool pointer_only)
26892726{
......@@ -2700,7 +2737,11 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
27002737
27012738 VariableTableEntry *var = find_variable(g, context, variable_name);
27022739 if (var) {
2703 return analyze_var_ref(g, node, var);
2740 TypeTableEntry *var_type = analyze_var_ref(g, node, var);
2741 if (!var_is_pure(var, var_type, context)) {
2742 mark_impure_fn(context);
2743 }
2744 return var_type;
27042745 }
27052746
27062747 AstNode *decl_node = find_decl(context, variable_name);
......@@ -2840,71 +2881,6 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc
28402881 return expected_rhs_type;
28412882}
28422883
2843static 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
2853static 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
29082884static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
29092885 AstNode *node)
29102886{
......@@ -2944,39 +2920,11 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im
29442920 return g->builtin_types.entry_bool;
29452921 }
29462922
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 }
29652923
2966 answer = bignum_cmp(&op1_val->data.x_bignum, &op2_val->data.x_bignum);
2967 } else {
2968 bool are_equal = const_values_equal(op1_val, op2_val, resolved_type);
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 }
2924 ConstExprValue *out_val = &get_resolved_expr(node)->const_val;
2925 eval_const_expr_bin_op(op1_val, op1_type, bin_op_type, op2_val, op2_type, out_val);
2926 return g->builtin_types.entry_bool;
29772927
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);
29802928}
29812929
29822930static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
......@@ -3002,9 +2950,9 @@ static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *i
30022950 return g->builtin_types.entry_bool;
30032951 }
30042952
3005 bool answer = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op_type, op2_val->data.x_bool);
3006 bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
3007 return resolve_expr_const_val_as_bool(g, node, answer, depends_on_compile_var);
2953 ConstExprValue *out_val = &get_resolved_expr(node)->const_val;
2954 eval_const_expr_bin_op(op1_val, op1_type, bin_op_type, op2_val, op2_type, out_val);
2955 return g->builtin_types.entry_bool;
30082956}
30092957
30102958static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
......@@ -3041,7 +2989,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
30412989 }
30422990
30432991 analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2);
3044 return g->builtin_types.entry_void;
2992 return resolve_expr_const_val_as_void(g, node);
30452993 }
30462994 case BinOpTypeBoolOr:
30472995 case BinOpTypeBoolAnd:
......@@ -3720,6 +3668,10 @@ static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import
37203668 }
37213669
37223670 ConstExprValue *cond_val = &get_resolved_expr(*cond)->const_val;
3671 if (cond_val->undef) {
3672 add_node_error(g, first_executing_node(*cond), buf_sprintf("branch on undefined value"));
3673 return cond_type;
3674 }
37233675 if (cond_val->ok && !cond_val->depends_on_compile_var) {
37243676 const char *str_val = cond_val->data.x_bool ? "true" : "false";
37253677 add_node_error(g, first_executing_node(*cond),
......@@ -3849,92 +3801,18 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
38493801 }
38503802}
38513803
3852static 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
39333804static TypeTableEntry *resolve_cast(CodeGen *g, BlockContext *context, AstNode *node,
39343805 AstNode *expr_node, TypeTableEntry *wanted_type, CastOp op, bool need_alloca)
39353806{
39363807 node->data.fn_call_expr.cast_op = op;
3937 eval_const_expr_implicit_cast(g, node, expr_node);
3808
3809 ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val;
3810 TypeTableEntry *other_type = get_resolved_expr(expr_node)->type_entry;
3811 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
3812 if (other_val->ok) {
3813 eval_const_expr_implicit_cast(node->data.fn_call_expr.cast_op, other_val, other_type, const_val);
3814 }
3815
39383816 if (need_alloca) {
39393817 if (context->fn_entry) {
39403818 context->fn_entry->cast_alloca_list.append(node);
......@@ -4360,6 +4238,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
43604238 }
43614239 case BuiltinFnIdMemcpy:
43624240 {
4241 mark_impure_fn(context);
4242
43634243 AstNode *dest_node = node->data.fn_call_expr.params.at(0);
43644244 AstNode *src_node = node->data.fn_call_expr.params.at(1);
43654245 AstNode *len_node = node->data.fn_call_expr.params.at(2);
......@@ -4398,6 +4278,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
43984278 }
43994279 case BuiltinFnIdMemset:
44004280 {
4281 mark_impure_fn(context);
4282
44014283 AstNode *dest_node = node->data.fn_call_expr.params.at(0);
44024284 AstNode *char_node = node->data.fn_call_expr.params.at(1);
44034285 AstNode *len_node = node->data.fn_call_expr.params.at(2);
......@@ -4630,13 +4512,15 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
46304512 case BuiltinFnIdErrName:
46314513 return analyze_err_name(g, import, context, node);
46324514 case BuiltinFnIdBreakpoint:
4515 mark_impure_fn(context);
46334516 return g->builtin_types.entry_void;
46344517 }
46354518 zig_unreachable();
46364519}
46374520
46384521static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
4639 TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *fn_type, TypeTableEntry *struct_type)
4522 TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *fn_type,
4523 AstNode *struct_node)
46404524{
46414525 assert(node->type == NodeTypeFnCallExpr);
46424526
......@@ -4648,7 +4532,7 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
46484532 int src_param_count = fn_type->data.fn.fn_type_id.param_count;
46494533 int actual_param_count = node->data.fn_call_expr.params.length;
46504534
4651 if (struct_type) {
4535 if (struct_node) {
46524536 actual_param_count += 1;
46534537 }
46544538
......@@ -4662,17 +4546,31 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
46624546 buf_sprintf("expected %d arguments, got %d", src_param_count, actual_param_count));
46634547 }
46644548
4549 bool all_args_const_expr = true;
4550
4551 if (struct_node) {
4552 ConstExprValue *struct_const_val = &get_resolved_expr(struct_node)->const_val;
4553 if (!struct_const_val->ok) {
4554 all_args_const_expr = false;
4555 }
4556 }
4557
46654558 // analyze each parameter. in the case of a method, we already analyzed the
46664559 // first parameter in order to figure out which struct we were calling a method on.
46674560 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);
4561 AstNode **child = &node->data.fn_call_expr.params.at(i);
46694562 // determine the expected type for each parameter
46704563 TypeTableEntry *expected_param_type = nullptr;
4671 int fn_proto_i = i + (struct_type ? 1 : 0);
4564 int fn_proto_i = i + (struct_node ? 1 : 0);
46724565 if (fn_proto_i < src_param_count) {
46734566 expected_param_type = fn_type->data.fn.fn_type_id.param_info[fn_proto_i].type;
46744567 }
4675 analyze_expression(g, import, context, expected_param_type, child);
4568 analyze_expression(g, import, context, expected_param_type, *child);
4569
4570 ConstExprValue *const_arg_val = &get_resolved_expr(*child)->const_val;
4571 if (!const_arg_val->ok) {
4572 all_args_const_expr = false;
4573 }
46764574 }
46774575
46784576 TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
......@@ -4681,6 +4579,30 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
46814579 return return_type;
46824580 }
46834581
4582 FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
4583 if (fn_table_entry && fn_table_entry->is_pure && all_args_const_expr) {
4584 if (fn_table_entry->anal_state == FnAnalStateReady) {
4585 analyze_fn_body(g, fn_table_entry);
4586 } else if (fn_table_entry->anal_state == FnAnalStateProbing) {
4587 mark_impure_fn(context);
4588 }
4589 if (fn_table_entry->is_pure) {
4590 if (fn_table_entry->anal_state == FnAnalStateComplete) {
4591 ConstExprValue *result_val = &get_resolved_expr(node)->const_val;
4592 if (eval_fn(g, node, fn_table_entry, result_val, 1000, struct_node)) {
4593 // function evaluation generated an error
4594 return g->builtin_types.entry_invalid;
4595 }
4596 return return_type;
4597 } else if (fn_table_entry->anal_state == FnAnalStateSkipped) {
4598 return g->builtin_types.entry_invalid;
4599 }
4600 } else {
4601 // calling an impure fn is impure
4602 mark_impure_fn(context);
4603 }
4604 }
4605
46844606 if (handle_is_ptr(return_type)) {
46854607 context->fn_entry->cast_alloca_list.append(node);
46864608 }
......@@ -4689,13 +4611,13 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
46894611}
46904612
46914613static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, BlockContext *context,
4692 TypeTableEntry *expected_type, AstNode *node, FnTableEntry *fn_table_entry, TypeTableEntry *struct_type)
4614 TypeTableEntry *expected_type, AstNode *node, FnTableEntry *fn_table_entry, AstNode *struct_node)
46934615{
46944616 assert(node->type == NodeTypeFnCallExpr);
46954617
46964618 node->data.fn_call_expr.fn_entry = fn_table_entry;
46974619
4698 return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_type);
4620 return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_node);
46994621}
47004622
47014623static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
......@@ -4861,17 +4783,17 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
48614783 return analyze_cast_expr(g, import, context, node);
48624784 }
48634785 } else if (invoke_type_entry->id == TypeTableEntryIdFn) {
4864 TypeTableEntry *bare_struct_type;
4786 AstNode *struct_node;
48654787 if (fn_ref_expr->type == NodeTypeFieldAccessExpr &&
48664788 fn_ref_expr->data.field_access_expr.is_member_fn)
48674789 {
4868 bare_struct_type = fn_ref_expr->data.field_access_expr.bare_struct_type;
4790 struct_node = fn_ref_expr;
48694791 } else {
4870 bare_struct_type = nullptr;
4792 struct_node = nullptr;
48714793 }
48724794
48734795 return analyze_fn_call_raw(g, import, context, expected_type, node,
4874 const_val->data.x_fn, bare_struct_type);
4796 const_val->data.x_fn, struct_node);
48754797 } else if (invoke_type_entry->id == TypeTableEntryIdGenericFn) {
48764798 return analyze_generic_fn_call(g, import, context, expected_type, node, const_val->data.x_type);
48774799 } else {
......@@ -5421,6 +5343,8 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import,
54215343static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
54225344 TypeTableEntry *expected_type, AstNode *node)
54235345{
5346 mark_impure_fn(context);
5347
54245348 node->data.asm_expr.return_count = 0;
54255349 TypeTableEntry *return_type = g->builtin_types.entry_void;
54265350 for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) {
......@@ -5641,8 +5565,10 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
56415565 if (fn_proto_node->data.fn_proto.skip) {
56425566 // we detected an error with this function definition which prevents us
56435567 // from further analyzing it.
5568 fn_table_entry->anal_state = FnAnalStateSkipped;
56445569 return;
56455570 }
5571 fn_table_entry->anal_state = FnAnalStateProbing;
56465572
56475573 BlockContext *context = node->data.fn_def.block_context;
56485574
......@@ -5697,6 +5623,8 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
56975623 buf_ptr(&label->decl_node->data.label.name)));
56985624 }
56995625 }
5626
5627 fn_table_entry->anal_state = FnAnalStateComplete;
57005628}
57015629
57025630static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContext *block_context,
......@@ -6005,7 +5933,9 @@ void semantic_analyze(CodeGen *g) {
60055933
60065934 for (int i = 0; i < g->fn_defs.length; i += 1) {
60075935 FnTableEntry *fn_entry = g->fn_defs.at(i);
6008 analyze_fn_body(g, fn_entry);
5936 if (fn_entry->anal_state == FnAnalStateReady) {
5937 analyze_fn_body(g, fn_entry);
5938 }
60095939 }
60105940}
60115941
src/eval.cpp created+607
......@@ -0,0 +1,607 @@
1#include "eval.hpp"
2#include "analyze.hpp"
3
4static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val);
5
6bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) {
7 switch (type_entry->id) {
8 case TypeTableEntryIdEnum:
9 {
10 ConstEnumValue *enum1 = &a->data.x_enum;
11 ConstEnumValue *enum2 = &b->data.x_enum;
12 if (enum1->tag == enum2->tag) {
13 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum1->tag];
14 if (type_has_bits(enum_field->type_entry)) {
15 zig_panic("TODO const expr analyze enum special value for equality");
16 } else {
17 return true;
18 }
19 }
20 return false;
21 }
22 case TypeTableEntryIdMetaType:
23 return a->data.x_type == b->data.x_type;
24 case TypeTableEntryIdVoid:
25 return true;
26 case TypeTableEntryIdPureError:
27 return a->data.x_err.err == b->data.x_err.err;
28 case TypeTableEntryIdFn:
29 return a->data.x_fn == b->data.x_fn;
30 case TypeTableEntryIdBool:
31 return a->data.x_bool == b->data.x_bool;
32 case TypeTableEntryIdInt:
33 case TypeTableEntryIdFloat:
34 case TypeTableEntryIdNumLitFloat:
35 case TypeTableEntryIdNumLitInt:
36 return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum);
37 case TypeTableEntryIdPointer:
38 zig_panic("TODO");
39 case TypeTableEntryIdArray:
40 zig_panic("TODO");
41 case TypeTableEntryIdStruct:
42 zig_panic("TODO");
43 case TypeTableEntryIdUndefLit:
44 zig_panic("TODO");
45 case TypeTableEntryIdMaybe:
46 zig_panic("TODO");
47 case TypeTableEntryIdErrorUnion:
48 zig_panic("TODO");
49 case TypeTableEntryIdTypeDecl:
50 zig_panic("TODO");
51 case TypeTableEntryIdNamespace:
52 zig_panic("TODO");
53 case TypeTableEntryIdGenericFn:
54 case TypeTableEntryIdInvalid:
55 case TypeTableEntryIdUnreachable:
56 zig_unreachable();
57 }
58 zig_unreachable();
59}
60
61
62static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out);
63
64static bool eval_block(EvalFn *ef, AstNode *node, ConstExprValue *out) {
65 assert(node->type == NodeTypeBlock);
66
67 EvalScope *my_scope = allocate<EvalScope>(1);
68 my_scope->block_context = node->block_context;
69 ef->scope_stack.append(my_scope);
70
71 for (int i = 0; i < node->data.block.statements.length; i += 1) {
72 AstNode *child = node->data.block.statements.at(i);
73 if (eval_expr(ef, child, out)) return true;
74 }
75
76 ef->scope_stack.pop();
77
78 return false;
79}
80
81static bool eval_return(EvalFn *ef, AstNode *node, ConstExprValue *out) {
82 assert(node->type == NodeTypeReturnExpr);
83
84 eval_expr(ef, node->data.return_expr.expr, ef->return_expr);
85 return true;
86}
87
88static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) {
89 if (bin_op == BinOpTypeBoolOr) {
90 return a || b;
91 } else if (bin_op == BinOpTypeBoolAnd) {
92 return a && b;
93 } else {
94 zig_unreachable();
95 }
96}
97
98static void eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,
99 ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *))
100{
101 bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum);
102 assert(!overflow);
103 out_val->ok = true;
104 out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
105}
106
107void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
108 BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val)
109{
110 assert(op1_val->ok);
111 assert(op2_val->ok);
112 assert(op1_type == op2_type);
113
114 switch (bin_op) {
115 case BinOpTypeAssign:
116 case BinOpTypeAssignTimes:
117 case BinOpTypeAssignDiv:
118 case BinOpTypeAssignMod:
119 case BinOpTypeAssignPlus:
120 case BinOpTypeAssignMinus:
121 case BinOpTypeAssignBitShiftLeft:
122 case BinOpTypeAssignBitShiftRight:
123 case BinOpTypeAssignBitAnd:
124 case BinOpTypeAssignBitXor:
125 case BinOpTypeAssignBitOr:
126 case BinOpTypeAssignBoolAnd:
127 case BinOpTypeAssignBoolOr:
128 out_val->ok = true;
129 return;
130 case BinOpTypeBoolOr:
131 case BinOpTypeBoolAnd:
132 assert(op1_type->id == TypeTableEntryIdBool);
133 assert(op2_type->id == TypeTableEntryIdBool);
134 out_val->data.x_bool = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op, op2_val->data.x_bool);
135 out_val->ok = true;
136 out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
137 return;
138 case BinOpTypeCmpEq:
139 case BinOpTypeCmpNotEq:
140 case BinOpTypeCmpLessThan:
141 case BinOpTypeCmpGreaterThan:
142 case BinOpTypeCmpLessOrEq:
143 case BinOpTypeCmpGreaterOrEq:
144 {
145 bool type_can_gt_lt_cmp = (op1_type->id == TypeTableEntryIdNumLitFloat ||
146 op1_type->id == TypeTableEntryIdNumLitInt ||
147 op1_type->id == TypeTableEntryIdFloat ||
148 op1_type->id == TypeTableEntryIdInt);
149 bool answer;
150 if (type_can_gt_lt_cmp) {
151 bool (*bignum_cmp)(BigNum *, BigNum *);
152 if (bin_op == BinOpTypeCmpEq) {
153 bignum_cmp = bignum_cmp_eq;
154 } else if (bin_op == BinOpTypeCmpNotEq) {
155 bignum_cmp = bignum_cmp_neq;
156 } else if (bin_op == BinOpTypeCmpLessThan) {
157 bignum_cmp = bignum_cmp_lt;
158 } else if (bin_op == BinOpTypeCmpGreaterThan) {
159 bignum_cmp = bignum_cmp_gt;
160 } else if (bin_op == BinOpTypeCmpLessOrEq) {
161 bignum_cmp = bignum_cmp_lte;
162 } else if (bin_op == BinOpTypeCmpGreaterOrEq) {
163 bignum_cmp = bignum_cmp_gte;
164 } else {
165 zig_unreachable();
166 }
167
168 answer = bignum_cmp(&op1_val->data.x_bignum, &op2_val->data.x_bignum);
169 } else {
170 bool are_equal = const_values_equal(op1_val, op2_val, op1_type);
171 if (bin_op == BinOpTypeCmpEq) {
172 answer = are_equal;
173 } else if (bin_op == BinOpTypeCmpNotEq) {
174 answer = !are_equal;
175 } else {
176 zig_unreachable();
177 }
178 }
179
180 out_val->depends_on_compile_var =
181 op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
182 out_val->data.x_bool = answer;
183 out_val->ok = true;
184 return;
185 }
186 case BinOpTypeAdd:
187 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add);
188 case BinOpTypeBinOr:
189 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or);
190 case BinOpTypeBinXor:
191 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor);
192 case BinOpTypeBinAnd:
193 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and);
194 case BinOpTypeBitShiftLeft:
195 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl);
196 case BinOpTypeBitShiftRight:
197 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr);
198 case BinOpTypeSub:
199 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub);
200 case BinOpTypeMult:
201 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul);
202 case BinOpTypeDiv:
203 {
204 bool is_int = false;
205 bool is_float = false;
206 if (op1_type->id == TypeTableEntryIdInt ||
207 op1_type->id == TypeTableEntryIdNumLitInt)
208 {
209 is_int = true;
210 } else if (op1_type->id == TypeTableEntryIdFloat ||
211 op1_type->id == TypeTableEntryIdNumLitFloat)
212 {
213 is_float = true;
214 }
215 if ((is_int && op2_val->data.x_bignum.data.x_uint == 0) ||
216 (is_float && op2_val->data.x_bignum.data.x_float == 0.0))
217 {
218 zig_panic("TODO handle errors in eval");
219 } else {
220 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div);
221 }
222 }
223 case BinOpTypeMod:
224 return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod);
225 case BinOpTypeUnwrapMaybe:
226 zig_panic("TODO");
227 case BinOpTypeStrCat:
228 zig_panic("TODO");
229 case BinOpTypeInvalid:
230 zig_unreachable();
231 }
232 zig_unreachable();
233}
234
235static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
236 assert(node->type == NodeTypeBinOpExpr);
237
238 AstNode *op1 = node->data.bin_op_expr.op1;
239 AstNode *op2 = node->data.bin_op_expr.op2;
240
241 TypeTableEntry *op1_type = get_resolved_expr(op1)->type_entry;
242 TypeTableEntry *op2_type = get_resolved_expr(op2)->type_entry;
243
244 ConstExprValue op1_val = {0};
245 if (eval_expr(ef, op1, &op1_val)) return true;
246
247 ConstExprValue op2_val = {0};
248 if (eval_expr(ef, op2, &op2_val)) return true;
249
250 BinOpType bin_op = node->data.bin_op_expr.bin_op;
251
252 eval_const_expr_bin_op(&op1_val, op1_type, bin_op, &op2_val, op2_type, out_val);
253
254 return false;
255}
256
257static EvalVar *find_var(EvalFn *ef, Buf *name) {
258 int scope_index = ef->scope_stack.length - 1;
259 while (scope_index >= 0) {
260 EvalScope *scope = ef->scope_stack.at(scope_index);
261 for (int var_i = 0; var_i < scope->vars.length; var_i += 1) {
262 EvalVar *var = &scope->vars.at(var_i);
263 if (buf_eql_buf(var->name, name)) {
264 return var;
265 }
266 }
267 scope_index -= 1;
268 }
269
270 return nullptr;
271}
272
273static bool eval_symbol_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
274 assert(node->type == NodeTypeSymbol);
275
276 Buf *name = &node->data.symbol_expr.symbol;
277 EvalVar *var = find_var(ef, name);
278
279 *out_val = var->value;
280
281 return false;
282}
283
284static TypeTableEntry *resolve_expr_type(AstNode *node) {
285 Expr *expr = get_resolved_expr(node);
286 TypeTableEntry *type_entry = expr->type_entry;
287 assert(type_entry->id == TypeTableEntryIdMetaType);
288 ConstExprValue *const_val = &expr->const_val;
289 assert(const_val->ok);
290 return const_val->data.x_type;
291}
292
293static bool eval_container_init_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
294 assert(node->type == NodeTypeContainerInitExpr);
295
296 AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr;
297 ContainerInitKind kind = container_init_expr->kind;
298 TypeTableEntry *container_type = resolve_expr_type(container_init_expr->type);
299 out_val->ok = true;
300
301 if (container_type->id == TypeTableEntryIdStruct &&
302 !container_type->data.structure.is_unknown_size_array &&
303 kind == ContainerInitKindStruct)
304 {
305 int expr_field_count = container_init_expr->entries.length;
306 int actual_field_count = container_type->data.structure.src_field_count;
307 assert(expr_field_count == actual_field_count);
308
309 out_val->data.x_struct.fields = allocate<ConstExprValue*>(actual_field_count);
310
311 for (int i = 0; i < expr_field_count; i += 1) {
312 AstNode *val_field_node = container_init_expr->entries.at(i);
313 assert(val_field_node->type == NodeTypeStructValueField);
314
315 TypeStructField *type_field = val_field_node->data.struct_val_field.type_struct_field;
316 int field_index = type_field->src_index;
317
318 ConstExprValue src_field_val = {0};
319 if (eval_expr(ef, val_field_node->data.struct_val_field.expr, &src_field_val)) return true;
320
321 ConstExprValue *dest_field_val = allocate<ConstExprValue>(1);
322 *dest_field_val = src_field_val;
323
324 out_val->data.x_struct.fields[field_index] = dest_field_val;
325 out_val->depends_on_compile_var = out_val->depends_on_compile_var ||
326 src_field_val.depends_on_compile_var;
327 }
328 } else if (container_type->id == TypeTableEntryIdVoid) {
329 return false;
330 } else {
331 zig_panic("TODO");
332 }
333
334
335 return false;
336}
337
338static bool eval_if_bool_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
339 assert(node->type == NodeTypeIfBoolExpr);
340
341 ConstExprValue cond_val = {0};
342 if (eval_expr(ef, node->data.if_bool_expr.condition, &cond_val)) return true;
343
344 AstNode *exec_node = cond_val.data.x_bool ?
345 node->data.if_bool_expr.then_block : node->data.if_bool_expr.else_node;
346
347 if (exec_node) {
348 if (eval_expr(ef, exec_node, out_val)) return true;
349 }
350 out_val->ok = true;
351 return false;
352}
353
354void eval_const_expr_implicit_cast(CastOp cast_op,
355 ConstExprValue *other_val, TypeTableEntry *other_type,
356 ConstExprValue *const_val)
357{
358 const_val->depends_on_compile_var = other_val->depends_on_compile_var;
359 const_val->undef = other_val->undef;
360
361 assert(other_val != const_val);
362 switch (cast_op) {
363 case CastOpNoCast:
364 zig_unreachable();
365 case CastOpNoop:
366 case CastOpWidenOrShorten:
367 case CastOpPointerReinterpret:
368 *const_val = *other_val;
369 break;
370 case CastOpPtrToInt:
371 case CastOpIntToPtr:
372 // can't do it
373 break;
374 case CastOpToUnknownSizeArray:
375 {
376 assert(other_type->id == TypeTableEntryIdArray);
377
378 ConstExprValue *all_fields = allocate<ConstExprValue>(2);
379 ConstExprValue *ptr_field = &all_fields[0];
380 ConstExprValue *len_field = &all_fields[1];
381
382 const_val->data.x_struct.fields = allocate<ConstExprValue*>(2);
383 const_val->data.x_struct.fields[0] = ptr_field;
384 const_val->data.x_struct.fields[1] = len_field;
385
386 ptr_field->ok = true;
387 ptr_field->data.x_ptr.ptr = other_val->data.x_array.fields;
388 ptr_field->data.x_ptr.len = other_type->data.array.len;
389
390 len_field->ok = true;
391 bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len);
392
393 const_val->ok = true;
394 break;
395 }
396 case CastOpMaybeWrap:
397 const_val->data.x_maybe = other_val;
398 const_val->ok = true;
399 break;
400 case CastOpErrorWrap:
401 const_val->data.x_err.err = nullptr;
402 const_val->data.x_err.payload = other_val;
403 const_val->ok = true;
404 break;
405 case CastOpPureErrorWrap:
406 const_val->data.x_err.err = other_val->data.x_err.err;
407 const_val->ok = true;
408 break;
409 case CastOpErrToInt:
410 {
411 uint64_t value = other_val->data.x_err.err ? other_val->data.x_err.err->value : 0;
412 bignum_init_unsigned(&const_val->data.x_bignum, value);
413 const_val->ok = true;
414 break;
415 }
416 case CastOpIntToFloat:
417 bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum);
418 const_val->ok = true;
419 break;
420 case CastOpFloatToInt:
421 bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum);
422 const_val->ok = true;
423 break;
424 case CastOpBoolToInt:
425 bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0);
426 const_val->ok = true;
427 break;
428 }
429}
430
431static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
432 assert(node->type == NodeTypeFnCallExpr);
433
434 CastOp cast_op = node->data.fn_call_expr.cast_op;
435 if (node->data.fn_call_expr.is_builtin) {
436 zig_panic("TODO");
437 } else if (cast_op != CastOpNoCast) {
438 AstNode *expr_node = node->data.fn_call_expr.params.at(0);
439 Expr *expr = get_resolved_expr(expr_node);
440 eval_const_expr_implicit_cast(cast_op, &expr->const_val, expr->type_entry, out_val);
441 return false;
442 }
443
444 AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
445 if (node->data.fn_call_expr.enum_type) {
446 zig_panic("TODO");
447 }
448
449 FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
450
451 if (fn_ref_expr->type == NodeTypeFieldAccessExpr &&
452 fn_ref_expr->data.field_access_expr.is_member_fn)
453 {
454 zig_panic("TODO");
455 }
456
457 if (!fn_table_entry) {
458 zig_panic("TODO");
459 }
460
461 int param_count = node->data.fn_call_expr.params.length;
462 ConstExprValue *args = allocate<ConstExprValue>(param_count);
463 for (int i = 0; i < param_count; i += 1) {
464 AstNode *param_expr_node = node->data.fn_call_expr.params.at(i);
465 ConstExprValue *param_val = &args[i];
466 if (eval_expr(ef, param_expr_node, param_val)) return true;
467 }
468
469 ef->root->branches_used += 1;
470
471 eval_fn_args(ef->root, fn_table_entry, args, out_val);
472 return false;
473}
474
475static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
476 if (ef->root->branches_used > ef->root->branch_quota) {
477 ef->root->exceeded_quota_node = node;
478 return true;
479 }
480 switch (node->type) {
481 case NodeTypeBlock:
482 return eval_block(ef, node, out);
483 case NodeTypeReturnExpr:
484 return eval_return(ef, node, out);
485 case NodeTypeBinOpExpr:
486 return eval_bin_op_expr(ef, node, out);
487 case NodeTypeSymbol:
488 return eval_symbol_expr(ef, node, out);
489 case NodeTypeContainerInitExpr:
490 return eval_container_init_expr(ef, node, out);
491 case NodeTypeIfBoolExpr:
492 return eval_if_bool_expr(ef, node, out);
493 case NodeTypeFnCallExpr:
494 return eval_fn_call_expr(ef, node, out);
495 case NodeTypeRoot:
496 case NodeTypeFnProto:
497 case NodeTypeFnDef:
498 case NodeTypeFnDecl:
499 case NodeTypeParamDecl:
500 case NodeTypeDirective:
501 case NodeTypeDefer:
502 case NodeTypeVariableDeclaration:
503 case NodeTypeTypeDecl:
504 case NodeTypeErrorValueDecl:
505 case NodeTypeUnwrapErrorExpr:
506 case NodeTypeNumberLiteral:
507 case NodeTypeStringLiteral:
508 case NodeTypeCharLiteral:
509 case NodeTypePrefixOpExpr:
510 case NodeTypeArrayAccessExpr:
511 case NodeTypeSliceExpr:
512 case NodeTypeFieldAccessExpr:
513 case NodeTypeUse:
514 case NodeTypeBoolLiteral:
515 case NodeTypeNullLiteral:
516 case NodeTypeUndefinedLiteral:
517 case NodeTypeIfVarExpr:
518 case NodeTypeWhileExpr:
519 case NodeTypeForExpr:
520 case NodeTypeSwitchExpr:
521 case NodeTypeSwitchProng:
522 case NodeTypeSwitchRange:
523 case NodeTypeLabel:
524 case NodeTypeGoto:
525 case NodeTypeBreak:
526 case NodeTypeContinue:
527 case NodeTypeAsmExpr:
528 case NodeTypeStructDecl:
529 case NodeTypeStructField:
530 case NodeTypeStructValueField:
531 case NodeTypeArrayType:
532 case NodeTypeErrorType:
533 case NodeTypeTypeLiteral:
534 zig_unreachable();
535 }
536}
537
538static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args, ConstExprValue *out_val) {
539 EvalFn ef = {0};
540 ef.root = efr;
541 ef.fn = fn;
542 ef.return_expr = out_val;
543
544 EvalScope *root_scope = allocate<EvalScope>(1);
545 root_scope->block_context = fn->fn_def_node->data.fn_def.body->block_context;
546 ef.scope_stack.append(root_scope);
547
548 int param_count = fn->type_entry->data.fn.fn_type_id.param_count;
549 for (int i = 0; i < param_count; i += 1) {
550 AstNode *decl_param_node = fn->proto_node->data.fn_proto.params.at(i);
551 assert(decl_param_node->type == NodeTypeParamDecl);
552
553 ConstExprValue *src_const_val = &args[i];
554 assert(src_const_val->ok);
555
556 root_scope->vars.add_one();
557 EvalVar *eval_var = &root_scope->vars.last();
558 eval_var->name = &decl_param_node->data.param_decl.name;
559 eval_var->value = *src_const_val;
560 }
561
562 return eval_expr(&ef, fn->fn_def_node->data.fn_def.body, out_val);
563
564}
565
566bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_val,
567 int branch_quota, AstNode *struct_node)
568{
569 assert(node->type == NodeTypeFnCallExpr);
570
571 EvalFnRoot efr = {0};
572 efr.codegen = g;
573 efr.fn = fn;
574 efr.call_node = node;
575 efr.branch_quota = branch_quota;
576
577 int call_param_count = node->data.fn_call_expr.params.length;
578 int type_param_count = fn->type_entry->data.fn.fn_type_id.param_count;
579 ConstExprValue *args = allocate<ConstExprValue>(type_param_count);
580 int next_arg_index = 0;
581 if (struct_node) {
582 ConstExprValue *struct_val = &get_resolved_expr(struct_node)->const_val;
583 assert(struct_val->ok);
584 args[next_arg_index] = *struct_val;
585 next_arg_index += 1;
586 }
587 for (int call_index = 0; call_index < call_param_count; call_index += 1) {
588 AstNode *call_param_node = node->data.fn_call_expr.params.at(call_index);
589 ConstExprValue *src_const_val = &get_resolved_expr(call_param_node)->const_val;
590 assert(src_const_val->ok);
591 args[next_arg_index] = *src_const_val;
592 next_arg_index += 1;
593 }
594 eval_fn_args(&efr, fn, args, out_val);
595
596 if (efr.exceeded_quota_node) {
597 ErrorMsg *msg = add_node_error(g, fn->fn_def_node,
598 buf_sprintf("function evaluation exceeded %d branches", efr.branch_quota));
599
600 add_error_note(g, msg, efr.call_node, buf_sprintf("called from here"));
601 add_error_note(g, msg, efr.exceeded_quota_node, buf_sprintf("quota exceeded here"));
602 return true;
603 }
604
605 return false;
606}
607
src/eval.hpp created+24
......@@ -0,0 +1,24 @@
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
13bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_val, int branch_quota,
14 AstNode *struct_node);
15
16bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry);
17void 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
20void eval_const_expr_implicit_cast(CastOp cast_op,
21 ConstExprValue *other_val, TypeTableEntry *other_type,
22 ConstExprValue *const_val);
23
24#endif