public VariableResolveResult ResolveVariableWithName(string varName, Parsed.Object fromNode) { var result = new VariableResolveResult(); // Search in the stitch / knot that owns the node first var ownerFlow = fromNode == null ? this : fromNode.ClosestFlowBase(); // Argument if (ownerFlow.arguments != null) { foreach (var arg in ownerFlow.arguments) { if (arg.identifier.name.Equals(varName)) { result.found = true; result.isArgument = true; result.ownerFlow = ownerFlow; return(result); } } } // Temp var story = this.story; // optimisation if (ownerFlow != story && ownerFlow.variableDeclarations.ContainsKey(varName)) { result.found = true; result.ownerFlow = ownerFlow; result.isTemporary = true; return(result); } // Global if (story.variableDeclarations.ContainsKey(varName)) { result.found = true; result.ownerFlow = story; result.isGlobal = true; return(result); } result.found = false; return(result); }
public Parsed.Path PathRelativeTo(Parsed.Object otherObj) { var ownAncestry = ancestry; var otherAncestry = otherObj.ancestry; Parsed.Object highestCommonAncestor = null; int minLength = System.Math.Min(ownAncestry.Count, otherAncestry.Count); for (int i = 0; i < minLength; ++i) { var a1 = ancestry [i]; var a2 = otherAncestry [i]; if (a1 == a2) { highestCommonAncestor = a1; } else { break; } } FlowBase commonFlowAncestor = highestCommonAncestor as FlowBase; if (commonFlowAncestor == null) { commonFlowAncestor = highestCommonAncestor.ClosestFlowBase(); } var pathComponents = new List <string> (); bool hasWeavePoint = false; FlowLevel baseFlow = FlowLevel.WeavePoint; var ancestor = this; while (ancestor && (ancestor != commonFlowAncestor) && !(ancestor is Fiction)) { if (ancestor == commonFlowAncestor) { break; } if (!hasWeavePoint) { var weavePointAncestor = ancestor as IWeavePoint; if (weavePointAncestor != null && weavePointAncestor.name != null) { pathComponents.Add(weavePointAncestor.name); hasWeavePoint = true; continue; } } var flowAncestor = ancestor as FlowBase; if (flowAncestor) { pathComponents.Add(flowAncestor.name); baseFlow = flowAncestor.flowLevel; } ancestor = ancestor.parent; } pathComponents.Reverse(); if (pathComponents.Count > 0) { return(new Path(baseFlow, pathComponents)); } return(null); }
// 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; } } } } }