Example #1
0
        // Given a variable pointer with just the name of the target known, resolve to a variable
        // pointer that more specifically points to the exact instance: whether it's global,
        // or the exact position of a temporary on the callstack.
        VariablePointerValue ResolveVariablePointer(VariablePointerValue varPointer)
        {
            int contextIndex = varPointer.contextIndex;

            if (contextIndex == -1)
            {
                contextIndex = GetContextIndexOfVariableNamed(varPointer.variableName);
            }

            var valueOfVariablePointedTo = GetRawVariableWithName(varPointer.variableName, contextIndex);

            // Extra layer of indirection:
            // When accessing a pointer to a pointer (e.g. when calling nested or
            // recursive functions that take a variable references, ensure we don't create
            // a chain of indirection by just returning the final target.
            var doubleRedirectionPointer = valueOfVariablePointedTo as VariablePointerValue;

            if (doubleRedirectionPointer)
            {
                return(doubleRedirectionPointer);
            }

            // Make copy of the variable pointer so we're not using the value direct from
            // the runtime. Temporary must be local to the current scope.
            else
            {
                return(new VariablePointerValue(varPointer.variableName, contextIndex));
            }
        }
Example #2
0
        internal void Assign(VariableAssignment varAss, Runtime.Object value)
        {
            var name         = varAss.variableName;
            int contextIndex = -1;

            // Are we assigning to a global variable?
            bool setGlobal = false;

            if (varAss.isNewDeclaration)
            {
                setGlobal = varAss.isGlobal;
            }
            else
            {
                setGlobal = _globalVariables.ContainsKey(name);
            }

            // Constructing new variable pointer reference
            if (varAss.isNewDeclaration)
            {
                var varPointer = value as VariablePointerValue;
                if (varPointer)
                {
                    var fullyResolvedVariablePointer = ResolveVariablePointer(varPointer);
                    value = fullyResolvedVariablePointer;
                }
            }

            // Assign to existing variable pointer?
            // Then assign to the variable that the pointer is pointing to by name.
            else
            {
                // De-reference variable reference to point to
                VariablePointerValue existingPointer = null;
                do
                {
                    existingPointer = GetRawVariableWithName(name, contextIndex) as VariablePointerValue;
                    if (existingPointer)
                    {
                        name         = existingPointer.variableName;
                        contextIndex = existingPointer.contextIndex;
                        setGlobal    = (contextIndex == 0);
                    }
                } while(existingPointer);
            }


            if (setGlobal)
            {
                SetGlobal(name, value);
            }
            else
            {
                _callStack.SetTemporaryVariable(name, value, varAss.isNewDeclaration, contextIndex);
            }
        }
