static bool ComplainExcessAttributes(Directive dt, ParsedTemplate pt)
        {
            if (dt.Attributes.Count == 0)
            {
                return(false);
            }
            StringBuilder sb    = new StringBuilder("Unknown attributes ");
            bool          first = true;

            foreach (string key in dt.Attributes.Keys)
            {
                if (!first)
                {
                    sb.Append(", ");
                }
                else
                {
                    first = false;
                }
                sb.Append(key);
            }
            sb.Append(" found in ");
            sb.Append(dt.Name);
            sb.Append(" directive.");
            pt.LogWarning(sb.ToString(), dt.StartLocation);
            return(false);
        }
示例#2
0
        public string PreprocessTemplate(string content, ITextTemplatingEngineHost host, string className,
                                         string classNamespace, out string language, out string [] references)
        {
            if (content == null)
            {
                throw new ArgumentNullException(nameof(content));
            }
            if (host == null)
            {
                throw new ArgumentNullException(nameof(host));
            }
            if (className == null)
            {
                throw new ArgumentNullException(nameof(className));
            }
            language   = null;
            references = null;

            var pt = ParsedTemplate.FromTextInternal(content, host);

            if (pt.Errors.HasErrors)
            {
                host.LogErrors(pt.Errors);
                return(null);
            }
            return(PreprocessTemplateInternal(pt, content, host, className, classNamespace, out language, out references));
        }
 public CompiledTemplate(ParsedTemplate parsedTemplate, ITextTemplatingEngineHost host, Assembly assembly, TemplateSettings settings)
 {
     this.host           = host;
     this.assembly       = assembly;
     this.settings       = settings;
     this.parsedTemplate = parsedTemplate;
 }
示例#4
0
        public async Task <string> ProcessTemplateAsync(ParsedTemplate pt, string content, TemplateSettings settings, ITextTemplatingEngineHost host, CancellationToken token = default)
        {
            var tpl = await CompileTemplateAsync(pt, content, host, settings, token).ConfigureAwait(false);

            using (tpl?.template) {
                return(tpl?.template.Process());
            }
        }
示例#5
0
 public string ProcessTemplate(ParsedTemplate pt, string inputFile, string inputContent, ref string outputFile)
 {
     OutputFile = outputFile;
     using (var compiled = Engine.CompileTemplate(pt, inputContent, this)) {
         var result = compiled?.Process();
         outputFile = OutputFile;
         return(result);
     }
 }
示例#6
0
        public static ParsedTemplate FromText(string content, ITextTemplatingEngineHost host)
        {
            ParsedTemplate template = new ParsedTemplate(host.TemplateFile);

            try {
                template.Parse(host, new Tokeniser(host.TemplateFile, content));
            } catch (ParserException ex) {
                template.LogError(ex.Message, ex.Location);
            }
            return(template);
        }
示例#7
0
        public IProcessTransformationRunner PrepareTransformationRunner(string content, ITextTemplatingEngineHost host, IProcessTransformationRunFactory runFactory, bool debugging = false)
        {
            if (content == null)
            {
                throw new ArgumentNullException(nameof(content));
            }
            if (host == null)
            {
                throw new ArgumentNullException(nameof(host));
            }
            if (runFactory == null)
            {
                throw new ArgumentNullException(nameof(runFactory));
            }

            if (host is ITextTemplatingSessionHost sessionHost)
            {
                if (sessionHost.Session == null)
                {
                    sessionHost.Session = sessionHost.CreateSession();
                }
            }

            IProcessTransformationRunner runner = null;

            ParsedTemplate pt = ParsedTemplate.FromText(content, host);

            TemplateSettings settings = GetSettings(host, pt);

            settings.Debug = debugging || settings.CachedTemplates;

            EnsureParameterValuesExist(settings, host, pt);

            try {
                if (pt.Errors.HasErrors)
                {
                    return(null);
                }

                runner = CompileAndPrepareRunner(pt, content, host, runFactory, settings);
            }
            catch (Exception ex) {
                if (IsCriticalException(ex))
                {
                    throw;
                }
                pt.LogError(string.Format(CultureInfo.CurrentCulture, VsTemplatingErrorResources.ExceptionProcessingTemplate, ex), new Location(host.TemplateFile, -1, -1));
            }
            finally {
                host.LogErrors(pt.Errors);
            }

            return(runner);
        }
        public string ProcessTemplate(string content, ITextTemplatingEngineHost host)
        {
            ParsedTemplate pt = ParsedTemplate.FromText(content, host);

            if (pt.Errors.HasErrors)
            {
                host.LogErrors(pt.Errors);
                return(null);
            }

            TemplateSettings settings = GetSettings(host, pt);

            if (pt.Errors.HasErrors)
            {
                host.LogErrors(pt.Errors);
                return(null);
            }

            CodeCompileUnit ccu = GenerateCompileUnit(host, pt, settings);

            if (pt.Errors.HasErrors)
            {
                host.LogErrors(pt.Errors);
                return(null);
            }

            System.Reflection.Assembly results = GenerateCode(host, pt, settings, ccu);
            if (pt.Errors.HasErrors)
            {
                host.LogErrors(pt.Errors);
                return(null);
            }

            if (!String.IsNullOrEmpty(settings.Extension))
            {
                host.SetFileExtension(settings.Extension);
            }
            if (settings.Encoding != null)
            {
                //FIXME: when is this called with false?
                host.SetOutputEncoding(settings.Encoding, true);
            }

            string output = "";

            try {
                output = Run(results, settings.Namespace + "." + settings.Name, host, settings.Culture);
            } catch (Exception ex) {
                pt.LogError("Error running transform: " + ex.ToString());
            }
            host.LogErrors(pt.Errors);
            return(output);
        }
