/// <summary> /// Converts this specification to XML (that can be parsed by the constructor) /// </summary> /// <returns>An XML string that can be parsed by the constructor</returns> public static string ToXmlString(Specification S) { StringBuilder SB = new StringBuilder(); SB.Append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"); SB.AppendLine(""); // empty line SB.Append("<" + XML_G25_SPEC + "\n"); bool customLicense = false; // used later on to know whether to emit full license text { // output attributes of g25spec element { // license string licString = S.m_license; if (licString == Licenses.GPL_LICENSE) licString = XML_GPL; else if (licString == Licenses.BSD_LICENSE) licString = XML_BSD; else { licString = XML_CUSTOM; customLicense = true; } SB.Append("\t" + XML_LICENSE + "=\"" + licString + "\"\n"); } { // copyright if ((S.m_copyright != null) && (S.m_copyright.Length > 0)) SB.Append("\t" + XML_COPYRIGHT + "=\"" + S.m_copyright + "\"\n"); } { // language SB.Append("\t" + XML_LANGUAGE + "=\"" + S.GetOutputLanguageString() + "\"\n"); } // namespace if ((S.m_namespace != null) && (S.m_namespace.Length > 0)) SB.Append("\t" + XML_NAMESPACE + "=\"" + S.m_namespace + "\"\n"); // coordinate storage SB.Append("\t" + XML_COORD_STORAGE + "=\"" + ((S.m_coordStorage == COORD_STORAGE.ARRAY) ? XML_ARRAY : XML_VARIABLES) + "\"\n"); // operator bindings SB.Append("\t" + XML_DEFAULT_OPERATOR_BINDINGS + "=\"" + (S.DefaultOperatorBindings() ? XML_TRUE : XML_FALSE) + "\"\n"); // dimension SB.Append("\t" + XML_DIMENSION + "=\"" + S.m_dimension.ToString() + "\"\n"); // report usage of non-optimized functions SB.Append("\t" + XML_REPORT_USAGE + "=\"" + (S.m_reportUsage ? XML_TRUE : XML_FALSE) + "\"\n"); { // what type of GMV code to generate: SB.Append("\t" + XML_GMV_CODE + "=\""); switch (S.m_gmvCodeGeneration) { case GMV_CODE.EXPAND: SB.Append(XML_EXPAND); break; case GMV_CODE.RUNTIME: SB.Append(XML_RUNTIME); break; default: SB.Append("BAD GMV CODE OPTION"); break; } SB.Append("\"\n"); } { // what type of parser to generate: SB.Append("\t" + XML_PARSER + "=\""); switch (S.m_parserType) { case PARSER.NONE: SB.Append(XML_NONE); break; case PARSER.ANTLR: SB.Append(XML_ANTLR); break; case PARSER.BUILTIN: SB.Append(XML_BUILTIN); break; default: SB.Append("BAD PARSER OPTION"); break; } SB.Append("\"\n"); } // generate test suite SB.Append("\t" + XML_TEST_SUITE + "=\"" + (S.m_generateTestSuite ? XML_TRUE : XML_FALSE) + "\"\n"); } SB.Append("\t>\n"); // end of <g25spec> entry SB.AppendLine(""); // empty line if (customLicense) // output custom license SB.Append("<" + XML_CUSTOM_LICENSE + ">" + S.m_license + "</" + XML_CUSTOM_LICENSE + ">\n"); if (S.m_verbatimCode.Count > 0) // output verbatim code { foreach (VerbatimCode VC in S.m_verbatimCode) { // determine if code is in XML or in file: bool hasCode = ((VC.m_verbatimCode != null) && (VC.m_verbatimCode.Length > 0)); // open XML tag SB.Append("<" + XML_VERBATIM); // output all filenames to which verbatim code should be applied for (int f = 0; f < VC.m_filenames.Count; f++) { SB.Append(" " + XML_FILENAME); if (f > 0) SB.Append((f + 1).ToString()); SB.Append("=\"" + VC.m_filenames[f] + "\""); } // output the filename where verbatim code comes from if ((VC.m_verbatimCodeFile != null) && (VC.m_verbatimCodeFile.Length > 0)) SB.Append(" " + XML_CODE_FILENAME + "=\"" + VC.m_verbatimCodeFile + "\""); // output position SB.Append(" " + XML_POSITION + "="); switch (VC.m_where) { case VerbatimCode.POSITION.TOP: SB.Append("\"" + XML_TOP + "\""); break; case VerbatimCode.POSITION.BOTTOM: SB.Append("\"" + XML_BOTTOM + "\""); break; case VerbatimCode.POSITION.BEFORE_MARKER: SB.Append("\"" + XML_BEFORE_MARKER + "\""); break; case VerbatimCode.POSITION.AFTER_MARKER: SB.Append("\"" + XML_AFTER_MARKER + "\""); break; } if ((VC.m_where == VerbatimCode.POSITION.BEFORE_MARKER) || (VC.m_where == VerbatimCode.POSITION.AFTER_MARKER)) { SB.Append(" " + XML_MARKER + "=\"" + VC.m_customMarker + "\""); } // output verbatim code that goes into XML, if present if (hasCode) { SB.Append(">" + VC.m_verbatimCode + "</" + XML_VERBATIM + ">\n"); } else SB.Append("/>\n"); } } if (S.m_outputDirectoryExplicitlySet) // output dir SB.Append("<" + XML_OUTPUT_DIRECTORY + " " + XML_PATH + "=\"" + S.m_outputDirectory + "\"/>\n"); { // overrides foreach (KeyValuePair<string, string> kvp in S.m_outputFilenameOverrides) { SB.Append("<" + XML_OUTPUT_FILENAME + " " + XML_DEFAULT_NAME + "=\"" + kvp.Key + "\" " + XML_CUSTOM_NAME + "=\"" + kvp.Value + "\"/>\n"); } } SB.AppendLine(""); // empty line { // inline SB.Append("<" + XML_INLINE + "\n"); SB.Append("\t" + XML_CONSTRUCTORS + "=\"" + ((S.m_inlineConstructors) ? XML_TRUE : XML_FALSE) + "\"\n"); SB.Append("\t" + XML_SET + "=\"" + ((S.m_inlineSet) ? XML_TRUE : XML_FALSE) + "\"\n"); SB.Append("\t" + XML_ASSIGN + "=\"" + ((S.m_inlineAssign) ? XML_TRUE : XML_FALSE) + "\"\n"); SB.Append("\t" + XML_OPERATORS + "=\"" + ((S.m_inlineOperators) ? XML_TRUE : XML_FALSE) + "\"\n"); SB.Append("\t" + XML_FUNCTIONS + "=\"" + ((S.m_inlineFunctions) ? XML_TRUE : XML_FALSE) + "\"\n"); SB.Append("\t/>\n"); // end of <inline> entry } SB.AppendLine(""); // empty line { // float types foreach (FloatType FT in S.m_floatTypes) { SB.Append("<" + XML_FLOAT_TYPE + " " + XML_TYPE + "=\"" + FT.type + "\""); if (FT.prefix.Length > 0) SB.Append(" " + XML_PREFIX + "=\"" + FT.prefix + "\""); if (FT.suffix.Length > 0) SB.Append(" " + XML_SUFFIX + "=\"" + FT.suffix + "\""); SB.Append("/>\n"); // end of <floatType> entry } } SB.AppendLine(""); // empty line { // basis vector names SB.Append("<" + XML_BASIS_VECTOR_NAMES); for (int i = 0; i < S.m_basisVectorNames.Count; i++) SB.Append("\n\t" + XML_NAME + (i + 1).ToString() + "=\"" + S.m_basisVectorNames[i] + "\""); SB.Append("\n\t/>\n"); // end of <basisVectorNames> entry } SB.AppendLine(""); // empty line { // metric // printed out in order of basisvectors foreach (Metric M in S.m_metric) { if (M.m_name == Specification.INTERNAL_EUCLIDEAN_METRIC) continue; // do not emit auto-generated metric to XML for (int v1 = 0; v1 < S.m_dimension; v1++) for (int v2 = 0; v2 < S.m_dimension; v2++) for (int i = 0; i < M.m_metricBasisVectorIdx1.Count; i++) if ((v1 == M.m_metricBasisVectorIdx1[i]) && (v2 == M.m_metricBasisVectorIdx2[i])) { SB.Append("<" + XML_METRIC + " " + XML_NAME + "=\"" + M.m_name + "\""); if (!M.m_round) // default = true, so only print when false SB.Append(" " + XML_ROUND + "=\"" + XML_FALSE + "\""); SB.Append(">"); SB.Append(S.m_basisVectorNames[v1] + "." + S.m_basisVectorNames[v2] + "=" + M.m_metricValue[i]); SB.Append("</" + XML_METRIC + ">\n"); } } } SB.AppendLine(""); // empty line // operators foreach (Operator op in S.m_operators) { // first check if this isn't a 'default operator' if (S.m_defaultOperators.Contains(op)) continue; bool unary = (op.NbArguments == 1); string opStr = (unary) ? XML_UNARY_OPERATOR : XML_BINARY_OPERATOR; SB.Append("<" + opStr + " " + XML_SYMBOL + "=\"" + op.Symbol + "\" " + XML_FUNCTION + "=\"" + op.FunctionName + "\""); if (unary && (!op.IsPrefix)) { SB.Append(" " + XML_PREFIX + "=\"" + XML_FALSE + "\""); } SB.Append("/>\n"); } SB.AppendLine(""); // empty line if (S.m_GMV != null) // general multivector: { SB.Append("<" + XML_MV); // name SB.Append(" " + XML_NAME + "=\"" + S.m_GMV.Name + "\""); // compression (by grade, group) bool compressedByGrade = S.m_GMV.IsGroupedByGrade(S.m_dimension); SB.Append(" " + XML_COMPRESS + "=\""); if (compressedByGrade) SB.Append(XML_BY_GRADE + "\""); else SB.Append(XML_BY_GROUP + "\""); // coordinate order bool defaultCoordinateOrder = (compressedByGrade && S.m_GMV.CompareBasisBladeOrder(rsbbp.ListToDoubleArray(S.m_basisBladeParser.GetDefaultBasisBlades()))); SB.Append(" " + XML_COORDINATE_ORDER + "=\""); if (defaultCoordinateOrder) SB.Append(XML_DEFAULT + "\""); else SB.Append(XML_CUSTOM + "\""); // memory allocation method SB.Append(" " + XML_MEM_ALLOC + "=\""); if (S.m_GMV.MemoryAllocationMethod == GMV.MEM_ALLOC_METHOD.PARITY_PURE) SB.Append(XML_PARITY_PURE + "\""); else if (S.m_GMV.MemoryAllocationMethod == GMV.MEM_ALLOC_METHOD.FULL) SB.Append(XML_FULL + "\""); else SB.Append(XML_DYNAMIC + "\""); SB.Append(">\n"); if (!defaultCoordinateOrder) { // emit coordinate order: string[] bvNames = (string[])S.m_basisVectorNames.ToArray(); // loop over all groups: for (int g = 0; g < S.m_GMV.NbGroups; g++) { SB.Append("<" + XML_GROUP + ">"); // loop over all basis blades of group for (int i = 0; i < S.m_GMV.Group(g).Length; i++) { if (i > 0) SB.Append(" "); string bbStr = BasisBladeToString(S.m_GMV.BasisBlade(g, i), bvNames); SB.Append(bbStr); } SB.Append("</" + XML_GROUP + ">\n"); } } SB.Append("</" + XML_MV + ">\n"); } SB.AppendLine(""); // empty line // specialized multivectors for (int i = 0; i < S.m_SMV.Count; i++) { SB.Append(SMVtoXmlString(S, S.m_SMV[i])); } SB.AppendLine(""); // empty line // constants for (int i = 0; i < S.m_constant.Count; i++) { // assume only SMV constants for now ConstantSMV C = S.m_constant[i] as ConstantSMV; if (C == null) continue; // check if type has name X+CONSTANT_TYPE_SUFFIX and is constant if ((C.Type.GetName().Equals(C.Name + Specification.CONSTANT_TYPE_SUFFIX)) && (C.Type as SMV).IsConstant()) continue; SB.Append(ConstantToXmlString(S, C)); } SB.AppendLine(""); // empty line // outermorphisms { // i = -1 = m_GOM, the rest is m_SOM for (int i = -1; i < S.m_SOM.Count; i++) { if (i == 0) SB.AppendLine(""); // empty line OM om = (i == -1) ? S.m_GOM as OM : S.m_SOM[i] as OM; if (om == null) continue; string XMLtag = ((om is GOM) ? XML_OM : XML_SOM); SB.Append("<" + XMLtag); // name SB.Append(" " + XML_NAME + "=\"" + om.Name + "\""); // coordinate order: bool rangeEqualsDomain = om.DomainAndRangeAreEqual(); bool defaultCoordOrder = rangeEqualsDomain && om.CompareDomainOrder(rsbbp.ListToDoubleArray(S.m_basisBladeParser.GetDefaultBasisBlades())); SB.Append(" " + XML_COORDINATE_ORDER + "=\"" + ((defaultCoordOrder) ? XML_DEFAULT : XML_CUSTOM) + "\""); // end of XMLtag SB.Append(">\n"); if (!defaultCoordOrder) { string[] bvNames = (string[])S.m_basisVectorNames.ToArray(); for (int dr = 0; dr < 2; dr++) { string XML_DOMAIN_OR_RANGE = (dr == 0) ? XML_DOMAIN : XML_RANGE; RefGA.BasisBlade[][] B = (dr == 0) ? om.Domain : om.Range; if ((dr == 1) && rangeEqualsDomain) continue; SB.Append("<" + XML_DOMAIN_OR_RANGE + ">"); bool first = true; for (int g = 0; g < B.Length; g++) { for (int b = 0; b < B[g].Length; b++) { if (!first) SB.Append(" "); String bbStr = BasisBladeToString(B[g][b], bvNames); SB.Append(bbStr); first = false; } } SB.Append("</" + XML_DOMAIN_OR_RANGE + ">\n"); } // output domain info if (!rangeEqualsDomain) { // output range info } } SB.Append("</" + XMLtag + ">\n"); } } SB.AppendLine(""); // empty line // function generation specifications for (int i = 0; i < S.m_functions.Count; i++) SB.AppendLine(FunctionToXmlString(S, S.m_functions[i])); SB.AppendLine(""); // empty line SB.Append("</" + XML_G25_SPEC + ">\n"); return SB.ToString(); }