예제 #1
0
파일: Story.cs 프로젝트: inkle/ink
        public Runtime.Story ExportRuntime(ErrorHandler errorHandler = null)
		{
            _errorHandler = errorHandler;

            // Find all constants before main export begins, so that VariableReferences know
            // whether to generate a runtime variable reference or the literal value
            constants = new Dictionary<string, Expression> ();
            foreach (var constDecl in FindAll<ConstantDeclaration> ()) {

                // Check for duplicate definitions
                Parsed.Expression existingDefinition = null;
                if (constants.TryGetValue (constDecl.constantName, out existingDefinition)) {
                    if (!existingDefinition.Equals (constDecl.expression)) {
                        var errorMsg = string.Format ("CONST '{0}' has been redefined with a different value. Multiple definitions of the same CONST are valid so long as they contain the same value. Initial definition was on {1}.", constDecl.constantName, existingDefinition.debugMetadata);
                        Error (errorMsg, constDecl, isWarning:false);
                    }
                }

                constants [constDecl.constantName] = constDecl.expression;
            }

            externals = new Dictionary<string, ExternalDeclaration> ();

			// Get default implementation of runtimeObject, which calls ContainerBase's generation method
            var rootContainer = runtimeObject as Runtime.Container;

            // Export initialisation of global variables
            // TODO: We *could* add this as a declarative block to the story itself...
            var variableInitialisation = new Runtime.Container ();
            variableInitialisation.AddContent (Runtime.ControlCommand.EvalStart ());

            // Global variables are those that are local to the story and marked as global
            foreach (var nameDeclPair in variableDeclarations) {
                var varName = nameDeclPair.Key;
                var varDecl = nameDeclPair.Value;
                if (varDecl.isGlobalDeclaration) {
                    varDecl.expression.GenerateIntoContainer (variableInitialisation);
                    var runtimeVarAss = new Runtime.VariableAssignment (varName, isNewDeclaration:true);
                    runtimeVarAss.isGlobal = true;
                    variableInitialisation.AddContent (runtimeVarAss);
                }
            }

            variableInitialisation.AddContent (Runtime.ControlCommand.EvalEnd ());
            variableInitialisation.AddContent (Runtime.ControlCommand.End ());

            if (variableDeclarations.Count > 0) {
                variableInitialisation.name = "global decl";
                rootContainer.AddToNamedContentOnly (variableInitialisation);
            }

            // Signal that it's safe to exit without error, even if there are no choices generated
            // (this only happens at the end of top level content that isn't in any particular knot)
            rootContainer.AddContent (Runtime.ControlCommand.Done ());

			// Replace runtimeObject with Story object instead of the Runtime.Container generated by Parsed.ContainerBase
            var runtimeStory = new Runtime.Story (rootContainer);
			runtimeObject = runtimeStory;

            if (hadError)
                return null;

            // Optimisation step - inline containers that can be
            FlattenContainersIn (rootContainer);

			// Now that the story has been fulled parsed into a hierarchy,
			// and the derived runtime hierarchy has been built, we can
			// resolve referenced symbols such as variables and paths.
			// e.g. for paths " -> knotName --> stitchName" into an INKPath (knotName.stitchName)
			// We don't make any assumptions that the INKPath follows the same
			// conventions as the script format, so we resolve to actual objects before
			// translating into an INKPath. (This also allows us to choose whether
			// we want the paths to be absolute)
			ResolveReferences (this);

            if (hadError)
                return null;

            runtimeStory.ResetState ();

			return runtimeStory;
		}