示例#9
0
        public string PreprocessTemplate(ParsedTemplate pt, string inputFile, string inputContent, string className)
        {
            string classNamespace = null;
            int    s = className.LastIndexOf('.');

            if (s > 0)
            {
                classNamespace = className.Substring(0, s);
                className      = className.Substring(s + 1);
            }

            return(Engine.PreprocessTemplate(pt, inputContent, this, className, classNamespace, out string language, out string [] references));
        }
示例#10
0
 public string ProcessTemplate(
     ParsedTemplate pt,
     string inputFile,
     string inputContent,
     ref string outputFile,
     TemplateSettings settings = null)
 {
     TemplateFile = inputFile;
     OutputFile   = outputFile;
     BuildProjectMetadata();
     using (var compiled = Engine.CompileTemplate(pt, inputContent, this, settings)) {
         var result = compiled?.Process();
         outputFile = OutputFile;
         return(result);
     }
 }
示例#11
0
        public static ParsedTemplate FromText(string content, ITextTemplatingEngineHost host)
        {
            if (host == null)
            {
                throw new ArgumentNullException(nameof(host));
            }

            var template = new ParsedTemplate(host.TemplateFile);

            try {
                template.Parse(host, new Tokeniser(host.TemplateFile, content));
            } catch (ParserException ex) {
                template.LogError(ex.Message, ex.Location);
            }
            return(template);
        }
        public CompiledTemplate CompileTemplate(string content, ITextTemplatingEngineHost host)
        {
            ParsedTemplate pt = ParsedTemplate.FromText(content, host);

            if (pt.Errors.HasErrors)
            {
                host.LogErrors(pt.Errors);
                return(null);
            }

            TemplateSettings settings = GetSettings(host, pt);

            if (pt.Errors.HasErrors)
            {
                host.LogErrors(pt.Errors);
                return(null);
            }

            CodeCompileUnit ccu = GenerateCompileUnit(host, pt, settings);

            if (pt.Errors.HasErrors)
            {
                host.LogErrors(pt.Errors);
                return(null);
            }

            System.Reflection.Assembly results = GenerateCode(host, pt, settings, ccu);
            if (pt.Errors.HasErrors)
            {
                host.LogErrors(pt.Errors);
                return(null);
            }

            if (!String.IsNullOrEmpty(settings.Extension))
            {
                host.SetFileExtension(settings.Extension);
            }
            if (settings.Encoding != null)
            {
                //FIXME: when is this called with false?
                host.SetOutputEncoding(settings.Encoding, true);
            }

            return(new CompiledTemplate(pt, host, results, settings));
        }
示例#13
0
        public string PreprocessTemplate(
            ParsedTemplate pt,
            string inputFile,
            string inputContent,
            string className,
            TemplateSettings settings = null)
        {
            TemplateFile = inputFile;
            BuildProjectMetadata();
            string classNamespace = null;
            int    s = className.LastIndexOf('.');

            if (s > 0)
            {
                classNamespace = className.Substring(0, s);
                className      = className.Substring(s + 1);
            }

            return(Engine.PreprocessTemplate(pt, inputContent, this, className, classNamespace, out string language, out string [] references, settings));
        }
示例#14
0
        public string PreprocessTemplate(ParsedTemplate pt, string content, TemplateSettings settings, ITextTemplatingEngineHost host, out string language, out string[] references)
        {
            if (pt is null)
            {
                throw new ArgumentNullException(nameof(pt));
            }
            if (string.IsNullOrEmpty(content))
            {
                throw new ArgumentException($"'{nameof (content)}' cannot be null or empty.", nameof(content));
            }
            if (settings is null)
            {
                throw new ArgumentNullException(nameof(settings));
            }
            if (host is null)
            {
                throw new ArgumentNullException(nameof(host));
            }

            return(PreprocessTemplateInternal(pt, content, settings, host, out language, out references));
        }
示例#15
0
        internal static string PreprocessTemplateInternal(ParsedTemplate pt, string content, TemplateSettings settings, ITextTemplatingEngineHost host, out string language, out string[] references)
        {
            settings.IncludePreprocessingHelpers = string.IsNullOrEmpty(settings.Inherits);
            settings.IsPreprocessed = true;
            language = settings.Language;

            var ccu = GenerateCompileUnit(host, content, pt, settings);

            references = ProcessReferences(host, pt, settings).ToArray();

            host.LogErrors(pt.Errors);
            if (pt.Errors.HasErrors)
            {
                return(null);
            }

            var options = new CodeGeneratorOptions();

            using var sw = new StringWriter();
            settings.Provider.GenerateCodeFromCompileUnit(ccu, sw, options);
            return(sw.ToString());
        }
