Skip to content

Commit a47d4c4

Browse files
committed
Regex
1 parent 7262147 commit a47d4c4

17 files changed

+262
-102
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Text.RegularExpressions;
3+
4+
namespace Serilog.Expressions.Ast
5+
{
6+
class IndexOfMatchExpression : Expression
7+
{
8+
public Expression Corpus { get; }
9+
public Regex Regex { get; }
10+
11+
public IndexOfMatchExpression(Expression corpus, Regex regex)
12+
{
13+
Corpus = corpus ?? throw new ArgumentNullException(nameof(corpus));
14+
Regex = regex ?? throw new ArgumentNullException(nameof(regex));
15+
}
16+
}
17+
}

src/Serilog.Expressions/Expressions/Ast/LambdaExpression.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public LambdaExpression(ParameterExpression[] parameters, Expression body)
1616

1717
public override string ToString()
1818
{
19-
return "\\(" + string.Join(",", Parameters.Select(p => p.ToString())) + "){" + Body + "}";
19+
return "|" + string.Join(", ", Parameters.Select(p => p.ToString())) + "| {" + Body + "}";
2020
}
2121
}
22-
}
22+
}

src/Serilog.Expressions/Expressions/BuiltInProperty.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ static class BuiltInProperty
88
public const string Message = "Message";
99
public const string MessageTemplate = "MessageTemplate";
1010
public const string Properties = "Properties";
11+
public const string Undefined = "Undefined";
1112
}
1213
}

