/// <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); }
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); }
/// <inheritdoc/> public override QsStatementKind OnStatementKind(QsStatementKind kind) { this.SharedState.ContainsParamRef = false; // Every statement kind starts off false return(base.OnStatementKind(kind)); }
/// <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)); }