// Check given symbol type against everything that's of a higher priority in the ordered SymbolType enum (above). // When the given symbol type level is reached, we early-out / return. public void CheckForNamingCollisions(Parsed.Object obj, Identifier identifier, SymbolType symbolType, string typeNameOverride = null) { string typeNameToPrint = typeNameOverride ?? obj.typeName; if (IsReservedKeyword(identifier?.name)) { obj.Error("'" + name + "' cannot be used for the name of a " + typeNameToPrint.ToLower() + " because it's a reserved keyword"); return; } if (FunctionCall.IsBuiltIn(identifier?.name)) { obj.Error("'" + name + "' cannot be used for the name of a " + typeNameToPrint.ToLower() + " because it's a built in function"); return; } // Top level knots FlowBase knotOrFunction = ContentWithNameAtLevel(identifier?.name, FlowLevel.Knot) as FlowBase; if (knotOrFunction && (knotOrFunction != obj || symbolType == SymbolType.Arg)) { NameConflictError(obj, identifier?.name, knotOrFunction, typeNameToPrint); return; } if (symbolType < SymbolType.List) { return; } // Lists foreach (var namedListDef in _listDefs) { var listDefName = namedListDef.Key; var listDef = namedListDef.Value; if (identifier?.name == listDefName && obj != listDef && listDef.variableAssignment != obj) { NameConflictError(obj, identifier?.name, listDef, typeNameToPrint); } // We don't check for conflicts between individual elements in // different lists because they are namespaced. if (!(obj is ListElementDefinition)) { foreach (var item in listDef.itemDefinitions) { if (identifier?.name == item.name) { NameConflictError(obj, identifier?.name, item, typeNameToPrint); } } } } // Don't check for VAR->VAR conflicts because that's handled separately // (necessary since checking looks up in a dictionary) if (symbolType <= SymbolType.Var) { return; } // Global variable collision VariableAssignment varDecl = null; if (variableDeclarations.TryGetValue(identifier?.name, out varDecl)) { if (varDecl != obj && varDecl.isGlobalDeclaration && varDecl.listDefinition == null) { NameConflictError(obj, identifier?.name, varDecl, typeNameToPrint); } } if (symbolType < SymbolType.SubFlowAndWeave) { return; } // Stitches, Choices and Gathers var path = new Path(identifier); var targetContent = path.ResolveFromContext(obj); if (targetContent && targetContent != obj) { NameConflictError(obj, identifier?.name, targetContent, typeNameToPrint); return; } if (symbolType < SymbolType.Arg) { return; } // Arguments to the current flow if (symbolType != SymbolType.Arg) { FlowBase flow = obj as FlowBase; if (flow == null) { flow = obj.ClosestFlowBase(); } if (flow && flow.hasParameters) { foreach (var arg in flow.arguments) { if (arg.identifier?.name == identifier?.name) { obj.Error(typeNameToPrint + " '" + name + "': Name has already been used for a argument to " + flow.identifier + " on " + flow.debugMetadata); return; } } } } }
void NameConflictError(Parsed.Object obj, string name, Parsed.Object existingObj, string typeNameToPrint) { obj.Error(typeNameToPrint + " '" + name + "': name has already been used for a " + existingObj.typeName.ToLower() + " on " + existingObj.debugMetadata); }