Skip to content

Commit fce3b07

Browse files
authored
cache Antlr parse result (#3621)
* add cache in parser * make some renaming
1 parent 6f09a65 commit fce3b07

File tree

1 file changed

+69
-34
lines changed

1 file changed

+69
-34
lines changed

libraries/Microsoft.Bot.Builder.LanguageGeneration/TemplatesParser.cs

Lines changed: 69 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public static Templates ParseFile(
4444
var fullPath = Path.GetFullPath(filePath.NormalizePath());
4545
var content = File.ReadAllText(fullPath);
4646

47-
return ParseText(content, fullPath, importResolver, expressionParser);
47+
return InnerParseText(content, fullPath, importResolver, expressionParser);
4848
}
4949

5050
/// <summary>
@@ -61,20 +61,39 @@ public static Templates ParseText(
6161
ImportResolverDelegate importResolver = null,
6262
ExpressionParser expressionParser = null)
6363
{
64-
importResolver = importResolver ?? DefaultFileResolver;
65-
var lg = new Templates(content: content, id: id, importResolver: importResolver, expressionParser: expressionParser);
64+
return InnerParseText(content, id, importResolver, expressionParser);
65+
}
6666

67+
/// <summary>
68+
/// Parser to turn lg content into a <see cref="Templates"/> based on the original LGFile.
69+
/// </summary>
70+
/// <param name="content">Text content contains lg templates.</param>
71+
/// <param name="lg">original LGFile.</param>
72+
/// <returns>new <see cref="Templates"/> entity.</returns>
73+
public static Templates ParseTextWithRef(string content, Templates lg)
74+
{
75+
if (lg == null)
76+
{
77+
throw new ArgumentNullException(nameof(lg));
78+
}
79+
80+
var id = "inline content";
81+
var newLG = new Templates(content: content, id: id, importResolver: lg.ImportResolver, options: lg.Options);
6782
var diagnostics = new List<Diagnostic>();
6883
try
6984
{
7085
var (templates, imports, invalidTemplateErrors, options) = AntlrParse(content, id);
71-
lg.AddRange(templates);
72-
lg.Imports = imports;
73-
lg.Options = options;
86+
newLG.AddRange(templates);
87+
newLG.Imports = imports;
88+
newLG.Options = options;
7489
diagnostics.AddRange(invalidTemplateErrors);
7590

76-
lg.References = GetReferences(lg, importResolver);
77-
var semanticErrors = new StaticChecker(lg).Check();
91+
newLG.References = GetReferences(newLG)
92+
.Union(lg.References)
93+
.Union(new List<Templates> { lg })
94+
.ToList();
95+
96+
var semanticErrors = new StaticChecker(newLG).Check();
7897
diagnostics.AddRange(semanticErrors);
7998
}
8099
catch (TemplateException ex)
@@ -86,41 +105,47 @@ public static Templates ParseText(
86105
diagnostics.Add(BuildDiagnostic(err.Message, source: id));
87106
}
88107

89-
lg.Diagnostics = diagnostics;
108+
newLG.Diagnostics = diagnostics;
90109

91-
return lg;
110+
return newLG;
92111
}
93112

94113
/// <summary>
95-
/// Parser to turn lg content into a <see cref="Templates"/> based on the original LGFile.
114+
/// Parser to turn lg content into a <see cref="Templates"/>.
96115
/// </summary>
97116
/// <param name="content">Text content contains lg templates.</param>
98-
/// <param name="lg">original LGFile.</param>
117+
/// <param name="id">id is the identifier of content. If importResolver is null, id must be a full path string. </param>
118+
/// <param name="importResolver">resolver to resolve LG import id to template text.</param>
119+
/// <param name="expressionParser">expressionEngine parser engine for parsing expressions.</param>
120+
/// <param name="cachedTemplates">give the file path and templates to avoid parsing and to improve performance.</param>
99121
/// <returns>new <see cref="Templates"/> entity.</returns>
100-
public static Templates ParseTextWithRef(string content, Templates lg)
122+
private static Templates InnerParseText(
123+
string content,
124+
string id = "",
125+
ImportResolverDelegate importResolver = null,
126+
ExpressionParser expressionParser = null,
127+
Dictionary<string, Templates> cachedTemplates = null)
101128
{
102-
if (lg == null)
129+
cachedTemplates = cachedTemplates ?? new Dictionary<string, Templates>();
130+
if (cachedTemplates.ContainsKey(id))
103131
{
104-
throw new ArgumentNullException(nameof(lg));
132+
return cachedTemplates[id];
105133
}
106134

107-
var id = "inline content";
108-
var newLG = new Templates(content: content, id: id, importResolver: lg.ImportResolver, options: lg.Options);
135+
importResolver = importResolver ?? DefaultFileResolver;
136+
var lg = new Templates(content: content, id: id, importResolver: importResolver, expressionParser: expressionParser);
137+
109138
var diagnostics = new List<Diagnostic>();
110139
try
111140
{
112141
var (templates, imports, invalidTemplateErrors, options) = AntlrParse(content, id);
113-
newLG.AddRange(templates);
114-
newLG.Imports = imports;
115-
newLG.Options = options;
142+
lg.AddRange(templates);
143+
lg.Imports = imports;
144+
lg.Options = options;
116145
diagnostics.AddRange(invalidTemplateErrors);
117146

118-
newLG.References = GetReferences(newLG, newLG.ImportResolver)
119-
.Union(lg.References)
120-
.Union(new List<Templates> { lg })
121-
.ToList();
122-
123-
var semanticErrors = new StaticChecker(newLG).Check();
147+
lg.References = GetReferences(lg, cachedTemplates);
148+
var semanticErrors = new StaticChecker(lg).Check();
124149
diagnostics.AddRange(semanticErrors);
125150
}
126151
catch (TemplateException ex)
@@ -132,9 +157,9 @@ public static Templates ParseTextWithRef(string content, Templates lg)
132157
diagnostics.Add(BuildDiagnostic(err.Message, source: id));
133158
}
134159

135-
newLG.Diagnostics = diagnostics;
160+
lg.Diagnostics = diagnostics;
136161

137-
return newLG;
162+
return lg;
138163
}
139164

