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 }