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); }
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; }
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()); } }
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); } }
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); }
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); }
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)); }
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); } }
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)); }
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)); }
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)); }
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()); }
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)); }
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; } }
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); }
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); }
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); }
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); }
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); }
public CompiledTemplate CompileTemplate( ParsedTemplate pt, string content, ITextTemplatingEngineHost host, TemplateSettings settings = null) => CompileTemplate(pt, content, host, out var _, settings);