Esempio n. 1
0
        internal int?DebugLineNumberOfPath(Path path)
        {
            if (path == null)
            {
                return(null);
            }

            // Try to get a line number from debug metadata
            var root = this.rootContentContainer;

            if (root)
            {
                Runtime.Object targetContent = root.ContentAtPath(path).obj;
                if (targetContent)
                {
                    var dm = targetContent.debugMetadata;
                    if (dm != null)
                    {
                        return(dm.startLineNumber);
                    }
                }
            }

            return(null);
        }
Esempio n. 2
0
        void PushToOutputStreamIndividual(Runtime.Object obj)
        {
            var glue = obj as Runtime.Glue;
            var text = obj as Runtime.StringValue;

            bool includeInOutput = true;

            if (glue)
            {
                // Found matching left-glue for right-glue? Close it.
                Glue matchingRightGlue = null;
                if (glue.isLeft)
                {
                    matchingRightGlue = MatchRightGlueForLeftGlue(glue);
                }

                // Left/Right glue is auto-generated for inline expressions
                // where we want to absorb newlines but only in a certain direction.
                // "Bi" glue is written by the user in their ink with <>
                if (glue.isLeft || glue.isBi)
                {
                    TrimNewlinesFromOutputStream(matchingRightGlue);
                }

                includeInOutput = glue.isBi || glue.isRight;
            }

            else if (text)
            {
                if (currentGlueIndex != -1)
                {
                    // Absorb any new newlines if there's existing glue
                    // in the output stream.
                    // Also trim any extra whitespace (spaces/tabs) if so.
                    if (text.isNewline)
                    {
                        TrimFromExistingGlue();
                        includeInOutput = false;
                    }

                    // Able to completely reset when
                    else if (text.isNonWhitespace)
                    {
                        RemoveExistingGlue();
                    }
                }
                else if (text.isNewline)
                {
                    if (outputStreamEndsInNewline || !outputStreamContainsContent)
                    {
                        includeInOutput = false;
                    }
                }
            }

            if (includeInOutput)
            {
                _outputStream.Add(obj);
            }
        }
Esempio n. 3
0
        internal int?DebugLineNumberOfPath(Path path)
        {
            if (path == null)
            {
                return(null);
            }

            // Try to get a line number from debug metadata
            var root = this.rootContentContainer;

            if (root)
            {
                Runtime.Object targetContent = null;

                // Sometimes paths can be "invalid" if they're externally defined
                // in the game. TODO: Change ContentAtPath to return null, and
                // only throw an exception in places that actually care!
                try {
                    targetContent = root.ContentAtPath(path);
                } catch { }

                if (targetContent)
                {
                    var dm = targetContent.debugMetadata;
                    if (dm != null)
                    {
                        return(dm.startLineNumber);
                    }
                }
            }

            return(null);
        }
Esempio n. 4
0
        public bool RuntimeObjectsEqual(Runtime.Object obj1, Runtime.Object obj2)
        {
            if (obj1.GetType() != obj2.GetType())
            {
                return(false);
            }

            // Perform equality on int/float manually to avoid boxing
            var intVal = obj1 as IntValue;

            if (intVal != null)
            {
                return(intVal.value == ((IntValue)obj2).value);
            }

            var floatVal = obj1 as FloatValue;

            if (floatVal != null)
            {
                return(floatVal.value == ((FloatValue)obj2).value);
            }

            // Other Value type (using proper Equals: list, string, divert path)
            var val1 = obj1 as Value;
            var val2 = obj2 as Value;

            if (val1 != null)
            {
                return(val1.valueObject.Equals(val2.valueObject));
            }

            throw new System.Exception("FastRoughDefinitelyEquals: Unsupported runtime object type: " + obj1.GetType());
        }
