Skip to content

Commit c42f6a4

Browse files
committed
More repetition WIP
1 parent e0a45cf commit c42f6a4

File tree

9 files changed

+191
-2
lines changed

9 files changed

+191
-2
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
3+
namespace Serilog.Expressions.Ast
4+
{
5+
class NamedLocalExpression : Expression
6+
{
7+
public NamedLocalExpression(string name)
8+
{
9+
Name = name ?? throw new ArgumentNullException(nameof(name));
10+
}
11+
12+
public string Name { get; }
13+
14+
public override string ToString()
15+
{
16+
// No unambiguous syntax for this right now, `$` will do to make these stand out when debugging,
17+
// but the result won't round-trip parse.
18+
return $"${Name}";
19+
}
20+
}
21+
}

src/Serilog.Expressions/Expressions/Compilation/Linq/Intrinsics.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,15 @@ public static bool CoerceToScalarBoolean(LogEventPropertyValue value)
134134

135135
public static LogEventPropertyValue? GetPropertyValue(EvaluationContext ctx, string propertyName)
136136
{
137-
if (!Locals.TryGetValue(ctx.Locals, propertyName, out var value) &&
138-
!ctx.LogEvent.Properties.TryGetValue(propertyName, out value))
137+
if (!ctx.LogEvent.Properties.TryGetValue(propertyName, out var value))
138+
return null;
139+
140+
return value;
141+
}
142+
143+
public static LogEventPropertyValue? GetLocalValue(EvaluationContext ctx, string localName)
144+
{
145+
if (!Locals.TryGetValue(ctx.Locals, localName, out var value))
139146
return null;
140147

141148
return value;

src/Serilog.Expressions/Expressions/Compilation/Linq/LinqExpressionCompiler.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,18 @@ protected override ExpressionBody Transform(AmbientPropertyExpression px)
156156
};
157157
}
158158

159+
// Don't close over the AST node.
159160
var propertyName = px.PropertyName;
160161
return Splice(context => Intrinsics.GetPropertyValue(context, propertyName));
161162
}
162163

