public string GetSwitchLookupCode() { List <string> output = new List <string>(); foreach (string key in this.stringSwitchLookups.Keys) { string lookupName = key; Dictionary <string, int> valuesToInts = this.stringSwitchLookups[key]; output.Add(lookupName); output.Add(" = { "); bool first = true; foreach (string skey in valuesToInts.Keys) { if (!first) { first = false; output.Add(", "); } output.Add(StringTokenUtil.ConvertStringValueToCode(skey)); output.Add(": "); output.Add("" + valuesToInts[skey]); } output.Add(" };\r\n"); } foreach (string lookupName in this.intListLookups.Keys) { List <int> actualList = new List <int>(); Dictionary <int, int> lookup = this.intListLookups[lookupName]; int explicitMax = this.explicitMaxes[lookupName]; int defaultCaseId = this.defaultCaseIds[lookupName]; while (actualList.Count <= explicitMax) { actualList.Add(defaultCaseId); } foreach (int ikey in lookup.Keys) { while (actualList.Count <= ikey) { actualList.Add(defaultCaseId); } actualList[ikey] = lookup[ikey]; } output.Add(lookupName); output.Add(" = ["); for (int i = 0; i < actualList.Count; ++i) { if (i > 0) { output.Add(", "); } output.Add(actualList[i] + ""); } output.Add("];\r\n"); } return(string.Join("", output)); }
public override void ExportProject( Dictionary <string, FileOutput> output, IList <LibraryForExport> libraries, ResourceDatabase resourceDatabase, Options options) { List <string> jsExtraHead = new List <string>() { options.GetStringOrEmpty(ExportOptionKey.JS_HEAD_EXTRAS) }; if (options.GetBool(ExportOptionKey.JS_FULL_PAGE)) { jsExtraHead.Add( "<script type=\"text/javascript\">" + "C$common$globalOptions['fullscreen'] = true;" + "</script>"); } options.SetOption(ExportOptionKey.JS_HEAD_EXTRAS, string.Join("\n", jsExtraHead)); Dictionary <string, string> replacements = this.GenerateReplacementDictionary(options, resourceDatabase); TemplateReader templateReader = new TemplateReader(new PkgAwareFileUtil(), this); TemplateSet vmTemplates = templateReader.GetVmTemplates(); output["vm.js"] = new FileOutput() { Type = FileOutputType.Text, TextContent = vmTemplates.GetText("vm.js"), }; List <LibraryForExport> librariesWithCode = new List <LibraryForExport>(); foreach (LibraryForExport library in libraries.Where(lib => lib.HasNativeCode)) { string libraryName = library.Name; TemplateSet libTemplates = templateReader.GetLibraryTemplates(library); List <string> libraryLines = new List <string>(); libraryLines.Add(libTemplates.GetText("gen/lib_" + libraryName.ToLowerInvariant() + ".js")); libraryLines.Add(""); libraryLines.Add("C$common$scrapeLibFuncNames('" + libraryName.ToLowerInvariant() + "');"); libraryLines.Add(""); // add helper functions after the scrape. foreach (string jsHelperFile in libTemplates.GetPaths("source/", ".js")) { libraryLines.Add(libTemplates.GetText(jsHelperFile)); libraryLines.Add(""); } output["libs/lib_" + libraryName.ToLowerInvariant() + ".js"] = new FileOutput() { Type = FileOutputType.Text, TextContent = string.Join(this.NL, libraryLines), }; librariesWithCode.Add(library); } Dictionary <string, string> htmlReplacements = new Dictionary <string, string>(replacements); replacements["JS_LIB_INCLUSIONS"] = GenerateJsLibInclusionHtml(output.Keys); this.CopyResourceAsText(output, "index.html", "Resources/HostHtml.txt", replacements); this.CopyResourceAsText(output, "test_server.py", "Resources/TestServerPy.txt", replacements); this.CopyResourceAsText(output, "common.js", "Resources/Common.txt", replacements); System.Text.StringBuilder resourcesJs = new System.Text.StringBuilder(); foreach (FileOutput textResource in resourceDatabase.TextResources) { resourcesJs.Append("C$common$addTextRes("); resourcesJs.Append(StringTokenUtil.ConvertStringValueToCode(textResource.CanonicalFileName)); resourcesJs.Append(", "); resourcesJs.Append(StringTokenUtil.ConvertStringValueToCode(textResource.TextContent)); resourcesJs.Append(");\n"); } foreach (FileOutput fontResource in resourceDatabase.FontResources) { resourcesJs.Append("C$common$addBinaryRes("); resourcesJs.Append(StringTokenUtil.ConvertStringValueToCode(fontResource.CanonicalFileName)); resourcesJs.Append(", '"); resourcesJs.Append(Base64.ToBase64(fontResource.GetFinalBinaryContent())); resourcesJs.Append("');\n"); } FileOutput imageSheetManifest = resourceDatabase.ImageSheetManifestFile; resourcesJs.Append("C$common$addTextRes('image_sheets.txt', "); resourcesJs.Append(imageSheetManifest == null ? "''" : StringTokenUtil.ConvertStringValueToCode(imageSheetManifest.TextContent)); resourcesJs.Append(");\n"); resourcesJs.Append("C$common$resourceManifest = "); resourcesJs.Append(StringTokenUtil.ConvertStringValueToCode(resourceDatabase.ResourceManifestFile.TextContent)); resourcesJs.Append(";\n"); string filePrefix = options.GetStringOrNull(ExportOptionKey.JS_FILE_PREFIX); if (filePrefix != null) { resourcesJs.Append("C$common$jsFilePrefix = "); resourcesJs.Append(StringTokenUtil.ConvertStringValueToCode(filePrefix)); resourcesJs.Append(";\n"); } output["resources.js"] = new FileOutput() { Type = FileOutputType.Text, TextContent = resourcesJs.ToString(), }; output["bytecode.js"] = new FileOutput() { Type = FileOutputType.Text, TextContent = "C$bytecode = " + StringTokenUtil.ConvertStringValueToCode(resourceDatabase.ByteCodeFile.TextContent) + ";", }; foreach (string imageResourceFile in resourceDatabase.ImageSheetFiles.Keys) { FileOutput file = resourceDatabase.ImageSheetFiles[imageResourceFile]; output["resources/images/" + imageResourceFile] = file; } foreach (FileOutput audioResourceFile in resourceDatabase.AudioResources) { output["resources/audio/" + audioResourceFile.CanonicalFileName] = audioResourceFile; } // TODO: minify JavaScript across all of output dictionary }
internal override IList <Executable> Resolve(ParserContext parser) { TODO.MakeSwitchStatementFallthroughsErrors(); if (this.explicitMax != null) { throw new ParserException(this.explicitMaxToken, "Unexpected token: '{'"); } bool useExplicitMax = this.explicitMax != null; int explicitMax = 0; if (useExplicitMax) { this.explicitMax = this.explicitMax.Resolve(parser); if (!(this.explicitMax is IntegerConstant)) { throw new ParserException(this.explicitMax, "Explicit max must be an integer."); } explicitMax = ((IntegerConstant)this.explicitMax).Value; } this.Condition = this.Condition.Resolve(parser); int integers = 0; int strings = 0; int largestSpan = 0; HashSet <int> intCases = new HashSet <int>(); HashSet <string> stringCases = new HashSet <string>(); foreach (Chunk chunk in this.chunks) { if (chunk.Cases.Length > largestSpan) { largestSpan = chunk.Cases.Length; } for (int i = 0; i < chunk.Cases.Length; ++i) { if (chunk.Cases[i] != null) { Expression caseExpr = chunk.Cases[i].Resolve(parser); chunk.Cases[i] = caseExpr; if (caseExpr is IntegerConstant) { int intValue = ((IntegerConstant)caseExpr).Value; if (intCases.Contains(intValue)) { throw new ParserException(caseExpr, "Duplicate case value in same switch: " + intValue); } intCases.Add(intValue); } else if (caseExpr is StringConstant) { string strValue = ((StringConstant)caseExpr).Value; if (stringCases.Contains(strValue)) { throw new ParserException(caseExpr, "Duplicate case value in same switch: " + StringTokenUtil.ConvertStringValueToCode(strValue)); } stringCases.Add(strValue); } if (chunk.Cases[i] is IntegerConstant) { integers++; } else if (chunk.Cases[i] is StringConstant) { strings++; } else { if (chunk.Cases[i] is DotField) { // Since most enums are in all caps, offer a more helpful error message when there's a dot followed by all caps. string field = ((DotField)chunk.Cases[i]).FieldToken.Value; if (field.ToUpperInvariant() == field) { throw new ParserException(chunk.Cases[i], "Only strings, integers, and enums can be used in a switch statement. It looks like this is probably supposed to be an enum. Make sure that it is spelled correctly."); } } throw new ParserException(chunk.Cases[i], "Only strings, integers, and enums can be used in a switch statement."); } } } chunk.Code = Resolve(parser, chunk.Code).ToArray(); } if (integers != 0 && strings != 0) { throw new ParserException(this, "Cannot mix string and integer cases in a single switch statement."); } if (integers == 0 && strings == 0) { if (this.chunks.Length == 0) { throw new ParserException(this, "Cannot have a blank switch statement."); } if (this.chunks.Length > 1) { throw new Exception("only had default but had multiple chunks. This should have been prevented at parse-time."); } return(this.chunks[0].Code); } Chunk lastChunk = this.chunks[this.chunks.Length - 1]; Expression lastCase = lastChunk.Cases[lastChunk.Cases.Length - 1]; this.ContainsDefault = lastCase == null; this.UsesStrings = strings != 0; this.IsSafe = !this.ContainsDefault; this.IsContinuous = integers != 0 && largestSpan == 1 && this.IsSafe && this.DetermineContinuousness(); return(this.CompilationResolution(parser)); }