示例#16
0
        public string PreprocessTemplate(ParsedTemplate pt, string content, ITextTemplatingEngineHost host, string className,
                                         string classNamespace, out string language, out string [] references, TemplateSettings settings = null)
        {
            if (content == null)
            {
                throw new ArgumentNullException(nameof(content));
            }
            if (pt == null)
            {
                throw new ArgumentNullException(nameof(pt));
            }
            if (host == null)
            {
                throw new ArgumentNullException(nameof(host));
            }
            if (className == null)
            {
                throw new ArgumentNullException(nameof(className));
            }

            return(PreprocessTemplateInternal(pt, content, host, className, classNamespace, out language, out references, settings));
        }
示例#17
0
        static void AddCoercedSessionParameters(ToolTemplateGenerator generator, ParsedTemplate pt, Dictionary <string, string> properties)
        {
            if (properties.Count == 0)
            {
                return;
            }

            var session = generator.GetOrCreateSession();

            foreach (var p in properties)
            {
                var directive = pt.Directives.FirstOrDefault(d =>
                                                             d.Name == "parameter" &&
                                                             d.Attributes.TryGetValue("name", out string attVal) &&
                                                             attVal == p.Key);

                if (directive != null)
                {
                    directive.Attributes.TryGetValue("type", out string typeName);
                    var mappedType = ParameterDirectiveProcessor.MapTypeName(typeName);
                    if (mappedType != "System.String")
                    {
                        if (ConvertType(mappedType, p.Value, out object converted))
                        {
                            session [p.Key] = converted;
                            continue;
                        }

                        generator.Errors.Add(
                            new CompilerError(
                                null, 0, 0, null,
                                $"Could not convert property '{p.Key}'='{p.Value}' to parameter type '{typeName}'"
                                )
                            );
                    }
                }
                session [p.Key] = p.Value;
            }
        }
示例#18
0
        public async Task <CompiledTemplate> CompileTemplateAsync(string content, ITextTemplatingEngineHost host, CancellationToken token)
        {
            if (content == null)
            {
                throw new ArgumentNullException(nameof(content));
            }
            if (host == null)
            {
                throw new ArgumentNullException(nameof(host));
            }

            var pt = ParsedTemplate.FromTextInternal(content, host);

            if (pt.Errors.HasErrors)
            {
                host.LogErrors(pt.Errors);
                return(null);
            }

            var tpl = await CompileTemplateInternal(pt, content, host, null, token).ConfigureAwait(false);

            return(tpl?.template);
        }
示例#19
0
        static string PreprocessTemplateInternal(ParsedTemplate pt, string content, ITextTemplatingEngineHost host, string className,
                                                 string classNamespace, out string language, out string[] references, TemplateSettings settings = null)
        {
            settings ??= GetSettings(host, pt);

            if (pt.Errors.HasErrors)
            {
                host.LogErrors(pt.Errors);
                language   = null;
                references = null;
                return(null);
            }

            if (className != null)
            {
                settings.Name = className;
            }
            if (classNamespace != null)
            {
                settings.Namespace = classNamespace;
            }

            return(PreprocessTemplateInternal(pt, content, settings, host, out language, out references));
        }
        public static CodeCompileUnit GenerateCompileUnit(ITextTemplatingEngineHost host, string content, ParsedTemplate pt, TemplateSettings settings)
        {
            ProcessDirectives(content, settings, pt.Errors);

            //prep the compile unit
            var ccu      = new CodeCompileUnit();
            var namespac = ccu.AddNamespace(settings.Namespace.NullIfEmpty());

            foreach (string ns in settings.Imports.Union(host.StandardImports))
            {
                namespac.AddImport(new CodeNamespaceImport(ns));
            }

            var baseInfo = TemplateBaseTypeInfo.FromSettings(settings);

            var type = namespac.AddClass(settings.Name)
                       .AsPartial()
                       .Inherits(baseInfo.Reference)
                       .WithVisibility(settings.InternalVisibility? TypeAttributes.NotPublic : TypeAttributes.Public);

            if (baseInfo.Declaration is not null)
            {
                namespac.AddType(baseInfo.Declaration);
            }

            GenerateTransformMethod(type, settings, pt, host.TemplateFile, baseInfo.HasVirtualTransformMethod);

            //class code and attributes from processors
            foreach (var processor in settings.DirectiveProcessors.Values)
            {
                if (processor.GetClassCodeForProcessingRun().NullIfEmpty() is string classCode)
                {
                    type.AddSnippetMember(classCode);
                }
                processor.GetTemplateClassCustomAttributes()?.AddTo(type);
            }

            //generate the Host property if needed
            if (settings.HostSpecific && !settings.HostPropertyOnBase)
            {
                GenerateHostProperty(type, settings.HostType);
            }

            GenerateInitializationMethod(type, settings, baseInfo.HasVirtualInitializeMethod);

            return(ccu);
        }