Esempio n. 5
0
        Runtime.Object GetRawVariableWithName(string name, int contextIndex)
        {
            Runtime.Object varValue = null;

            // 0 context = global
            if (contextIndex == 0 || contextIndex == -1)
            {
                if (_globalVariables.TryGetValue(name, out varValue))
                {
                    return(varValue);
                }

                // Getting variables can actually happen during globals set up since you can do
                //  VAR x = A_LIST_ITEM
                // So _defaultGlobalVariables may be null.
                // We need to do this check though in case a new global is added, so we need to
                // revert to the default globals dictionary since an initial value hasn't yet been set.
                if (_defaultGlobalVariables != null && _defaultGlobalVariables.TryGetValue(name, out varValue))
                {
                    return(varValue);
                }

                var listItemValue = _listDefsOrigin.FindSingleItemListWithName(name);
                if (listItemValue)
                {
                    return(listItemValue);
                }
            }

            // Temporary
            varValue = _callStack.GetTemporaryVariableWithName(name, contextIndex);

            return(varValue);
        }
Esempio n. 6
0
        Runtime.Object GetRawVariableWithName(string name, int contextIndex)
        {
            Runtime.Object varValue = null;

            // 0 context = global
            if (contextIndex == 0 || contextIndex == -1)
            {
                if (_globalVariables.TryGetValue(name, out varValue))
                {
                    return(varValue);
                }

                var listItemValue = _listDefsOrigin.FindSingleItemListWithName(name);
                if (listItemValue)
                {
                    return(listItemValue);
                }
            }

            // Temporary
            varValue = _callStack.GetTemporaryVariableWithName(name, contextIndex);

            if (varValue == null)
            {
                throw new System.Exception("RUNTIME ERROR: Variable '" + name + "' could not be found in context '" + contextIndex + "'. This shouldn't be possible so is a bug in the ink engine. Please try to construct a minimal story that reproduces the problem and report to inkle, thank you!");
            }

            return(varValue);
        }
        internal void PushEvaluationStack(Runtime.Object obj)
        {
            // Include metadata about the origin List for list values when
            // they're used, so that lower level functions can make use
            // of the origin list to get related items, or make comparisons
            // with the integer values etc.
            var listValue = obj as ListValue;

            if (listValue)
            {
                // Update origin when list is has something to indicate the list origin
                var rawList = listValue.value;
                var names   = rawList.originNames;
                if (names != null)
                {
                    var origins = new List <ListDefinition> ();
                    foreach (var n in names)
                    {
                        ListDefinition def = null;
                        story.listDefinitions.TryGetDefinition(n, out def);
                        if (!origins.Contains(def))
                        {
                            origins.Add(def);
                        }
                    }

                    rawList.origins = origins;
                }
            }

            evaluationStack.Add(obj);
        }
Esempio n. 8
0
 void AddDivertToResolve(Runtime.Divert divert, Runtime.Object targetContent)
 {
     _sequenceDivertsToResove.Add(new SequenceDivertToResolve()
     {
         divert        = divert,
         targetContent = targetContent
     });
 }
Esempio n. 9
0
        public void TryAddNamedContent(Runtime.Object contentObj)
        {
            var namedContentObj = contentObj as INamedContent;

            if (namedContentObj != null && namedContentObj.hasValidName)
            {
                AddToNamedContentOnly(namedContentObj);
            }
        }
Esempio n. 10
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);
            }
        }
Esempio n. 11
0
        void RetainListOriginsForAssignment(Runtime.Object oldValue, Runtime.Object newValue)
        {
            var oldList = oldValue as ListValue;
            var newList = newValue as ListValue;

            if (oldList && newList && newList.value.Count == 0)
            {
                newList.value.SetInitialOriginNames(oldList.value.originNames);
            }
        }
Esempio n. 12
0
        public static void RetainListOriginsForAssignment(Runtime.Object oldValue, Runtime.Object newValue)
        {
            var oldList = oldValue as ListValue;
            var newList = newValue as ListValue;

            // When assigning the emtpy list, try to retain any initial origin names
            if (oldList && newList && newList.value.Count == 0)
            {
                newList.value.SetInitialOriginNames(oldList.value.originNames);
            }
        }