Example #3
0
        // ----------------------
        // JSON ENCODING SCHEME
        // ----------------------
        //
        // Glue:           "<>", "G<", "G>"
        //
        // ControlCommand: "ev", "out", "/ev", "du" "pop", "->->", "~ret", "str", "/str", "nop",
        //                 "choiceCnt", "turns", "visit", "seq", "thread", "done", "end"
        //
        // NativeFunction: "+", "-", "/", "*", "%" "~", "==", ">", "<", ">=", "<=", "!=", "!"... etc
        //
        // Void:           "void"
        //
        // Value:          "^string value", "^^string value beginning with ^"
        //                 5, 5.2
        //                 {"^->": "path.target"}
        //                 {"^var": "varname", "ci": 0}
        //
        // Container:      [...]
        //                 [...,
        //                     {
        //                         "subContainerName": ...,
        //                         "#f": 5,                    // flags
        //                         "#n": "containerOwnName"    // only if not redundant
        //                     }
        //                 ]
        //
        // Divert:         {"->": "path.target", "c": true }
        //                 {"->": "path.target", "var": true}
        //                 {"f()": "path.func"}
        //                 {"->t->": "path.tunnel"}
        //                 {"x()": "externalFuncName", "exArgs": 5}
        //
        // Var Assign:     {"VAR=": "varName", "re": true}   // reassignment
        //                 {"temp=": "varName"}
        //
        // Var ref:        {"VAR?": "varName"}
        //                 {"CNT?": "stitch name"}
        //
        // ChoicePoint:    {"*": pathString,
        //                  "flg": 18 }
        //
        // Choice:         Nothing too clever, it's only used in the save state,
        //                 there's not likely to be many of them.
        //
        // Tag:            {"#": "the tag text"}
        public static Runtime.Object JTokenToRuntimeObject(object token)
        {
            if (token is int || token is float)
            {
                return(Value.Create(token));
            }

            if (token is string)
            {
                string str = (string)token;

                // String value
                char firstChar = str[0];
                if (firstChar == '^')
                {
                    return(new StringValue(str.Substring(1)));
                }
                else if (firstChar == '\n' && str.Length == 1)
                {
                    return(new StringValue("\n"));
                }

                // Glue
                if (str == "<>")
                {
                    return(new Runtime.Glue());
                }

                // Control commands (would looking up in a hash set be faster?)
                for (int i = 0; i < _controlCommandNames.Length; ++i)
                {
                    string cmdName = _controlCommandNames [i];
                    if (str == cmdName)
                    {
                        return(new Runtime.ControlCommand((ControlCommand.CommandType)i));
                    }
                }

                // Native functions
                // "^" conflicts with the way to identify strings, so now
                // we know it's not a string, we can convert back to the proper
                // symbol for the operator.
                if (str == "L^")
                {
                    str = "^";
                }
                if (NativeFunctionCall.CallExistsWithName(str))
                {
                    return(NativeFunctionCall.CallWithName(str));
                }

                // Pop
                if (str == "->->")
                {
                    return(Runtime.ControlCommand.PopTunnel());
                }
                else if (str == "~ret")
                {
                    return(Runtime.ControlCommand.PopFunction());
                }

                // Void
                if (str == "void")
                {
                    return(new Runtime.Void());
                }
            }

            if (token is Dictionary <string, object> )
            {
                var    obj = (Dictionary <string, object>)token;
                object propValue;

                // Divert target value to path
                if (obj.TryGetValue("^->", out propValue))
                {
                    return(new DivertTargetValue(new Path((string)propValue)));
                }

                // VariablePointerValue
                if (obj.TryGetValue("^var", out propValue))
                {
                    var varPtr = new VariablePointerValue((string)propValue);
                    if (obj.TryGetValue("ci", out propValue))
                    {
                        varPtr.contextIndex = (int)propValue;
                    }
                    return(varPtr);
                }

                // Divert
                bool        isDivert      = false;
                bool        pushesToStack = false;
                PushPopType divPushType   = PushPopType.Function;
                bool        external      = false;
                if (obj.TryGetValue("->", out propValue))
                {
                    isDivert = true;
                }
                else if (obj.TryGetValue("f()", out propValue))
                {
                    isDivert      = true;
                    pushesToStack = true;
                    divPushType   = PushPopType.Function;
                }
                else if (obj.TryGetValue("->t->", out propValue))
                {
                    isDivert      = true;
                    pushesToStack = true;
                    divPushType   = PushPopType.Tunnel;
                }
                else if (obj.TryGetValue("x()", out propValue))
                {
                    isDivert      = true;
                    external      = true;
                    pushesToStack = false;
                    divPushType   = PushPopType.Function;
                }
                if (isDivert)
                {
                    var divert = new Divert();
                    divert.pushesToStack = pushesToStack;
                    divert.stackPushType = divPushType;
                    divert.isExternal    = external;

                    string target = propValue.ToString();

                    if (obj.TryGetValue("var", out propValue))
                    {
                        divert.variableDivertName = target;
                    }
                    else
                    {
                        divert.targetPathString = target;
                    }

                    divert.isConditional = obj.TryGetValue("c", out propValue);

                    if (external)
                    {
                        if (obj.TryGetValue("exArgs", out propValue))
                        {
                            divert.externalArgs = (int)propValue;
                        }
                    }

                    return(divert);
                }

                // Choice
                if (obj.TryGetValue("*", out propValue))
                {
                    var choice = new ChoicePoint();
                    choice.pathStringOnChoice = propValue.ToString();

                    if (obj.TryGetValue("flg", out propValue))
                    {
                        choice.flags = (int)propValue;
                    }

                    return(choice);
                }

                // Variable reference
                if (obj.TryGetValue("VAR?", out propValue))
                {
                    return(new VariableReference(propValue.ToString()));
                }
                else if (obj.TryGetValue("CNT?", out propValue))
                {
                    var readCountVarRef = new VariableReference();
                    readCountVarRef.pathStringForCount = propValue.ToString();
                    return(readCountVarRef);
                }

                // Variable assignment
                bool isVarAss    = false;
                bool isGlobalVar = false;
                if (obj.TryGetValue("VAR=", out propValue))
                {
                    isVarAss    = true;
                    isGlobalVar = true;
                }
                else if (obj.TryGetValue("temp=", out propValue))
                {
                    isVarAss    = true;
                    isGlobalVar = false;
                }
                if (isVarAss)
                {
                    var varName   = propValue.ToString();
                    var isNewDecl = !obj.TryGetValue("re", out propValue);
                    var varAss    = new VariableAssignment(varName, isNewDecl);
                    varAss.isGlobal = isGlobalVar;
                    return(varAss);
                }

                // Tag
                if (obj.TryGetValue("#", out propValue))
                {
                    return(new Runtime.Tag((string)propValue));
                }

                // List value
                if (obj.TryGetValue("list", out propValue))
                {
                    var listContent = (Dictionary <string, object>)propValue;
                    var rawList     = new InkList();
                    if (obj.TryGetValue("origins", out propValue))
                    {
                        var namesAsObjs = (List <object>)propValue;
                        rawList.SetInitialOriginNames(namesAsObjs.Cast <string>().ToList());
                    }
                    foreach (var nameToVal in listContent)
                    {
                        var item = new InkListItem(nameToVal.Key);
                        var val  = (int)nameToVal.Value;
                        rawList.Add(item, val);
                    }
                    return(new ListValue(rawList));
                }

                // Used when serialising save state only
                if (obj ["originalChoicePath"] != null)
                {
                    return(JObjectToChoice(obj));
                }
            }

            // Array is always a Runtime.Container
            if (token is List <object> )
            {
                return(JArrayToContainer((List <object>)token));
            }

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

            throw new System.Exception("Failed to convert token to runtime object: " + token);
        }
