Inheritance: Expression
Exemplo n.º 1
0
        public override void ResolveReferences(Story context)
        {
            if (isEmpty || isEnd || isDone)
            {
                return;
            }

            if (targetContent)
            {
                runtimeDivert.targetPath = targetContent.runtimePath;
            }

            // Resolve children (the arguments)
            base.ResolveReferences(context);

            // May be null if it's a built in function (e.g. TURNS_SINCE)
            // or if it's a variable target.
            var targetFlow = targetContent as FlowBase;

            if (targetFlow)
            {
                if (!targetFlow.isFunction && this.isFunctionCall)
                {
                    base.Error(targetFlow.name + " hasn't been marked as a function, but it's being called as one. Do you need to delcare the knot as '== function " + targetFlow.name + " =='?");
                }
                else if (targetFlow.isFunction && !this.isFunctionCall && !(this.parent is DivertTarget))
                {
                    base.Error(targetFlow.name + " can't be diverted to. It can only be called as a function since it's been marked as such: '" + targetFlow.name + "(...)'");
                }
            }

            // Check validity of target content
            bool targetWasFound = targetContent != null;
            bool isBuiltIn      = false;
            bool isExternal     = false;

            if (target.numberOfComponents == 1)
            {
                // BuiltIn means TURNS_SINCE, CHOICE_COUNT, RANDOM or SEED_RANDOM
                isBuiltIn = FunctionCall.IsBuiltIn(target.firstComponent);

                // Client-bound function?
                isExternal = context.IsExternal(target.firstComponent);

                if (isBuiltIn || isExternal)
                {
                    if (!isFunctionCall)
                    {
                        base.Error(target.firstComponent + " must be called as a function: ~ " + target.firstComponent + "()");
                    }
                    if (isExternal)
                    {
                        runtimeDivert.isExternal = true;
                        if (arguments != null)
                        {
                            runtimeDivert.externalArgs = arguments.Count;
                        }
                        runtimeDivert.pushesToStack = false;
                        runtimeDivert.targetPath    = new Runtime.Path(this.target.firstComponent);
                        CheckExternalArgumentValidity(context);
                    }
                    return;
                }
            }

            // Variable target?
            if (runtimeDivert.variableDivertName != null)
            {
                return;
            }

            if (!targetWasFound && !isBuiltIn && !isExternal)
            {
                Error("target not found: '" + target + "'");
            }
        }
Exemplo n.º 2
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;
                        }
                    }
                }
            }
        }