Esempio n. 13
0
        public void AddContent(Runtime.Object contentObj)
        {
            content.Add(contentObj);

            if (contentObj.parent)
            {
                throw new System.Exception("content is already in " + contentObj.parent);
            }

            contentObj.parent = this;

            TryAddNamedContent(contentObj);
        }
Esempio n. 14
0
        public void InsertContent(Runtime.Object contentObj, int index)
        {
            content.Insert(index, contentObj);

            if (contentObj.parent)
            {
                throw new System.Exception("content is already in " + contentObj.parent);
            }

            contentObj.parent = this;

            TryAddNamedContent(contentObj);
        }
Esempio n. 15
0
        internal object CompleteFunctionEvaluationFromGame()
        {
            if (callStack.currentElement.type != PushPopType.FunctionEvaluationFromGame)
            {
                throw new StoryException("Expected external function evaluation to be complete. Stack trace: " + callStack.callStackTrace);
            }

            int originalEvaluationStackHeight = callStack.currentElement.evaluationStackHeightWhenPushed;

            // Do we have a returned value?
            // Potentially pop multiple values off the stack, in case we need
            // to clean up after ourselves (e.g. caller of EvaluateFunction may
            // have passed too many arguments, and we currently have no way to check for that)
            Runtime.Object returnedObj = null;
            while (evaluationStack.Count > originalEvaluationStackHeight)
            {
                var poppedObj = PopEvaluationStack();
                if (returnedObj == null)
                {
                    returnedObj = poppedObj;
                }
            }

            // Finally, pop the external function evaluation
            PopCallstack(PushPopType.FunctionEvaluationFromGame);

            // What did we get back?
            if (returnedObj)
            {
                if (returnedObj is Runtime.Void)
                {
                    return(null);
                }

                // Some kind of value, if not void
                var returnVal = returnedObj as Runtime.Value;

                // DivertTargets get returned as the string of components
                // (rather than a Path, which isn't public)
                if (returnVal.valueType == ValueType.DivertTarget)
                {
                    return(returnVal.valueObject.ToString());
                }

                // Other types can just have their exact object type:
                // int, float, string. VariablePointers get returned as strings.
                return(returnVal.valueObject);
            }

            return(null);
        }
Esempio n. 16
0
        Runtime.Object GetVariableWithName(string name, int contextIndex)
        {
            Runtime.Object varValue = GetRawVariableWithName(name, contextIndex);

            // Get value from pointer?
            var varPointer = varValue as VariablePointerValue;

            if (varPointer)
            {
                varValue = ValueAtVariablePointer(varPointer);
            }

            return(varValue);
        }
        internal object CompleteExternalFunctionEvaluation()
        {
            // Do we have a returned value?
            // Potentially pop multiple values off the stack, in case we need
            // to clean up after ourselves (e.g. caller of EvaluateFunction may
            // have passed too many arguments, and we currently have no way to check for that)
            Runtime.Object returnedObj = null;
            while (evaluationStack.Count > _originalEvaluationStackHeight)
            {
                var poppedObj = PopEvaluationStack();
                if (returnedObj == null)
                {
                    returnedObj = poppedObj;
                }
            }

            // Restore our own state
            callStack                      = _originalCallstack;
            _originalCallstack             = null;
            _originalEvaluationStackHeight = 0;

            // Restore the callstack that the variablesState uses
            variablesState.callStack = callStack;

            // What did we get back?
            if (returnedObj)
            {
                if (returnedObj is Runtime.Void)
                {
                    return(null);
                }

                // Some kind of value, if not void
                var returnVal = returnedObj as Runtime.Value;

                // DivertTargets get returned as the string of components
                // (rather than a Path, which isn't public)
                if (returnVal.valueType == ValueType.DivertTarget)
                {
                    return(returnVal.valueObject.ToString());
                }

                // Other types can just have their exact object type:
                // int, float, string. VariablePointers get returned as strings.
                return(returnVal.valueObject);
            }

            return(null);
        }
