Inheritance: Parsed.Object
Esempio n. 1
0
        public override void ResolveReferences(Story context)
        {
            if (_finalLooseEndTarget)
            {
                var flowEndPath = _finalLooseEndTarget.path;
                foreach (var finalLooseEndDivert in _finalLooseEnds)
                {
                    finalLooseEndDivert.targetPath = flowEndPath;
                }
            }

            if (_startingSubFlowDivert)
            {
                _startingSubFlowDivert.targetPath = _startingSubFlowRuntime.path;
            }

            base.ResolveReferences(context);

            // Check validity of parameter names
            if (arguments != null)
            {
                foreach (var arg in arguments)
                {
                    // Don't allow reserved words for argument names
                    if (VariableAssignment.IsReservedKeyword(arg.name))
                    {
                        Error("Argument '" + arg.name + "' is a reserved word, please choose another name");
                        continue;
                    }

                    // Does argument conflict with a knot/stitch/label?
                    var           pathOfTheoreticalTarget = new Path(arg.name);
                    Parsed.Object target = pathOfTheoreticalTarget.ResolveFromContext(this);
                    if (target)
                    {
                        Error("Argument '" + arg.name + "' conflicts with a " + target.GetType().Name + " on " + target.debugMetadata + ", ");
                        continue;
                    }

                    // Does argument conflict with another variable name?
                    if (context.ResolveVariableWithName(arg.name, fromNode: this.parent).found)
                    {
                        Error("Argument '" + arg.name + "' conflicts with existing variable definition at higher scope.");
                        continue;
                    }
                }
            }
        }
Esempio n. 2
0
        public override void ResolveReferences(Story context)
        {
            base.ResolveReferences(context);

            VariableAssignment varDecl = null;

            if (this.isNewTemporaryDeclaration && story.variableDeclarations.TryGetValue(variableName, out varDecl))
            {
                if (varDecl.isGlobalDeclaration)
                {
                    Error("global variable '" + variableName + "' already exists with the same name (declared on " + varDecl.debugMetadata + ")");
                    return;
                }
            }

            if (this.isGlobalDeclaration)
            {
                var variableReference = expression as VariableReference;
                if (variableReference && !variableReference.isConstantReference && !variableReference.isListItemReference)
                {
                    Error("global variable assignments cannot refer to other variables, only literal values, constants and list items");
                }
            }

            if (IsReservedKeyword(variableName))
            {
                Error("cannot use '" + variableName + "' as a variable since it's a reserved ink keyword");
                return;
            }

            if (!this.isNewTemporaryDeclaration)
            {
                if (!context.ResolveVariableWithName(this.variableName, fromNode: this).found)
                {
                    if (story.constants.ContainsKey(variableName))
                    {
                        Error("Can't re-assign to a constant (do you need to use VAR when declaring '" + this.variableName + "'?)", this);
                    }
                    else
                    {
                        Error("Variable could not be found to assign to: '" + this.variableName + "'", this);
                    }
                }
            }
        }
Esempio n. 3
0
        public void TryAddNewVariableDeclaration(VariableAssignment varDecl)
        {
            var varName = varDecl.variableName;

            if (variableDeclarations.ContainsKey(varName))
            {
                var prevDeclError = "";
                var debugMetadata = variableDeclarations [varName].debugMetadata;
                if (debugMetadata != null)
                {
                    prevDeclError = " (" + variableDeclarations [varName].debugMetadata + ")";
                }
                Error("found declaration variable '" + varName + "' that was already declared" + prevDeclError, varDecl, false);

                return;
            }

            variableDeclarations [varDecl.variableName] = varDecl;
        }
Esempio n. 4
0
        protected Parsed.Object TempDeclarationOrAssignment()
        {
            Whitespace ();

            bool isNewDeclaration = ParseTempKeyword();

            Whitespace ();

            string varName = null;
            if (isNewDeclaration) {
                varName = (string)Expect (Identifier, "variable name");
            } else {
                varName = Parse(Identifier);
            }

            if (varName == null) {
                return null;
            }

            Whitespace();

            // Optional assignment
            Expression assignedExpression = null;
            if (ParseString ("=") != null) {
                assignedExpression = (Expression)Expect (Expression, "value expression to be assigned to temporary variable");
            }

            // If it's neither an assignment nor a new declaration,
            // it's got nothing to do with this rule (e.g. it's actually just "~ myExpr" or even "~ myFunc()"
            else if (!isNewDeclaration) {
                return null;
            }

            // Default zero assignment
            else {
                assignedExpression = new Number (0);
            }

            var result = new VariableAssignment (varName, assignedExpression);
            result.isNewTemporaryDeclaration = isNewDeclaration;
            return result;
        }
Esempio n. 5
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;
                        }
                    }
                }
            }
        }
Esempio n. 6
0
        protected Parsed.Object VariableDeclaration()
        {
            Whitespace ();

            var id = Parse (Identifier);
            if (id != "VAR")
                return null;

            Whitespace ();

            var varName = Expect (Identifier, "variable name") as string;

            Whitespace ();

            Expect (String ("="), "the '=' for an assignment of a value, e.g. '= 5' (initial values are mandatory)");

            Whitespace ();

            var expr = Expect (Expression, "initial value for ") as Parsed.Expression;
            if (!(expr is Number || expr is StringExpression || expr is DivertTarget || expr is VariableReference)) {
                Error ("initial value for a variable must be a number, constant, or divert target");
            }

            // Ensure string expressions are simple
            else if (expr is StringExpression) {
                var strExpr = expr as StringExpression;
                if (!strExpr.isSingleString)
                    Error ("Constant strings cannot contain any logic.");
            }

            var result = new VariableAssignment (varName, expr);
            result.isGlobalDeclaration = true;
            return result;
        }
Esempio n. 7
0
        public void TryAddNewVariableDeclaration(VariableAssignment varDecl)
        {
            var varName = varDecl.variableName;
            if (variableDeclarations.ContainsKey (varName)) {

                var prevDeclError = "";
                var debugMetadata = variableDeclarations [varName].debugMetadata;
                if (debugMetadata != null) {
                    prevDeclError = " ("+variableDeclarations [varName].debugMetadata+")";
                }
                Error("found declaration variable '"+varName+"' that was already declared"+prevDeclError, varDecl, false);

                return;
            }

            variableDeclarations [varDecl.variableName] = varDecl;
        }