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 }