Esempio n. 18
0
        public void SetTemporaryVariable(string name, Runtime.Object value, bool declareNew, int contextIndex = -1)
        {
            if (contextIndex == -1)
            {
                contextIndex = currentElementIndex + 1;
            }

            var contextElement = callStack [contextIndex - 1];

            if (!declareNew && !contextElement.temporaryVariables.ContainsKey(name))
            {
                throw new System.Exception("Could not find temporary variable to set: " + name);
            }
            contextElement.temporaryVariables [name] = value;
        }
Esempio n. 19
0
        public void SetGlobal(string variableName, Runtime.Object value)
        {
            Runtime.Object oldValue = null;
            if (patch == null || !patch.TryGetGlobal(variableName, out oldValue))
            {
                _globalVariables.TryGetValue(variableName, out oldValue);
            }

            if (patch != null)
            {
                patch.SetGlobal(variableName, value);
            }
            else
            {
                _globalVariables [variableName] = value;
            }
        }
Esempio n. 20
0
        // Normal content gets added into the latest Choice or Gather by default,
        // unless there hasn't been one yet.
        void AddGeneralRuntimeContent(Runtime.Object content)
        {
            // Content is allowed to evaluate runtimeObject to null
            // (e.g. AuthorWarning, which doesn't make it into the runtime)
            if (content == null)
            {
                return;
            }

            if (addContentToPreviousWeavePoint)
            {
                previousWeavePoint.runtimeContainer.AddContent(content);
            }
            else
            {
                currentContainer.AddContent(content);
            }
        }
Esempio n. 21
0
            public Thread(JToken jsonToken, Story storyContext) : this()
            {
                JObject jThreadObj = (JObject)jsonToken;

                threadIndex = jThreadObj ["threadIndex"].ToObject <int> ();

                JArray jThreadCallstack = (JArray)jThreadObj ["callstack"];

                foreach (JToken jElTok in jThreadCallstack)
                {
                    JObject jElementObj = (JObject)jElTok;

                    PushPopType pushPopType = (PushPopType)jElementObj ["type"].ToObject <int>();

                    Container currentContainer = null;
                    int       contentIndex     = 0;

                    string currentContainerPathStr = null;
                    JToken currentContainerPathStrToken;
                    if (jElementObj.TryGetValue("cPath", out currentContainerPathStrToken))
                    {
                        currentContainerPathStr = currentContainerPathStrToken.ToString();
                        currentContainer        = storyContext.ContentAtPath(new Path(currentContainerPathStr)) as Container;
                        contentIndex            = jElementObj ["idx"].ToObject <int> ();
                    }

                    bool inExpressionEvaluation = jElementObj ["exp"].ToObject <bool> ();

                    var el = new Element(pushPopType, currentContainer, contentIndex, inExpressionEvaluation);

                    var jObjTemps = (JObject)jElementObj ["temp"];
                    el.temporaryVariables = Json.JObjectToDictionaryRuntimeObjs(jObjTemps);

                    callstack.Add(el);
                }

                JToken prevContentObjPath = jThreadObj["previousContentObject"];

                if (prevContentObjPath != null)
                {
                    var prevPath = new Path(prevContentObjPath.ToString());
                    previousContentObject = storyContext.ContentAtPath(prevPath);
                }
            }
Esempio n. 22
0
        public SearchResult ContentAtPath(Path path, int partialPathStart = 0, int partialPathLength = -1)
        {
            if (partialPathLength == -1)
            {
                partialPathLength = path.length;
            }

            var result = new SearchResult();

            result.approximate = false;

            Container currentContainer = this;

            Runtime.Object currentObj = this;

            for (int i = partialPathStart; i < partialPathLength; ++i)
            {
                var comp = path.GetComponent(i);

                // Path component was wrong type
                if (currentContainer == null)
                {
                    result.approximate = true;
                    break;
                }

                var foundObj = currentContainer.ContentWithPathComponent(comp);

                // Couldn't resolve entire path?
                if (foundObj == null)
                {
                    result.approximate = true;
                    break;
                }

                currentObj       = foundObj;
                currentContainer = foundObj as Container;
            }

            result.obj = currentObj;

            return(result);
        }