예제 #2
0
        public Runtime.Story ExportRuntime(ErrorHandler errorHandler = null)
        {
            _errorHandler = errorHandler;

            // Find all constants before main export begins, so that VariableReferences know
            // whether to generate a runtime variable reference or the literal value
            constants = new Dictionary <string, Expression> ();
            foreach (var constDecl in FindAll <ConstantDeclaration> ())
            {
                // Check for duplicate definitions
                Parsed.Expression existingDefinition = null;
                if (constants.TryGetValue(constDecl.constantName, out existingDefinition))
                {
                    if (!existingDefinition.Equals(constDecl.expression))
                    {
                        var errorMsg = string.Format("CONST '{0}' has been redefined with a different value. Multiple definitions of the same CONST are valid so long as they contain the same value. Initial definition was on {1}.", constDecl.constantName, existingDefinition.debugMetadata);
                        Error(errorMsg, constDecl, isWarning: false);
                    }
                }

                constants [constDecl.constantName] = constDecl.expression;
            }

            // List definitions are treated like constants too - they should be usable
            // from other variable declarations.
            _listDefs = new Dictionary <string, ListDefinition> ();
            foreach (var listDef in FindAll <ListDefinition> ())
            {
                _listDefs [listDef.identifier?.name] = listDef;
            }

            externals = new Dictionary <string, ExternalDeclaration> ();

            // Resolution of weave point names has to come first, before any runtime code generation
            // since names have to be ready before diverts start getting created.
            // (It used to be done in the constructor for a weave, but didn't allow us to generate
            // errors when name resolution failed.)
            ResolveWeavePointNaming();

            // Get default implementation of runtimeObject, which calls ContainerBase's generation method
            var rootContainer = runtimeObject as Runtime.Container;

            // Export initialisation of global variables
            // TODO: We *could* add this as a declarative block to the story itself...
            var variableInitialisation = new Runtime.Container();

            variableInitialisation.AddContent(Runtime.ControlCommand.EvalStart());

            // Global variables are those that are local to the story and marked as global
            var runtimeLists = new List <Runtime.ListDefinition> ();

            foreach (var nameDeclPair in variableDeclarations)
            {
                var varName = nameDeclPair.Key;
                var varDecl = nameDeclPair.Value;
                if (varDecl.isGlobalDeclaration)
                {
                    if (varDecl.listDefinition != null)
                    {
                        _listDefs[varName] = varDecl.listDefinition;
                        variableInitialisation.AddContent(varDecl.listDefinition.runtimeObject);
                        runtimeLists.Add(varDecl.listDefinition.runtimeListDefinition);
                    }
                    else
                    {
                        varDecl.expression.GenerateIntoContainer(variableInitialisation);
                    }

                    var runtimeVarAss = new Runtime.VariableAssignment(varName, isNewDeclaration: true);
                    runtimeVarAss.isGlobal = true;
                    variableInitialisation.AddContent(runtimeVarAss);
                }
            }

            variableInitialisation.AddContent(Runtime.ControlCommand.EvalEnd());
            variableInitialisation.AddContent(Runtime.ControlCommand.End());

            if (variableDeclarations.Count > 0)
            {
                variableInitialisation.name = "global decl";
                rootContainer.AddToNamedContentOnly(variableInitialisation);
            }

            // Signal that it's safe to exit without error, even if there are no choices generated
            // (this only happens at the end of top level content that isn't in any particular knot)
            rootContainer.AddContent(Runtime.ControlCommand.Done());

            // Replace runtimeObject with Story object instead of the Runtime.Container generated by Parsed.ContainerBase
            var runtimeStory = new Runtime.Story(rootContainer, runtimeLists);

            runtimeObject = runtimeStory;

            if (_hadError)
            {
                return(null);
            }

            // Optimisation step - inline containers that can be
            FlattenContainersIn(rootContainer);

            // Now that the story has been fulled parsed into a hierarchy,
            // and the derived runtime hierarchy has been built, we can
            // resolve referenced symbols such as variables and paths.
            // e.g. for paths " -> knotName --> stitchName" into an INKPath (knotName.stitchName)
            // We don't make any assumptions that the INKPath follows the same
            // conventions as the script format, so we resolve to actual objects before
            // translating into an INKPath. (This also allows us to choose whether
            // we want the paths to be absolute)
            ResolveReferences(this);

            if (_hadError)
            {
                return(null);
            }

            runtimeStory.ResetState();

            return(runtimeStory);
        }
예제 #3
0
        public Runtime.Story ExportRuntime(ErrorHandler errorHandler = null)
        {
            _errorHandler = errorHandler;

            // Find all constants before main export begins, so that VariableReferences know
            // whether to generate a runtime variable reference or the literal value
            constants = new Dictionary <string, Expression> ();
            foreach (var constDecl in FindAll <ConstantDeclaration> ())
            {
                constants [constDecl.constantName] = constDecl.expression;
            }

            externals = new Dictionary <string, ExternalDeclaration> ();

            // Get default implementation of runtimeObject, which calls ContainerBase's generation method
            var rootContainer = runtimeObject as Runtime.Container;

            // Export initialisation of global variables
            // TODO: We *could* add this as a declarative block to the story itself...
            var variableInitialisation = new Runtime.Container();

            variableInitialisation.AddContent(Runtime.ControlCommand.EvalStart());

            // Global variables are those that are local to the story and marked as global
            foreach (var nameDeclPair in variableDeclarations)
            {
                var varName = nameDeclPair.Key;
                var varDecl = nameDeclPair.Value;
                if (varDecl.isGlobalDeclaration)
                {
                    varDecl.expression.GenerateIntoContainer(variableInitialisation);
                    var runtimeVarAss = new Runtime.VariableAssignment(varName, isNewDeclaration: true);
                    runtimeVarAss.isGlobal = true;
                    variableInitialisation.AddContent(runtimeVarAss);
                }
            }

            variableInitialisation.AddContent(Runtime.ControlCommand.EvalEnd());
            variableInitialisation.AddContent(Runtime.ControlCommand.End());

            if (variableDeclarations.Count > 0)
            {
                variableInitialisation.name = "global decl";
                rootContainer.AddToNamedContentOnly(variableInitialisation);
            }

            // Signal that it's safe to exit without error, even if there are no choices generated
            // (this only happens at the end of top level content that isn't in any particular knot)
            rootContainer.AddContent(Runtime.ControlCommand.Done());

            // Replace runtimeObject with Story object instead of the Runtime.Container generated by Parsed.ContainerBase
            var runtimeStory = new Runtime.Story(rootContainer);

            runtimeObject = runtimeStory;

            if (hadError)
            {
                return(null);
            }

            // Now that the story has been fulled parsed into a hierarchy,
            // and the derived runtime hierarchy has been built, we can
            // resolve referenced symbols such as variables and paths.
            // e.g. for paths " -> knotName --> stitchName" into an INKPath (knotName.stitchName)
            // We don't make any assumptions that the INKPath follows the same
            // conventions as the script format, so we resolve to actual objects before
            // translating into an INKPath. (This also allows us to choose whether
            // we want the paths to be absolute)
            ResolveReferences(this);

            if (hadError)
            {
                return(null);
            }

            runtimeStory.ResetState();

            return(runtimeStory);
        }