Example #4
0
 internal Runtime.Object ValueAtVariablePointer(VariablePointerValue pointer)
 {
     return(GetVariableWithName(pointer.variableName, pointer.contextIndex));
 }
Example #5
0
        // ----------------------
        // JSON ENCODING SCHEME
        // ----------------------
        //
        // Glue:           "<>", "G<", "G>"
        //
        // ControlCommand: "ev", "out", "/ev", "du" "pop", "->->", "~ret", "str", "/str", "nop",
        //                 "choiceCnt", "turns", "visit", "seq", "thread", "done", "end"
        //
        // NativeFunction: "+", "-", "/", "*", "%" "~", "==", ">", "<", ">=", "<=", "!=", "!"... etc
        //
        // Void:           "void"
        //
        // Value:          "^string value", "^^string value beginning with ^"
        //                 5, 5.2
        //                 {"^->": "path.target"}
        //                 {"^var": "varname", "ci": 0}
        //
        // Container:      [...]
        //                 [...,
        //                     {
        //                         "subContainerName": ...,
        //                         "#f": 5,                    // flags
        //                         "#n": "containerOwnName"    // only if not redundant
        //                     }
        //                 ]
        //
        // Divert:         {"->": "path.target", "c": true }
        //                 {"->": "path.target", "var": true}
        //                 {"f()": "path.func"}
        //                 {"->t->": "path.tunnel"}
        //                 {"x()": "externalFuncName", "exArgs": 5}
        //
        // Var Assign:     {"VAR=": "varName", "re": true}   // reassignment
        //                 {"temp=": "varName"}
        //
        // Var ref:        {"VAR?": "varName"}
        //                 {"CNT?": "stitch name"}
        //
        // ChoicePoint:    {"*": pathString,
        //                  "flg": 18 }
        //
        // Choice:         Nothing too clever, it's only used in the save state,
        //                 there's not likely to be many of them.
        public static Runtime.Object JTokenToRuntimeObject(object token)
        {
            if (token is int || token is float)
            {
                return(Value.Create(token));
            }

            if (token is string)
            {
                string str = (string)token;

                // String value
                char firstChar = str[0];
                if (firstChar == '^')
                {
                    return(new StringValue(str.Substring(1)));
                }
                else if (firstChar == '\n' && str.Length == 1)
                {
                    return(new StringValue("\n"));
                }

                // Glue
                if (str == "<>")
                {
                    return(new Runtime.Glue(GlueType.Bidirectional));
                }
                else if (str == "G<")
                {
                    return(new Runtime.Glue(GlueType.Left));
                }
                else if (str == "G>")
                {
                    return(new Runtime.Glue(GlueType.Right));
                }

                // Control commands (would looking up in a hash set be faster?)
                for (int i = 0; i < _controlCommandNames.Length; ++i)
                {
                    string cmdName = _controlCommandNames [i];
                    if (str == cmdName)
                    {
                        return(new Runtime.ControlCommand((ControlCommand.CommandType)i));
                    }
                }

                // Native functions
                if (NativeFunctionCall.CallExistsWithName(str))
                {
                    return(NativeFunctionCall.CallWithName(str));
                }

                // Pop
                if (str == "->->")
                {
                    return(Runtime.ControlCommand.PopTunnel());
                }
                else if (str == "~ret")
                {
                    return(Runtime.ControlCommand.PopFunction());
                }

                // Void
                if (str == "void")
                {
                    return(new Runtime.Void());
                }
            }

            if (token is Dictionary <string, object> )
            {
                var    obj = (Dictionary <string, object>)token;
                object propValue;

                // Divert target value to path
                if (obj.TryGetValue("^->", out propValue))
                {
                    return(new DivertTargetValue(new Path((string)propValue)));
                }

                // VariablePointerValue
                if (obj.TryGetValue("^var", out propValue))
                {
                    var varPtr = new VariablePointerValue((string)propValue);
                    if (obj.TryGetValue("ci", out propValue))
                    {
                        varPtr.contextIndex = (int)propValue;
                    }
                    return(varPtr);
                }

                // Divert
                bool        isDivert      = false;
                bool        pushesToStack = false;
                PushPopType divPushType   = PushPopType.Function;
                bool        external      = false;
                if (obj.TryGetValue("->", out propValue))
                {
                    isDivert = true;
                }
                else if (obj.TryGetValue("f()", out propValue))
                {
                    isDivert      = true;
                    pushesToStack = true;
                    divPushType   = PushPopType.Function;
                }
                else if (obj.TryGetValue("->t->", out propValue))
                {
                    isDivert      = true;
                    pushesToStack = true;
                    divPushType   = PushPopType.Tunnel;
                }
                else if (obj.TryGetValue("x()", out propValue))
                {
                    isDivert      = true;
                    external      = true;
                    pushesToStack = false;
                    divPushType   = PushPopType.Function;
                }
                if (isDivert)
                {
                    var divert = new Divert();
                    divert.pushesToStack = pushesToStack;
                    divert.stackPushType = divPushType;
                    divert.isExternal    = external;

                    string target = propValue.ToString();

                    if (obj.TryGetValue("var", out propValue))
                    {
                        divert.variableDivertName = target;
                    }
                    else
                    {
                        divert.targetPathString = target;
                    }

                    divert.isConditional = obj.TryGetValue("c", out propValue);

                    if (external)
                    {
                        if (obj.TryGetValue("exArgs", out propValue))
                        {
                            divert.externalArgs = (int)propValue;
                        }
                    }

                    return(divert);
                }

                // Choice
                if (obj.TryGetValue("*", out propValue))
                {
                    var choice = new ChoicePoint();
                    choice.pathStringOnChoice = propValue.ToString();

                    if (obj.TryGetValue("flg", out propValue))
                    {
                        choice.flags = (int)propValue;
                    }

                    return(choice);
                }

                // Variable reference
                if (obj.TryGetValue("VAR?", out propValue))
                {
                    return(new VariableReference(propValue.ToString()));
                }
                else if (obj.TryGetValue("CNT?", out propValue))
                {
                    var readCountVarRef = new VariableReference();
                    readCountVarRef.pathStringForCount = propValue.ToString();
                    return(readCountVarRef);
                }

                // Variable assignment
                bool isVarAss    = false;
                bool isGlobalVar = false;
                if (obj.TryGetValue("VAR=", out propValue))
                {
                    isVarAss    = true;
                    isGlobalVar = true;
                }
                else if (obj.TryGetValue("temp=", out propValue))
                {
                    isVarAss    = true;
                    isGlobalVar = false;
                }
                if (isVarAss)
                {
                    var varName   = propValue.ToString();
                    var isNewDecl = !obj.TryGetValue("re", out propValue);
                    var varAss    = new VariableAssignment(varName, isNewDecl);
                    varAss.isGlobal = isGlobalVar;
                    return(varAss);
                }

                if (obj ["originalChoicePath"] != null)
                {
                    return(JObjectToChoice(obj));
                }
            }

            // Array is always a Runtime.Container
            if (token is List <object> )
            {
                return(JArrayToContainer((List <object>)token));
            }

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

            throw new System.Exception("Failed to convert token to runtime object: " + token);
        }