1 /// Copyright: Copyright (c) 2021 Andrey Penechko. 2 /// License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 3 /// Authors: Andrey Penechko. 4 module vox.fe.ast.ast_node; 5 6 import std.traits : getUDAs; 7 import vox.all; 8 9 mixin template AstNodeData(AstType _astType = AstType.abstract_node, int default_flags = 0, AstNodeState _init_state = AstNodeState.parse_done) 10 { 11 import std.bitmanip : bitfields; 12 13 // how many fields this mixin template has 14 private enum NUM_BASE_FIELDS = 5; 15 16 this(Args...)(TokenIndex loc, Args args) { 17 this(loc); 18 enum len = this.tupleof.length - NUM_BASE_FIELDS; 19 enum numDefault = len - args.length; 20 static assert(args.length <= len, "Too many args"); 21 this.tupleof[NUM_BASE_FIELDS..$-numDefault] = args; 22 } 23 24 this(TokenIndex loc) { 25 this.loc = loc; 26 this.astType = _astType; 27 this.flags = cast(ushort)default_flags; 28 this.state = _init_state; 29 } 30 31 TokenIndex loc; 32 AstType astType = _astType; 33 34 mixin(bitfields!( 35 AstNodeState, "state", 4, 36 uint, "subType", 4, 37 )); 38 ushort flags = cast(ushort)default_flags; 39 40 // Stores one PropertyState per NodeProperty for up to 16 properties 41 uint propertyStates; 42 43 PropertyState getPropertyState(NodeProperty prop) { 44 return cast(PropertyState)((propertyStates >> (prop * 2)) & 0b11); 45 } 46 47 void setPropertyState(NodeProperty prop, PropertyState state) { 48 uint mask = ~(uint(0b11) << (prop * 2)); 49 propertyStates = (propertyStates & mask) | (uint(state) << (prop * 2)); 50 } 51 52 T* as(T)(CompilationContext* c) { 53 static if (hasAstNodeType!T) 54 { 55 c.assertf(astType == getAstNodeType!T, "as(%s) got %s", T.stringof, astType); 56 } 57 return cast(T*)&this; 58 } 59 60 TypeNode* as_type(CompilationContext* c) return { 61 c.assertf(isType, loc, "as_type(%s)", astType); 62 return cast(TypeNode*)&this; 63 } 64 65 // Returns pointer to attributes. Only valid if hasAttributes flag is set 66 AttributeInfo* attributeInfo() return { 67 assert(hasAttributes); 68 return cast(AttributeInfo*)(cast(void*)(&this) - AttributeInfo.sizeof); 69 } 70 71 bool hasExternAttrib() { 72 if (!hasAttributes) return false; 73 return attributeInfo.isExternal; 74 } 75 76 // Returns last @extern attribute attached to the node 77 AstNode* getExternAttrib(CompilationContext* c) { 78 if (!hasAttributes) return null; 79 foreach_reverse(AstIndex attrib; attributeInfo.attributes) { 80 auto attribNode = attrib.get_node(c); 81 if (attribNode.astType != AstType.decl_builtin_attribute) continue; 82 if (attribNode.subType == BuiltinAttribSubType.extern_syscall) return attribNode; 83 if (attribNode.subType == BuiltinAttribSubType.extern_module) return attribNode; 84 } 85 return null; 86 } 87 88 bool isError() { return astType == AstType.error; } 89 bool isModOrPack() { return astType == AstType.decl_module || astType == AstType.decl_package; } 90 bool isType() { return cast(bool)(flags & AstFlags.isType); } 91 bool isLvalue() { return cast(bool)(flags & AstFlags.isLvalue); } 92 bool hasAttributes(){ return cast(bool)(flags & AstFlags.hasAttributes); } 93 bool isTemplateInstance() { return cast(bool)(flags & AstFlags.isTemplateInstance); } 94 bool isGlobal() { return (flags & AstFlags.scopeKindMask) == AstFlags.isGlobal; } 95 bool isMember() { return (flags & AstFlags.scopeKindMask) == AstFlags.isMember; } 96 bool isLocal() { return (flags & AstFlags.scopeKindMask) == AstFlags.isLocal; } 97 } 98 99 struct AstNode 100 { 101 mixin AstNodeData; 102 } 103 104 @(AstType.error) 105 struct ErrorAstNode 106 { 107 mixin AstNodeData!(AstType.error); 108 } 109 110 alias AstNodes = Array!AstIndex; 111 alias AstNodeMap = HashMap!(Identifier, AstIndex, Identifier.init); 112 113 enum hasAstNodeType(T) = getUDAs!(T, AstType).length > 0; 114 enum getAstNodeType(T) = getUDAs!(T, AstType)[0]; 115 116 AstNodePrinter printer(AstIndex nodeIndex, CompilationContext* context) 117 { 118 return AstNodePrinter(nodeIndex, context); 119 } 120 121 struct AstNodePrinter 122 { 123 AstIndex nodeIndex; 124 CompilationContext* context; 125 126 void toString(scope void delegate(const(char)[]) sink) { 127 if (!nodeIndex) { 128 sink("<null>"); 129 return; 130 } 131 AstNode* node = context.getAstNode(nodeIndex); 132 if (node.isType) node.as_type(context).printType(sink, context); 133 } 134 } 135 136 void print_node_name(ref TextSink sink, AstIndex nodeIndex, CompilationContext* c) 137 { 138 AstNode* node = c.getAstNode(nodeIndex); 139 switch(node.astType) with(AstType) 140 { 141 case decl_alias: sink.put(c.idString(node.as!AliasDeclNode(c).id)); break; 142 case decl_builtin: sink.put(c.idString(node.as!BuiltinNode(c).id)); break; 143 case decl_module: sink.formattedWrite("%s", node.as!ModuleDeclNode(c).fqn.pr(c)); break; 144 case decl_struct: sink.put(c.idString(node.as!StructDeclNode(c).id)); break; 145 case decl_function: sink.put(c.idString(node.as!FunctionDeclNode(c).id)); break; 146 case decl_var: sink.put(c.idString(node.as!VariableDeclNode(c).id)); break; 147 case decl_enum: sink.put(c.idString(node.as!EnumDeclaration(c).id)); break; 148 case decl_enum_member: sink.put(c.idString(node.as!EnumMemberDecl(c).id)); break; 149 case expr_name_use: sink.put(c.idString(node.as!NameUseExprNode(c).id(c))); break; 150 case expr_member: sink.put(c.idString(node.as!MemberExprNode(c).memberId(c))); break; 151 case decl_template: sink.put(c.idString(node.as!TemplateDeclNode(c).id)); break; 152 case type_basic: sink.put(basicTypeNames[node.as!BasicTypeNode(c).basicType]); break; 153 case type_ptr: 154 print_node_name(sink, node.as!PtrTypeNode(c).base, c); 155 sink.put("*"); 156 break; 157 case type_slice: 158 print_node_name(sink, node.as!SliceTypeNode(c).base, c); 159 sink.put("[]"); 160 break; 161 case type_static_array: 162 auto arr = node.as!StaticArrayTypeNode(c); 163 print_node_name(sink, arr.base, c); 164 sink.putf("[%s]", arr.length); 165 break; 166 case type_func_sig: 167 auto sig = node.as!FunctionSignatureNode(c); 168 print_node_name(sink, sig.returnType, c); 169 sink.put(" function("); 170 foreach(i, AstIndex param; sig.parameters) 171 { 172 if (i > 0) sink.put(", "); 173 print_node_name(sink, param, c); 174 } 175 sink.put(")"); 176 break; 177 case expr_call: 178 print_node_name(sink, node.as!CallExprNode(c).callee, c); 179 break; 180 default: sink.formattedWrite("%s", node.astType); 181 } 182 } 183 184 void check_is_type(ref AstIndex nodeIndex, CompilationContext* c) 185 { 186 AstNode* node = c.getAstNode(nodeIndex); 187 if (!node.isType) { 188 c.error(node.loc, "%s is not a type", get_node_kind_name(nodeIndex, c)); 189 nodeIndex = CommonAstNodes.type_error; 190 } 191 } 192 193 ref Identifier get_node_id(AstIndex nodeIndex, CompilationContext* c) 194 { 195 AstNode* node = c.getAstNode(nodeIndex); 196 switch(node.astType) with(AstType) 197 { 198 case decl_alias: return node.as!AliasDeclNode(c).id; 199 case decl_builtin: return node.as!BuiltinNode(c).id; 200 case decl_module: return node.as!ModuleDeclNode(c).fqn; 201 case decl_struct: return node.as!StructDeclNode(c).id; 202 case decl_function: return node.as!FunctionDeclNode(c).id; 203 case decl_var: return node.as!VariableDeclNode(c).id; 204 case decl_enum: return node.as!EnumDeclaration(c).id; 205 case decl_enum_member: return node.as!EnumMemberDecl(c).id; 206 case expr_name_use: return node.as!NameUseExprNode(c).id(c); 207 case expr_member: return node.as!MemberExprNode(c).memberId(c); 208 case decl_template: return node.as!TemplateDeclNode(c).id; 209 default: assert(false, format("got %s", node.astType)); 210 } 211 } 212 213 AstIndex get_node_type(AstIndex nodeIndex, CompilationContext* c) 214 { 215 if (nodeIndex.isUndefined) return nodeIndex; 216 217 AstNode* node = c.getAstNode(nodeIndex); 218 //c.assertf(node.state >= AstNodeState.type_check_done, "get_node_type on node %s in state %s", node.astType, node.state); 219 220 switch(node.astType) with(AstType) 221 { 222 case decl_alias: return node.as!AliasDeclNode(c).initializer.get_node_type(c); 223 case decl_struct: return nodeIndex; 224 case decl_function: return node.as!FunctionDeclNode(c).signature.get_node_type(c); 225 case decl_var: return node.as!VariableDeclNode(c).type.get_node_type(c); 226 case decl_enum: return nodeIndex; 227 case decl_enum_member: return node.as!EnumMemberDecl(c).type.get_node_type(c); 228 case type_basic, type_func_sig, type_ptr, type_slice, type_static_array: return nodeIndex; 229 case expr_name_use: return node.as!NameUseExprNode(c).entity.get_node_type(c); 230 case error, literal_null, literal_bool, literal_int, literal_float, literal_string, literal_array, literal_special, expr_call, expr_index, expr_slice, expr_bin_op, expr_un_op, expr_type_conv, expr_member: 231 return node.as!ExpressionNode(c).type.get_node_type(c); 232 233 default: assert(false, format("get_node_type used on %s", node.astType)); 234 } 235 } 236 237 AstIndex get_node_alias(AstIndex nodeIndex, CompilationContext* c) 238 { 239 if (nodeIndex.isUndefined) return nodeIndex; 240 241 AstNode* node = c.getAstNode(nodeIndex); 242 //c.assertf(node.state >= AstNodeState.type_check_done, "get_node_type on node in state %s", node.state); 243 244 switch(node.astType) with(AstType) 245 { 246 case decl_alias: return node.as!AliasDeclNode(c).initializer.get_node_alias(c); 247 case decl_struct: return CommonAstNodes.type_type; 248 case decl_function: return CommonAstNodes.type_type; 249 case decl_var: return CommonAstNodes.type_alias; 250 case decl_enum: return CommonAstNodes.type_type; 251 case decl_enum_member: return CommonAstNodes.type_alias; 252 case type_basic, type_func_sig, type_ptr, type_slice, type_static_array: return CommonAstNodes.type_type; 253 case expr_name_use: return node.as!NameUseExprNode(c).entity.get_node_alias(c); 254 case error, literal_null, literal_bool, literal_int, literal_float, literal_string, literal_array, literal_special, expr_call, expr_index, expr_slice, expr_bin_op, expr_un_op, expr_type_conv, expr_member: 255 return CommonAstNodes.type_alias; 256 257 default: assert(false, format("get_node_alias used on %s", node.astType)); 258 } 259 } 260 261 AstIndex get_expr_type(AstIndex nodeIndex, CompilationContext* c) 262 out(res; res.isDefined, "null result") 263 { 264 assert(nodeIndex, "get_expr_type nodeIndex is null"); 265 266 AstNode* node = c.getAstNode(nodeIndex); 267 //c.assertf(node.state >= AstNodeState.type_check_done, "get_expr_type on node in state %s", node.state); 268 269 switch(node.astType) with(AstType) 270 { 271 case decl_alias: return node.as!AliasDeclNode(c).initializer.get_expr_type(c); 272 case decl_struct: return CommonAstNodes.type_type; 273 case decl_function: return node.as!FunctionDeclNode(c).signature.get_node_type(c); 274 case decl_var: return node.as!VariableDeclNode(c).type.get_node_type(c); 275 case decl_enum: return CommonAstNodes.type_type; 276 case decl_enum_member: return node.as!EnumMemberDecl(c).type.get_node_type(c); 277 case type_basic, type_func_sig, type_ptr, type_slice, type_static_array: return CommonAstNodes.type_type; 278 case expr_name_use: return node.as!NameUseExprNode(c).type; 279 case error, literal_null, literal_bool, literal_int, literal_float, literal_string, literal_array, literal_special, expr_call, expr_index, expr_slice, expr_bin_op, expr_un_op, expr_type_conv, expr_member: 280 return node.as!ExpressionNode(c).type.get_node_type(c); 281 282 default: assert(false, format("get_expr_type used on %s", node.astType)); 283 } 284 } 285 286 AstIndex get_effective_node(AstIndex nodeIndex, CompilationContext* c) 287 { 288 if (nodeIndex.isUndefined) return nodeIndex; 289 290 AstNode* node = c.getAstNode(nodeIndex); 291 //c.assertf(node.state >= AstNodeState.type_check_done, "get_effective_node on node in state %s", node.state); 292 293 switch(node.astType) with(AstType) 294 { 295 case decl_alias: return node.as!AliasDeclNode(c).initializer.get_effective_node(c); 296 case decl_alias_array: return nodeIndex; 297 case decl_template: return nodeIndex; 298 case decl_struct: return nodeIndex; 299 case decl_builtin: return nodeIndex; 300 case decl_function: return nodeIndex; 301 case decl_var: return nodeIndex; 302 case decl_enum: return nodeIndex; 303 case decl_enum_member: return nodeIndex; 304 case type_basic, type_ptr, type_slice, type_static_array: return nodeIndex; 305 case expr_name_use: return node.as!NameUseExprNode(c).entity.get_effective_node(c); 306 case error, literal_int, literal_float, literal_string, literal_array, literal_special, expr_call, expr_index, expr_slice, expr_bin_op, expr_un_op, expr_type_conv, expr_member: 307 return nodeIndex; 308 309 default: assert(false, format("get_effective_node used on %s", node.astType)); 310 } 311 } 312 313 AstIndex get_ast_index(T)(T* node, CompilationContext* context) 314 { 315 return context.getAstNodeIndex(node); 316 } 317 318 string get_node_kind_name(AstIndex nodeIndex, CompilationContext* c) 319 { 320 AstNode* node = c.getAstNode(nodeIndex); 321 322 switch(node.astType) with(AstType) 323 { 324 case decl_alias: return "alias"; 325 case decl_struct: return "struct"; 326 case decl_function: return "function"; 327 case decl_var: return "variable"; 328 case decl_enum: return "enum"; 329 case decl_enum_member: return "enum member"; 330 case type_basic: return "basic type"; 331 case type_ptr: return "pointer type"; 332 case type_slice: return "slice type"; 333 case type_static_array: return "static array type"; 334 case expr_name_use: return node.as!NameUseExprNode(c).entity.get_node_kind_name(c); 335 case literal_int: return "int literal"; 336 case literal_float: return "float literal"; 337 case literal_string: return "string literal"; 338 case literal_array: return "array literal"; 339 case literal_special: return "special literal"; 340 case expr_call: return "call expression"; 341 case expr_index: return "index expression"; 342 case expr_slice: return "slice expression"; 343 case expr_bin_op: return "binary expression"; 344 case expr_un_op: return "unary expression"; 345 case expr_type_conv: return "type conversion expression"; 346 case expr_member: return "member access expression"; 347 348 default: return node.astType.to!string; 349 } 350 } 351 352 AstIndex find_innermost_owner(ScopeIndex parentScope, AstType ownerType, CompilationContext* c) 353 { 354 c.assertf(ownerType == AstType.decl_struct || 355 ownerType == AstType.decl_module || 356 ownerType == AstType.decl_function, 357 "Invalid owner type requested (%s)", ownerType); 358 359 while(true) 360 { 361 c.assertf(parentScope.isDefined, "Undefined scope"); 362 Scope* sc = parentScope.get_scope(c); 363 364 c.assertf(sc.owner.isDefined, "Undefined owner"); 365 AstNode* ownerNode = sc.owner.get_node(c); 366 367 if (ownerNode.astType == ownerType) return sc.owner; 368 369 // module is the top scope 370 // didn't find the requested owner 371 if (ownerNode.astType == AstType.decl_module) return AstIndex(0); 372 373 parentScope = sc.parentScope; 374 } 375 }