140165
/// <summary>
@@ -280,16 +305,16 @@ private static IList<TemplateImport> ExtractLGImports(LGFileParser.FileContext f
280305
.ToList();
281306
}
282307

283-
private static IList<Templates> GetReferences(Templates file, ImportResolverDelegate importResolver)
308+
private static IList<Templates> GetReferences(Templates file, Dictionary<string, Templates> cachedTemplates = null)
284309
{
285310
var resourcesFound = new HashSet<Templates>();
286-
ResolveImportResources(file, resourcesFound, importResolver);
311+
ResolveImportResources(file, resourcesFound, cachedTemplates ?? new Dictionary<string, Templates>());
287312

288313
resourcesFound.Remove(file);
289314
return resourcesFound.ToList();
290315
}
291316

292-
private static void ResolveImportResources(Templates start, HashSet<Templates> resourcesFound, ImportResolverDelegate importResolver)
317+
private static void ResolveImportResources(Templates start, HashSet<Templates> resourcesFound, Dictionary<string, Templates> cachedTemplates)
293318
{
294319
var resourceIds = start.Imports.Select(lg => lg.Id);
295320
resourcesFound.Add(start);
@@ -298,11 +323,21 @@ private static void ResolveImportResources(Templates start, HashSet<Templates> r
298323
{
299324
try
300325
{
301-
var (content, path) = importResolver(start.Id, id);
326+
var (content, path) = start.ImportResolver(start.Id, id);
302327
if (resourcesFound.All(u => u.Id != path))
303328
{
304-
var childResource = ParseText(content, path, importResolver, start.ExpressionParser);
305-
ResolveImportResources(childResource, resourcesFound, importResolver);
329+
Templates childResource;
330+
if (cachedTemplates.ContainsKey(path))
331+
{
332+
childResource = cachedTemplates[path];
333+
}
334+
else
335+
{
336+
childResource = InnerParseText(content, path, start.ImportResolver, start.ExpressionParser, cachedTemplates);
337+
cachedTemplates.Add(path, childResource);
338+
}
339+
340+
ResolveImportResources(childResource, resourcesFound, cachedTemplates);
306341
}
307342
}
308343
catch (TemplateException err)

0 commit comments

Comments
 (0)