/// <summary>
                /// Converts conditional statements whose top-most condition is an OR.
                /// Creates a nested structure without the top-most OR.
                /// </summary>
                private (bool, QsConditionalStatement) ProcessOR(QsConditionalStatement conditionStatment)
                {
                    // This method expects elif blocks to have been abstracted out
                    if (conditionStatment.ConditionalBlocks.Length != 1)
                    {
                        return(false, conditionStatment);
                    }

                    var(condition, block) = conditionStatment.ConditionalBlocks[0];

                    if (condition.Expression is ExpressionKind.OR orCondition)
                    {
                        var subCondition  = new QsConditionalStatement(ImmutableArray.Create(Tuple.Create(orCondition.Item2, block)), conditionStatment.Default);
                        var subIfStatment = new QsStatement(
                            QsStatementKind.NewQsConditionalStatement(subCondition),
                            LocalDeclarations.Empty,
                            block.Location,
                            QsComments.Empty);
                        var newDefault = QsNullable <QsPositionedBlock> .NewValue(new QsPositionedBlock(
                                                                                      new QsScope(ImmutableArray.Create(subIfStatment), block.Body.KnownSymbols),
                                                                                      block.Location,
                                                                                      QsComments.Empty));

                        return(true, new QsConditionalStatement(ImmutableArray.Create(Tuple.Create(orCondition.Item1, block)), newDefault));
                    }
                    else
                    {
                        return(false, conditionStatment);
                    }
                }
            public override QsStatementKind onConjugation(QsConjugation stm)
            {
                var inner            = stm.InnerTransformation;
                var innerLoc         = this._Scope.onLocation(inner.Location);
                var transformedInner = new QsPositionedBlock(this._Scope.Transform(inner.Body), innerLoc, inner.Comments);

                return(QsStatementKind.NewQsConjugation(new QsConjugation(stm.OuterTransformation, transformedInner)));
            }
            /// <inheritdoc/>
            public override QsStatementKind OnConjugation(QsConjugation stm)
            {
                var superInWithinBlock = this.SharedState.InWithinBlock;
                this.SharedState.InWithinBlock = true;
                var (_, outer) = this.OnPositionedBlock(QsNullable<TypedExpression>.Null, stm.OuterTransformation);
                this.SharedState.InWithinBlock = superInWithinBlock;

                var (_, inner) = this.OnPositionedBlock(QsNullable<TypedExpression>.Null, stm.InnerTransformation);

                return QsStatementKind.NewQsConjugation(new QsConjugation(outer, inner));
            }
            /// <inheritdoc/>
            public override QsStatementKind OnValueUpdate(QsValueUpdate stm)
            {
                // If lhs contains an identifier found in the scope's known variables (variables from the super-scope), the scope is not valid
                var lhs = this.Expressions.OnTypedExpression(stm.Lhs);

                if (this.SharedState.ContainsParamRef)
                {
                    this.SharedState.IsValidScope = false;
                }

                var rhs = this.Expressions.OnTypedExpression(stm.Rhs);
                return QsStatementKind.NewQsValueUpdate(new QsValueUpdate(lhs, rhs));
            }
 /// <summary>
 /// Takes an expression that is the call to a conditional control API operation and the original statement,
 /// and creates a statement from the given expression.
 /// </summary>
 private QsStatement CreateControlStatement(QsStatement statement, TypedExpression callExpression)
 {
     if (callExpression != null)
     {
         return(new QsStatement(
                    QsStatementKind.NewQsExpressionStatement(callExpression),
                    statement.SymbolDeclarations,
                    QsNullable <QsLocation> .Null,
                    statement.Comments));
     }
     else
     {
         // ToDo: add diagnostic message here
         return(statement); // If the blocks can't be converted, return the original
     }
 }
                /// <summary>
                /// Converts if-elif-else structures to nested if-else structures.
                /// </summary>
                private (bool, QsConditionalStatement) ProcessElif(QsConditionalStatement conditionStatment)
                {
                    if (conditionStatment.ConditionalBlocks.Length < 2)
                    {
                        return(false, conditionStatment);
                    }

                    var subCondition         = new QsConditionalStatement(conditionStatment.ConditionalBlocks.RemoveAt(0), conditionStatment.Default);
                    var secondConditionBlock = conditionStatment.ConditionalBlocks[1].Item2;
                    var subIfStatment        = new QsStatement(
                        QsStatementKind.NewQsConditionalStatement(subCondition),
                        LocalDeclarations.Empty,
                        secondConditionBlock.Location,
                        secondConditionBlock.Comments);
                    var newDefault = QsNullable <QsPositionedBlock> .NewValue(new QsPositionedBlock(
                                                                                  new QsScope(ImmutableArray.Create(subIfStatment), secondConditionBlock.Body.KnownSymbols),
                                                                                  secondConditionBlock.Location,
                                                                                  QsComments.Empty));

                    return(true, new QsConditionalStatement(ImmutableArray.Create(conditionStatment.ConditionalBlocks[0]), newDefault));
                }
                /// <summary>
                /// Converts conditional statements to nested structures so they do not
                /// have elif blocks or top-most OR or AND conditions.
                /// </summary>
                private QsStatement ReshapeConditional(QsStatement statement)
                {
                    if (statement.Statement is QsStatementKind.QsConditionalStatement condition)
                    {
                        var stm = condition.Item;
                        (_, stm) = ProcessElif(stm);
                        bool wasOrProcessed, wasAndProcessed;
                        do
                        {
                            (wasOrProcessed, stm)  = ProcessOR(stm);
                            (wasAndProcessed, stm) = ProcessAND(stm);
                        } while (wasOrProcessed || wasAndProcessed);

                        return(new QsStatement(
                                   QsStatementKind.NewQsConditionalStatement(stm),
                                   statement.SymbolDeclarations,
                                   statement.Location,
                                   statement.Comments));
                    }
                    return(statement);
                }
