private Editor() { shadowClass = new ShadowClass(); contexts = new Contexts(shadowClass); codeLexer = new CodeLexer(contexts); templateLexer = new TemplateLexer(contexts); }
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 TemplateLexer(Contexts contexts) { _contexts = contexts; _fileContext = contexts.Find(nameof(File)); }
private static bool ParseLambda(Stream stream, ShadowClass shadowClass, Contexts contexts, 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 == "TypeArguments") 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; }
public CodeLexer(Contexts contexts) { this.contexts = contexts; this.fileContext = contexts.Find(nameof(File)); }