From 766eff90579c1aab2c657e28fd846f91ed1b12bc Mon Sep 17 00:00:00 2001 From: James Luck Date: Fri, 22 Apr 2022 09:03:12 +1000 Subject: [PATCH 1/2] Adding support for deep cloning of `Expr`. Also clarified documentation. Removed some mutations on non-`Expr` types (breaking change). --- README.md | 2 +- src/PromQL.Parser/Ast.cs | 35 +++++++++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ae43975..141b907 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ BinaryExpr { VectorMatching = ... } ``` -All non-value AST types are mutable and can also be updated in place using a visitor such as `DepthFirstExpressionVisitor`. +Deep cloning of `Expr` is also supported via `Expr.DeepClone()`. Additionally all `Expr` AST types are mutable and can also be updated in place using a visitor such as `DepthFirstExpressionVisitor`. ### Emitting PromQL expressions An Abstract Syntax Tree can be converted back to its PromQL string representation, e.g: diff --git a/src/PromQL.Parser/Ast.cs b/src/PromQL.Parser/Ast.cs index 3798b29..37a0da6 100644 --- a/src/PromQL.Parser/Ast.cs +++ b/src/PromQL.Parser/Ast.cs @@ -1,16 +1,16 @@ using System; using System.Collections.Immutable; +using System.Linq; using System.Text; using ExhaustiveMatching; using Superpower.Model; -using Superpower.Parsers; namespace PromQL.Parser.Ast { /// /// Base of all PromQL syntactic components. /// - public interface IPromQlNode + public interface IPromQlNode { void Accept(IVisitor visitor); TextSpan? Span { get; } @@ -35,6 +35,12 @@ public interface IPromQlNode public interface Expr : IPromQlNode { ValueType Type { get; } + + /// + /// Makes a deep clone of an expression. + /// + /// + public Expr DeepClone(); } /// @@ -67,6 +73,7 @@ public AggregateExpr(AggregateOperator @operator, Expr expr, Expr param, bool wi public ValueType Type => ValueType.Vector; public void Accept(IVisitor visitor) => visitor.Visit(this); + public Expr DeepClone() => this with {Expr = Expr.DeepClone(), Param = Param?.DeepClone() }; } /// @@ -95,6 +102,8 @@ public ValueType Type return ValueType.Vector; } } + + public Expr DeepClone() => this with { LeftHandSide = LeftHandSide.DeepClone(), RightHandSide = RightHandSide.DeepClone() }; } /// @@ -119,10 +128,10 @@ public VectorMatching(bool returnBool) : this (DefaultMatchCardinality, Immutabl { } - public Operators.VectorMatchCardinality MatchCardinality { get; set; } = MatchCardinality; - public bool On { get; set; } = On; - public ImmutableArray Include { get; set; } = Include; - public bool ReturnBool { get; set; } = ReturnBool; + public Operators.VectorMatchCardinality MatchCardinality { get; } = MatchCardinality; + public bool On { get; } = On; + public ImmutableArray Include { get; } = Include; + public bool ReturnBool { get; } = ReturnBool; public void Accept(IVisitor visitor) => visitor.Visit(this); }; @@ -146,6 +155,8 @@ public FunctionCall(Function function, params Expr[] args) public void Accept(IVisitor visitor) => visitor.Visit(this); + public Expr DeepClone() => this with { Args = Args.Select(a => a.DeepClone()).ToImmutableArray() }; + protected virtual bool PrintMembers(StringBuilder builder) { builder.AppendLine($"{nameof(Function)} = {Function.Name}, "); @@ -161,6 +172,7 @@ public record ParenExpression(Expr Expr, TextSpan? Span = null) : Expr public Expr Expr { get; set; } = Expr; public void Accept(IVisitor visitor) => visitor.Visit(this); public ValueType Type => Expr.Type; + public Expr DeepClone() => this with { Expr = Expr.DeepClone() }; } public record OffsetExpr(Expr Expr, Duration Duration, TextSpan? Span = null) : Expr @@ -169,6 +181,7 @@ public record OffsetExpr(Expr Expr, Duration Duration, TextSpan? Span = null) : public Duration Duration { get; set; } = Duration; public void Accept(IVisitor visitor) => visitor.Visit(this); public ValueType Type => Expr.Type; + public Expr DeepClone() => this with { Expr = Expr.DeepClone() }; } public record MatrixSelector(VectorSelector Vector, Duration Duration, TextSpan? Span = null) : Expr @@ -177,6 +190,7 @@ public record MatrixSelector(VectorSelector Vector, Duration Duration, TextSpan? public Duration Duration { get; set; } = Duration; public void Accept(IVisitor visitor) => visitor.Visit(this); public ValueType Type => ValueType.Matrix; + public Expr DeepClone() => this with { }; } public record UnaryExpr(Operators.Unary Operator, Expr Expr, TextSpan? Span = null) : Expr @@ -186,6 +200,7 @@ public record UnaryExpr(Operators.Unary Operator, Expr Expr, TextSpan? Span = nu public void Accept(IVisitor visitor) => visitor.Visit(this); public ValueType Type => Expr.Type; + public Expr DeepClone() => this with { Expr = Expr.DeepClone() }; } public record VectorSelector : Expr @@ -216,11 +231,12 @@ public VectorSelector(MetricIdentifier metricIdentifier, LabelMatchers labelMatc public ValueType Type => ValueType.Vector; public void Accept(IVisitor visitor) => visitor.Visit(this); + public Expr DeepClone() => this with { }; } public record LabelMatchers(ImmutableArray Matchers, TextSpan? Span = null) : IPromQlNode { - protected virtual bool PrintMembers(System.Text.StringBuilder builder) + protected virtual bool PrintMembers(StringBuilder builder) { builder.Append($"{nameof(Matchers)} = "); Matchers.PrintArray(builder); @@ -247,6 +263,7 @@ public record NumberLiteral(double Value, TextSpan? Span = null) : Expr { public void Accept(IVisitor visitor) => visitor.Visit(this); public ValueType Type => ValueType.Scalar; + public Expr DeepClone() => this with { }; } public record Duration(TimeSpan Value, TextSpan? Span = null) : IPromQlNode @@ -258,6 +275,7 @@ public record StringLiteral(char Quote, string Value, TextSpan? Span = null) : E { public void Accept(IVisitor visitor) => visitor.Visit(this); public ValueType Type => ValueType.String; + public Expr DeepClone() => this with { }; } public record SubqueryExpr(Expr Expr, Duration Range, Duration? Step = null, TextSpan? Span = null) : Expr @@ -268,6 +286,7 @@ public record SubqueryExpr(Expr Expr, Duration Range, Duration? Step = null, Tex public ValueType Type => ValueType.Matrix; public void Accept(IVisitor visitor) => visitor.Visit(this); + public Expr DeepClone() => this with { Expr = Expr.DeepClone() }; } internal static class Extensions @@ -278,7 +297,7 @@ internal static void PrintArray(this ImmutableArray arr, System.Text.Strin sb.Append("[ "); for (int i = 0; i < arr.Length; i++) { - sb.Append(arr[i].ToString()); + sb.Append(arr[i]); if (i < arr.Length - 1) sb.Append(", "); } From 72033cf427813aaf758f4cc37e609781724567df Mon Sep 17 00:00:00 2001 From: James Luck Date: Fri, 22 Apr 2022 09:08:15 +1000 Subject: [PATCH 2/2] Some properties should be writable to support construction of objects --- src/PromQL.Parser/Ast.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PromQL.Parser/Ast.cs b/src/PromQL.Parser/Ast.cs index 37a0da6..a3f5549 100644 --- a/src/PromQL.Parser/Ast.cs +++ b/src/PromQL.Parser/Ast.cs @@ -128,9 +128,9 @@ public VectorMatching(bool returnBool) : this (DefaultMatchCardinality, Immutabl { } - public Operators.VectorMatchCardinality MatchCardinality { get; } = MatchCardinality; + public Operators.VectorMatchCardinality MatchCardinality { get; internal set; } = MatchCardinality; public bool On { get; } = On; - public ImmutableArray Include { get; } = Include; + public ImmutableArray Include { get; internal set; } = Include; public bool ReturnBool { get; } = ReturnBool; public void Accept(IVisitor visitor) => visitor.Visit(this);