authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-11 17:29:59-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-12 09:35:33-07:00
logfa605485ea94ae9a59c8c1c0d66ee263e0bfa722
treed7b7eb1f48c910b44a910decf709f430df711c9f
parenta177e305342c25e83d6b65e24561c27e3c2e4c91

eval: support more node types


3 files changed, 212 insertions(+), 14 deletions(-)

src/all_types.hpp+2-1
......@@ -497,8 +497,8 @@ struct AstNodeWhileExpr {
497497};
498498
499499struct AstNodeForExpr {
500 AstNode *elem_node; // always a symbol
501500 AstNode *array_expr;
501 AstNode *elem_node; // always a symbol
502502 AstNode *index_node; // always a symbol, might be null
503503 AstNode *body;
504504
......@@ -1054,6 +1054,7 @@ struct EvalFnRoot {
10541054 int branch_quota;
10551055 int branches_used;
10561056 AstNode *exceeded_quota_node;
1057 bool abort;
10571058};
10581059
10591060struct EvalFn {
src/codegen.cpp+4-7
......@@ -1074,15 +1074,12 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lva
10741074
10751075 AstNode *struct_expr = node->data.field_access_expr.struct_expr;
10761076 TypeTableEntry *struct_type = get_expr_type(struct_expr);
1077 Buf *name = &node->data.field_access_expr.field_name;
10781077
10791078 if (struct_type->id == TypeTableEntryIdArray) {
1080 if (buf_eql_str(name, "len")) {
1081 return LLVMConstInt(g->builtin_types.entry_isize->type_ref,
1082 struct_type->data.array.len, false);
1083 } else {
1084 zig_panic("gen_field_access_expr bad array field");
1085 }
1079 Buf *name = &node->data.field_access_expr.field_name;
1080 assert(buf_eql_str(name, "len"));
1081 return LLVMConstInt(g->builtin_types.entry_isize->type_ref,
1082 struct_type->data.array.len, false);
10861083 } else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer &&
10871084 struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct))
10881085 {
src/eval.cpp+206-6
......@@ -327,6 +327,13 @@ static bool eval_container_init_expr(EvalFn *ef, AstNode *node, ConstExprValue *
327327 }
328328 } else if (container_type->id == TypeTableEntryIdVoid) {
329329 return false;
330 } else if (container_type->id == TypeTableEntryIdUnreachable) {
331 ef->root->abort = true;
332 ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node,
333 buf_sprintf("function evaluation reached unreachable expression"));
334 add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here"));
335 add_error_note(ef->root->codegen, msg, node, buf_sprintf("unreachable expression here"));
336 return true;
330337 } else {
331338 zig_panic("TODO");
332339 }
......@@ -472,6 +479,194 @@ static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val
472479 return false;
473480}
474481
482static bool eval_field_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
483 assert(node->type == NodeTypeFieldAccessExpr);
484
485 AstNode *struct_expr = node->data.field_access_expr.struct_expr;
486 TypeTableEntry *struct_type = get_resolved_expr(struct_expr)->type_entry;
487
488 if (struct_type->id == TypeTableEntryIdArray) {
489 Buf *name = &node->data.field_access_expr.field_name;
490 assert(buf_eql_str(name, "len"));
491 zig_panic("TODO");
492 } else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer &&
493 struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct))
494 {
495 TypeStructField *tsf = node->data.field_access_expr.type_struct_field;
496 assert(tsf);
497 if (struct_type->id == TypeTableEntryIdStruct) {
498 ConstExprValue struct_val = {0};
499 if (eval_expr(ef, struct_expr, &struct_val)) return true;
500 ConstExprValue *field_value = struct_val.data.x_struct.fields[tsf->src_index];
501 *out_val = *field_value;
502 } else {
503 zig_panic("TODO");
504 }
505 } else if (struct_type->id == TypeTableEntryIdMetaType) {
506 zig_panic("TODO");
507 } else if (struct_type->id == TypeTableEntryIdNamespace) {
508 zig_panic("TODO");
509 } else {
510 zig_unreachable();
511 }
512
513 return false;
514}
515
516static bool eval_for_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
517 assert(node->type == NodeTypeForExpr);
518
519 AstNode *array_node = node->data.for_expr.array_expr;
520 AstNode *elem_node = node->data.for_expr.elem_node;
521 AstNode *index_node = node->data.for_expr.index_node;
522 AstNode *body_node = node->data.for_expr.body;
523
524 TypeTableEntry *array_type = get_resolved_expr(array_node)->type_entry;
525
526 ConstExprValue array_val = {0};
527 if (eval_expr(ef, array_node, &array_val)) return true;
528
529 assert(elem_node->type == NodeTypeSymbol);
530 Buf *elem_var_name = &elem_node->data.symbol_expr.symbol;
531
532 Buf *index_var_name = nullptr;
533 if (index_node) {
534 assert(index_node->type == NodeTypeSymbol);
535 index_var_name = &index_node->data.symbol_expr.symbol;
536 }
537
538 uint64_t it_index = 0;
539 uint64_t array_len;
540 ConstExprValue **array_ptr_val;
541 if (array_type->id == TypeTableEntryIdArray) {
542 array_len = array_type->data.array.len;
543 array_ptr_val = array_val.data.x_array.fields;
544 } else if (array_type->id == TypeTableEntryIdStruct) {
545 ConstExprValue *len_field_val = array_val.data.x_struct.fields[1];
546 array_len = len_field_val->data.x_bignum.data.x_uint;
547 array_ptr_val = array_val.data.x_struct.fields[0]->data.x_ptr.ptr;
548 } else {
549 zig_unreachable();
550 }
551
552 EvalScope *my_scope = allocate<EvalScope>(1);
553 my_scope->block_context = body_node->block_context;
554 ef->scope_stack.append(my_scope);
555
556 for (; it_index < array_len; it_index += 1) {
557 my_scope->vars.resize(0);
558
559 if (index_var_name) {
560 my_scope->vars.add_one();
561 EvalVar *index_var = &my_scope->vars.last();
562 index_var->name = index_var_name;
563 memset(&index_var->value, 0, sizeof(ConstExprValue));
564 index_var->value.ok = true;
565 bignum_init_unsigned(&index_var->value.data.x_bignum, it_index);
566 }
567 {
568 my_scope->vars.add_one();
569 EvalVar *elem_var = &my_scope->vars.last();
570 elem_var->name = elem_var_name;
571 elem_var->value = *array_ptr_val[it_index];
572 }
573
574 ConstExprValue body_val = {0};
575 if (eval_expr(ef, body_node, &body_val)) return true;
576
577 ef->root->branches_used += 1;
578 }
579
580 ef->scope_stack.pop();
581
582 return false;
583}
584
585static bool eval_array_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
586 assert(node->type == NodeTypeArrayAccessExpr);
587
588 AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr;
589 AstNode *index_node = node->data.array_access_expr.subscript;
590
591 TypeTableEntry *array_type = get_resolved_expr(array_ref_node)->type_entry;
592
593 ConstExprValue array_val = {0};
594 if (eval_expr(ef, array_ref_node, &array_val)) return true;
595
596 ConstExprValue index_val = {0};
597 if (eval_expr(ef, index_node, &index_val)) return true;
598 uint64_t index_int = index_val.data.x_bignum.data.x_uint;
599
600 if (array_type->id == TypeTableEntryIdPointer) {
601 if (index_int >= array_val.data.x_ptr.len) {
602 zig_panic("TODO");
603 }
604 *out_val = *array_val.data.x_ptr.ptr[index_int];
605 } else if (array_type->id == TypeTableEntryIdStruct) {
606 assert(array_type->data.structure.is_unknown_size_array);
607
608 ConstExprValue *len_value = array_val.data.x_struct.fields[1];
609 uint64_t len_int = len_value->data.x_bignum.data.x_uint;
610 if (index_int >= len_int) {
611 zig_panic("TODO");
612 }
613
614 ConstExprValue *ptr_value = array_val.data.x_struct.fields[0];
615 *out_val = *ptr_value->data.x_ptr.ptr[index_int];
616 } else if (array_type->id == TypeTableEntryIdArray) {
617 uint64_t array_len = array_type->data.array.len;
618 if (index_int >= array_len) {
619 zig_panic("TODO");
620 }
621 *out_val = *array_val.data.x_array.fields[index_int];
622 } else {
623 zig_unreachable();
624 }
625
626 return false;
627}
628
629static bool eval_bool_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
630 assert(node->type == NodeTypeBoolLiteral);
631
632 out_val->ok = true;
633 out_val->deep_const = true;
634 out_val->data.x_bool = node->data.bool_literal.value;
635
636 return false;
637}
638
639static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
640 assert(node->type == NodeTypePrefixOpExpr);
641
642 PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op;
643
644 ConstExprValue expr_val = {0};
645 if (eval_expr(ef, node->data.prefix_op_expr.primary_expr, &expr_val)) return true;
646
647 switch (prefix_op) {
648 case PrefixOpBoolNot:
649 *out_val = expr_val;
650 out_val->data.x_bool = !out_val->data.x_bool;
651 break;
652 case PrefixOpBinNot:
653 case PrefixOpNegation:
654 case PrefixOpAddressOf:
655 case PrefixOpConstAddressOf:
656 case PrefixOpDereference:
657 case PrefixOpMaybe:
658 case PrefixOpError:
659 case PrefixOpUnwrapError:
660 case PrefixOpUnwrapMaybe:
661 zig_panic("TODO");
662 case PrefixOpInvalid:
663 zig_unreachable();
664 }
665
666 return false;
667}
668
669
475670static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
476671 if (ef->root->branches_used > ef->root->branch_quota) {
477672 ef->root->exceeded_quota_node = node;
......@@ -492,6 +687,16 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
492687 return eval_if_bool_expr(ef, node, out);
493688 case NodeTypeFnCallExpr:
494689 return eval_fn_call_expr(ef, node, out);
690 case NodeTypeFieldAccessExpr:
691 return eval_field_access_expr(ef, node, out);
692 case NodeTypeForExpr:
693 return eval_for_expr(ef, node, out);
694 case NodeTypeArrayAccessExpr:
695 return eval_array_access_expr(ef, node, out);
696 case NodeTypeBoolLiteral:
697 return eval_bool_literal_expr(ef, node, out);
698 case NodeTypePrefixOpExpr:
699 return eval_prefix_op_expr(ef, node, out);
495700 case NodeTypeRoot:
496701 case NodeTypeFnProto:
497702 case NodeTypeFnDef:
......@@ -506,17 +711,12 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
506711 case NodeTypeNumberLiteral:
507712 case NodeTypeStringLiteral:
508713 case NodeTypeCharLiteral:
509 case NodeTypePrefixOpExpr:
510 case NodeTypeArrayAccessExpr:
511714 case NodeTypeSliceExpr:
512 case NodeTypeFieldAccessExpr:
513715 case NodeTypeUse:
514 case NodeTypeBoolLiteral:
515716 case NodeTypeNullLiteral:
516717 case NodeTypeUndefinedLiteral:
517718 case NodeTypeIfVarExpr:
518719 case NodeTypeWhileExpr:
519 case NodeTypeForExpr:
520720 case NodeTypeSwitchExpr:
521721 case NodeTypeSwitchProng:
522722 case NodeTypeSwitchRange:
......@@ -602,6 +802,6 @@ bool eval_fn(CodeGen *g, AstNode *node, FnTableEntry *fn, ConstExprValue *out_va
602802 return true;
603803 }
604804
605 return false;
805 return efr.abort;
606806}
607807