src/Serilog.Expressions/Expressions/Compilation/Arrays/ConstantArrayEvaluator.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ namespace Serilog.Expressions.Compilation.Arrays
88
{
99
class ConstantArrayEvaluator : IdentityTransformer
1010
{
11+
static readonly ConstantArrayEvaluator Instance = new ConstantArrayEvaluator();
12+
1113
public static Expression Evaluate(Expression expression)
1214
{
13-
var evaluator = new ConstantArrayEvaluator();
14-
return evaluator.Transform(expression);
15+
return Instance.Transform(expression);
1516
}
1617

1718
protected override Expression Transform(ArrayExpression ax)

src/Serilog.Expressions/Expressions/Compilation/ExpressionCompiler.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Serilog.Expressions.Compilation.Is;
55
using Serilog.Expressions.Compilation.Linq;
66
using Serilog.Expressions.Compilation.Properties;
7+
using Serilog.Expressions.Compilation.Text;
78
using Serilog.Expressions.Compilation.Wildcards;
89

910
namespace Serilog.Expressions.Compilation
@@ -13,6 +14,7 @@ static class ExpressionCompiler
1314
public static CompiledExpression Compile(Expression expression)
1415
{
1516
var actual = expression;
17+
actual = TextMatchingTransformer.Rewrite(actual);
1618
actual = PropertiesObjectAccessorTransformer.Rewrite(actual);
1719
actual = ConstantArrayEvaluator.Evaluate(actual);
1820
actual = NotInRewriter.Rewrite(actual);

src/Serilog.Expressions/Expressions/Compilation/In/NotInRewriter.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ namespace Serilog.Expressions.Compilation.In
55
{
66
class NotInRewriter : IdentityTransformer
77
{
8+
static readonly NotInRewriter Instance = new NotInRewriter();
9+
810
public static Expression Rewrite(Expression expression)
911
{
10-
var rewriter = new NotInRewriter();
11-
return rewriter.Transform(expression);
12+
return Instance.Transform(expression);
1213
}
1314

1415
protected override Expression Transform(CallExpression lx)

src/Serilog.Expressions/Expressions/Compilation/Is/IsOperatorTransformer.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ namespace Serilog.Expressions.Compilation.Is
66
{
77
class IsOperatorTransformer : IdentityTransformer
88
{
9+
static readonly IsOperatorTransformer Instance = new IsOperatorTransformer();
10+
911
public static Expression Rewrite(Expression expression)
1012
{
11-
return new IsOperatorTransformer().Transform(expression);
13+
return Instance.Transform(expression);
1214
}
1315

1416
protected override Expression Transform(CallExpression lx)

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

Lines changed: 83 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Linq;
44
using System.Linq.Expressions;
55
using System.Reflection;
6+
using System.Text.RegularExpressions;
67
using Serilog.Events;
78
using Serilog.Expressions.Ast;
89
using Serilog.Expressions.Compilation.Transformations;
@@ -11,20 +12,37 @@
1112
using Expression = Serilog.Expressions.Ast.Expression;
1213
using LambdaExpression = System.Linq.Expressions.LambdaExpression;
1314
using ParameterExpression = System.Linq.Expressions.ParameterExpression;
15+
using LX = System.Linq.Expressions.Expression;
1416

1517
namespace Serilog.Expressions.Compilation.Linq
1618
{
1719
class LinqExpressionCompiler : SerilogExpressionTransformer<Expression<CompiledExpression>>
1820
{
21+
static readonly LinqExpressionCompiler Instance = new LinqExpressionCompiler();
22+
1923
static readonly IDictionary<string, MethodInfo> OperatorMethods = typeof(RuntimeOperators)
2024
.GetTypeInfo()
2125
.GetMethods(BindingFlags.Static | BindingFlags.Public)
2226
.ToDictionary(m => m.Name, StringComparer.OrdinalIgnoreCase);
2327

24-
static readonly ConstructorInfo SequenceValueCtor =
25-
typeof(SequenceValue).GetConstructor(new[] {typeof(IEnumerable<LogEventPropertyValue>)});
28+
static readonly MethodInfo ConstructSequenceValueMethod = typeof(LinqExpressionCompiler)
29+
.GetMethod(nameof(ConstructSequenceValue), BindingFlags.Static | BindingFlags.Public);
30+
31+
static readonly MethodInfo CoerceToScalarBooleanMethod = typeof(LinqExpressionCompiler)
32+
.GetMethod(nameof(CoerceToScalarBoolean), BindingFlags.Static | BindingFlags.Public);
2633

27-
static readonly MethodInfo CoerceTrue = typeof(LinqExpressionCompiler).GetMethod(nameof(CoerceToScalarBoolean), BindingFlags.Static | BindingFlags.Public);
34+
static readonly MethodInfo IndexOfMatchMethod = typeof(LinqExpressionCompiler)
35+
.GetMethod(nameof(IndexOfMatch), BindingFlags.Static | BindingFlags.Public);
36+
37+
static readonly LogEventPropertyValue NegativeOne = new ScalarValue(-1);
38+
39+
public static LogEventPropertyValue ConstructSequenceValue(LogEventPropertyValue[] elements)
40+
{
41+
// Avoid upsetting Serilog's (currently) fragile `SequenceValue.Render()`.
42+
if (elements.Any(el => el == null))
43+
return null;
44+
return new SequenceValue(elements);
45+
}
2846

2947
public static LogEventPropertyValue CoerceToScalarBoolean(LogEventPropertyValue value)
3048
{
@@ -33,11 +51,24 @@ public static LogEventPropertyValue CoerceToScalarBoolean(LogEventPropertyValue
3351
return RuntimeOperators.ScalarBoolean(false);
3452
}
3553

54+
public static LogEventPropertyValue IndexOfMatch(LogEventPropertyValue value, Regex regex)
55+
{
56+
if (value is ScalarValue scalar &&
57+
scalar.Value is string s)
58+
{
59+
var m = regex.Match(s);
60+
if (m.Success)
61+
return new ScalarValue(m.Index);
62+
return NegativeOne;
63+
}
64+
65+
return null;
66+
}
67+
3668
public static CompiledExpression Compile(Expression expression)
3769
{
3870
if (expression == null) throw new ArgumentNullException(nameof(expression));
39-
var compiler = new LinqExpressionCompiler();
40-
return compiler.Transform(expression).Compile();
71+
return Instance.Transform(expression).Compile();
4172
}
4273

4374
protected override Expression<CompiledExpression> Transform(CallExpression lx)
@@ -50,11 +81,11 @@ protected override Expression<CompiledExpression> Transform(CallExpression lx)
5081

5182
var operands = lx.Operands.Select(Transform).ToArray();
5283

53-
var context = System.Linq.Expressions.Expression.Parameter(typeof(LogEvent));
84+
var context = LX.Parameter(typeof(LogEvent));
5485

5586
var operandValues = operands.Select(o => Splice(o, context));
5687
var operandVars = new List<ParameterExpression>();
57-
var rtn = System.Linq.Expressions.Expression.Label(typeof(LogEventPropertyValue));
88+
var rtn = LX.Label(typeof(LogEventPropertyValue));
5889

5990
var statements = new List<System.Linq.Expressions.Expression>();
6091
var first = true;
@@ -64,38 +95,38 @@ protected override Expression<CompiledExpression> Transform(CallExpression lx)
6495
{
6596
if (shortCircuit)
6697
{
67-
shortCircuitElse = System.Linq.Expressions.Expression.Call(CoerceTrue, op);
98+
shortCircuitElse = LX.Call(CoerceToScalarBooleanMethod, op);
6899
break;
69100
}
70101

71-
var opam = System.Linq.Expressions.Expression.Variable(typeof(LogEventPropertyValue));
102+
var opam = LX.Variable(typeof(LogEventPropertyValue));
72103
operandVars.Add(opam);
73-
statements.Add(System.Linq.Expressions.Expression.Assign(opam, op));
104+
statements.Add(LX.Assign(opam, op));
74105

75106
if (first && Operators.SameOperator(lx.OperatorName, Operators.OpAnd))
76107
{
77108
Expression<Func<LogEventPropertyValue, bool>> shortCircuitIf = v => !(v is ScalarValue) || !true.Equals(((ScalarValue)v).Value);
78109
var scc = Splice(shortCircuitIf, opam);
79-
statements.Add(System.Linq.Expressions.Expression.IfThen(scc, System.Linq.Expressions.Expression.Return(rtn, System.Linq.Expressions.Expression.Constant(new ScalarValue(false), typeof(LogEventPropertyValue)))));
110+
statements.Add(LX.IfThen(scc, LX.Return(rtn, LX.Constant(new ScalarValue(false), typeof(LogEventPropertyValue)))));
80111
shortCircuit = true;
81112
}
82113

83114
if (first && Operators.SameOperator(lx.OperatorName, Operators.OpOr))
84115
{
85116
Expression<Func<LogEventPropertyValue, bool>> shortCircuitIf = v => v is ScalarValue && true.Equals(((ScalarValue)v).Value);
86117
var scc = Splice(shortCircuitIf, opam);
87-
statements.Add(System.Linq.Expressions.Expression.IfThen(scc, System.Linq.Expressions.Expression.Return(rtn, System.Linq.Expressions.Expression.Constant(new ScalarValue(true), typeof(LogEventPropertyValue)))));
118+
statements.Add(LX.IfThen(scc, LX.Return(rtn, LX.Constant(new ScalarValue(true), typeof(LogEventPropertyValue)))));
88119
shortCircuit = true;
89120
}
90121

91122
first = false;
92123
}
93124

94-
statements.Add(System.Linq.Expressions.Expression.Return(rtn, shortCircuitElse ?? System.Linq.Expressions.Expression.Call(m, operandVars)));
95-
statements.Add(System.Linq.Expressions.Expression.Label(rtn, System.Linq.Expressions.Expression.Constant(null, typeof(LogEventPropertyValue))));
125+
statements.Add(LX.Return(rtn, shortCircuitElse ?? LX.Call(m, operandVars)));
126+
statements.Add(LX.Label(rtn, LX.Constant(null, typeof(LogEventPropertyValue))));
96127

97-
return System.Linq.Expressions.Expression.Lambda<CompiledExpression>(
98-
System.Linq.Expressions.Expression.Block(typeof(LogEventPropertyValue), operandVars, statements),
128+
return LX.Lambda<CompiledExpression>(
129+
LX.Block(typeof(LogEventPropertyValue), operandVars, statements),
99130
context);
100131
}
101132

@@ -104,31 +135,31 @@ protected override Expression<CompiledExpression> Transform(AccessorExpression s
104135
var tgv = typeof(LinqExpressionCompiler).GetTypeInfo().GetMethod(nameof(TryGetStructurePropertyValue), BindingFlags.Static | BindingFlags.Public);
105136
var recv = Transform(spx.Receiver);
106137

107-
var context = System.Linq.Expressions.Expression.Parameter(typeof(LogEvent));
138+
var context = LX.Parameter(typeof(LogEvent));
108139

109-
var r = System.Linq.Expressions.Expression.Variable(typeof(object));
110-
var str = System.Linq.Expressions.Expression.Variable(typeof(StructureValue));
111-
var result = System.Linq.Expressions.Expression.Variable(typeof(LogEventPropertyValue));
140+
var r = LX.Variable(typeof(object));
141+
var str = LX.Variable(typeof(StructureValue));
142+
var result = LX.Variable(typeof(LogEventPropertyValue));
112143

113-
var sx3 = System.Linq.Expressions.Expression.Call(tgv, str, System.Linq.Expressions.Expression.Constant(spx.MemberName, typeof(string)), result);
144+
var sx3 = LX.Call(tgv, str, LX.Constant(spx.MemberName, typeof(string)), result);
114145

115-
var sx1 = System.Linq.Expressions.Expression.Condition(sx3,
146+
var sx1 = LX.Condition(sx3,
116147
result,
117-
System.Linq.Expressions.Expression.Constant(null, typeof(LogEventPropertyValue)));
148+
LX.Constant(null, typeof(LogEventPropertyValue)));
118149

119-
var sx2 = System.Linq.Expressions.Expression.Block(typeof(LogEventPropertyValue),
120-
System.Linq.Expressions.Expression.Assign(str, System.Linq.Expressions.Expression.TypeAs(r, typeof(StructureValue))),
121-
System.Linq.Expressions.Expression.Condition(System.Linq.Expressions.Expression.Equal(str, System.Linq.Expressions.Expression.Constant(null, typeof(StructureValue))),
122-
System.Linq.Expressions.Expression.Constant(null, typeof(LogEventPropertyValue)),
150+
var sx2 = LX.Block(typeof(LogEventPropertyValue),
151+
LX.Assign(str, LX.TypeAs(r, typeof(StructureValue))),
152+
LX.Condition(LX.Equal(str, LX.Constant(null, typeof(StructureValue))),
153+
LX.Constant(null, typeof(LogEventPropertyValue)),
123154
sx1));
124155

125-
var assignR = System.Linq.Expressions.Expression.Assign(r, Splice(recv, context));
126-
var getValue = System.Linq.Expressions.Expression.Condition(System.Linq.Expressions.Expression.Equal(r, System.Linq.Expressions.Expression.Constant(null, typeof(LogEventPropertyValue))),
127-
System.Linq.Expressions.Expression.Constant(null, typeof(LogEventPropertyValue)),
156+
var assignR = LX.Assign(r, Splice(recv, context));
157+
var getValue = LX.Condition(LX.Equal(r, LX.Constant(null, typeof(LogEventPropertyValue))),
158+
LX.Constant(null, typeof(LogEventPropertyValue)),
128159
sx2);
129160

130-
return System.Linq.Expressions.Expression.Lambda<CompiledExpression>(
131-
System.Linq.Expressions.Expression.Block(typeof(LogEventPropertyValue), new[] { r, str, result }, assignR, getValue),
161+
return LX.Lambda<CompiledExpression>(
162+
LX.Block(typeof(LogEventPropertyValue), new[] { r, str, result }, assignR, getValue),
132163
context);
133164
}
134165

@@ -165,6 +196,7 @@ protected override Expression<CompiledExpression> Transform(AmbientPropertyExpre
165196
if (px.PropertyName == BuiltInProperty.Properties)
166197
return context => new StructureValue(context.Properties.Select(kvp => new LogEventProperty(kvp.Key, kvp.Value)), null);
167198

199+
// Also @Undefined
168200
return context => null;
169201
}
170202

@@ -207,8 +239,8 @@ static LogEventPropertyValue NormalizeBuiltInProperty(string rawValue)
207239

208240
protected override Expression<CompiledExpression> Transform(Ast.LambdaExpression lmx)
209241
{
210-
var context = System.Linq.Expressions.Expression.Parameter(typeof(LogEvent));
211-
var parms = lmx.Parameters.Select(px => Tuple.Create(px, System.Linq.Expressions.Expression.Parameter(typeof(LogEventPropertyValue), px.ParameterName))).ToList();
242+
var context = LX.Parameter(typeof(LogEvent));
243+
var parms = lmx.Parameters.Select(px => Tuple.Create(px, LX.Parameter(typeof(LogEventPropertyValue), px.ParameterName))).ToList();
212244
var body = Splice(Transform(lmx.Body), context);
213245
var paramSwitcher = new ExpressionConstantMapper(parms.ToDictionary(px => (object)px.Item1, px => (System.Linq.Expressions.Expression)px.Item2));
214246
var rewritten = paramSwitcher.Visit(body);
@@ -221,17 +253,17 @@ protected override Expression<CompiledExpression> Transform(Ast.LambdaExpression
221253
else
222254
throw new NotSupportedException("Unsupported lambda signature.");
223255

224-
var lambda = System.Linq.Expressions.Expression.Lambda(delegateType, rewritten, parms.Select(px => px.Item2).ToArray());
256+
var lambda = LX.Lambda(delegateType, rewritten!, parms.Select(px => px.Item2).ToArray());
225257

226-
return System.Linq.Expressions.Expression.Lambda<CompiledExpression>(lambda, context);
258+
return LX.Lambda<CompiledExpression>(lambda, context);
227259
}
228260

229261
protected override Expression<CompiledExpression> Transform(Ast.ParameterExpression prx)
230262
{
231263
// Will be within a lambda, which will subsequently sub-in the actual value
232-
var context = System.Linq.Expressions.Expression.Parameter(typeof(LogEvent));
233-
var constant = System.Linq.Expressions.Expression.Constant(prx, typeof(object));
234-
return System.Linq.Expressions.Expression.Lambda<CompiledExpression>(constant, context);
264+
var context = LX.Parameter(typeof(LogEvent));
265+
var constant = LX.Constant(prx, typeof(object));
266+
return LX.Lambda<CompiledExpression>(constant, context);
235267
}
236268

237269
protected override Expression<CompiledExpression> Transform(IndexerWildcardExpression wx)
@@ -241,16 +273,24 @@ protected override Expression<CompiledExpression> Transform(IndexerWildcardExpre
241273

242274
protected override Expression<CompiledExpression> Transform(ArrayExpression ax)
243275
{
244-
var context = System.Linq.Expressions.Expression.Parameter(typeof(LogEvent));
276+
var context = LX.Parameter(typeof(LogEvent));
245277
var elements = ax.Elements.Select(Transform).Select(ex => Splice(ex, context)).ToArray();
246-
var arr = System.Linq.Expressions.Expression.NewArrayInit(typeof(LogEventPropertyValue), elements);
247-
var sv = System.Linq.Expressions.Expression.New(SequenceValueCtor, System.Linq.Expressions.Expression.Convert(arr, typeof(IEnumerable<LogEventPropertyValue>)));
248-
return System.Linq.Expressions.Expression.Lambda<CompiledExpression>(System.Linq.Expressions.Expression.Convert(sv, typeof(LogEventPropertyValue)), context);
278+
var arr = LX.NewArrayInit(typeof(LogEventPropertyValue), elements);
279+
var sv = LX.Call(ConstructSequenceValueMethod, arr);
280+
return LX.Lambda<CompiledExpression>(sv, context);
249281
}
250282

251283
protected override Expression<CompiledExpression> Transform(IndexerExpression ix)
252284
{
253285
return Transform(new CallExpression(Operators.OpElementAt, ix.Receiver, ix.Index));
254286
}
287+
288+
protected override Expression<CompiledExpression> Transform(IndexOfMatchExpression mx)
289+
{
290+
var context = LX.Parameter(typeof(LogEvent));
291+
var rx = LX.Constant(mx.Regex);
292+
var target = Splice(Transform(mx.Corpus), context);
293+
return LX.Lambda<CompiledExpression>(LX.Call(IndexOfMatchMethod, target, rx), context);
294+
}
255295
}
256296
}

src/Serilog.Expressions/Expressions/Compilation/Properties/PropertiesObjectAccessorTransformer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ public static Expression Rewrite(Expression actual)
1212

1313
protected override Expression Transform(AccessorExpression ax)
1414
{
15-
if (!Pattern.IsAmbientProperty(ax.Receiver, "Properties", true))
15+
if (!Pattern.IsAmbientProperty(ax.Receiver, BuiltInProperty.Properties, true))
1616
return base.Transform(ax);
1717

1818
return new AmbientPropertyExpression(ax.MemberName, false);
1919
}
2020

2121
protected override Expression Transform(IndexerExpression ix)
2222
{
23-
if (!Pattern.IsAmbientProperty(ix.Receiver, "Properties", true) ||
23+
if (!Pattern.IsAmbientProperty(ix.Receiver, BuiltInProperty.Properties, true) ||
2424
!Pattern.IsStringConstant(ix.Index, out var name))
2525
return base.Transform(ix);
2626

0 commit comments

Comments
 (0)