1 /// Copyright: Copyright (c) 2017-2019 Andrey Penechko. 2 /// License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 3 /// Authors: Andrey Penechko. 4 module vox.fe.ast.decl.enum_; 5 6 import vox.all; 7 import vox.fe.ast.ast_index; 8 9 @(AstType.decl_enum) 10 struct EnumDeclaration 11 { 12 mixin ScopeDeclNodeData!(AstType.decl_enum, AstFlags.isType); 13 ScopeIndex parentScope; 14 ScopeIndex memberScope; 15 AstIndex memberType; 16 Identifier id; 17 18 private enum Flags : ushort 19 { 20 isAnonymous = AstFlags.userFlag 21 } 22 23 this(TokenIndex loc, ScopeIndex parentScope, ScopeIndex memberScope, AstNodes members, AstIndex memberType, Identifier id) 24 { 25 this.loc = loc; 26 this.astType = AstType.decl_enum; 27 this.flags = AstFlags.isType; 28 this.parentScope = parentScope; 29 this.memberScope = memberScope; 30 this.declarations = members; 31 this.memberType = memberType; 32 this.id = id; 33 } 34 35 /// Anonymous / not a type 36 this(TokenIndex loc, ScopeIndex parentScope, ScopeIndex memberScope, AstNodes members, AstIndex memberType) 37 { 38 this.loc = loc; 39 this.astType = AstType.decl_enum; 40 this.flags = Flags.isAnonymous; 41 this.parentScope = parentScope; 42 this.memberScope = memberScope; 43 this.declarations = members; 44 this.memberType = memberType; 45 } 46 47 bool isAnonymous() { return cast(bool)(flags & Flags.isAnonymous); } 48 SizeAndAlignment sizealign(CompilationContext* c) { 49 c.assertf(!isAnonymous, loc, "Anonymous enums are not a type"); 50 c.assertf(memberType.isDefined, loc, "Enum has no member type"); 51 return require_type_size(memberType, c); 52 } 53 } 54 55 void print_enum(EnumDeclaration* node, ref AstPrintState state) 56 { 57 if (node.isAnonymous) 58 state.print("ENUM ", node.memberType.printer(state.context)); 59 else 60 state.print("ENUM ", node.memberType.printer(state.context), " ", state.context.idString(node.id)); 61 print_ast(node.declarations, state); 62 } 63 64 void post_clone_enum(EnumDeclaration* node, ref CloneState state) 65 { 66 state.fixScope(node.parentScope); 67 state.fixScope(node.memberScope); 68 state.fixAstIndex(node.memberType); 69 state.fixAstNodes(node.declarations); 70 } 71 72 void name_register_self_enum(AstIndex nodeIndex, EnumDeclaration* node, ref NameRegisterState state) { 73 node.state = AstNodeState.name_register_self; 74 if (!node.isAnonymous) node.parentScope.insert_scope(node.id, nodeIndex, state.context); 75 node.state = AstNodeState.name_register_self_done; 76 } 77 78 void name_register_nested_enum(AstIndex nodeIndex, EnumDeclaration* node, ref NameRegisterState state) { 79 node.state = AstNodeState.name_register_nested; 80 require_name_register(node.memberType, state); 81 require_name_register(node.declarations, state); 82 node.state = AstNodeState.name_register_nested_done; 83 } 84 85 void name_resolve_enum(EnumDeclaration* node, ref NameResolveState state) { 86 node.state = AstNodeState.name_resolve; 87 require_name_resolve(node.memberType, state); 88 require_name_resolve(node.declarations, state); 89 node.state = AstNodeState.name_resolve_done; 90 } 91 92 void type_check_enum(EnumDeclaration* node, ref TypeCheckState state) 93 { 94 node.state = AstNodeState.type_check; 95 require_type_check(node.memberType, state); 96 require_type_check(node.declarations, state, IsNested.no); 97 node.state = AstNodeState.type_check_done; 98 } 99 100 IrIndex gen_ir_type_enum(EnumDeclaration* node, CompilationContext* context) 101 { 102 return gen_ir_type(node.memberType, context); 103 } 104 105 IrIndex gen_init_value_enum(EnumDeclaration* node, CompilationContext* c) 106 { 107 c.assertf(node.declarations.length > 0, node.loc, "Enum %s has no members", c.idString(node.id)); 108 return node.declarations[0].get!EnumMemberDecl(c).gen_init_value_enum_member(c); 109 } 110 111 @(AstType.decl_enum_member) 112 struct EnumMemberDecl 113 { 114 mixin AstNodeData!(AstType.decl_enum_member); 115 ScopeIndex parentScope; 116 AstIndex type; 117 AstIndex initializer; 118 Identifier id; 119 ushort scopeIndex; 120 IrIndex initValue; // cached value of initializer, calculated in type check 121 } 122 123 IrIndex gen_init_value_enum_member(EnumMemberDecl* node, CompilationContext* c) { 124 final switch(node.getPropertyState(NodeProperty.init_value)) { 125 case PropertyState.not_calculated: break; 126 case PropertyState.calculating: c.circular_dependency; 127 case PropertyState.calculated: return node.initValue; 128 } 129 130 c.begin_node_property_calculation(node, NodeProperty.init_value); 131 scope(exit) c.end_node_property_calculation(node, NodeProperty.init_value); 132 133 if (node.initializer) { 134 if (node.type) { 135 auto type = node.type.get_node(c); 136 137 if (type.astType == AstType.decl_enum) { 138 require_type_check(type.as!EnumDeclaration(c).memberType, c, IsNested.no); 139 } else require_type_check(node.type, c); 140 141 require_type_check_expr(node.type, node.initializer, c); 142 //writefln(" autoconvTo %s", printer(node.type, c)); 143 TypeConvResKind res = checkTypeConversion(node.initializer.get_expr_type(c), node.type, node.initializer, c); 144 if (res.successful) { 145 insertCast(node.initializer, node.type, res, c); 146 if (node.initializer.get_expr_type(c) != CommonAstNodes.type_error) 147 node.initValue = eval_static_expr(node.initializer, c); 148 } else { 149 c.error(node.initializer.loc(c), 150 "Cannot convert expression of type `%s` to `%s`", 151 node.initializer.get_expr_type(c).printer(c), 152 node.type.printer(c)); 153 } 154 } else { 155 require_type_check(node.initializer, c); 156 node.type = get_expr_type(node.initializer, c); 157 if (node.type != CommonAstNodes.type_error) { 158 node.initValue = eval_static_expr(node.initializer, c); 159 } 160 } 161 } 162 return node.initValue; 163 } 164 165 void print_enum_member(EnumMemberDecl* node, ref AstPrintState state) 166 { 167 state.print("ENUM MEMBER ", node.type.printer(state.context), " ", state.context.idString(node.id)); 168 if (node.initializer) print_ast(node.initializer, state); 169 } 170 171 void post_clone_enum_member(EnumMemberDecl* node, ref CloneState state) 172 { 173 state.fixScope(node.parentScope); 174 state.fixAstIndex(node.type); 175 state.fixAstIndex(node.initializer); 176 } 177 178 void name_register_self_enum_member(AstIndex nodeIndex, EnumMemberDecl* node, ref NameRegisterState state) { 179 node.state = AstNodeState.name_register_self; 180 node.parentScope.insert_scope(node.id, nodeIndex, state.context); 181 node.state = AstNodeState.name_register_self_done; 182 } 183 184 void name_register_nested_enum_member(AstIndex nodeIndex, EnumMemberDecl* node, ref NameRegisterState state) { 185 CompilationContext* c = state.context; 186 node.state = AstNodeState.name_register_nested; 187 if (node.type) { 188 auto type = node.type.get_node(c); 189 if (type.astType == AstType.decl_enum) { 190 require_name_register(type.as!EnumDeclaration(c).memberType, state); 191 } else require_name_register(node.type, state); 192 } 193 if (node.initializer) require_name_register(node.initializer, state); 194 node.state = AstNodeState.name_register_nested_done; 195 } 196 197 void name_resolve_enum_member(EnumMemberDecl* node, ref NameResolveState state) { 198 CompilationContext* c = state.context; 199 node.state = AstNodeState.name_resolve; 200 if (node.type) { 201 auto type = node.type.get_node(c); 202 if (type.astType == AstType.decl_enum) { 203 require_name_resolve(type.as!EnumDeclaration(c).memberType, state); 204 } else require_name_resolve(node.type, state); 205 } 206 if (node.initializer) require_name_resolve(node.initializer, state); 207 node.state = AstNodeState.name_resolve_done; 208 } 209 210 void type_check_enum_member(EnumMemberDecl* node, ref TypeCheckState state) 211 { 212 CompilationContext* c = state.context; 213 node.state = AstNodeState.type_check; 214 gen_init_value_enum_member(node, c); 215 node.state = AstNodeState.type_check_done; 216 }