Esempio n. 23
0
        void SetGlobal(string variableName, Runtime.Object value)
        {
            Runtime.Object oldValue = null;
            _globalVariables.TryGetValue(variableName, out oldValue);

            _globalVariables [variableName] = value;

            if (variableChangedEvent != null && !value.Equals(oldValue))
            {
                if (batchObservingVariableChanges)
                {
                    _changedVariables.Add(variableName);
                }
                else
                {
                    variableChangedEvent(variableName, value);
                }
            }
        }
Esempio n. 24
0
        // Push to output stream, but split out newlines in text for consistency
        // in dealing with them later.
        internal void PushToOutputStream(Runtime.Object obj)
        {
            var text = obj as StringValue;

            if (text)
            {
                var listText = TrySplittingHeadTailWhitespace(text);
                if (listText != null)
                {
                    foreach (var textObj in listText)
                    {
                        PushToOutputStreamIndividual(textObj);
                    }
                    return;
                }
            }

            PushToOutputStreamIndividual(obj);
        }
Esempio n. 25
0
            public Thread(Dictionary <string, object> jThreadObj, Story storyContext) : this()
            {
                threadIndex = (int)jThreadObj ["threadIndex"];

                List <object> jThreadCallstack = (List <object>)jThreadObj ["callstack"];

                foreach (object jElTok in jThreadCallstack)
                {
                    var jElementObj = (Dictionary <string, object>)jElTok;

                    PushPopType pushPopType = (PushPopType)(int)jElementObj ["type"];

                    Container currentContainer = null;
                    int       contentIndex     = 0;

                    string currentContainerPathStr = null;
                    object currentContainerPathStrToken;
                    if (jElementObj.TryGetValue("cPath", out currentContainerPathStrToken))
                    {
                        currentContainerPathStr = currentContainerPathStrToken.ToString();
                        currentContainer        = storyContext.ContentAtPath(new Path(currentContainerPathStr)) as Container;
                        contentIndex            = (int)jElementObj ["idx"];
                    }

                    bool inExpressionEvaluation = (bool)jElementObj ["exp"];

                    var el = new Element(pushPopType, currentContainer, contentIndex, inExpressionEvaluation);

                    var jObjTemps = (Dictionary <string, object>)jElementObj ["temp"];
                    el.temporaryVariables = Json.JObjectToDictionaryRuntimeObjs(jObjTemps);

                    callstack.Add(el);
                }

                object prevContentObjPath;

                if (jThreadObj.TryGetValue("previousContentObject", out prevContentObjPath))
                {
                    var prevPath = new Path((string)prevContentObjPath);
                    previousContentObject = storyContext.ContentAtPath(prevPath);
                }
            }
Esempio n. 26
0
        // Get variable value, dereferencing a variable pointer if necessary
        public Runtime.Object GetTemporaryVariableWithName(string name, int contextIndex = -1)
        {
            if (contextIndex == -1)
            {
                contextIndex = currentElementIndex + 1;
            }

            Runtime.Object varValue = null;

            var contextElement = callStack [contextIndex - 1];

            if (contextElement.temporaryVariables.TryGetValue(name, out varValue))
            {
                return(varValue);
            }
            else
            {
                return(null);
            }
        }
Esempio n. 27
0
        public void SetTemporaryVariable(string name, Runtime.Object value, bool declareNew, int contextIndex = -1)
        {
            if (contextIndex == -1)
            {
                contextIndex = currentElementIndex + 1;
            }

            var contextElement = callStack [contextIndex - 1];

            if (!declareNew && !contextElement.temporaryVariables.ContainsKey(name))
            {
                throw new StoryException("Could not find temporary variable to set: " + name);
            }

            Runtime.Object oldValue;
            if (contextElement.temporaryVariables.TryGetValue(name, out oldValue))
            {
                ListValue.RetainListOriginsForAssignment(oldValue, value);
            }

            contextElement.temporaryVariables [name] = value;
        }