示例#21
0
        protected virtual IProcessTransformationRunner CompileAndPrepareRunner(ParsedTemplate pt, string content, ITextTemplatingEngineHost host, IProcessTransformationRunFactory runFactory, TemplateSettings settings)
        {
            TransformationRunner runner = null;
            bool success = false;

            if (pt == null)
            {
                throw new ArgumentNullException(nameof(pt));
            }

            if (host == null)
            {
                throw new ArgumentNullException(nameof(host));
            }

            if (runFactory == null)
            {
                throw new ArgumentNullException(nameof(runFactory));
            }

            if (settings == null)
            {
                throw new ArgumentNullException(nameof(settings));
            }

            try {
                try {
                    if (runFactory.CreateTransformationRunner() is TransformationRunner theRunner)
                    {
                        runner = theRunner;
                    }
                }
                catch (Exception ex) {
                    if (IsCriticalException(ex))
                    {
                        throw;
                    }
                    pt.LogError(ex.ToString(), new Location(host.TemplateFile));
                }
                if (runner != null && !runner.Errors.HasErrors)
                {
                    // reference the assemblies and ensure they are path rooted
                    settings.SetAssemblies(ProcessReferences(host, pt, settings));
                    if (!pt.Errors.HasErrors)
                    {
                        try {
                            success = runFactory.PrepareTransformation(runner.RunnerId, pt, content, host, settings);
                        }
                        catch (SerializationException) {
                            pt.LogError(VsTemplatingErrorResources.SessionHostMarshalError, new Location(host.TemplateFile));
                            throw;
                        }
                    }
                }
            }
            catch (Exception ex) {
                if (IsCriticalException(ex))
                {
                    throw;
                }
                pt.LogError(ex.ToString(), new Location(host.TemplateFile, -1, -1));
            }
            finally {
                if (runner != null)
                {
                    pt.Errors.AddRange(runFactory.GetErrors(runner.RunnerId));
                }
            }

            return(success ? runner : null);
        }
示例#22
0
 static void EnsureParameterValuesExist(TemplateSettings settings, ITextTemplatingEngineHost host, ParsedTemplate pt)
 {
     foreach (var directive in settings.CustomDirectives)
     {
         if (directive.ProcessorName == nameof(ParameterDirectiveProcessor))
         {
             if (directive.Directive.Attributes.TryGetValue("name", out string parameterName))
             {
                 if (!string.IsNullOrEmpty(host.ResolveParameterValue(directive.Directive.Name, directive.ProcessorName, parameterName)))
                 {
                     continue;
                 }
             }
             pt.LogError(string.Format(CultureInfo.CurrentCulture, VsTemplatingErrorResources.CouldNotVerifyParameterValue, parameterName));
         }
     }
 }
        public static System.Reflection.Assembly GenerateCode(ITextTemplatingEngineHost host, ParsedTemplate pt,
                                                              TemplateSettings settings, CodeCompileUnit ccu)
        {
            CompilerParameters pars = new CompilerParameters();

            pars.GenerateExecutable = false;

            if (settings.Debug)
            {
                pars.GenerateInMemory        = false;
                pars.IncludeDebugInformation = true;
                pars.TempFiles.KeepFiles     = true;
            }
            else
            {
                pars.GenerateInMemory        = true;
                pars.IncludeDebugInformation = false;
            }

            //resolve and add assembly references
            var assemblies = new Dictionary <string, object>();

            UnionWith(assemblies, settings.Assemblies);
            UnionWith(assemblies, host.StandardAssemblyReferences);
            foreach (string assem in assemblies.Keys)
            {
                string resolvedAssem = host.ResolveAssemblyReference(assem);
                if (!String.IsNullOrEmpty(resolvedAssem))
                {
                    pars.ReferencedAssemblies.Add(resolvedAssem);
                }
                else
                {
                    pt.LogError("Could not resolve assembly reference '" + assem + "'");
                    return(null);
                }
            }
            CompilerResults results = settings.Provider.CompileAssemblyFromDom(pars, ccu);

            pt.Errors.AddRange(results.Errors);
            if (pt.Errors.HasErrors)
            {
                return(null);
            }
            return(results.CompiledAssembly);
        }