164+
protected override ExpressionBody Transform(NamedLocalExpression nlx)
165+
{
166+
// Don't close over the AST node.
167+
var name = nlx.Name;
168+
return Splice(context => Intrinsics.GetLocalValue(context, name));
169+
}
170+
163171
protected override ExpressionBody Transform(Ast.LambdaExpression lmx)
164172
{
165173
var parameters = lmx.Parameters.Select(px => Tuple.Create(px, LX.Parameter(typeof(LogEventPropertyValue), px.ParameterName))).ToList();

src/Serilog.Expressions/Expressions/Compilation/Transformations/FilterExpressionTransformer`1.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ protected virtual TResult Transform(Expression expression)
2929
protected abstract TResult Transform(CallExpression lx);
3030
protected abstract TResult Transform(ConstantExpression cx);
3131
protected abstract TResult Transform(AmbientPropertyExpression px);
32+
protected abstract TResult Transform(NamedLocalExpression nlx);
3233
protected abstract TResult Transform(AccessorExpression spx);
3334
protected abstract TResult Transform(LambdaExpression lmx);
3435
protected abstract TResult Transform(ParameterExpression prx);

src/Serilog.Expressions/Expressions/Compilation/Transformations/IdentityTransformer.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ protected override Expression Transform(AmbientPropertyExpression px)
3838
return px;
3939
}
4040

41+
protected override Expression Transform(NamedLocalExpression nlx)
42+
{
43+
return nlx;
44+
}
45+
4146
protected override Expression Transform(AccessorExpression spx)
4247
{
4348
if (!TryTransform(spx.Receiver, out var recv))

src/Serilog.Expressions/Expressions/Compilation/Wildcards/WildcardSearch.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ class WildcardSearch : SerilogExpressionTransformer<IndexerExpression?>
3131
return null;
3232
}
3333

34+
protected override IndexerExpression? Transform(NamedLocalExpression nlx)
35+
{
36+
return null;
37+
}
38+
3439
protected override IndexerExpression? Transform(AccessorExpression spx)
3540
{
3641
return Transform(spx.Receiver);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using Serilog.Expressions.Ast;
3+
4+
namespace Serilog.Templates.Ast
5+
{
6+
class Repetition: Template
7+
{
8+
public Expression Enumerable { get; }
9+
public string? KeyOrElementName { get; }
10+
public string? ValueName { get; }
11+
public Template Body { get; }
12+
public Template? Separator { get; }
13+
public Template? Alternative { get; }
14+
15+
public Repetition(
16+
Expression enumerable,
17+
string? keyOrElementName,
18+
string? valueName,
19+
Template body,
20+
Template? separator,
21+
Template? alternative)
22+
{
23+
Enumerable = enumerable ?? throw new ArgumentNullException(nameof(enumerable));
24+
KeyOrElementName = keyOrElementName;
25+
ValueName = valueName;
26+
Body = body ?? throw new ArgumentNullException(nameof(body));
27+
Separator = separator;
28+
Alternative = alternative;
29+
}
30+
}
31+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Serilog.Expressions.Ast;
5+
using Serilog.Expressions.Compilation.Transformations;
6+
7+
namespace Serilog.Templates.Compilation.NameResolution
8+
{
9+
class ExpressionLocalNameBinder : IdentityTransformer
10+
{
11+
readonly IReadOnlyCollection<string> _localNames;
12+
13+
public static Expression BindLocalValueNames(Expression expression, IReadOnlyCollection<string> locals)
14+
{
15+
var expressionLocalNameBinder = new ExpressionLocalNameBinder(locals);
16+
return expressionLocalNameBinder.Transform(expression);
17+
}
18+
19+
ExpressionLocalNameBinder(IReadOnlyCollection<string> localNames)
20+
{
21+
_localNames = localNames ?? throw new ArgumentNullException(nameof(localNames));
22+
}
23+
24+
protected override Expression Transform(AmbientPropertyExpression px)
25+
{
26+
if (!px.IsBuiltIn && _localNames.Contains(px.PropertyName))
27+
return new NamedLocalExpression(px.PropertyName);
28+
29+
return base.Transform(px);
30+
}
31+
}
32+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Serilog.Templates.Ast;
5+
6+
// ReSharper disable MemberCanBeMadeStatic.Local, SuggestBaseTypeForParameter
7+
8+
namespace Serilog.Templates.Compilation.NameResolution
9+
{
10+
class TemplateLocalNameBinder
11+
{
12+
public static Template BindLocalValueNames(Template template)
13+
{
14+
var binder = new TemplateLocalNameBinder();
15+
return binder.Transform(template, new Stack<string>());
16+
}
17+
18+
Template Transform(Template template, Stack<string> locals)
19+
{
20+
return template switch
21+
{
22+
TemplateBlock block => Transform(block, locals),
23+
LiteralText text => text,
24+
FormattedExpression fx => Transform(fx, locals),
25+
Conditional cond => Transform(cond, locals),
26+
Repetition rep => Transform(rep, locals),
27+
_ => throw new NotSupportedException("Unsupported template type.")
28+
};
29+
}
30+
31+
Template Transform(TemplateBlock block, Stack<string> locals)
32+
{
33+
return new TemplateBlock(block.Elements
34+
.Select(e => Transform(e, locals))
35+
.ToArray());
36+
}
37+
38+
Template Transform(FormattedExpression fx, Stack<string> locals)
39+
{
40+
if (locals.Count == 0)
41+
return fx;
42+
43+
return new FormattedExpression(
44+
ExpressionLocalNameBinder.BindLocalValueNames(fx.Expression, locals),
45+
fx.Format,
46+
fx.Alignment);
47+
}
48+
49+
Template Transform(Conditional cond, Stack<string> locals)
50+
{
51+
return new Conditional(
52+
cond.Condition,
53+
cond.Consequent,
54+
cond.Alternative != null ? Transform(cond.Alternative, locals) : null);
55+
}
56+
57+
Template Transform(Repetition rep, Stack<string> locals)
58+
{
59+
var orig = locals.Count;
60+
if (rep.KeyOrElementName != null)
61+
locals.Push(rep.KeyOrElementName);
62+
if (rep.ValueName != null)
63+
locals.Push(rep.ValueName);
64+
65+
var body = Transform(rep.Body, locals);
66+
67+
while (locals.Count != orig)
68+
locals.Pop();
69+
70+
return new Repetition(
71+
rep.Enumerable,
72+
rep.KeyOrElementName,
73+
rep.ValueName,
74+
body,
75+
rep.Separator != null ? Transform(rep.Separator, locals) : null,
76+
rep.Alternative != null ? Transform(rep.Alternative, locals) : null);
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)