This repository has been archived by the owner on Jan 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 172
/
Conjugations.cs
115 lines (100 loc) · 4.97 KB
/
Conjugations.cs
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Immutable;
using Microsoft.Quantum.QsCompiler.SyntaxTokens;
using Microsoft.Quantum.QsCompiler.SyntaxTree;
using Microsoft.Quantum.QsCompiler.Transformations.Core;
using Microsoft.Quantum.QsCompiler.Transformations.SearchAndReplace;
namespace Microsoft.Quantum.QsCompiler.Transformations.Conjugations
{
/// <summary>
/// Syntax tree transformation that inlines all conjugations, thus eliminating them from a given scope.
/// All exception thrown during transformation are caught and the action given upon instantiation - if any - is called upon them.
/// The syntax tree is left unchanged if an exception occurs. The Success property is true if and only if no exceptions occurred.
/// The generation of the adjoint for the outer block is subject to the same limitation as any adjoint auto-generation.
/// In particular, it is only guaranteed to be valid if operation calls only occur within expression statements, and
/// throws an InvalidOperationException if the outer block contains while-loops.
/// </summary>
public class InlineConjugations
: SyntaxTreeTransformation<InlineConjugations.TransformationState>
{
public class TransformationState
{
public bool Success { get; internal set; }
internal Action<Exception>? OnException { get; }
internal Func<QsScope, QsScope> ResolveNames { get; set; } =
new UniqueVariableNames().Statements.OnScope;
public void Reset() =>
this.ResolveNames = new UniqueVariableNames().Statements.OnScope;
public TransformationState(Action<Exception>? onException = null)
{
this.Success = true;
this.OnException = onException;
}
}
public InlineConjugations(Action<Exception>? onException = null)
: base(new TransformationState(onException))
{
this.Namespaces = new NamespaceTransformation(this);
this.Statements = new StatementTransformation(this);
this.Expressions = new ExpressionTransformation<TransformationState>(this, TransformationOptions.Disabled);
this.Types = new TypeTransformation<TransformationState>(this, TransformationOptions.Disabled);
}
/* helper classes */
private class StatementTransformation
: StatementTransformation<TransformationState>
{
public StatementTransformation(SyntaxTreeTransformation<TransformationState> parent)
: base(parent)
{
}
public override QsScope OnScope(QsScope scope)
{
var statements = ImmutableArray.CreateBuilder<QsStatement>();
foreach (var statement in scope.Statements)
{
if (statement.Statement is QsStatementKind.QsConjugation conj)
{
// since we are eliminating scopes,
// we need to make sure that the variables defined within the inlined scopes do not clash with other defined variables.
var outer = this.SharedState.ResolveNames(this.OnScope(conj.Item.OuterTransformation.Body));
var inner = this.SharedState.ResolveNames(this.OnScope(conj.Item.InnerTransformation.Body));
var adjOuter = outer.GenerateAdjoint(); // will add a unique name wrapper
statements.AddRange(outer.Statements);
statements.AddRange(inner.Statements);
statements.AddRange(adjOuter.Statements);
}
else
{
statements.Add(this.OnStatement(statement));
}
}
return new QsScope(statements.ToImmutableArray(), scope.KnownSymbols);
}
}
private class NamespaceTransformation
: NamespaceTransformation<TransformationState>
{
public NamespaceTransformation(SyntaxTreeTransformation<TransformationState> parent)
: base(parent)
{
}
public override Tuple<QsTuple<LocalVariableDeclaration<QsLocalSymbol, ResolvedType>>, QsScope> OnProvidedImplementation(
QsTuple<LocalVariableDeclaration<QsLocalSymbol, ResolvedType>> argTuple, QsScope body)
{
this.SharedState.Reset();
try
{
body = this.Transformation.Statements.OnScope(body);
}
catch (Exception ex)
{
this.SharedState.OnException?.Invoke(ex);
this.SharedState.Success = false;
}
return new Tuple<QsTuple<LocalVariableDeclaration<QsLocalSymbol, ResolvedType>>, QsScope>(argTuple, body);
}
}
}
}