-
-
Notifications
You must be signed in to change notification settings - Fork 190
Expand file tree
/
Copy pathMacroStatement.cs
More file actions
95 lines (76 loc) · 3.3 KB
/
MacroStatement.cs
File metadata and controls
95 lines (76 loc) · 3.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
using Fluid.Utils;
using Fluid.Values;
using System.Text.Encodings.Web;
namespace Fluid.Ast
{
public sealed class MacroStatement : TagStatement
{
public MacroStatement(string identifier, IReadOnlyList<FunctionCallArgument> arguments, IReadOnlyList<Statement> statements) : base(statements)
{
Identifier = identifier;
Arguments = arguments ?? [];
}
public string Identifier { get; }
public IReadOnlyList<FunctionCallArgument> Arguments { get; }
public override async ValueTask<Completion> WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context)
{
// Evaluate all default values only once
var defaultValues = new Dictionary<string, FluidValue>();
for (var i = 0; i < Arguments.Count; i++)
{
var argument = Arguments[i];
defaultValues[argument.Name] = argument.Expression == null ? NilValue.Instance : await argument.Expression.EvaluateAsync(context);
}
var f = new FunctionValue(async (args, c) =>
{
using var sb = StringBuilderPool.GetInstance();
using var sw = new StringWriter(sb.Builder);
context.EnterChildScope();
try
{
// Initialize the local context with the default values
foreach (var a in defaultValues)
{
context.SetValue(a.Key, a.Value);
}
var namedArguments = false;
// Apply all arguments from the invocation.
// As soon as a named argument is used, all subsequent ones need a name too.
for (var i = 0; i < args.Count; i++)
{
var positionalName = Arguments[i].Name;
namedArguments |= args.HasNamed(positionalName);
if (!namedArguments)
{
context.SetValue(positionalName, args.At(i));
}
else
{
context.SetValue(positionalName, args[positionalName]);
}
}
for (var i = 0; i < Statements.Count; i++)
{
var completion = await Statements[i].WriteToAsync(sw, encoder, context);
if (completion != Completion.Normal)
{
// Stop processing the block statements
// We return the completion to flow it to the outer loop
break;
}
}
var result = sw.ToString();
// Don't encode the result
return new StringValue(result, false);
}
finally
{
context.ReleaseScope();
}
});
context.SetValue(Identifier, f);
return Completion.Normal;
}
protected internal override Statement Accept(AstVisitor visitor) => visitor.VisitMacroStatement(this);
}
}