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.name_use; 5 6 import vox.all; 7 8 enum NameUseFlags : ushort 9 { 10 isSymResolved = AstFlags.userFlag << 0, 11 // used to prevent parentheses-free call when: 12 // - function address is taken 13 // - alias is taken 14 forbidParenthesesFreeCall = AstFlags.userFlag << 1, 15 } 16 17 enum NameUseSubType : ubyte { 18 referTo, 19 takeAddressOf, 20 takeAliasOf, 21 } 22 23 @(AstType.expr_name_use) 24 struct NameUseExprNode { 25 mixin ExpressionNodeData!(AstType.expr_name_use); 26 ScopeIndex parentScope; 27 union 28 { 29 private AstIndex _entity; // used when resolved, node contains Identifier internally 30 private Identifier _id; // used when not yet resolved 31 } 32 33 bool isSymResolved() { return cast(bool)(flags & NameUseFlags.isSymResolved); } 34 bool forbidParenthesesFreeCall() { return cast(bool)(flags & NameUseFlags.forbidParenthesesFreeCall); } 35 36 this(TokenIndex loc, ScopeIndex parentScope, Identifier id, AstIndex type = AstIndex.init) 37 { 38 this.loc = loc; 39 this.astType = AstType.expr_name_use; 40 this.state = AstNodeState.name_register_nested_done; 41 this.parentScope = parentScope; 42 this._id = id; 43 this.type = type; 44 } 45 46 void resolve(AstIndex n, CompilationContext* c) { 47 _entity = n; 48 assert(_entity); 49 this.flags |= NameUseFlags.isSymResolved; 50 } 51 AstIndex entity() { return isSymResolved ? _entity : AstIndex(); } 52 ref Identifier id(CompilationContext* context) return { 53 return isSymResolved ? _entity.get_node_id(context) : _id; 54 } 55 56 T* tryGet(T, AstType _astType)(CompilationContext* context) { 57 assert(isSymResolved); 58 AstNode* entityNode = context.getAstNode(_entity); 59 if (entityNode.astType != _astType) return null; 60 return cast(T*)entityNode; 61 } 62 63 T* get(T, AstType _astType)(CompilationContext* context) { 64 assert(isSymResolved); 65 AstNode* entityNode = context.getAstNode(_entity); 66 assert(entityNode.astType == _astType, format("%s used on %s", _astType, entityNode.astType)); 67 return cast(T*)entityNode; 68 } 69 70 alias varDecl = get!(VariableDeclNode, AstType.decl_var); 71 alias funcDecl = get!(FunctionDeclNode, AstType.decl_function); 72 alias structDecl = get!(StructDeclNode, AstType.decl_struct); 73 alias enumDecl = get!(EnumDeclaration, AstType.decl_enum); 74 alias enumMember = get!(EnumMemberDecl, AstType.decl_enum_member); 75 76 alias tryVarDecl = tryGet!(VariableDeclNode, AstType.decl_var); 77 alias tryFuncDecl = tryGet!(FunctionDeclNode, AstType.decl_function); 78 alias tryStructDecl = tryGet!(StructDeclNode, AstType.decl_struct); 79 alias tryEnumDecl = tryGet!(EnumDeclaration, AstType.decl_enum); 80 alias tryEnumMember = tryGet!(EnumMemberDecl, AstType.decl_enum_member); 81 } 82 83 void print_name_use(NameUseExprNode* node, ref AstPrintState state) 84 { 85 state.print("NAME_USE ", node.type.printer(state.context), " ", state.context.idString(node.id(state.context))); 86 } 87 88 void post_clone_name_use(NameUseExprNode* node, ref CloneState state) 89 { 90 CompilationContext* c = state.context; 91 state.fixScope(node.parentScope); 92 if (node.isSymResolved) 93 state.fixAstIndex(node._entity); 94 // _entity is resolved in template args 95 } 96 97 void name_resolve_name_use(ref AstIndex nodeIndex, NameUseExprNode* node, ref NameResolveState state) { 98 CompilationContext* c = state.context; 99 node.state = AstNodeState.name_resolve; 100 scope(exit) node.state = AstNodeState.name_resolve_done; 101 102 Identifier id = node.id(c); 103 104 Scope* currentScope = node.parentScope.get_scope(c); 105 106 AstIndex entity = lookupScopeIdRecursive(currentScope, id, node.loc, c); 107 108 if (entity == CommonAstNodes.node_error) 109 { 110 c.error(node.loc, "undefined identifier `%s`", c.idString(id)); 111 node.resolve(CommonAstNodes.node_error, c); 112 return; 113 } 114 115 node.resolve(entity, c); 116 AstNode* entityNode = entity.get_node(c); 117 118 switch(entityNode.astType) with(AstType) { 119 case decl_var: 120 auto var = entityNode.as!VariableDeclNode(c); 121 if (var.isMember) lowerToMember(nodeIndex, entity, node, var.scopeIndex, MemberSubType.struct_member, state); 122 break; 123 case decl_function: 124 auto func = entityNode.as!FunctionDeclNode(c); 125 if (func.isMember) lowerToMember(nodeIndex, entity, node, 0, MemberSubType.struct_method, state); 126 break; 127 case decl_enum_member, error: 128 // valid expr 129 break; 130 case decl_struct, decl_enum: 131 node.flags |= AstFlags.isType; 132 break; 133 case decl_alias: 134 require_name_resolve(entity, state); 135 if (entityNode.isType) node.flags |= AstFlags.isType; 136 // replace current node with aliased entity 137 // this will only replace node index of the current owner, other references will remain 138 // happens for enum type for example: it is referenced from enum type and from enum members 139 nodeIndex = entity.get!AliasDeclNode(c).initializer; 140 break; 141 case type_ptr: 142 case type_static_array: 143 case type_slice: 144 case expr_name_use: 145 case type_basic: 146 case literal_array: 147 case decl_alias_array: 148 // Happens after template arg replacement. Similar to alias 149 nodeIndex = entity; 150 break; 151 case decl_template: 152 break; 153 default: 154 c.internal_error(entityNode.loc, "Unknown entity %s", entityNode.astType); 155 } 156 } 157 158 private void lowerToMember(ref AstIndex nodeIndex, AstIndex entity, NameUseExprNode* node, uint scopeIndex, MemberSubType subType, ref NameResolveState state) 159 { 160 CompilationContext* c = state.context; 161 // rewrite as this.entity 162 // let member_access handle everything else 163 AstIndex thisName = c.appendAst!NameUseExprNode(node.loc, node.parentScope, CommonIds.id_this); 164 require_name_resolve(thisName, state); 165 AstIndex member = c.appendAst!MemberExprNode(node.loc, node.parentScope, thisName, entity, scopeIndex, subType); 166 if (node.isLvalue) 167 member.flags(c) |= AstFlags.isLvalue; 168 nodeIndex = member; 169 auto memberNode = member.get!MemberExprNode(c); 170 memberNode.flags |= MemberExprFlags.needsDeref; 171 memberNode.state = AstNodeState.name_resolve_done; 172 } 173 174 // Get type from variable declaration 175 void type_check_name_use(ref AstIndex nodeIndex, NameUseExprNode* node, ref TypeCheckState state) 176 { 177 type_calc_name_use(nodeIndex, node, state); 178 } 179 180 void type_calc_name_use(ref AstIndex nodeIndex, NameUseExprNode* node, ref TypeCheckState state) 181 { 182 CompilationContext* c = state.context; 183 184 final switch(node.getPropertyState(NodeProperty.type)) { 185 case PropertyState.not_calculated: break; 186 case PropertyState.calculating: c.circular_dependency; 187 case PropertyState.calculated: return; 188 } 189 190 c.begin_node_property_calculation(node, NodeProperty.type); 191 scope(exit) c.end_node_property_calculation(node, NodeProperty.type); 192 193 AstIndex parentType; 194 if (state.parentType.isDefined) 195 { 196 parentType = state.parentType.get_effective_node(c); 197 if (parentType == CommonAstNodes.type_alias) 198 node.flags |= NameUseFlags.forbidParenthesesFreeCall; 199 } 200 201 c.assertf(node.entity.isDefined, node.loc, "name null %s %s", node.isSymResolved, node.state); 202 switch(node.entity.astType(c)) 203 { 204 case AstType.decl_template: 205 node.state = AstNodeState.type_check_done; 206 207 auto templ = node.entity.get!TemplateDeclNode(c); 208 if (templ.body.astType(c) != AstType.decl_function) break; 209 210 if (!node.forbidParenthesesFreeCall) 211 { 212 // Call without parenthesis 213 // rewrite as call 214 nodeIndex = c.appendAst!CallExprNode(node.loc, AstIndex(), node.parentScope, nodeIndex); 215 nodeIndex.setState(c, AstNodeState.name_resolve_done); 216 require_type_check(nodeIndex, state); 217 break; 218 } 219 break; 220 221 case AstType.decl_function: 222 // check forbidParenthesesFreeCall to prevent call on func address take 223 if (!node.forbidParenthesesFreeCall) 224 { 225 // Call without parenthesis 226 // rewrite as call 227 nodeIndex = c.appendAst!CallExprNode(node.loc, AstIndex(), node.parentScope, nodeIndex); 228 nodeIndex.setState(c, AstNodeState.name_resolve_done); 229 require_type_check(nodeIndex, state); 230 break; 231 } 232 goto default; 233 234 case AstType.decl_var: 235 if (parentType == CommonAstNodes.type_alias) { 236 node.type = CommonAstNodes.type_alias; 237 node.state = AstNodeState.type_check_done; 238 //node.subType = NameUseSubType.takeAliasOf; 239 break; 240 } 241 goto default; 242 243 case AstType.decl_enum_member: 244 require_type_check(node._entity, state, IsNested.no); 245 goto default; 246 247 default: 248 node.state = AstNodeState.type_check; 249 c.assertf(node.isSymResolved, node.loc, "not resolved"); 250 node.type = node.entity.get_expr_type(state.context); 251 assert(node.type.isDefined); 252 node.state = AstNodeState.type_check_done; 253 break; 254 } 255 } 256 257 ExprValue ir_gen_name_use(ref IrGenState gen, IrIndex currentBlock, ref IrLabel nextStmt, NameUseExprNode* node) 258 { 259 CompilationContext* c = gen.context; 260 261 c.assertf(node.entity.isDefined, node.loc, "name null %s %s", node.isSymResolved, node.state); 262 263 if (node.type == CommonAstNodes.type_alias) { 264 return ExprValue(c.constants.add(makeIrType(IrBasicType.i32), node.entity.storageIndex)); 265 } else { 266 return ir_gen_expr(gen, node.entity, currentBlock, nextStmt); 267 } 268 }