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; }
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); }
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); }