Example #8
0
            public override ExpressionKind OnOperationCall(TypedExpression method, TypedExpression arg)
            {
                // An operation in an adjoint scope must return Unit, so extract the operation to be an
                // an additional statement and then replace it with Unit.
                var curExpression = this.SharedState.CurrentExpression.Peek();

                this.SharedState.AdditionalStatements.Add(
                    new QsStatement(
                        QsStatementKind.NewQsExpressionStatement(
                            new TypedExpression(
                                base.OnOperationCall(method, arg),
                                curExpression.TypeParameterResolutions.Select(x => Tuple.Create(x.Key.Item1, x.Key.Item2, x.Value)).ToImmutableArray(),
                                curExpression.ResolvedType,
                                curExpression.InferredInformation,
                                curExpression.Range)),
                        LocalDeclarations.Empty,
                        this.SharedState.StatementLocation,
                        QsComments.Empty));

                return(ExpressionKind.UnitValue);
            }
Example #9
0
 /// <inheritdoc/>
 public override QsStatementKind OnStatementKind(QsStatementKind kind)
 {
     this.SharedState.ContainsParamRef = false; // Every statement kind starts off false
     return(base.OnStatementKind(kind));
 }
Example #10
0
            /// <summary>
            /// Generates a new operation with the body's contents. All the known variables at the
            /// start of the block will become parameters to the new operation, and the operation
            /// will have all the valid type parameters of the calling context as type parameters.
            /// The generated operation is returned, along with a call to the new operation is
            /// also returned with all the type parameters and known variables being forwarded to
            /// the new operation as arguments.
            ///
            /// The given body should be validated with the SharedState.IsValidScope before using this function.
            /// </summary>
            public bool LiftBody(QsScope body, out QsCallable callable, out QsStatement callStatement)
            {
                if (!this.IsValidScope)
                {
                    callable      = null;
                    callStatement = null;
                    return(false);
                }

                var(generatedOp, originalArgumentType) = this.GenerateOperation(body);
                var generatedOpType = ResolvedType.New(ResolvedTypeKind.NewOperation(
                                                           Tuple.Create(
                                                               originalArgumentType,
                                                               ResolvedType.New(ResolvedTypeKind.UnitType)),
                                                           generatedOp.Signature.Information));

                // Forward the type parameters of the parent callable to the type arguments of the call to the generated operation.
                var typeArguments = this.CurrentCallable.TypeParameters;
                var generatedOpId = new TypedExpression(
                    ExpressionKind.NewIdentifier(
                        Identifier.NewGlobalCallable(generatedOp.FullName),
                        typeArguments),
                    typeArguments.IsNull
                        ? TypeArgsResolution.Empty
                        : typeArguments.Item
                    .Select(type => Tuple.Create(generatedOp.FullName, ((ResolvedTypeKind.TypeParameter)type.Resolution).Item.TypeName, type))
                    .ToImmutableArray(),
                    generatedOpType,
                    new InferredExpressionInformation(false, false),
                    QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null);

                var             knownSymbols = body.KnownSymbols.Variables;
                TypedExpression arguments    = null;

                if (knownSymbols.Any())
                {
                    var argumentArray = knownSymbols
                                        .Select(var => new TypedExpression(
                                                    ExpressionKind.NewIdentifier(
                                                        Identifier.NewLocalVariable(var.VariableName),
                                                        QsNullable <ImmutableArray <ResolvedType> > .Null),
                                                    TypeArgsResolution.Empty,
                                                    var.Type,
                                                    var.InferredInformation,
                                                    QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null))
                                        .ToImmutableArray();

                    arguments = new TypedExpression(
                        ExpressionKind.NewValueTuple(argumentArray),
                        TypeArgsResolution.Empty,
                        ResolvedType.New(ResolvedTypeKind.NewTupleType(argumentArray.Select(expr => expr.ResolvedType).ToImmutableArray())),
                        new InferredExpressionInformation(false, argumentArray.Any(exp => exp.InferredInformation.HasLocalQuantumDependency)),
                        QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null);
                }
                else
                {
                    arguments = new TypedExpression(
                        ExpressionKind.UnitValue,
                        TypeArgsResolution.Empty,
                        ResolvedType.New(ResolvedTypeKind.UnitType),
                        new InferredExpressionInformation(false, false),
                        QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null);
                }

                var call = new TypedExpression(
                    ExpressionKind.NewCallLikeExpression(generatedOpId, arguments),
                    typeArguments.IsNull
                        ? TypeArgsResolution.Empty
                        : typeArguments.Item
                    .Select(type => Tuple.Create(this.CurrentCallable.Callable.FullName, ((ResolvedTypeKind.TypeParameter)type.Resolution).Item.TypeName, type))
                    .ToImmutableArray(),
                    ResolvedType.New(ResolvedTypeKind.UnitType),
                    new InferredExpressionInformation(false, true),
                    QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null);

                // set output parameters
                callable      = generatedOp;
                callStatement = new QsStatement(
                    QsStatementKind.NewQsExpressionStatement(call),
                    LocalDeclarations.Empty,
                    QsNullable <QsLocation> .Null,
                    QsComments.Empty);

                return(true);
            }
        /// <summary>
        /// Creates a separate callable for each intrinsic specialization,
        /// and replaces the specialization implementations of the original callable with a call to these.
        /// Self adjoint generation directives in intrinsic callables are replaced by a provided implementation.
        /// Type constructors and generic callables or callables that already define a target instruction name are left unchanged.
        /// </summary>
        /// <exception cref="ArgumentException">
        /// An intrinsic callable contains non-intrinsic specializations
        /// or a non-intrinsic callable contains intrinsic specializations,
        /// or the a callable doesn't have a body specialization.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// A specialization has explicit type arguments;
        /// Monomorphization needs to run before separating target instructions.
        /// </exception>
        private static QsNamespace LiftIntrinsicSpecializations(QsNamespace ns)
        {
            var elements = ImmutableArray.CreateBuilder <QsNamespaceElement>();

            foreach (var element in ns.Elements)
            {
                if (element is QsNamespaceElement.QsCallable c &&
                    c.Item.Signature.TypeParameters.Length == 0 &&
                    !c.Item.Kind.IsTypeConstructor)
                {
                    if (c.Item.IsIntrinsic)
                    {
                        QsCallable callable = c.Item;
                        if (!callable.Specializations.Any(spec => spec.Kind.IsQsBody))
                        {
                            throw new ArgumentException("missing body specialization");
                        }
                        else if (callable.Specializations.Any(spec => spec.TypeArguments.IsValue))
                        {
                            throw new InvalidOperationException("specialization with type arguments");
                        }
                        else if (callable.Specializations.Length == 1 && callable.Attributes.Any(BuiltIn.DefinesTargetInstruction))
                        {
                            elements.Add(element);
                        }
                        else
                        {
                            QsQualifiedName GeneratedName(QsSpecializationKind kind) =>
                            new QsQualifiedName(callable.FullName.Namespace, $"{callable.FullName.Name}{SpecializationSuffix(kind)}");

                            var specializations = ImmutableArray.CreateRange(callable.Specializations.Select(spec =>
                            {
                                var inferredInfo = spec.Signature.Information.InferredInformation;
                                if (!inferredInfo.IsIntrinsic && !inferredInfo.IsSelfAdjoint)
                                {
                                    throw new ArgumentException("non-intrinsic specialization for intrinsic callable");
                                }

                                // Get the correct argument tuple both for the added intrinsic callable
                                // and the generated provided specialization that replaces the intrinsic one.
                                var argTuple = BuildSpecArgTuple(callable.ArgumentTuple, spec.Kind);

                                // Create a separate callable for that specialization,
                                // unless the specialization is not needed for a self-adjoint callable.

                                var genCallableSignature = new ResolvedSignature(
                                    ImmutableArray <QsLocalSymbol> .Empty,
                                    spec.Signature.ArgumentType,
                                    spec.Signature.ReturnType,
                                    new CallableInformation(
                                        ResolvedCharacteristics.Empty,
                                        new InferredCallableInformation(isIntrinsic: true, isSelfAdjoint: false)));
                                var genCallableName = GeneratedName(
                                    inferredInfo.IsSelfAdjoint && spec.Kind.IsQsAdjoint ? QsSpecializationKind.QsBody :
                                    inferredInfo.IsSelfAdjoint && spec.Kind.IsQsControlledAdjoint ? QsSpecializationKind.QsControlled :
                                    spec.Kind);

                                if (!inferredInfo.IsSelfAdjoint || spec.Kind.IsQsBody || spec.Kind.IsQsControlled)
                                {
                                    var genCallableBody = new QsSpecialization(
                                        QsSpecializationKind.QsBody,
                                        genCallableName,
                                        spec.Attributes,
                                        spec.Source,
                                        QsNullable <QsLocation> .Null,
                                        spec.TypeArguments,
                                        genCallableSignature,
                                        SpecializationImplementation.Intrinsic,
                                        spec.Documentation,
                                        spec.Comments);
                                    var genCallable = new QsCallable(
                                        callable.Kind,
                                        genCallableName,
                                        callable.Attributes,
                                        callable.Access,
                                        spec.Source,
                                        spec.Location,
                                        genCallableSignature,
                                        argTuple,
                                        ImmutableArray.Create(genCallableBody),
                                        ImmutableArray <string> .Empty,
                                        QsComments.Empty);
                                    elements.Add(QsNamespaceElement.NewQsCallable(genCallable));
                                }

                                // Create a specialization that calls into the generated callable,
                                // or the corresponding callable no callable for the specialization
                                // has been added due to hte operation being self-adjoint.

                                var genCallableType =
                                    callable.Kind == QsCallableKind.Operation
                                    ? OperationTypeFromSignature(genCallableSignature)
                                    : TypeKind.NewFunction(genCallableSignature.ArgumentType, genCallableSignature.ReturnType);
                                var call = SyntaxGenerator.CallNonGeneric(
                                    IdentifierForCallable(genCallableName, genCallableType),
                                    SyntaxGenerator.ArgumentTupleAsExpression(argTuple));
                                var statement = new QsStatement(
                                    QsStatementKind.NewQsReturnStatement(call),
                                    LocalDeclarations.Empty,
                                    QsNullable <QsLocation> .Null,
                                    QsComments.Empty);
                                var localDeclarations = new LocalDeclarations(
                                    SyntaxGenerator.ValidDeclarations(SyntaxGenerator.ExtractItems(argTuple)));

                                return(spec.WithImplementation(SpecializationImplementation.NewProvided(
                                                                   argTuple,
                                                                   new QsScope(ImmutableArray.Create(statement), localDeclarations))));
                            }));

                            // Create a callable that contains all specializations that
                            // call into the generated callables for each specialization.

                            var inlineAttribute = AttributeUtils.BuildAttribute(BuiltIn.Inline.FullName, SyntaxGenerator.UnitValue);
                            var signature       = new ResolvedSignature(
                                ImmutableArray <QsLocalSymbol> .Empty,
                                callable.Signature.ArgumentType,
                                callable.Signature.ReturnType,
                                new CallableInformation(
                                    callable.Signature.Information.Characteristics,
                                    new InferredCallableInformation(isSelfAdjoint: callable.IsSelfAdjoint, isIntrinsic: false)));
                            var redirect = new QsCallable(
                                callable.Kind,
                                callable.FullName,
                                ImmutableArray.Create(inlineAttribute),
                                callable.Access,
                                callable.Source,
                                callable.Location,
                                signature,
                                callable.ArgumentTuple,
                                specializations,
                                callable.Documentation,
                                callable.Comments);
                            elements.Add(QsNamespaceElement.NewQsCallable(redirect));
                        }
                    }
                    else if (c.Item.Specializations.Any(spec => spec.Implementation.IsIntrinsic))
                    {
                        throw new ArgumentException("intrinsic specialization for non-intrinsic callable");
                    }
                    else
                    {
                        elements.Add(element);
                    }
                }
        /// <summary>
        /// Replaces self adjoint generation directives in non-intrinsic callables with a provided implementation
        /// that calls the appropriate specialization of the callable.
        /// Intrinsic callables are left unchanged.
        /// </summary>
        private static QsNamespace ReplaceSelfAdjointSpecializations(QsNamespace ns)
        {
            var elements = ImmutableArray.CreateBuilder <QsNamespaceElement>();

            foreach (var element in ns.Elements)
            {
                if (element is QsNamespaceElement.QsCallable c)
                {
                    if (c.Item.IsSelfAdjoint && !c.Item.IsIntrinsic)
                    {
                        var callableId = IdentifierForCallable(
                            c.Item.FullName,
                            OperationTypeFromSignature(c.Item.Signature));

                        var callable = c.Item.WithSpecializations(specs =>
                                                                  ImmutableArray.CreateRange(specs.Select(spec =>
                        {
                            if (spec.Kind.IsQsBody || spec.Kind.IsQsControlled)
                            {
                                return(spec);
                            }
                            else
                            {
                                var argTuple = BuildSpecArgTuple(c.Item.ArgumentTuple, spec.Kind);
                                var callee   = spec.Kind.IsQsControlledAdjoint
                                        ? SyntaxGenerator.AutoGeneratedExpression(
                                    ExpressionKind.NewControlledApplication(callableId),
                                    OperationTypeFromSignature(spec.Signature),
                                    false)
                                        : callableId;

                                var call = SyntaxGenerator.CallNonGeneric(
                                    callee,
                                    SyntaxGenerator.ArgumentTupleAsExpression(argTuple));
                                var statement = new QsStatement(
                                    QsStatementKind.NewQsReturnStatement(call),
                                    LocalDeclarations.Empty,
                                    QsNullable <QsLocation> .Null,
                                    QsComments.Empty);
                                var localDeclarations = new LocalDeclarations(
                                    SyntaxGenerator.ValidDeclarations(SyntaxGenerator.ExtractItems(argTuple)));

                                return(spec.WithImplementation(SpecializationImplementation.NewProvided(
                                                                   argTuple,
                                                                   new QsScope(ImmutableArray.Create(statement), localDeclarations))));
                            }
                        })));
                        elements.Add(QsNamespaceElement.NewQsCallable(callable));
                    }
                    else
                    {
                        elements.Add(element);
                    }
                }
                else
                {
                    elements.Add(element);
                }
            }
            return(new QsNamespace(ns.Name, elements.ToImmutable(), ns.Documentation));
        }