예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        // 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;
                        }
                    }
                }
            }
        }