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.struct_; 5 6 import vox.all; 7 8 enum TypeFlags : ushort 9 { 10 type_size_mask = 1 << 0 | 1 << 1, // used for reading value 11 size_not_calculated = 0 << 1, // used for setting flags 12 size_is_calculating = 1 << 1, // used for setting flags 13 size_is_calculated = 2 << 1, // used for setting flags 14 15 userFlag = 1 << 2, 16 } 17 18 enum StructFlags : ushort 19 { 20 isOpaque = TypeFlags.userFlag << 0, 21 // Set if struct contains meta type member variables or methods 22 isCtfeOnly = TypeFlags.userFlag << 1, 23 isUnion = TypeFlags.userFlag << 2, 24 } 25 26 @(AstType.decl_struct) 27 struct StructDeclNode { 28 mixin ScopeDeclNodeData!(AstType.decl_struct, AstFlags.isType); 29 ScopeIndex parentScope; 30 ScopeIndex memberScope; // null if no body 31 Identifier id; 32 IrIndex irType; 33 IrIndex defaultVal; 34 35 this(TokenIndex loc, ScopeIndex parentScope, ScopeIndex memberScope, Identifier id) 36 { 37 this.loc = loc; 38 this.astType = AstType.decl_struct; 39 this.flags = AstFlags.isType; 40 this.parentScope = parentScope; 41 this.memberScope = memberScope; 42 this.id = id; 43 setPropertyState(NodeProperty.type, PropertyState.calculated); 44 } 45 46 TypeNode* typeNode() return { return cast(TypeNode*)&this; } 47 bool isOpaque() { return cast(bool)(flags & StructFlags.isOpaque); } 48 bool isCtfeOnly() { return cast(bool)(flags & StructFlags.isCtfeOnly); } 49 bool isUnion() { return cast(bool)(flags & StructFlags.isUnion); } 50 string structOrUnionString() { return isUnion ? "union" : "struct"; } 51 SizeAndAlignment sizealign(CompilationContext* c) { 52 gen_ir_type_struct(&this, c); 53 IrTypeStruct* structType = &c.types.get!IrTypeStruct(irType); 54 return structType.sizealign; 55 } 56 } 57 58 struct StructDynMemberIterator 59 { 60 StructDeclNode* node; 61 CompilationContext* c; 62 63 int opApply(scope int delegate(uint index, ref AstIndex member) dg) 64 { 65 uint memberIndex; 66 foreach(ref AstIndex decl; node.declarations) 67 { 68 if (!isDynamicStructMember(decl, c)) continue; 69 if (auto res = dg(memberIndex, decl)) return res; 70 ++memberIndex; 71 } 72 return 0; 73 } 74 } 75 76 bool isDynamicStructMember(AstIndex decl, CompilationContext* c) { 77 AstNode* member = decl.get_node(c); 78 if (member.astType != AstType.decl_var) return false; 79 VariableDeclNode* memberVar = member.as!VariableDeclNode(c); 80 if (!memberVar.isMember) return false; 81 return true; 82 } 83 84 void print_struct(StructDeclNode* node, ref AstPrintState state) 85 { 86 state.print(node.isUnion ? "UNION " : "STRUCT ", state.context.idString(node.id), node.isCtfeOnly ? " #ctfe" : null); 87 print_ast(node.declarations, state); 88 } 89 90 void post_clone_struct(StructDeclNode* node, ref CloneState state) 91 { 92 state.fixScope(node.parentScope); 93 state.fixScope(node.memberScope); 94 state.fixAstNodes(node.declarations); 95 } 96 97 void name_register_self_struct(AstIndex nodeIndex, StructDeclNode* node, ref NameRegisterState state) { 98 node.state = AstNodeState.name_register_self; 99 node.parentScope.insert_scope(node.id, nodeIndex, state.context); 100 node.state = AstNodeState.name_register_self_done; 101 } 102 103 void name_register_nested_struct(AstIndex nodeIndex, StructDeclNode* node, ref NameRegisterState state) { 104 node.state = AstNodeState.name_register_nested; 105 require_name_register(node.declarations, state); 106 node.state = AstNodeState.name_register_nested_done; 107 } 108 109 void name_resolve_struct(StructDeclNode* node, ref NameResolveState state) { 110 node.state = AstNodeState.name_resolve; 111 require_name_resolve(node.declarations, state); 112 node.state = AstNodeState.name_resolve_done; 113 } 114 115 void type_check_struct(StructDeclNode* node, ref TypeCheckState state) 116 { 117 node.state = AstNodeState.type_check; 118 require_type_check(node.declarations, state); 119 gen_ir_type_struct(node, state.context); 120 node.state = AstNodeState.type_check_done; 121 } 122 123 TypeConvResKind type_conv_struct(StructDeclNode* node, AstIndex typeBIndex, ref AstIndex expr, CompilationContext* c) 124 { 125 TypeNode* typeB = typeBIndex.get_type(c); 126 127 switch(typeB.astType) with(AstType) 128 { 129 case decl_enum: 130 if (c.getAstNodeIndex(node) == typeB.as_enum.memberType.get_node_type(c)) 131 return TypeConvResKind.no_e; 132 goto default; 133 default: return TypeConvResKind.fail; 134 } 135 } 136 137 IrIndex gen_init_value_struct(StructDeclNode* node, CompilationContext* c) 138 { 139 if (node.defaultVal.isDefined) return node.defaultVal; 140 141 IrIndex structType = node.gen_ir_type_struct(c); 142 uint numStructMembers = c.types.get!IrTypeStruct(structType).numMembers; 143 uint numArgSlots = node.isUnion ? 2 : numStructMembers; 144 IrIndex[] args = c.allocateTempArray!IrIndex(numArgSlots); 145 scope(exit) c.freeTempArray(args); 146 147 bool allZeroes = true; 148 foreach(uint memberIndex, AstIndex member; StructDynMemberIterator(node, c)) 149 { 150 VariableDeclNode* memberVar = member.get!VariableDeclNode(c); 151 IrIndex memberValue = memberVar.gen_init_value_var(c); 152 if (!memberValue.isConstantZero) allZeroes = false; 153 154 if (node.isUnion) { 155 // only initialize first member in default struct initializer 156 args[0] = c.constants.addZeroConstant(structType); // member index 157 args[1] = memberValue; // value 158 break; 159 } 160 161 args[memberIndex] = memberValue; 162 } 163 if (allZeroes) 164 node.defaultVal = c.constants.addZeroConstant(structType); 165 else 166 node.defaultVal = c.constants.addAggrecateConstant(structType, args); 167 168 return node.defaultVal; 169 } 170 171 void gen_ir_header_struct(StructDeclNode* node, CompilationContext* c) 172 { 173 final switch(node.getPropertyState(NodeProperty.ir_header)) { 174 case PropertyState.not_calculated: break; 175 case PropertyState.calculating: c.circular_dependency; 176 case PropertyState.calculated: return; 177 } 178 179 c.begin_node_property_calculation(node, NodeProperty.ir_header); 180 scope(exit) c.end_node_property_calculation(node, NodeProperty.ir_header); 181 182 uint numFields = 0; 183 foreach(uint memberIndex, AstIndex member; StructDynMemberIterator(node, c)) { 184 ++numFields; 185 } 186 187 node.irType = c.types.appendStruct(numFields, node.isUnion); 188 } 189 190 191 IrIndex gen_ir_type_struct(StructDeclNode* node, CompilationContext* c, AllowHeaderOnly allow_header_only = AllowHeaderOnly.no) 192 out(res; res.isTypeStruct, "Not a struct type") 193 { 194 final switch(node.getPropertyState(NodeProperty.ir_body)) { 195 case PropertyState.not_calculated: break; 196 case PropertyState.calculating: 197 if (allow_header_only) return node.irType; 198 c.circular_dependency; 199 case PropertyState.calculated: return node.irType; 200 } 201 202 // dependencies 203 gen_ir_header_struct(node, c); 204 205 c.begin_node_property_calculation(node, NodeProperty.ir_body); 206 scope(exit) c.end_node_property_calculation(node, NodeProperty.ir_body); 207 208 209 IrTypeStruct* structType = &c.types.get!IrTypeStruct(node.irType); 210 IrTypeStructMember[] members = structType.members; 211 212 uint memberIndex; 213 uint memberOffset; 214 uint maxMemberSize; 215 ubyte maxAlignmentPower = 0; 216 217 foreach(AstIndex memberAstIndex; node.declarations) 218 { 219 AstNode* member = c.getAstNode(memberAstIndex); 220 if (member.astType == AstType.decl_var) 221 { 222 if (!member.isMember) continue; // skip static members 223 auto var = member.as!(VariableDeclNode)(c); 224 require_type_check(var.type, c, IsNested.no); 225 IrIndex type = var.type.gen_ir_type(c); 226 SizeAndAlignment memberInfo = c.types.typeSizeAndAlignment(type); 227 maxAlignmentPower = max(maxAlignmentPower, memberInfo.alignmentPower); 228 memberOffset = alignValue!uint(memberOffset, 1 << memberInfo.alignmentPower); 229 if (node.isUnion) 230 members[memberIndex++] = IrTypeStructMember(type, 0); 231 else 232 members[memberIndex++] = IrTypeStructMember(type, memberOffset); 233 memberOffset += memberInfo.size; 234 maxMemberSize = max(maxMemberSize, memberInfo.size); 235 236 if (var.type.isMetaType(c)) { 237 node.flags |= StructFlags.isCtfeOnly; 238 } 239 } else if (member.astType == AstType.decl_function) { 240 if (member.as!(FunctionDeclNode)(c).isCtfeOnly(c)) { 241 node.flags |= StructFlags.isCtfeOnly; 242 } 243 } 244 } 245 246 memberOffset = alignValue!uint(memberOffset, 1 << maxAlignmentPower); 247 248 if (node.isUnion) 249 structType.sizealign = SizeAndAlignment(maxMemberSize, maxAlignmentPower); 250 else 251 structType.sizealign = SizeAndAlignment(memberOffset, maxAlignmentPower); 252 253 return node.irType; 254 }