authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-11 01:15:17-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-11 01:15:17-07:00
logaaa62eda727e5f878a7946e22ea294bde9a8364f
treeaab920d548670f0d0505f5e3bf4d920ea2df1b9f
parent2061cd50c0ec6cfcac60ea98f49e4333a4f508f1

simple enum support


4 files changed, 95 insertions(+), 18 deletions(-)

src/all_types.hpp+9-8
...@@ -87,6 +87,12 @@ struct TopLevelDecl {...@@ -87,6 +87,12 @@ struct TopLevelDecl {
87 bool in_current_deps;87 bool in_current_deps;
88};88};
8989
90struct TypeEnumField {
91 Buf *name;
92 TypeTableEntry *type_entry;
93 uint32_t value;
94};
95
90enum NodeType {96enum NodeType {
91 NodeTypeRoot,97 NodeTypeRoot,
92 NodeTypeRootExportDecl,98 NodeTypeRootExportDecl,
...@@ -316,6 +322,7 @@ struct AstNodeFieldAccessExpr {...@@ -316,6 +322,7 @@ struct AstNodeFieldAccessExpr {
316322
317 // populated by semantic analyzer323 // populated by semantic analyzer
318 TypeStructField *type_struct_field;324 TypeStructField *type_struct_field;
325 TypeEnumField *type_enum_field;
319 Expr resolved_expr;326 Expr resolved_expr;
320};327};
321328
...@@ -680,11 +687,10 @@ struct TypeStructField {...@@ -680,11 +687,10 @@ struct TypeStructField {
680 int src_index;687 int src_index;
681 int gen_index;688 int gen_index;
682};689};
683
684struct TypeTableEntryStruct {690struct TypeTableEntryStruct {
685 AstNode *decl_node;691 AstNode *decl_node;
686 bool is_packed;692 bool is_packed;
687 int field_count;693 uint32_t field_count;
688 TypeStructField *fields;694 TypeStructField *fields;
689 uint64_t size_bytes;695 uint64_t size_bytes;
690 bool is_invalid; // true if any fields are invalid696 bool is_invalid; // true if any fields are invalid
...@@ -709,14 +715,9 @@ struct TypeTableEntryMetaType {...@@ -709,14 +715,9 @@ struct TypeTableEntryMetaType {
709 TypeTableEntry *child_type;715 TypeTableEntry *child_type;
710};716};
711717
712struct TypeEnumField {
713 Buf *name;
714 TypeTableEntry *type_entry;
715};
716
717struct TypeTableEntryEnum {718struct TypeTableEntryEnum {
718 AstNode *decl_node;719 AstNode *decl_node;
719 int field_count;720 uint32_t field_count;
720 TypeEnumField *fields;721 TypeEnumField *fields;
721 bool is_invalid; // true if any fields are invalid722 bool is_invalid; // true if any fields are invalid
722723
src/analyze.cpp+52-8
...@@ -176,7 +176,7 @@ static TypeTableEntry *get_int_type_unsigned(CodeGen *g, uint64_t x) {...@@ -176,7 +176,7 @@ static TypeTableEntry *get_int_type_unsigned(CodeGen *g, uint64_t x) {
176176
177static TypeTableEntry *get_meta_type(CodeGen *g, TypeTableEntry *child_type) {177static TypeTableEntry *get_meta_type(CodeGen *g, TypeTableEntry *child_type) {
178 if (child_type->meta_parent) {178 if (child_type->meta_parent) {
179 return child_type->maybe_parent;179 return child_type->meta_parent;
180 } else {180 } else {
181 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMetaType);181 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMetaType);
182 buf_resize(&entry->name, 0);182 buf_resize(&entry->name, 0);
...@@ -705,7 +705,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt...@@ -705,7 +705,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
705705
706 assert(enum_type->di_type);706 assert(enum_type->di_type);
707707
708 int field_count = decl_node->data.struct_decl.fields.length;708 uint32_t field_count = decl_node->data.struct_decl.fields.length;
709709
710 enum_type->data.enumeration.field_count = field_count;710 enum_type->data.enumeration.field_count = field_count;
711 enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);711 enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
...@@ -723,12 +723,13 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt...@@ -723,12 +723,13 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
723 enum_type->data.enumeration.embedded_in_current = true;723 enum_type->data.enumeration.embedded_in_current = true;
724724
725 int gen_field_index = 0;725 int gen_field_index = 0;
726 for (int i = 0; i < field_count; i += 1) {726 for (uint32_t i = 0; i < field_count; i += 1) {
727 AstNode *field_node = decl_node->data.struct_decl.fields.at(i);727 AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
728 TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];728 TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
729 type_enum_field->name = &field_node->data.struct_field.name;729 type_enum_field->name = &field_node->data.struct_field.name;
730 type_enum_field->type_entry = resolve_type(g, field_node->data.struct_field.type,730 type_enum_field->type_entry = resolve_type(g, field_node->data.struct_field.type,
731 import, import->block_context, false);731 import, import->block_context, false);
732 type_enum_field->value = i;
732733
733 di_enumerators[i] = LLVMZigCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i);734 di_enumerators[i] = LLVMZigCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i);
734735
...@@ -1496,6 +1497,16 @@ TypeTableEntry *find_container(BlockContext *context, Buf *name) {...@@ -1496,6 +1497,16 @@ TypeTableEntry *find_container(BlockContext *context, Buf *name) {
1496 return nullptr;1497 return nullptr;
1497}1498}
14981499
1500static TypeEnumField *get_enum_field(TypeTableEntry *enum_type, Buf *name) {
1501 for (int i = 0; i < enum_type->data.enumeration.field_count; i += 1) {
1502 TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
1503 if (buf_eql_buf(type_enum_field->name, name)) {
1504 return type_enum_field;
1505 }
1506 }
1507 return nullptr;
1508}
1509
1499static TypeStructField *get_struct_field(TypeTableEntry *struct_type, Buf *name) {1510static TypeStructField *get_struct_field(TypeTableEntry *struct_type, Buf *name) {
1500 for (int i = 0; i < struct_type->data.structure.field_count; i += 1) {1511 for (int i = 0; i < struct_type->data.structure.field_count; i += 1) {
1501 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];1512 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
...@@ -1506,13 +1517,46 @@ static TypeStructField *get_struct_field(TypeTableEntry *struct_type, Buf *name)...@@ -1506,13 +1517,46 @@ static TypeStructField *get_struct_field(TypeTableEntry *struct_type, Buf *name)
1506 return nullptr;1517 return nullptr;
1507}1518}
15081519
1520static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1521 AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name)
1522{
1523 TypeEnumField *type_enum_field = get_enum_field(enum_type, field_name);
1524 field_access_node->data.field_access_expr.type_enum_field = type_enum_field;
1525 if (type_enum_field) {
1526 if (value_node) {
1527 if (type_enum_field->type_entry->id == TypeTableEntryIdVoid) {
1528 add_node_error(g, field_access_node,
1529 buf_sprintf("enum value '%s.%s' has void parameter",
1530 buf_ptr(&enum_type->name),
1531 buf_ptr(field_name)));
1532
1533 } else {
1534 analyze_expression(g, import, context, type_enum_field->type_entry, value_node);
1535 }
1536 } else if (type_enum_field->type_entry->id == TypeTableEntryIdVoid) {
1537 // OK
1538 } else {
1539 add_node_error(g, field_access_node,
1540 buf_sprintf("enum value '%s.%s' requires parameter of type '%s'",
1541 buf_ptr(&enum_type->name),
1542 buf_ptr(field_name),
1543 buf_ptr(&type_enum_field->type_entry->name)));
1544 }
1545 } else {
1546 add_node_error(g, field_access_node,
1547 buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
1548 buf_ptr(&enum_type->name)));
1549 }
1550 return enum_type;
1551}
1552
1509static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,1553static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1510 AstNode *node)1554 AstNode *node)
1511{1555{
1512 assert(node->type == NodeTypeFieldAccessExpr);1556 assert(node->type == NodeTypeFieldAccessExpr);
15131557
1514 TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr,1558 AstNode *struct_expr_node = node->data.field_access_expr.struct_expr;
1515 node->data.field_access_expr.struct_expr);1559 TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, struct_expr_node);
15161560
1517 TypeTableEntry *return_type;1561 TypeTableEntry *return_type;
15181562
...@@ -1548,9 +1592,9 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i...@@ -1548,9 +1592,9 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
1548 } else if (struct_type->id == TypeTableEntryIdMetaType &&1592 } else if (struct_type->id == TypeTableEntryIdMetaType &&
1549 struct_type->data.meta_type.child_type->id == TypeTableEntryIdEnum)1593 struct_type->data.meta_type.child_type->id == TypeTableEntryIdEnum)
1550 {1594 {
1551 //TypeTableEntry *enum_type = struct_type->data.meta_type.child_type;1595 TypeTableEntry *enum_type = struct_type->data.meta_type.child_type;
15521596 Buf *field_name = &node->data.field_access_expr.field_name;
1553 zig_panic("TODO enum field access");1597 return_type = analyze_enum_value_expr(g, import, context, node, nullptr, enum_type, field_name);
1554 } else {1598 } else {
1555 if (struct_type->id != TypeTableEntryIdInvalid) {1599 if (struct_type->id != TypeTableEntryIdInvalid) {
1556 add_node_error(g, node,1600 add_node_error(g, node,
src/codegen.cpp+21-2
...@@ -500,6 +500,15 @@ static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lva...@@ -500,6 +500,15 @@ static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lva
500 }500 }
501}501}
502502
503static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntry *enum_type) {
504 assert(node->type == NodeTypeFieldAccessExpr);
505
506 uint64_t value = node->data.field_access_expr.type_enum_field->value;
507 LLVMTypeRef tag_type_ref = enum_type->type_ref;
508
509 return LLVMConstInt(tag_type_ref, value, false);
510}
511
503static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) {512static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) {
504 assert(node->type == NodeTypeFieldAccessExpr);513 assert(node->type == NodeTypeFieldAccessExpr);
505514
...@@ -532,6 +541,12 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lva...@@ -532,6 +541,12 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lva
532 add_debug_source_node(g, node);541 add_debug_source_node(g, node);
533 return LLVMBuildLoad(g->builder, ptr, "");542 return LLVMBuildLoad(g->builder, ptr, "");
534 }543 }
544 } else if (struct_type->id == TypeTableEntryIdMetaType &&
545 struct_type->data.meta_type.child_type->id == TypeTableEntryIdEnum)
546 {
547 assert(!is_lvalue);
548 TypeTableEntry *enum_type = struct_type->data.meta_type.child_type;
549 return gen_enum_value_expr(g, node, enum_type);
535 } else {550 } else {
536 zig_panic("gen_field_access_expr bad struct type");551 zig_panic("gen_field_access_expr bad struct type");
537 }552 }
...@@ -875,11 +890,15 @@ static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) {...@@ -875,11 +890,15 @@ static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) {
875 if (op1_type->id == TypeTableEntryIdFloat) {890 if (op1_type->id == TypeTableEntryIdFloat) {
876 LLVMRealPredicate pred = cmp_op_to_real_predicate(node->data.bin_op_expr.bin_op);891 LLVMRealPredicate pred = cmp_op_to_real_predicate(node->data.bin_op_expr.bin_op);
877 return LLVMBuildFCmp(g->builder, pred, val1, val2, "");892 return LLVMBuildFCmp(g->builder, pred, val1, val2, "");
878 } else {893 } else if (op1_type->id == TypeTableEntryIdInt) {
879 assert(op1_type->id == TypeTableEntryIdInt);
880 LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op,894 LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op,
881 op1_type->data.integral.is_signed);895 op1_type->data.integral.is_signed);
882 return LLVMBuildICmp(g->builder, pred, val1, val2, "");896 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
897 } else if (op1_type->id == TypeTableEntryIdEnum) {
898 LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, false);
899 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
900 } else {
901 zig_unreachable();
883 }902 }
884}903}
885904
test/run_tests.cpp+13
...@@ -1031,6 +1031,19 @@ fn print_ok(val: #typeof(x)) -> #typeof(foo) {...@@ -1031,6 +1031,19 @@ fn print_ok(val: #typeof(x)) -> #typeof(foo) {
1031}1031}
1032const foo : i32 = 0;1032const foo : i32 = 0;
1033 )SOURCE", "OK\n");1033 )SOURCE", "OK\n");
1034
1035 add_simple_case("enum with void types", R"SOURCE(
1036use "std.zig";
1037enum Foo { A, B, C, D, }
1038pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
1039 const foo : Foo = Foo.B;
1040 if (foo != Foo.B) {
1041 print_str("BAD\n");
1042 }
1043 print_str("OK\n");
1044 return 0;
1045}
1046 )SOURCE", "OK\n");
1034}1047}
10351048
10361049