示例#24
0
        static int MainInternal(string [] args)
        {
            if (args.Length == 0)
            {
                ShowHelp(true);
            }

            var    generator = new ToolTemplateGenerator();
            string outputFile = null, inputFile = null;
            var    directives          = new List <string> ();
            var    parameters          = new List <string> ();
            var    properties          = new Dictionary <string, string> ();
            string preprocessClassName = null;
            bool   debug   = false;
            bool   verbose = false;

            optionSet = new OptionSet {
                {
                    "o=|out=",
                    "Name or path of the output {<file>}. Defaults to the input filename with its " +
                    "extension changed to `.txt'. Use `-' to output to stdout.",
                    s => outputFile = s
                },
                {
                    "r=",
                    "Name or path of an {<assembly>} reference. Assemblies will be resolved from the " +
                    "framework and the include folders",
                    s => generator.Refs.Add(s)
                },
                {
                    "u=|using=",
                    "Import a {<namespace>}' statement with a `using",
                    s => generator.Imports.Add(s)
                },
                {
                    "I=",
                    "Search {<directory>} when resolving file includes",
                    s => generator.IncludePaths.Add(s)
                },
                {
                    "P=",
                    "Search {<directory>} when resolving assembly references",
                    s => generator.ReferencePaths.Add(s)
                },
                {
                    "c=|class=",
                    "Preprocess the template into class {<name>}",
                    (s) => preprocessClassName = s
                },
                {
                    "p:=",
                    "Add a {<name>}={<value>} key-value pair to the template's `Session' " +
                    "dictionary. These can also be accessed using strongly typed " +
                    "properties declared with `<#@ parameter name=\"<name>\" type=\"<type>\" #> " +
                    "directives.",
                    (k, v) => properties[k] = v
                },
                {
                    "debug",
                    "Generate debug symbols and keep temp files",
                    s => debug = true
                },
                {
                    "v|verbose",
                    "Generate debug symbols and keep temp files",
                    s => verbose = true
                },
                {
                    "h|?|help",
                    "Show help",
                    s => ShowHelp(false)
                }
            };

            compatOptionSet = new OptionSet {
                {
                    "dp=",
                    "Directive processor (name!class!assembly)",
                    s => directives.Add(s)
                },
                {
                    "a=",
                    "Parameters (name=value) or ([processorName!][directiveName!]name!value)",
                    s => parameters.Add(s)
                },
            };

            var remainingArgs = optionSet.Parse(args);

            remainingArgs = compatOptionSet.Parse(remainingArgs);

            string inputContent = null;

            if (remainingArgs.Count != 1)
            {
                if (Console.IsInputRedirected)
                {
                    inputContent = Console.In.ReadToEnd();
                }
                else
                {
                    Console.Error.WriteLine("No input file specified.");
                    return(1);
                }
            }
            else
            {
                inputFile = remainingArgs [0];
                if (!File.Exists(inputFile))
                {
                    Console.Error.WriteLine("Input file '{0}' does not exist.", inputFile);
                    return(1);
                }
            }

            bool writeToStdout = outputFile == "-";

            if (!writeToStdout && string.IsNullOrEmpty(outputFile))
            {
                outputFile = inputFile;
                if (Path.HasExtension(outputFile))
                {
                    var dir = Path.GetDirectoryName(outputFile);
                    var fn  = Path.GetFileNameWithoutExtension(outputFile);
                    outputFile = Path.Combine(dir, fn + ".txt");
                }
                else
                {
                    outputFile = outputFile + ".txt";
                }
            }

            if (inputFile != null)
            {
                try {
                    inputContent = File.ReadAllText(inputFile);
                }
                catch (IOException ex) {
                    Console.Error.WriteLine("Could not read input file '" + inputFile + "':\n" + ex);
                    return(1);
                }
            }

            if (inputContent.Length == 0)
            {
                Console.Error.WriteLine("Input is empty");
                return(1);
            }

            foreach (var par in parameters)
            {
                if (!generator.TryAddParameter(par))
                {
                    Console.Error.WriteLine("Parameter has incorrect format: {0}", par);
                    return(1);
                }
            }

            if (!AddDirectiveProcessors(generator, directives))
            {
                return(1);
            }

            var pt = ParsedTemplate.FromText(inputContent, generator);

            TemplateSettings settings = TemplatingEngine.GetSettings(generator, pt);

            if (debug)
            {
                settings.Debug = true;
            }
            if (verbose)
            {
                settings.Log = Console.Out;
            }

            if (pt.Errors.Count > 0)
            {
                generator.Errors.AddRange(pt.Errors);
            }

            string outputContent = null;

            if (!generator.Errors.HasErrors)
            {
                AddCoercedSessionParameters(generator, pt, properties);
            }

            if (!generator.Errors.HasErrors)
            {
                if (preprocessClassName == null)
                {
                    outputContent = generator.ProcessTemplate(pt, inputFile, inputContent, ref outputFile, settings);
                }
                else
                {
                    outputContent = generator.PreprocessTemplate(pt, inputFile, inputContent, preprocessClassName, settings);
                }
            }

            if (generator.Errors.HasErrors)
            {
                Console.Error.WriteLine(inputFile == null ? "Processing failed." : $"Processing '{inputFile}' failed.");
            }

            try {
                if (!generator.Errors.HasErrors)
                {
                    if (writeToStdout)
                    {
                        Console.WriteLine(outputContent);
                    }
                    else
                    {
                        File.WriteAllText(outputFile, outputContent, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
                    }
                }
            }
            catch (IOException ex) {
                Console.Error.WriteLine("Could not write output file '" + outputFile + "':\n" + ex);
                return(1);
            }

            LogErrors(generator);

            return(generator.Errors.HasErrors ? 1 : 0);
        }
        public static CodeCompileUnit GenerateCompileUnit(ITextTemplatingEngineHost host, ParsedTemplate pt,
                                                          TemplateSettings settings)
        {
            //prep the compile unit
            var ccu      = new CodeCompileUnit();
            var namespac = new CodeNamespace(settings.Namespace);

            ccu.Namespaces.Add(namespac);

            var imports = new Dictionary <string, object> ();

            UnionWith(imports, settings.Imports);
            UnionWith(imports, host.StandardImports);
            foreach (string ns in imports.Keys)
            {
                namespac.Imports.Add(new CodeNamespaceImport(ns));
            }

            //prep the type
            var type = new CodeTypeDeclaration(settings.Name);

            type.IsPartial = true;
            if (!String.IsNullOrEmpty(settings.Inherits))
            {
                type.BaseTypes.Add(new CodeTypeReference(settings.Inherits));
            }
            else
            {
                type.BaseTypes.Add(new CodeTypeReference(typeof(TextTransformation)));
            }
            namespac.Types.Add(type);

            //prep the transform method
            var transformMeth = new CodeMemberMethod()
            {
                Name       = "TransformText",
                ReturnType = new CodeTypeReference(typeof(String)),
                Attributes = MemberAttributes.Public | MemberAttributes.Override
            };

            AddCodeDocComment(transformMeth, @"<summary>
Generates the text output of the transformation.
</summary>

<returns>
A string representing the generated text output of the text template transformation process.
</returns>

<remarks>
The text template transformation process has two steps. In the first step, the text template transformation
engine creates a class that is named the generated transformation class. In the second step, the engine
compiles and executes the generated transformation class, to produce the generated text output. The engine
calls <see cref=""TransformText""/> on the compiled generated transformation class to execute the text
template and generate the text output.
</remarks>");

            //method references that will need to be used multiple times
            var  writeMeth  = new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), "Write");
            bool helperMode = false;

            //build the code from the segments
            foreach (TemplateSegment seg in pt.Content)
            {
                CodeStatement st       = null;
                var           location = new CodeLinePragma(seg.StartLocation.FileName ?? host.TemplateFile, seg.StartLocation.Line);
                switch (seg.Type)
                {
                case SegmentType.Block:
                    if (helperMode)
                    {
                        //TODO: are blocks permitted after helpers?
                        throw new ParserException("Blocks are not permitted after helpers", seg.StartLocation);
                    }
                    st = new CodeSnippetStatement(seg.Text);
                    break;

                case SegmentType.Expression:
                    st = new CodeExpressionStatement(
                        new CodeMethodInvokeExpression(writeMeth, new CodeSnippetExpression(seg.Text)));
                    break;

                case SegmentType.Content:
                    st = new CodeExpressionStatement(new CodeMethodInvokeExpression(writeMeth, new CodePrimitiveExpression(seg.Text)));
                    break;

                case SegmentType.Helper:
                    type.Members.Add(new CodeSnippetTypeMember(seg.Text)
                    {
                        LinePragma = location
                    });
                    helperMode = true;
                    break;

                default:
                    throw new InvalidOperationException();
                }
                if (st != null)
                {
                    if (helperMode)
                    {
                        //convert the statement into a snippet member and attach it to the top level type
                        //TODO: is there a way to do this for languages that use indentation for blocks, e.g. python?
                        using (var writer = new StringWriter()) {
                            settings.Provider.GenerateCodeFromStatement(st, writer, null);
                            type.Members.Add(new CodeSnippetTypeMember(writer.ToString())
                            {
                                LinePragma = location
                            });
                        }
                    }
                    else
                    {
                        st.LinePragma = location;
                        transformMeth.Statements.Add(st);
                        continue;
                    }
                }
            }

            //complete the transform method
            transformMeth.Statements.Add(new CodeMethodReturnStatement(
                                             new CodeMethodInvokeExpression(
                                                 new CodePropertyReferenceExpression(
                                                     new CodeThisReferenceExpression(),
                                                     "GenerationEnvironment"),
                                                 "ToString")));
            type.Members.Add(transformMeth);

            //generate the Host property if needed
            if (settings.HostSpecific)
            {
                var hostField = new CodeMemberField(new CodeTypeReference(typeof(ITextTemplatingEngineHost)), "hostValue");
                hostField.Attributes = (hostField.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Private;
                type.Members.Add(hostField);

                var hostProp = new CodeMemberProperty()
                {
                    Name       = "Host",
                    Attributes = MemberAttributes.Public,
                    HasGet     = true,
                    HasSet     = true,
                    Type       = hostField.Type
                };
                var hostFieldRef = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "hostValue");
                hostProp.SetStatements.Add(new CodeAssignStatement(hostFieldRef, new CodePropertySetValueReferenceExpression()));
                hostProp.GetStatements.Add(new CodeMethodReturnStatement(hostFieldRef));
                type.Members.Add(hostProp);
            }

            return(ccu);
        }
        public static CodeCompileUnit GenerateCompileUnit(ITextTemplatingEngineHost host, ParsedTemplate pt,
                                                          TemplateSettings settings)
        {
            //prep the compile unit
            CodeCompileUnit ccu      = new CodeCompileUnit();
            CodeNamespace   namespac = new CodeNamespace(settings.Namespace);

            ccu.Namespaces.Add(namespac);

            HashSet <string> imports = new HashSet <string> ();

            imports.UnionWith(settings.Imports);
            imports.UnionWith(host.StandardImports);
            foreach (string ns in imports)
            {
                namespac.Imports.Add(new CodeNamespaceImport(ns));
            }

            //prep the type
            CodeTypeDeclaration type = new CodeTypeDeclaration(settings.Name);

            if (!String.IsNullOrEmpty(settings.Inherits))
            {
                type.BaseTypes.Add(new CodeTypeReference(settings.Inherits));
            }
            else
            {
                type.BaseTypes.Add(new CodeTypeReference(typeof(TextTransformation)));
            }
            namespac.Types.Add(type);

            //prep the transform method
            CodeMemberMethod transformMeth = new CodeMemberMethod();

            transformMeth.Name       = "TransformText";
            transformMeth.ReturnType = new CodeTypeReference(typeof(String));
            transformMeth.Attributes = MemberAttributes.Public | MemberAttributes.Override;

            //method references that will need to be used multiple times
            CodeMethodReferenceExpression writeMeth =
                new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), "Write");
            CodeMethodReferenceExpression toStringMeth =
                new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(typeof(ToStringHelper)), "ToStringWithCulture");

            //build the code from the segments
            foreach (TemplateSegment seg in pt.Content)
            {
                CodeStatement st = null;
                switch (seg.Type)
                {
                case SegmentType.Block:
                    st = new CodeSnippetStatement(seg.Text);
                    break;

                case SegmentType.Expression:
                    st = new CodeExpressionStatement(
                        new CodeMethodInvokeExpression(writeMeth,
                                                       new CodeMethodInvokeExpression(toStringMeth, new CodeSnippetExpression(seg.Text))));
                    break;

                case SegmentType.Content:
                    st = new CodeExpressionStatement(new CodeMethodInvokeExpression(writeMeth, new CodePrimitiveExpression(seg.Text)));
                    break;

                case SegmentType.Helper:
                    CodeTypeMember mem = new CodeSnippetTypeMember(seg.Text);
                    mem.LinePragma = new CodeLinePragma(host.TemplateFile, seg.StartLocation.Line);
                    type.Members.Add(mem);
                    break;

                default:
                    throw new InvalidOperationException();
                }
                if (st != null)
                {
                    st.LinePragma = new CodeLinePragma(host.TemplateFile, seg.StartLocation.Line);
                    transformMeth.Statements.Add(st);
                }
            }

            //complete the transform method
            transformMeth.Statements.Add(new CodeMethodReturnStatement(
                                             new CodeMethodInvokeExpression(
                                                 new CodePropertyReferenceExpression(
                                                     new CodeThisReferenceExpression(),
                                                     "GenerationEnvironment"),
                                                 "ToString")));
            type.Members.Add(transformMeth);

            //generate the Host property if needed
            if (settings.HostSpecific)
            {
                CodeMemberField hostField = new CodeMemberField(new CodeTypeReference(typeof(ITextTemplatingEngineHost)), "hostValue");
                hostField.Attributes = (hostField.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Private;
                type.Members.Add(hostField);
                CodeMemberProperty hostProp = new CodeMemberProperty();
                hostProp.Name       = "Host";
                hostProp.Attributes = MemberAttributes.Public;
                hostProp.HasGet     = hostProp.HasGet = true;
                hostProp.Type       = hostField.Type;
                CodeFieldReferenceExpression hostFieldRef = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "hostValue");
                hostProp.SetStatements.Add(new CodeAssignStatement(hostFieldRef, new CodePropertySetValueReferenceExpression()));
                hostProp.GetStatements.Add(new CodeMethodReturnStatement(hostFieldRef));
                type.Members.Add(hostProp);
            }

            return(ccu);
        }
        public static TemplateSettings GetSettings(ITextTemplatingEngineHost host, ParsedTemplate pt)
        {
            string language = null;

            TemplateSettings settings = new TemplateSettings();

            foreach (Directive dt in pt.Directives)
            {
                switch (dt.Name)
                {
                case "template":
                    string val = dt.Extract("language");
                    if (val != null)
                    {
                        language = val;
                    }
                    val = dt.Extract("debug");
                    if (val != null)
                    {
                        settings.Debug = string.Compare(val, "true", StringComparison.OrdinalIgnoreCase) == 0;
                    }
                    val = dt.Extract("inherits");
                    if (val != null)
                    {
                        settings.Inherits = val;
                    }
                    val = dt.Extract("culture");
                    if (val != null)
                    {
                        System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.GetCultureInfo(val);
                        if (culture == null)
                        {
                            pt.LogWarning("Could not find culture '" + val + "'", dt.StartLocation);
                        }
                        else
                        {
                            settings.Culture = culture;
                        }
                    }
                    val = dt.Extract("hostspecific");
                    if (val != null)
                    {
                        settings.HostSpecific = string.Compare(val, "true", StringComparison.OrdinalIgnoreCase) == 0;
                    }
                    break;

                case "assembly":
                    string name = dt.Extract("name");
                    if (name == null)
                    {
                        pt.LogError("Missing name attribute in assembly directive", dt.StartLocation);
                    }
                    else
                    {
                        settings.Assemblies.Add(name);
                    }
                    break;

                case "import":
                    string namespac = dt.Extract("namespace");
                    if (namespac == null)
                    {
                        pt.LogError("Missing namespace attribute in import directive", dt.StartLocation);
                    }
                    else
                    {
                        settings.Imports.Add(namespac);
                    }
                    break;

                case "output":
                    settings.Extension = dt.Extract("extension");
                    string encoding = dt.Extract("encoding");
                    if (encoding != null)
                    {
                        settings.Encoding = Encoding.GetEncoding("encoding");
                    }
                    break;

                case "include":
                    throw new InvalidOperationException("Include is handled in the parser");

                default:
                    throw new NotImplementedException("Custom directives are not supported yet");
                }
                ComplainExcessAttributes(dt, pt);
            }

            if (settings.Name == null)
            {
                settings.Name = string.Format("GeneratedTextTransformation{0:x}", new System.Random().Next());
            }
            if (settings.Namespace == null)
            {
                settings.Namespace = typeof(TextTransformation).Namespace;
            }

            //resolve the CodeDOM provider
            if (String.IsNullOrEmpty(language))
            {
                pt.LogError("No language was specified for the template");
                return(settings);
            }

            if (language == "C#v3.5")
            {
                Dictionary <string, string> providerOptions = new Dictionary <string, string> ();
                providerOptions.Add("CompilerVersion", "v3.5");
                settings.Provider = new CSharpCodeProvider(providerOptions);
            }
            else
            {
                settings.Provider = CodeDomProvider.CreateProvider(language);
            }

            if (settings.Provider == null)
            {
                pt.LogError("A provider could not be found for the language '" + language + "'");
                return(settings);
            }

            return(settings);
        }
        static void GenerateTransformMethod(CodeTypeDeclaration templateType, TemplateSettings settings, ParsedTemplate pt, string templateFile, bool isOverride)
        {
            string baseDirectory = Path.GetDirectoryName(templateFile);

            var transformMeth = Declare.Method("TransformText").Returns <string> ().AsVirtual();

            if (isOverride)
            {
                transformMeth.AsOverride();
            }

            transformMeth.WithStatements(Expression.This.SetProperty("GenerationEnvironment", Expression.Null));

            CodeExpression toStringHelper = settings.IsPreprocessed
                                ? Expression.This.Property("ToStringHelper")
                                : TypeReference.Global(typeof(ToStringHelper)).AsExpression();

            //method references that will need to be used multiple times
            var  writeMeth    = Expression.This.Method("Write");
            var  toStringMeth = toStringHelper.Method("ToStringWithCulture");
            bool helperMode   = false;

            //build the code from the segments
            foreach (TemplateSegment seg in pt.Content)
            {
                CodeStatement  st       = null;
                CodeLinePragma location = null;
                if (!settings.NoLinePragmas)
                {
                    var f = seg.StartLocation.FileName ?? templateFile;
                    if (!string.IsNullOrEmpty(f))
                    {
                        // FIXME: we need to know where the output file will be to make this work properly
                        if (settings.RelativeLinePragmas)
                        {
                            f = FileUtil.AbsoluteToRelativePath(baseDirectory, f);
                        }
                        else
                        {
                            f = Path.GetFullPath(f);
                        }
                    }
                    location = new CodeLinePragma(f, seg.StartLocation.Line);
                }
                switch (seg.Type)
                {
                case SegmentType.Block:
                    if (helperMode)
                    {
                        //TODO: are blocks permitted after helpers?
                        pt.LogError("Blocks are not permitted after helpers", seg.TagStartLocation);
                    }
                    st = Statement.Snippet(seg.Text);
                    break;

                case SegmentType.Expression:
                    st = writeMeth.Invoke(toStringMeth.Invoke(Expression.Snippet(seg.Text))).AsStatement();
                    break;

                case SegmentType.Content:
                    st = writeMeth.Invoke(Expression.Primitive(seg.Text)).AsStatement();
                    break;

                case SegmentType.Helper:
                    if (!string.IsNullOrEmpty(seg.Text))
                    {
                        templateType.AddSnippetMember(seg.Text, location);
                    }
                    helperMode = true;
                    break;

                default:
                    throw new InvalidOperationException();
                }
                if (st != null)
                {
                    if (helperMode)
                    {
                        //convert the statement into a snippet member and attach it to the top level type
                        //TODO: is there a way to do this for languages that use indentation for blocks, e.g. python?
                        using (var writer = new StringWriter()) {
                            settings.Provider.GenerateCodeFromStatement(st, writer, null);
                            var text = writer.ToString();
                            if (!string.IsNullOrEmpty(text))
                            {
                                templateType.AddSnippetMember(text, location);
                            }
                        }
                    }
                    else
                    {
                        st.LinePragma = location;
                        transformMeth.Statements.Add(st);
                        continue;
                    }
                }
            }

            transformMeth.WithStatements(Statement.Return(Expression.This.Property("GenerationEnvironment").InvokeMethod("ToString")));

            templateType.AddMember(transformMeth);
        }
示例#29
0
 public CompiledTemplate CompileTemplate(
     ParsedTemplate pt,
     string content,
     ITextTemplatingEngineHost host,
     TemplateSettings settings = null)
 => CompileTemplate(pt, content, host, out var _, settings);