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 5 /// We rely on the fact that nodes are allocated sequentially, 6 /// which allows us to simply copy a range on slots and fix indices, 7 /// in order to create template instance. 8 module vox.fe.ast.decl.template_; 9 10 import vox.all; 11 12 @(AstType.decl_template) 13 struct TemplateDeclNode 14 { 15 mixin AstNodeData!(AstType.decl_template); 16 /// For template name register 17 ScopeIndex parentScope; 18 /// Template parameters 19 AstNodes parameters; 20 /// Templated AST node (currently function or struct) 21 AstIndex body; 22 /// Points to the first index that needs to be copied 23 AstIndex body_start; 24 /// Points to the next index after body data 25 AstIndex after_body; 26 /// Template id. Same as underlying entity. 27 Identifier id; 28 /// Number of parameters before variadic parameter 29 /// Is equal to parameters.length when no variadic is present 30 ushort numParamsBeforeVariadic; 31 /// Cached template instances 32 Array!TemplateInstance instances; 33 34 bool hasVariadic() { return numParamsBeforeVariadic < parameters.length; }; 35 } 36 37 struct TemplateInstance 38 { 39 /// Template arguments of this instance 40 AstNodes args; 41 /// AST node created for instantiated template. Copy of TemplateDeclNode.body 42 AstIndex entity; 43 } 44 45 void print_template(TemplateDeclNode* node, ref AstPrintState state) 46 { 47 state.print("TEMPLATE ", state.context.idString(node.id)); 48 print_ast(node.parameters, state); 49 print_ast(node.body, state); 50 foreach (ref TemplateInstance inst; node.instances) 51 { 52 state.print("INSTANCE: ", state.context.idString(inst.entity.get_node_id(state.context))); 53 print_ast(inst.entity, state); 54 } 55 } 56 57 void post_clone_template(TemplateDeclNode* node, ref CloneState state) 58 { 59 state.fixScope(node.parentScope); 60 state.fixAstNodes(node.parameters); 61 state.fixAstIndex(node.body); 62 63 // TemplateDeclNode.after_body can be == to CloneState.cloned_to 64 // Fix it manually 65 // And it doesn't need node post clone code called 66 node.body_start.storageIndex += state.offset; 67 node.after_body.storageIndex += state.offset; 68 } 69 70 void name_register_self_template(AstIndex nodeIndex, TemplateDeclNode* node, ref NameRegisterState state) 71 { 72 node.state = AstNodeState.name_register_nested; 73 node.parentScope.insert_scope(node.id, nodeIndex, state.context); 74 node.state = AstNodeState.type_check_done; 75 } 76 77 78 enum TemplateParamDeclFlags : ushort 79 { 80 isVariadic = AstFlags.userFlag << 0, 81 } 82 83 @(AstType.decl_template_param) 84 struct TemplateParamDeclNode 85 { 86 mixin AstNodeData!(AstType.decl_template_param); 87 Identifier id; 88 ushort index; // index in the list of template parameters 89 90 bool isVariadic() { return cast(bool)(flags & TemplateParamDeclFlags.isVariadic); } 91 } 92 93 void print_template_param(TemplateParamDeclNode* node, ref AstPrintState state) 94 { 95 state.print("TEMPLATE PARAM ", state.context.idString(node.id), node.isVariadic ? "..." : null); 96 } 97 98 99 struct CloneState 100 { 101 CompilationContext* context; 102 103 // We need to add this offset to all indices inside copied slots that point into copied slots 104 uint offset; 105 106 /// Points to original nodes 107 AstIndex cloned_from; 108 AstIndex cloned_to; 109 110 /// We want to redirect all references from `template_parent_scope` to `instance_scope` 111 ScopeIndex template_parent_scope; 112 /// Scope where template was instantiated. Contains template arguments 113 ScopeIndex instance_scope; 114 115 void fixAstIndex(ref AstIndex nodeIndex) 116 { 117 // null is automatically out of bounds 118 if (nodeIndex.storageIndex >= cloned_from.storageIndex && nodeIndex.storageIndex < cloned_to.storageIndex) 119 { 120 nodeIndex.storageIndex += offset; 121 post_clone(nodeIndex, this); 122 } 123 } 124 125 void fixAstNodes(ref AstNodes nodes) 126 { 127 nodes = nodes.dup(context.arrayArena); 128 foreach(ref AstIndex index; nodes) 129 fixAstIndex(index); 130 } 131 132 void fixScope(ref ScopeIndex _scope) 133 { 134 // null is automatically out of bounds 135 if (_scope.storageIndex >= cloned_from.storageIndex && _scope.storageIndex < cloned_to.storageIndex) 136 { 137 //writefln("fix %s -> %s", _scope, AstIndex(_scope.storageIndex + offset)); 138 _scope.storageIndex += offset; 139 140 Scope* s = _scope.get_scope(context); 141 post_clone_scope(s, this); 142 } 143 else if (_scope == template_parent_scope) 144 { 145 assert(_scope.isDefined); 146 // redirect to this scope for instance argument resolution 147 //writefln("fix %s -> %s", _scope, instance_scope); 148 _scope = instance_scope; 149 } 150 } 151 } 152 153 AstIndex get_template_instance(AstIndex templateIndex, TokenIndex start, AstNodes args, ref TypeCheckState state) 154 { 155 CompilationContext* c = state.context; 156 auto templ = templateIndex.get!TemplateDeclNode(c); 157 158 ++c.numTemplateInstanceLookups; 159 auto numParams = templ.parameters.length; 160 auto numArgs = args.length; 161 162 AstIndex errNumArgs() { 163 c.error(start, 164 "Wrong number of template arguments (%s), must be %s", 165 numArgs, 166 numParams); 167 return CommonAstNodes.node_error; 168 } 169 170 void checkArg(size_t index, AstIndex arg) 171 { 172 if (!arg.isType(c)) 173 { 174 // will be lifted in the future 175 c.error(arg.loc(c), 176 "Template argument %s, must be a type, not %s", index+1, 177 arg.astType(c)); 178 } 179 } 180 181 // Verify arguments. For now only types are supported 182 foreach(size_t i, AstIndex arg; args) { 183 checkArg(i, arg); 184 } 185 186 bool hasVariadic = templ.numParamsBeforeVariadic < numParams; 187 AstNodes variadicTypes; 188 if (hasVariadic) { 189 // handle variadic parameter 190 if (numArgs < numParams && numParams - numArgs > 1) return errNumArgs; 191 192 foreach(size_t i; templ.numParamsBeforeVariadic..numArgs) { 193 variadicTypes.put(c.arrayArena, args[i]); 194 } 195 } else if (numArgs != numParams) { 196 return errNumArgs; 197 } 198 199 // Check if there is existing instance 200 instance_loop: 201 foreach(ref TemplateInstance instance; templ.instances) 202 { 203 // templates with variadics can have different number of instance arguments 204 if (instance.args.length != numArgs) continue; 205 206 foreach(size_t i, AstIndex arg; instance.args) 207 { 208 if (!same_type(arg, args[i], c)) continue instance_loop; 209 } 210 211 // Found match, reuse instance 212 return instance.entity; 213 } 214 215 // No matching instances found 216 // Create new instance 217 218 ++c.numTemplateInstantiations; 219 220 // Create scope for arguments 221 ScopeIndex instance_scope = c.appendScope; 222 Scope* newScope = c.getAstScope(instance_scope); 223 newScope.parentScope = templ.parentScope; 224 newScope.debugName = "template instance"; 225 newScope.kind = newScope.parentScope.get_scope(c).kind; 226 227 // Register template instance arguments 228 foreach(size_t i; 0..templ.numParamsBeforeVariadic) 229 { 230 AstIndex paramIndex = templ.parameters[i]; 231 auto param = paramIndex.get!TemplateParamDeclNode(c); 232 newScope.insert(param.id, args[i], c); 233 } 234 235 // register variadic (must be single node) 236 if (hasVariadic) 237 { 238 AstIndex paramIndex = templ.parameters[templ.numParamsBeforeVariadic]; 239 auto param = paramIndex.get!TemplateParamDeclNode(c); 240 241 // Create array of variadic types 242 auto arrayIndex = c.appendAst!AliasArrayDeclNode(param.loc, variadicTypes); 243 auto arrayNode = arrayIndex.get!AliasArrayDeclNode(c); 244 245 newScope.insert(param.id, arrayIndex, c); 246 } 247 248 // Clone template body and apply fixes 249 CloneState cloneState = clone_node(templ.body_start, templ.after_body, instance_scope, c); 250 AstIndex instance = templ.body; 251 cloneState.fixAstIndex(instance); 252 253 // Node may need to know if is a result of template instantiation 254 instance.flags(c) |= AstFlags.isTemplateInstance; 255 256 // Create identifier for instance 257 set_instance_id(instance, args, c); 258 259 // Cache instance 260 templ.instances.put(c.arrayArena, TemplateInstance(args, instance)); 261 262 // Type check instance 263 // Must be registered before type check to prevent infinite recursion in case of recursive templates 264 require_type_check(instance, c); 265 266 return instance; 267 } 268 269 void set_instance_id(AstIndex instance_index, AstNodes instance_args, CompilationContext* c) 270 { 271 Identifier* id = &instance_index.get_node_id(c); 272 TextSink* sink = &c.tempBuf; 273 sink.clear; 274 sink.put(c.idString(*id)); 275 sink.put("["); 276 foreach(size_t i, AstIndex arg; instance_args) 277 { 278 if (i > 0) sink.put(", "); 279 print_node_name(*sink, arg, c); 280 } 281 sink.put("]"); 282 const(char)[] idString = sink.data.data; 283 *id = c.idMap.getOrReg(c, idString); 284 } 285 286 /// Perform copiying of AST subtree and index fixing 287 /// node_start..after_node is the range of slots to be copied 288 /// instance_scope is the scope created around AST subtree copy 289 /// All nodes need to fixed via CloneState through indices pointing inside cloned tree 290 CloneState clone_node(AstIndex node_start, AstIndex after_node, ScopeIndex instance_scope, CompilationContext* c) 291 { 292 c.assertf(after_node.storageIndex > node_start.storageIndex, "%s > %s", node_start, after_node); 293 AstIndex slots_start = AstIndex(c.astBuffer.uintLength); 294 c.assertf(slots_start.storageIndex > node_start.storageIndex, "%s > %s", slots_start, node_start); 295 296 uint num_slots_to_copy = after_node.storageIndex - node_start.storageIndex; 297 // allocate space at the end 298 uint[] slots = c.astBuffer.voidPut(num_slots_to_copy); 299 // copy slots 300 slots[] = c.astBuffer.bufPtr[node_start.storageIndex..after_node.storageIndex]; 301 302 CloneState state = { 303 context : c, 304 offset : slots_start.storageIndex - node_start.storageIndex, 305 cloned_from : node_start, 306 cloned_to : after_node, 307 template_parent_scope : instance_scope.get_scope(c).parentScope, 308 instance_scope : instance_scope, 309 }; 310 311 return state; 312 } 313 314 /// Applies offset to indices pointing into copied area 315 /// Happens before name register 316 void post_clone(AstIndex nodeIndex, ref CloneState state) 317 { 318 CompilationContext* c = state.context; 319 320 AstNode* node = c.getAstNode(nodeIndex); 321 322 if (node.hasAttributes) { 323 post_clone_attributes(node.attributeInfo, state); 324 } 325 326 final switch(node.astType) with(AstType) 327 { 328 case error: c.internal_error(node.loc, "Visiting error node"); 329 case abstract_node: c.internal_error(node.loc, "Visiting abstract node"); 330 331 case decl_alias: post_clone_alias(cast(AliasDeclNode*)node, state); break; 332 case decl_alias_array: break; 333 case decl_builtin: break; 334 case decl_builtin_attribute: break; 335 case decl_module: assert(false); 336 case decl_package: assert(false); 337 case decl_import: post_clone_import(cast(ImportDeclNode*)node, state); break; 338 case decl_function: post_clone_func(cast(FunctionDeclNode*)node, state); break; 339 case decl_var: post_clone_var(cast(VariableDeclNode*)node, state); break; 340 case decl_struct: post_clone_struct(cast(StructDeclNode*)node, state); break; 341 case decl_enum: post_clone_enum(cast(EnumDeclaration*)node, state); break; 342 case decl_enum_member: post_clone_enum_member(cast(EnumMemberDecl*)node, state); break; 343 case decl_static_assert: post_clone_static_assert(cast(StaticAssertDeclNode*)node, state); break; 344 case decl_static_foreach: post_clone_static_foreach(cast(StaticForeachDeclNode*)node, state); break; 345 case decl_static_if: post_clone_static_if(cast(StaticIfDeclNode*)node, state); break; 346 case decl_static_version: post_clone_static_version(cast(StaticVersionDeclNode*)node, state); break; 347 case decl_template: post_clone_template(cast(TemplateDeclNode*)node, state); break; 348 case decl_template_param: break; 349 350 case stmt_block: post_clone_block(cast(BlockStmtNode*)node, state); break; 351 case stmt_if: post_clone_if(cast(IfStmtNode*)node, state); break; 352 case stmt_while: post_clone_while(cast(WhileStmtNode*)node, state); break; 353 case stmt_do_while: post_clone_do(cast(DoWhileStmtNode*)node, state); break; 354 case stmt_for: post_clone_for(cast(ForStmtNode*)node, state); break; 355 case stmt_switch: post_clone_switch(cast(SwitchStmtNode*)node, state); break; 356 case stmt_return: post_clone_return(cast(ReturnStmtNode*)node, state); break; 357 case stmt_break: break; 358 case stmt_continue: break; 359 360 case expr_name_use: post_clone_name_use(cast(NameUseExprNode*)node, state); break; 361 case expr_member: post_clone_member(cast(MemberExprNode*)node, state); break; 362 case expr_bin_op: post_clone_binary_op(cast(BinaryExprNode*)node, state); break; 363 case expr_un_op: post_clone_unary_op(cast(UnaryExprNode*)node, state); break; 364 case expr_call: post_clone_call(cast(CallExprNode*)node, state); break; 365 case expr_named_argument: post_clone_named_argument(cast(NamedArgumenExprNode*)node, state); break; 366 case expr_index: post_clone_index(cast(IndexExprNode*)node, state); break; 367 case expr_slice: post_clone_expr_slice(cast(SliceExprNode*)node, state); break; 368 case expr_type_conv: post_clone_type_conv(cast(TypeConvExprNode*)node, state); break; 369 370 case literal_int: break; 371 case literal_float: break; 372 case literal_string: break; 373 case literal_null: break; 374 case literal_bool: break; 375 case literal_array: break; 376 case literal_special: break; 377 378 case type_basic: break; 379 case type_func_sig: post_clone_func_sig(cast(FunctionSignatureNode*)node, state); break; 380 case type_ptr: post_clone_ptr(cast(PtrTypeNode*)node, state); break; 381 case type_static_array: post_clone_static_array(cast(StaticArrayTypeNode*)node, state); break; 382 case type_slice: post_clone_slice(cast(SliceTypeNode*)node, state); break; 383 } 384 }