private Editor() { shadowClass = new ShadowClass(); contexts = new Contexts(shadowClass); codeLexer = new CodeLexer(contexts); templateLexer = new TemplateLexer(contexts); }
public static Type Compile(ShadowClass shadowClass) { if (Directory.Exists(Constants.TempDirectory) == false) { Directory.CreateDirectory(Constants.TempDirectory); } var filname = Path.GetRandomFileName(); var path = Path.Combine(Constants.TempDirectory, filname); var result = shadowClass.Compile(path); if (result.Success) return Assembly.LoadFrom(path).GetTypes().FirstOrDefault(); var errors = result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error); foreach (var error in errors) { var message = error.GetMessage(); message = message.Replace("__Typewriter.", string.Empty); message = message.Replace("__Code.", string.Empty); message = message.Replace("publicstatic", string.Empty); Log.Error("Template error: {0} {1}", error.Id, message); } throw new Exception("Failed to compile template."); }
public static string Parse(string template, List<Type> extensions) { if (string.IsNullOrWhiteSpace(template)) return null; var output = string.Empty; var stream = new Stream(template); var shadowClass = new ShadowClass(); var contexts = new Contexts(shadowClass); shadowClass.Clear(); while (stream.Advance()) { if (ParseCodeBlock(stream, shadowClass)) continue; if (ParseLambda(stream, shadowClass, contexts, ref output)) continue; output += stream.Current; } shadowClass.Parse(); extensions.Clear(); extensions.Add(Compiler.Compile(shadowClass)); extensions.AddRange(FindExtensionClasses(shadowClass)); return output; }
public Contexts(ShadowClass shadowClass) { var assembly = typeof(ContextAttribute).Assembly; ParseCodeModel(assembly); ParseExtensions(shadowClass); }
private static void ParseCode(Stream stream, ShadowClass shadowClass) { var code = new StringBuilder(); do { code.Append(stream.Current); } while (stream.Advance()); shadowClass.AddBlock(code.ToString(), 0); }
private static bool ParseLambda(Stream stream, ShadowClass shadowClass, ref string template) { if (stream.Current == '$') { var identifier = stream.PeekWord(1); if (identifier != null) { var filter = stream.PeekBlock(identifier.Length + 2, '(', ')'); if (filter != null && stream.Peek(filter.Length + 2 + identifier.Length + 1) == '[') { try { var index = filter.IndexOf("=>", StringComparison.Ordinal); if (index > 0) { var name = filter.Substring(0, index); var contextName = identifier; // Todo: Make the TemplateCodeParser context aware if (contextName == "GenericTypeArguments") contextName = "Types"; else if (contextName.StartsWith("Nested")) contextName = contextName.Remove(0, 6); var type = Contexts.Find(contextName)?.Type.FullName; if (type == null) return false; var methodIndex = counter++; shadowClass.AddLambda(filter, type, name, methodIndex); stream.Advance(filter.Length + 2 + identifier.Length); template += $"${identifier}($__{methodIndex})"; return true; } } catch { } } } } return false; }
private static bool ParseCodeBlock(Stream stream, ShadowClass shadowClass) { if (stream.Current == '$' && stream.Peek() == '{') { stream.Advance(); var block = stream.PeekBlock(1, '{', '}'); var codeStream = new Stream(block, stream.Position + 1); ParseUsings(codeStream, shadowClass); ParseCode(codeStream, shadowClass); stream.Advance(block.Length + 1); return true; } return false; }
private static IEnumerable<Type> FindExtensionClasses(ShadowClass shadowClass) { var types = new List<Type>(); var usings = shadowClass.Snippets.Where(s => s.Type == SnippetType.Using && s.Code.StartsWith("using")); foreach (var usingStatement in usings.Select(u => u.Code)) { var ns = usingStatement.Remove(0, 5).Trim().Trim(';'); foreach (var assembly in shadowClass.ReferencedAssemblies) { types.AddRange(assembly.GetExportedTypes().Where(t => t.Namespace == ns && t.GetMethods(BindingFlags.Static | BindingFlags.Public).Any(m => m.IsDefined(typeof (ExtensionAttribute), false) && m.GetParameters().First().ParameterType.Namespace == "Typewriter.CodeModel"))); } } return types; }
private static void ParseUsings(Stream stream, ShadowClass shadowClass) { stream.Advance(); while (true) { stream.SkipWhitespace(); if ((stream.Current == 'u' && stream.PeekWord() == "using") || (stream.Current == '/' && stream.Peek() == '/')) { var line = stream.PeekLine(); shadowClass.AddUsing(line, stream.Position); stream.Advance(line.Length); continue; } break; } }
private void ParseExtensions(ShadowClass shadowClass) { foreach (var assembly in shadowClass.ReferencedAssemblies) { var methods = assembly.GetExportedTypes().SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Public) .Where(m => m.IsDefined(typeof (ExtensionAttribute), false) && m.GetParameters().First().ParameterType.Namespace == "Typewriter.CodeModel")); foreach (var method in methods) { var parameters = method.GetParameters(); if (parameters.Count() != 1) continue; var context = items.Values.FirstOrDefault(c => c.Type == parameters.First().ParameterType); if (context != null) { var identifier = CreateIdentifier(method); context.AddExtensionIdentifier(method.ReflectedType.Namespace, identifier); } } } }
public SemanticModel(ShadowClass shadowClass) { this.shadowClass = shadowClass; }