/// <summary> /// Writes the specification in code to the specified <see cref="TextWriter"/>. /// </summary> /// <param name="spec">The specification to write.</param> /// <param name="writer">The write to use.</param> protected virtual void WriteCode(OpcodeSpec spec, TextWriter writer) { WriteWarning(writer); WriteCodeUsingDirectives(writer); writer.WriteLine(); WriteCodeOpcodeClassStart(spec, writer); WriteCodeOpcodeClassProperties(spec, writer); writer.WriteLine(T + T + "#region Constructors"); WriteCodeOpcodeClassConstructors(spec, writer); writer.WriteLine(T + T + "#endregion"); writer.WriteLine(); WriteCodeOpcodeVariantMethod(spec, writer); WriteCodeOpcodeClassEnd(writer); WriteCodeSubnamespaceStart(writer); WriteCodeInstrClassStart(spec, writer); WriteCodeInstrOpcodeVariantMethods(spec, spec.Name, writer); foreach (string aka in spec.Aka) { writer.WriteLine(); writer.WriteLine(); writer.WriteLine(); WriteCodeInstrOpcodeVariantMethods(spec, aka, writer); } WriteCodeInstrClassEnd(writer); writer.WriteLine(); WriteCodeOpcodeClassField(spec, writer); WriteCodeSubnamespaceEnd(writer); WriteWarning(writer); }
/// <summary> /// Writes the specification tests to the specified <see cref="TextWriter"/>. /// </summary> /// <param name="spec">The specification to write.</param> /// <param name="writer">The write to use.</param> protected virtual void WriteTest(OpcodeSpec spec, TextWriter writer) { WriteWarning(writer); WriteTestUsingDirectives(writer); writer.WriteLine(); WriteTestClassStart(spec, writer); WriteTestClassTests(spec, writer); WriteTestClassEnd(writer); WriteWarning(writer); }
/// <summary> /// Writes the namespace declaration start and the test class declaration start. /// </summary> /// <param name="spec">The opcode specification.</param> /// <param name="writer">The <see cref="TextWriter"/> to write to.</param> protected void WriteTestClassStart(OpcodeSpec spec, TextWriter writer) { writer.WriteLine("namespace {0}", OpcodeTestNamespace); writer.WriteLine("{"); writer.WriteLine(T + "/// <summary>"); writer.WriteLine(T + "/// Tests all variants of the {0} opcode.", spec.Mnemonic.ToUpperInvariant()); writer.WriteLine(T + "/// </summary>"); writer.WriteLine(T + "[TestFixture]"); writer.WriteLine(T + "public class {0} : {1}", AsValidIdentifier(spec.Name + "Tests"), GetTestBaseClassName()); writer.WriteLine(T + "{"); }
/// <summary> /// Writes the specification in code to the specified code writer, /// and tests for it to the specified test writer. /// </summary> /// <param name="spec">The specification to write.</param> /// <param name="codeWriter">The code writer to use; /// or <see langword="null"/> to write no code.</param> /// <param name="testWriter">The test writer to use; /// or <see langword="null"/> to write no tests.</param> public void Write(OpcodeSpec spec, TextWriter codeWriter, TextWriter testWriter) { if (codeWriter != null) { WriteCode(spec, codeWriter); } if (testWriter != null) { WriteTest(spec, testWriter); } }
/// <summary> /// Writes the namespace declaration start and the opcode class declaration start. /// </summary> /// <param name="spec">The opcode specification.</param> /// <param name="writer">The <see cref="TextWriter"/> to write to.</param> protected void WriteCodeOpcodeClassStart(OpcodeSpec spec, TextWriter writer) { writer.WriteLine("namespace {0}", OpcodeNamespace); writer.WriteLine("{"); writer.WriteLine(T + "/// <summary>"); writer.WriteLine(T + "/// The {0} ({1}) instruction opcode.", spec.Mnemonic.ToUpperInvariant(), spec.ShortDescription); writer.WriteLine(T + "/// </summary>"); writer.WriteLine(T + "public class {0} : {1}", AsValidIdentifier(spec.Name + "Opcode"), GetOpcodeBaseClassName()); writer.WriteLine(T + "{"); }
/// <summary> /// Writes the main constructor for the opcode class. /// </summary> /// <param name="spec">The opcode specification.</param> /// <param name="writer">The <see cref="TextWriter"/> to write to.</param> protected void WriteCodeOpcodeClassMainConstructor(OpcodeSpec spec, TextWriter writer) { string className = AsValidIdentifier(spec.Name + "Opcode"); writer.WriteLine(T + T + "/// <summary>"); writer.WriteLine(T + T + "/// Initializes a new instance of the <see cref=\"{0}\"/> class.", className); writer.WriteLine(T + T + "/// </summary>"); writer.WriteLine(T + T + "public {0}()", className); writer.WriteLine(T + T + T + ": base(\"{0}\", GetOpcodeVariants())", spec.Mnemonic.ToLowerInvariant()); writer.WriteLine(T + T + "{"); writer.WriteLine(T + T + "}"); }
/// <summary> /// Writes the read-only field member o the Opcode partial class. /// </summary> /// <param name="spec">The opcode specification.</param> /// <param name="writer">The <see cref="TextWriter"/> to write to.</param> void WriteCodeOpcodeClassField(OpcodeSpec spec, TextWriter writer) { writer.WriteLine(T + "partial class {0}", GetOpcodeStaticClassName()); writer.WriteLine(T + "{"); writer.WriteLine(T + T + "/// <summary>"); writer.WriteLine(T + T + "/// The {0} ({1}) instruction opcode.", spec.Mnemonic.ToUpperInvariant(), spec.ShortDescription); writer.WriteLine(T + T + "/// </summary>"); writer.WriteLine(T + T + "public static readonly {0} {1} = new {2}();", GetOpcodeBaseClassName(), AsValidIdentifier(spec.Name), AsValidIdentifier(spec.Name + "Opcode")); writer.WriteLine(T + "}"); }
/// <summary> /// Writes the <c>GetOpcodeVariants</c> method for the opcode class. /// </summary> /// <param name="spec">The opcode specification.</param> /// <param name="writer">The <see cref="TextWriter"/> to write to.</param> protected void WriteCodeOpcodeVariantMethod(OpcodeSpec spec, TextWriter writer) { string variantClassName = GetOpcodeVariantClassName(); writer.WriteLine(T + T + "/// <summary>"); writer.WriteLine(T + T + "/// Returns the opcode variants of this opcode."); writer.WriteLine(T + T + "/// </summary>"); writer.WriteLine(T + T + "/// <returns>An enumerable collection of <see cref=\"{0}\"/> objects.</returns>", variantClassName); writer.WriteLine(T + T + "private static IEnumerable<{0}> GetOpcodeVariants()", variantClassName); writer.WriteLine(T + T + "{"); writer.WriteLine(T + T + T + "return new {0}[]{{", variantClassName); //writer.WriteLine(T + T + T + T + "#region Variants"); foreach (var variant in spec.Variants) { WriteCodeOpcodeVariant(spec, variant, writer); } //writer.WriteLine(T + T + T + T + "#endregion"); writer.WriteLine(T + T + T + "};"); writer.WriteLine(T + T + "}"); }
/// <summary> /// Reads an opcode variant. /// </summary> void ReadOpcodeVariant(OpcodeSpec opcodeSpec) { ExpectRead("var"); var opcodeVariantSpec = factory.CreateOpcodeVariantSpec(); opcodeSpec.Variants.Add(opcodeVariantSpec); string opcodeBytesStr = ReadIdentifier(); opcodeVariantSpec.OpcodeBytes = ReadByteArray(opcodeBytesStr); ApplyAnnotations(opcodeVariantSpec); reader.ReadListInRegion(ScriptReader.RegionType.Parentheses, ",", () => { ReadAnnotations(); string operandType = ReadIdentifier(); string operandName = ReadIdentifier(); object defaultValue = null; if (reader.Peek().Equals("=")) { reader.Read(); defaultValue = ReadAnyValue(); } var operandSpec = factory.CreateOperandSpec(operandType, defaultValue); opcodeVariantSpec.Operands.Add(operandSpec); operandSpec.Name = operandName; ApplyAnnotations(operandSpec); }); ExpectRead(";"); }
/// <summary> /// Writes the properties for the opcode class. /// </summary> /// <param name="spec">The opcode specification.</param> /// <param name="writer">The <see cref="TextWriter"/> to write to.</param> protected virtual void WriteCodeOpcodeClassProperties(OpcodeSpec spec, TextWriter writer) { }
/// <summary> /// Writes the specification in code to the specified code writer, /// and tests for it to the specified test writer. /// </summary> /// <param name="spec">The specification to write.</param> /// <param name="codeWriter">The code writer to use; /// or <see langword="null"/> to write no code.</param> /// <param name="testWriter">The test writer to use; /// or <see langword="null"/> to write no tests.</param> public void Write(OpcodeSpec spec, TextWriter codeWriter, TextWriter testWriter) { if (codeWriter != null) WriteCode(spec, codeWriter); if (testWriter != null) WriteTest(spec, testWriter); }
/// <summary> /// Writes the specification in code to the specified code stream, /// and tests for it to the specified test stream. /// </summary> /// <param name="spec">The specification to write.</param> /// <param name="codeStream">The code <see cref="Stream"/> to write to; /// or <see langword="null"/> to write no code.</param> /// <param name="testStream">The test <see cref="Stream"/> to write to; /// or <see langword="null"/> to write no tests.</param> public void Write(OpcodeSpec spec, Stream codeStream, Stream testStream) { using (var codeWriter = new StreamWriter(codeStream, Encoding.UTF8)) using (var testWriter = new StreamWriter(testStream, Encoding.UTF8)) Write(spec, codeWriter, testWriter); }
/// <summary> /// Writes an opcode variant method. /// </summary> /// <param name="spec">The opcode specification.</param> /// <param name="mnemonic">The mnemonic to use.</param> /// <param name="writer">The <see cref="TextWriter"/> to write to.</param> protected abstract void WriteCodeInstrOpcodeVariantMethods(OpcodeSpec spec, string mnemonic, TextWriter writer);
/// <summary> /// Writes the constructors for the opcode class. /// </summary> /// <param name="spec">The opcode specification.</param> /// <param name="writer">The <see cref="TextWriter"/> to write to.</param> protected virtual void WriteCodeOpcodeClassConstructors(OpcodeSpec spec, TextWriter writer) { WriteCodeOpcodeClassMainConstructor(spec, writer); }
/// <summary> /// Writes the tests. /// </summary> /// <param name="spec">The opcode specification.</param> /// <param name="writer">The <see cref="TextWriter"/> to write to.</param> protected abstract void WriteTestClassTests(OpcodeSpec spec, TextWriter writer);
/// <summary> /// Writes the namespace declaration start and the <c>Instr</c> class declaration start. /// </summary> /// <param name="spec">The opcode specification.</param> /// <param name="writer">The <see cref="TextWriter"/> to write to.</param> protected void WriteCodeInstrClassStart(OpcodeSpec spec, TextWriter writer) { writer.WriteLine(T + "partial class Instr"); writer.WriteLine(T + "{"); }
/// <summary> /// Writes the specification in code to the specified code file, /// and tests for it to the specified test file. /// </summary> /// <param name="spec">The specification to write.</param> /// <param name="codeFile">The full path to the code file to write to; /// or <see langword="null"/> to write no code.</param> /// <param name="testFile">The full path to the code file to write to; /// or <see langword="null"/> to write no tests.</param> /// <remarks> /// Any data that is already in the files is overwritten and discarded. /// </remarks> public void Write(OpcodeSpec spec, string codeFile, string testFile) { using (var codeStream = File.Create(codeFile)) using (var testStream = File.Create(testFile)) Write(spec, codeStream, testStream); }
/// <summary> /// Returns the file name of the test file for the specified opcode. /// </summary> /// <param name="opcodeSpec">The opcode specification.</param> /// <returns>A filename.</returns> static string GetTestFilename(OpcodeSpec opcodeSpec) { return SpecWriter.AsValidIdentifier(opcodeSpec.Name + "Tests") + ".generated.cs"; }
/// <summary> /// Returns the file name of the test file for the specified opcode. /// </summary> /// <param name="opcodeSpec">The opcode specification.</param> /// <returns>A filename.</returns> static string GetTestFilename(OpcodeSpec opcodeSpec) { return(SpecWriter.AsValidIdentifier(opcodeSpec.Name + "Tests") + ".generated.cs"); }
/// <summary> /// Writes the opcode variant specification in the variants array. /// </summary> /// <param name="spec">The opcode specification.</param> /// <param name="variant">The opcode variant.</param> /// <param name="writer">The <see cref="TextWriter"/> to write to.</param> protected abstract void WriteCodeOpcodeVariant(OpcodeSpec spec, OpcodeVariantSpec variant, TextWriter writer);