diff options
Diffstat (limited to 'tools/Sandcastle/Source/BuildAssembler/BuildComponents/SyntaxComponent.cs')
-rw-r--r-- | tools/Sandcastle/Source/BuildAssembler/BuildComponents/SyntaxComponent.cs | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/tools/Sandcastle/Source/BuildAssembler/BuildComponents/SyntaxComponent.cs b/tools/Sandcastle/Source/BuildAssembler/BuildComponents/SyntaxComponent.cs new file mode 100644 index 0000000..39c68f9 --- /dev/null +++ b/tools/Sandcastle/Source/BuildAssembler/BuildComponents/SyntaxComponent.cs @@ -0,0 +1,280 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// +using System; +using System.Collections.Generic; +using System.Configuration; +using System.IO; +using System.Reflection; +using System.Xml; +using System.Xml.XPath; + +namespace Microsoft.Ddue.Tools { + + + public class SyntaxComponent : BuildComponent { + + public SyntaxComponent (BuildAssembler assembler, XPathNavigator configuration) : base(assembler, configuration) { + + XPathNavigator syntax_node = configuration.SelectSingleNode("syntax"); + string syntax_input_xpath = syntax_node.GetAttribute("input", String.Empty); + if (String.IsNullOrEmpty(syntax_input_xpath)) throw new ConfigurationErrorsException("You must specify an XPath for input in the syntax element."); + syntax_input = XPathExpression.Compile(syntax_input_xpath); + string syntax_output_xpath = syntax_node.GetAttribute("output", String.Empty); + if (String.IsNullOrEmpty(syntax_output_xpath)) throw new ConfigurationErrorsException("You must specify an XPath for output in the syntax element."); + syntax_output = XPathExpression.Compile(syntax_output_xpath); + + writerType = typeof(ManagedSyntaxWriter); + //if (writerType == null) Console.WriteLine("null writer"); + + XPathNodeIterator generator_nodes = configuration.Select("generators/generator"); + foreach (XPathNavigator generator_node in generator_nodes) { + + // get the data to load the generator + string assembly_path = generator_node.GetAttribute("assembly", String.Empty); + if (String.IsNullOrEmpty(assembly_path)) WriteMessage(MessageLevel.Error, "Each generator element must have an assembly attribute."); + string type_name = generator_node.GetAttribute("type", String.Empty); + if (String.IsNullOrEmpty(type_name)) WriteMessage(MessageLevel.Error, "Each generator element must have a type attribute."); + + // expand environment variables in the path + assembly_path = Environment.ExpandEnvironmentVariables(assembly_path); + + //Console.WriteLine("loading {0} from {1}", type_name, assembly_path); + try { + Assembly assembly = Assembly.LoadFrom(assembly_path); + SyntaxGenerator generator = (SyntaxGenerator)assembly.CreateInstance(type_name, false, BindingFlags.Public | BindingFlags.Instance, null, new Object[1] { generator_node.Clone() }, null, null); + + if (generator == null) { + WriteMessage(MessageLevel.Error, String.Format("The type '{0}' does not exist in the assembly '{1}'.", type_name, assembly_path)); + } else { + generators.Add(generator); + } + + } catch (IOException e) { + WriteMessage(MessageLevel.Error, String.Format("A file access error occured while attempting to load the build component '{0}'. The error message is: {1}", assembly_path, e.Message)); + } catch (BadImageFormatException e) { + WriteMessage(MessageLevel.Error, String.Format("A syntax generator assembly '{0}' is invalid. The error message is: {1}.", assembly_path, e.Message)); + } catch (TypeLoadException e) { + WriteMessage(MessageLevel.Error, String.Format("The type '{0}' does not exist in the assembly '{1}'. The error message is: {2}", type_name, assembly_path, e.Message)); + } catch (MissingMethodException e) { + WriteMessage(MessageLevel.Error, String.Format("The type '{0}' in the assembly '{1}' does not have an appropriate constructor. The error message is: {2}", type_name, assembly_path, e.Message)); + } catch (TargetInvocationException e) { + WriteMessage(MessageLevel.Error, String.Format("An error occured while attempting to instantiate the type '{0}' in the assembly '{1}'. The error message is: {2}", type_name, assembly_path, e.InnerException.Message)); + } catch (InvalidCastException e) { + WriteMessage(MessageLevel.Error, String.Format("The type '{0}' in the assembly '{1}' is not a SyntaxGenerator.", type_name, assembly_path)); + } + } + + WriteMessage(MessageLevel.Info, String.Format("Loaded {0} syntax generators.", generators.Count)); + + } + + private XPathExpression syntax_input; + + private XPathExpression syntax_output; + + private Type writerType; + + private List<SyntaxGenerator> generators = new List<SyntaxGenerator>(); + + public override void Apply (XmlDocument document, string key) { + + XPathNavigator input = document.CreateNavigator().SelectSingleNode(syntax_input); + if (input == null) Console.WriteLine("null input"); + + XPathNavigator output = document.CreateNavigator().SelectSingleNode(syntax_output); + if (output == null) Console.WriteLine("null output"); + + SyntaxWriter writer = (SyntaxWriter) Activator.CreateInstance(writerType, new Object[1] { output }); + + foreach (SyntaxGenerator generator in generators) { + generator.WriteSyntax(input, writer); + } + + } + + } + + // the writer + + public abstract class SyntaxWriter { + + protected SyntaxWriter (XPathNavigator location) {} + + // Syntax block APIs + + public virtual int Position { + get { + return (-1); + } + } + + public abstract void WriteStartBlock(string language); + + public abstract void WriteStartSubBlock(string classId); + + public abstract void WriteEndSubBlock(); + + public abstract void WriteString(string text); + + public abstract void WriteStringWithStyle (string text, string style); + + public abstract void WriteReferenceLink (string reference); + + public abstract void WriteReferenceLink (string reference, string text); + + public virtual void WriteLine () { + WriteString("\n"); + } + + public virtual void WriteKeyword (string keyword) { + WriteStringWithStyle(keyword, "keyword"); + } + + public virtual void WriteParameter (string parameter) { + WriteStringWithStyle(parameter, "parameter"); + } + + public virtual void WriteIdentifier (string identifier) { + WriteStringWithStyle(identifier, "identifier"); + } + + public virtual void WriteLiteral (string literal) { + WriteStringWithStyle(literal, "literal"); + } + + public virtual void WriteMessage(string message) + { + WriteMessage(message, null); + } + + public abstract void WriteMessage(string message, IEnumerable<string> parameters); + + public abstract void WriteEndBlock(); + + } + + // the concrete writer + // the should really be moved out + + public class ManagedSyntaxWriter : SyntaxWriter { + + public ManagedSyntaxWriter (XPathNavigator location) : base(location) { + if (location == null) Console.WriteLine("null location"); + this.location = location; + } + + XPathNavigator location; + + XmlWriter writer; + + // position along the line + int position = 0; + + public override int Position { + get { + return (position); + } + } + + public override void WriteStartBlock(string language) + { + writer = location.AppendChild(); + writer.WriteStartElement("div"); + writer.WriteAttributeString("codeLanguage", language); + position = 0; + } + + public override void WriteStartSubBlock(string classId) + { + writer.WriteStartElement("div"); + writer.WriteAttributeString("class", classId); + position = 0; + } + + public override void WriteEndSubBlock() + { + writer.WriteEndElement(); + position = 0; + } + + public override void WriteLine () { + base.WriteLine(); + position = 0; + } + + public override void WriteString(string text) + { + writer.WriteString(text); + position += text.Length; + } + + public override void WriteStringWithStyle (string text, string style) { + writer.WriteStartElement("span"); + writer.WriteAttributeString("class", style); + WriteString(text); + writer.WriteEndElement(); + position += text.Length; + } + + public override void WriteReferenceLink (string reference) { + writer.WriteStartElement("referenceLink"); + writer.WriteAttributeString("target", reference); + writer.WriteAttributeString("prefer-overload", "false"); + writer.WriteAttributeString("show-container", "false"); + writer.WriteAttributeString("show-templates", "false"); + writer.WriteAttributeString("show-parameters", "false"); + writer.WriteEndElement(); + position += 10; // approximate + } + + public override void WriteReferenceLink (string reference, string text) { + writer.WriteStartElement("referenceLink"); + writer.WriteAttributeString("target", reference); + writer.WriteAttributeString("prefer-overload", "false"); + writer.WriteAttributeString("show-container", "false"); + writer.WriteAttributeString("show-templates", "false"); + writer.WriteAttributeString("show-parameters", "false"); + writer.WriteString(text); + writer.WriteEndElement(); + position += text.Length; + } + + public override void WriteEndBlock () { + writer.WriteEndElement(); + writer.Close(); + position = 0; + } + + public override void WriteMessage(string message, IEnumerable<string> parameters) + { + writer.WriteStartElement("span"); + writer.WriteAttributeString("class", "message"); + writer.WriteStartElement("include"); + writer.WriteAttributeString("item", message); + if (parameters != null) + { + foreach (string parameter in parameters) + { + writer.WriteStartElement("parameter"); + writer.WriteRaw(parameter); + writer.WriteEndElement(); + } + } + writer.WriteEndElement(); + writer.WriteEndElement(); + } + + } + + // the abstract generator + + public abstract class SyntaxGenerator { + + protected SyntaxGenerator (XPathNavigator configuration) { } + + public abstract void WriteSyntax (XPathNavigator reflection, SyntaxWriter writer); + + } + + +}
\ No newline at end of file |