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.expr.index;
5 
6 import vox.all;
7 
8 
9 @(AstType.expr_index)
10 struct IndexExprNode {
11 	mixin ExpressionNodeData!(AstType.expr_index);
12 	ScopeIndex parentScope; // needed to resolve `this` pointer in member access
13 	AstIndex array;
14 	AstNodes indices;
15 }
16 
17 void print_index(IndexExprNode* node, ref AstPrintState state)
18 {
19 	state.print("INDEX");
20 	print_ast(node.array, state);
21 	print_ast(node.indices, state);
22 }
23 
24 void post_clone_index(IndexExprNode* node, ref CloneState state)
25 {
26 	state.fixScope(node.parentScope);
27 	state.fixAstIndex(node.array);
28 	state.fixAstNodes(node.indices);
29 }
30 
31 void name_register_nested_index(IndexExprNode* node, ref NameRegisterState state) {
32 	node.state = AstNodeState.name_register_nested;
33 	require_name_register(node.array, state);
34 	require_name_register(node.indices, state);
35 	node.state = AstNodeState.name_register_nested_done;
36 }
37 
38 void name_resolve_index(ref AstIndex nodeIndex, IndexExprNode* node, ref NameResolveState state)
39 {
40 	CompilationContext* c = state.context;
41 
42 	node.state = AstNodeState.name_resolve;
43 	AstIndex arrayCopy = node.array; // link to node before it replaces itself
44 	require_name_resolve(node.array, state);
45 	require_name_resolve(node.indices, state);
46 
47 	AstIndex effective_array = node.array.get_effective_node(c);
48 
49 	if (effective_array.isType(c))
50 	{
51 		// convert to static array type inplace
52 
53 		// if this fires allocate new node instead of repurposing this one
54 		static assert(IndexExprNode.sizeof >= StaticArrayTypeNode.sizeof, "IndexExprNode.sizeof < StaticArrayTypeNode.sizeof");
55 		static assert(IndexExprNode.sizeof >= SliceTypeNode.sizeof, "IndexExprNode.sizeof < SliceTypeNode.sizeof");
56 		IndexExprNode copy = *node;
57 		if (copy.indices.length == 0)
58 		{
59 			// in the future this can also be slice expression
60 			auto sliceType = cast(SliceTypeNode*)node;
61 			*sliceType = SliceTypeNode(copy.loc, CommonAstNodes.type_type, copy.array);
62 		}
63 		else if (copy.indices.length == 1)
64 		{
65 			auto arrayType = cast(StaticArrayTypeNode*)node;
66 			*arrayType = StaticArrayTypeNode(copy.loc, CommonAstNodes.type_type, copy.array, copy.indices[0]);
67 		}
68 		else
69 		{
70 			c.error(node.loc, "Invalid number of indices: %s", copy.indices.length);
71 			node.type = CommonAstNodes.type_error;
72 		}
73 	}
74 	else if (effective_array.astType(c) == AstType.decl_template)
75 	{
76 		// must be template instantiation. Copy isType
77 		if (effective_array.get!TemplateDeclNode(c).body.isType(c))
78 			node.flags |= AstFlags.isType;
79 	}
80 	else if (effective_array.astType(c) == AstType.decl_alias_array && node.indices.length == 1)
81 	{
82 		if (arrayCopy.astType(c) == AstType.expr_name_use)
83 		{
84 			auto nameUse = arrayCopy.get!NameUseExprNode(c);
85 			// replace current node with aliased entity
86 			// reuse name_use
87 			IrIndex indexVal = eval_static_expr(node.indices[0], c);
88 			auto arr = effective_array.get!AliasArrayDeclNode(c);
89 			ulong index = c.constants.get(indexVal).i64;
90 
91 			if (index >= arr.items.length) {
92 				c.error(node.loc, "Accessing index %s of array of length %s", index, arr.items.length);
93 			} else {
94 				AstIndex item = arr.items[index];
95 				if (item.get_effective_node(c).isType(c))
96 					nameUse.flags |= AstFlags.isType;
97 				nameUse.resolve(item, c);
98 				nodeIndex = arrayCopy;
99 			}
100 
101 		}
102 	}
103 	node.state = AstNodeState.name_resolve_done;
104 }
105 
106 void type_check_index(ref AstIndex nodeIndex, IndexExprNode* node, ref TypeCheckState state)
107 {
108 	CompilationContext* c = state.context;
109 
110 	node.state = AstNodeState.type_check;
111 	scope(exit) node.state = AstNodeState.type_check_done;
112 
113 	AstIndex effective_array = node.array.get_effective_node(c);
114 	AstType array_ast_type = effective_array.astType(c);
115 
116 	if (array_ast_type == AstType.decl_template)
117 	{
118 		require_type_check(node.indices, state);
119 		// template instantiation
120 		nodeIndex = get_template_instance(effective_array, node.loc, node.indices, state);
121 		if (nodeIndex == CommonAstNodes.node_error) {
122 			node.type = CommonAstNodes.type_error;
123 			return;
124 		}
125 
126 		if (nodeIndex.astType(c) == AstType.decl_function)
127 		{
128 			nodeIndex = c.appendAst!CallExprNode(node.loc, AstIndex(), node.parentScope, nodeIndex);
129 			nodeIndex.setState(c, AstNodeState.name_resolve_done);
130 		}
131 
132 		require_type_check(nodeIndex, state);
133 		return;
134 	}
135 
136 	if (array_ast_type == AstType.expr_member)
137 	{
138 		// template instantiation
139 		MemberExprNode* memberExpr = effective_array.get!MemberExprNode(c);
140 		LookupResult res = lookupMember(effective_array, memberExpr, state);
141 
142 		if (res == LookupResult.success) {
143 			AstIndex memberIndex = memberExpr.member(c);
144 
145 			if (memberExpr.subType == MemberSubType.struct_templ_method) {
146 				// rewrite as call
147 				nodeIndex = c.appendAst!CallExprNode(node.loc, AstIndex(), node.parentScope, nodeIndex);
148 				nodeIndex.setState(c, AstNodeState.name_resolve_done);
149 				require_type_check(nodeIndex, state);
150 				return;
151 			}
152 		}
153 	}
154 
155 	node.array.flags(c) |= AstFlags.isLvalue;
156 	require_type_check(node.array, state);
157 	require_type_check(node.indices, state);
158 
159 	{
160 		if (node.indices.length != 1)
161 		{
162 			c.error(node.loc, "Array indexing only supports single index, not %s", node.indices.length);
163 			if (node.indices.length < 1) return;
164 			// if > 1 continue with 0-th index
165 		}
166 
167 		// array/ptr/slice indexing
168 		autoconvTo(node.indices[0], CommonAstNodes.type_i64, c);
169 		switch (node.array.get_expr_type(c).astType(c)) with(AstType)
170 		{
171 			case type_ptr, type_static_array, type_slice:
172 				// valid
173 				node.type = node.array.get_expr_type(c).get_type(c).getElementType(c);
174 				break;
175 			default:
176 				node.type = CommonAstNodes.type_error;
177 				c.error(node.loc, "Cannot index value of type `%s`", node.array.get_expr_type(c).printer(c));
178 				break;
179 		}
180 	}
181 }
182 
183 ExprValue ir_gen_index(ref IrGenState gen, IrIndex curBlock, ref IrLabel nextStmt, IndexExprNode* node)
184 {
185 	CompilationContext* c = gen.context;
186 
187 	c.assertf(node.indices.length == 1, "%s", node.indices.length);
188 
189 	IrLabel afterRight = IrLabel(curBlock);
190 	ExprValue indexLvalue = ir_gen_expr(gen, node.indices[0], curBlock, afterRight);
191 	curBlock = afterRight.blockIndex;
192 	IrIndex indexRvalue = indexLvalue.rvalue(gen, node.loc, curBlock);
193 
194 	IrLabel afterIndex = IrLabel(curBlock);
195 	ExprValue arrayLvalue = ir_gen_expr(gen, node.array, curBlock, afterIndex);
196 	curBlock = afterIndex.blockIndex;
197 
198 	IrIndex aggregateIndex = c.constants.addZeroConstant(makeIrType(IrBasicType.i32));
199 	IrIndex slicePtrIndex = c.constants.add(makeIrType(IrBasicType.i32), 1);
200 
201 	ExpressionNode* arrayExpr = node.array.get_expr(c);
202 	switch (arrayExpr.type.get_type(c).astType) with(AstType)
203 	{
204 		case type_ptr:
205 			IrIndex ptrRvalue = arrayLvalue.rvalue(gen, node.loc, curBlock);
206 			IrIndex result = buildGEP(gen, node.loc, curBlock, ptrRvalue, indexRvalue);
207 			gen.builder.addJumpToLabel(curBlock, nextStmt);
208 			return ExprValue(result, ExprValueKind.ptr_to_data, IsLvalue.yes);
209 
210 		case type_static_array:
211 			ExprValue result = arrayLvalue.member(gen, node.loc, curBlock, indexRvalue);
212 			gen.builder.addJumpToLabel(curBlock, nextStmt);
213 			return result;
214 
215 		case type_slice:
216 			ExprValue ptrLvalue = arrayLvalue.member(gen, node.loc, curBlock, slicePtrIndex);
217 			IrIndex ptr = ptrLvalue.rvalue(gen, node.loc, curBlock);
218 			IrIndex result = buildGEP(gen, node.loc, curBlock, ptr, indexRvalue);
219 			gen.builder.addJumpToLabel(curBlock, nextStmt);
220 			return ExprValue(result, ExprValueKind.ptr_to_data, IsLvalue.yes);
221 
222 		default:
223 			c.internal_error("Cannot index %s", arrayExpr.type.printer(c));
224 	}
225 }