Esempio n. 28
0
        public void SetGlobal(string variableName, Runtime.Object value)
        {
            Runtime.Object oldValue = null;
            if (patch == null || !patch.TryGetGlobal(variableName, out oldValue))
            {
                _globalVariables.TryGetValue(variableName, out oldValue);
            }

            ListValue.RetainListOriginsForAssignment(oldValue, value);

            if (patch != null)
            {
                patch.SetGlobal(variableName, value);
            }
            else
            {
                _globalVariables [variableName] = value;
            }

            if (variableChangedEvent != null && !value.Equals(oldValue))
            {
                if (batchObservingVariableChanges)
                {
                    if (patch != null)
                    {
                        patch.AddChangedVariable(variableName);
                    }
                    else if (_changedVariablesForBatchObs != null)
                    {
                        _changedVariablesForBatchObs.Add(variableName);
                    }
                }
                else
                {
                    variableChangedEvent(variableName, value);
                }
            }
        }
Esempio n. 29
0
        public Runtime.Object ContentAtPath(Path path, int partialPathLength = -1)
        {
            if (partialPathLength == -1)
            {
                partialPathLength = path.length;
            }

            Container currentContainer = this;

            Runtime.Object currentObj = this;

            for (int i = 0; i < partialPathLength; ++i)
            {
                var comp = path.GetComponent(i);
                if (currentContainer == null)
                {
                    throw new System.Exception("Path continued, but previous object wasn't a container: " + currentObj);
                }
                currentObj       = currentContainer.ContentWithPathComponent(comp);
                currentContainer = currentObj as Container;
            }

            return(currentObj);
        }
Esempio n. 30
0
        Runtime.Object GetRawVariableWithName(string name, int contextIndex)
        {
            Runtime.Object varValue = null;

            // 0 context = global
            if (contextIndex == 0 || contextIndex == -1)
            {
                if (_globalVariables.TryGetValue(name, out varValue))
                {
                    return(varValue);
                }

                var listItemValue = _listDefsOrigin.FindSingleItemListWithName(name);
                if (listItemValue)
                {
                    return(listItemValue);
                }
            }

            // Temporary
            varValue = _callStack.GetTemporaryVariableWithName(name, contextIndex);

            return(varValue);
        }
Esempio n. 31
0
			public Thread(Dictionary<string, object> jThreadObj, Story storyContext) : this() {
                threadIndex = (int) jThreadObj ["threadIndex"];

				List<object> jThreadCallstack = (List<object>) jThreadObj ["callstack"];
				foreach (object jElTok in jThreadCallstack) {

					var jElementObj = (Dictionary<string, object>)jElTok;

                    PushPopType pushPopType = (PushPopType)(int)jElementObj ["type"];

					Container currentContainer = null;
					int contentIndex = 0;

					string currentContainerPathStr = null;
					object currentContainerPathStrToken;
					if (jElementObj.TryGetValue ("cPath", out currentContainerPathStrToken)) {
						currentContainerPathStr = currentContainerPathStrToken.ToString ();
						currentContainer = storyContext.ContentAtPath (new Path(currentContainerPathStr)) as Container;
                        contentIndex = (int) jElementObj ["idx"];
					}

                    bool inExpressionEvaluation = (bool)jElementObj ["exp"];

					var el = new Element (pushPopType, currentContainer, contentIndex, inExpressionEvaluation);

					var jObjTemps = (Dictionary<string, object>) jElementObj ["temp"];
					el.temporaryVariables = Json.JObjectToDictionaryRuntimeObjs (jObjTemps);

					callstack.Add (el);
				}

				object prevContentObjPath;
				if( jThreadObj.TryGetValue("previousContentObject", out prevContentObjPath) ) {
					var prevPath = new Path((string)prevContentObjPath);
                    previousContentObject = storyContext.ContentAtPath(prevPath);
                }
			}