/// <summary>
        /// Returns a list of suggested completion items for the given position.
        /// <para/>
        /// Returns null if any argument is null or the position is invalid.
        /// Returns an empty completion list if the given position is within a comment.
        /// </summary>
        public static CompletionList Completions(
            this FileContentManager file, CompilationUnit compilation, Position position)
        {
            if (file == null || compilation == null || position == null || !Utils.IsValidPosition(position))
            {
                return(null);
            }
            if (file.GetLine(position.Line).WithoutEnding.Length < position.Character)
            {
                return(Enumerable.Empty <CompletionItem>().ToCompletionList(false));
            }

            var(scope, previous) = GetCompletionEnvironment(file, position, out var fragment);
            if (scope == null)
            {
                return(GetFallbackCompletions(file, compilation, position).ToCompletionList(false));
            }

            var result = GetCompletionKinds(
                scope,
                previous != null ? QsNullable <QsFragmentKind> .NewValue(previous) : QsNullable <QsFragmentKind> .Null,
                GetFragmentTextBeforePosition(file, fragment, position));

            if (result is CompletionResult.Success success)
            {
                return(success.Item
                       .SelectMany(kind => GetCompletionsForKind(file, compilation, position, kind))
                       .ToCompletionList(false));
            }
            else
            {
                return(GetFallbackCompletions(file, compilation, position).ToCompletionList(false));
            }
        }
                /// <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);
                    }
                }
Пример #3
0
        // routines related to "reconstructing" the syntax tree from the saved tokens to do context checks

        /// <summary>
        /// Returns the context object for the given token index, ignoring empty fragments.
        /// Throws an ArgumentNullException if the given token index is null.
        /// </summary>
        private static Context.SyntaxTokenContext GetContext(this CodeFragment.TokenIndex tokenIndex)
        {
            if (tokenIndex == null)
            {
                throw new ArgumentNullException(nameof(tokenIndex));
            }
            QsNullable <QsFragmentKind> Nullable(CodeFragment fragment) =>
            fragment?.Kind == null
                ? QsNullable <QsFragmentKind> .Null
                : fragment.IncludeInCompilation
                ? QsNullable <QsFragmentKind> .NewValue(fragment.Kind)
                : QsNullable <QsFragmentKind> .NewValue(QsFragmentKind.InvalidFragment);

            var self         = tokenIndex.GetFragment();
            var previous     = tokenIndex.PreviousOnScope()?.GetFragment(); // excludes empty tokens
            var next         = tokenIndex.NextOnScope()?.GetFragment();     // excludes empty tokens
            var parents      = tokenIndex.GetNonEmptyParents().Select(tIndex => Nullable(tIndex.GetFragment())).ToArray();
            var nullableSelf = self?.Kind == null                           // special treatment such that errors for fragments excluded from compilation still get logged...
                ? QsNullable <QsFragmentKind> .Null
                : QsNullable <QsFragmentKind> .NewValue(self.Kind);

            var headerRange = self?.HeaderRange ?? QsCompilerDiagnostic.DefaultRange;

            return(new Context.SyntaxTokenContext(headerRange, nullableSelf, Nullable(previous), Nullable(next), parents));
        }
                /// <summary>
                /// Gets an identifier and argument tuple for the built-in operation NoOp.
                /// </summary>
                private (TypedExpression, TypedExpression) GetNoOp()
                {
                    var opInfo = BuiltIn.NoOp;

                    var properties      = new[] { OpProperty.Adjointable, OpProperty.Controllable };
                    var characteristics = new CallableInformation(
                        ResolvedCharacteristics.FromProperties(properties),
                        new InferredCallableInformation(((BuiltInKind.Operation)opInfo.Kind).IsSelfAdjoint, false));

                    var unitType      = ResolvedType.New(ResolvedTypeKind.UnitType);
                    var operationType = ResolvedType.New(ResolvedTypeKind.NewOperation(
                                                             Tuple.Create(unitType, unitType),
                                                             characteristics));

                    var args = new TypedExpression(
                        ExpressionKind.UnitValue,
                        TypeArgsResolution.Empty,
                        unitType,
                        new InferredExpressionInformation(false, false),
                        QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null);
                    var typeArgs = ImmutableArray.Create(unitType);

                    var identifier = new TypedExpression(
                        ExpressionKind.NewIdentifier(
                            Identifier.NewGlobalCallable(opInfo.FullName),
                            QsNullable <ImmutableArray <ResolvedType> > .NewValue(typeArgs)),
                        typeArgs
                        .Zip(((BuiltInKind.Operation)opInfo.Kind).TypeParameters, (type, param) => Tuple.Create(opInfo.FullName, param, type))
                        .ToImmutableArray(),
                        operationType,
                        new InferredExpressionInformation(false, false),
                        QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null);

                    return(identifier, args);
                }
        /// <summary>
        /// Given the location information for a declared symbol,
        /// as well as the position of the declaration within which the symbol is declared,
        /// returns the zero-based line and character index indicating the position of the symbol in the file.
        /// Returns null if the given object is not compatible with the position information generated by this CompilationBuilder.
        /// </summary>
        public static Position SymbolPosition(QsLocation rootLocation, QsNullable <Position> symbolPosition, Range symbolRange)
        {
            // the position offset is set to null (only) for variables defined in the declaration
            var offset = symbolPosition.IsNull ? rootLocation.Offset : rootLocation.Offset + symbolPosition.Item;

            return(offset + symbolRange.Start);
        }
Пример #6
0
        /// <summary>
        /// Given the location information for a declared symbol,
        /// as well as the position of the declaration within which the symbol is declared,
        /// returns the zero-based line and character index indicating the position of the symbol in the file.
        /// Returns null if the given object is not compatible with the position information generated by this CompilationBuilder.
        /// </summary>
        public static Tuple <int, int> SymbolPosition(QsLocation rootLocation, QsNullable <Tuple <int, int> > symbolPosition, Tuple <QsPositionInfo, QsPositionInfo> symbolRange)
        {
            var offset = symbolPosition.IsNull // the position offset is set to null (only) for variables defined in the declaration
                ? DeclarationPosition(rootLocation)
                : StatementPosition(rootLocation.Offset, symbolPosition.Item);

            return(DeclarationPosition(GetAbsolutePosition(new Position(offset.Item1, offset.Item2), symbolRange.Item1)));
        }
Пример #7
0
                public override QsStatement OnStatement(QsStatement stm)
                {
                    this.SharedState.ExprTypeParamResolutions.Clear();
                    this.SharedState.CurrentStatementOffset = stm.Location.IsValue
                        ? QsNullable <Position> .NewValue(stm.Location.Item.Offset)
                        : QsNullable <Position> .Null;

                    return(base.OnStatement(stm));
                }
Пример #8
0
 /// <inheritdoc/>
 public override ExpressionKind OnIdentifier(Identifier sym, QsNullable <ImmutableArray <ResolvedType> > tArgs)
 {
     if (sym is Identifier.LocalVariable local &&
         this.SharedState.GeneratedOpParams.Any(param => param.VariableName.Equals(local.Item)))
     {
         this.SharedState.ContainsParamRef = true;
     }
     return(base.OnIdentifier(sym, tArgs));
 }
                public override ExpressionKind OnIdentifier(Identifier sym, QsNullable <ImmutableArray <ResolvedType> > tArgs)
                {
                    if (sym is Identifier.GlobalCallable global)
                    {
                        this.SharedState.AddDependency(global.Item);
                    }

                    return(ExpressionKind.InvalidExpr);
                }
                private (TypedExpression Id, TypedExpression Args)? IsValidScope(QsScope? scope)
                {
                    // if the scope has exactly one statement in it and that statement is a call like expression statement
                    if (scope != null &&
                        scope.Statements.Length == 1 &&
                        scope.Statements[0].Statement is QsStatementKind.QsExpressionStatement expr &&
                        expr.Item.ResolvedType.Resolution.IsUnitType &&
                        expr.Item.Expression is ExpressionKind.CallLikeExpression call &&
                        !TypedExpression.IsPartialApplication(expr.Item.Expression) &&
                        call.Item1.Expression is ExpressionKind.Identifier)
                    {
                        var newCallIdentifier = call.Item1;
                        var callTypeArguments = expr.Item.TypeParameterResolutions;

                        // This relies on anything having type parameters must be a global callable.
                        if (newCallIdentifier.Expression is ExpressionKind.Identifier id &&
                            id.Item1 is Identifier.GlobalCallable global &&
                            callTypeArguments.Any())
                        {
                            // We are dissolving the application of arguments here, so the call's type argument
                            // resolutions have to be moved to the 'identifier' sub expression.
                            var combination           = new TypeResolutionCombination(expr.Item);
                            var combinedTypeArguments = combination.CombinedResolutionDictionary.FilterByOrigin(global.Item);
                            QsCompilerError.Verify(combination.IsValid, "failed to combine type parameter resolution");

                            var globalCallable = this.SharedState.Compilation.Namespaces
                                                 .Where(ns => ns.Name.Equals(global.Item.Namespace))
                                                 .Callables()
                                                 .FirstOrDefault(c => c.FullName.Name.Equals(global.Item.Name));

                            QsCompilerError.Verify(globalCallable != null, $"Could not find the global reference {global.Item}.");

                            var callableTypeParameters = globalCallable.Signature.TypeParameters.Select(param =>
                            {
                                var name = param as QsLocalSymbol.ValidName;
                                QsCompilerError.Verify(!(name is null), "Invalid type parameter name.");
                                return(name);
                            });

                            newCallIdentifier = new TypedExpression(
                                ExpressionKind.NewIdentifier(
                                    id.Item1,
                                    QsNullable <ImmutableArray <ResolvedType> > .NewValue(
                                        callableTypeParameters
                                        .Select(x => combinedTypeArguments[Tuple.Create(global.Item, x.Item)]).ToImmutableArray())),
                                TypedExpression.AsTypeArguments(combinedTypeArguments),
                                call.Item1.ResolvedType,
                                call.Item1.InferredInformation,
                                call.Item1.Range);
                        }

                        return(newCallIdentifier, call.Item2);
                    }

                    return(null);
                }
Пример #11
0
            public override QsExpressionKind <TypedExpression, Identifier, ResolvedType> OnIdentifier
                (Identifier sym, QsNullable <ImmutableArray <ResolvedType> > tArgs)
            {
                var name =
                    sym is Identifier.LocalVariable var ? var.Item.Value :
                    sym is Identifier.GlobalCallable global ? global.Item.ToString() :
                    null;

                if (name != null)
                {
                    this.SharedState.AddIdentifier(name);
                }
                return(base.OnIdentifier(sym, tArgs));
            }
Пример #12
0
                public override ExpressionKind OnIdentifier(Identifier sym, QsNullable <ImmutableArray <ResolvedType> > tArgs)
                {
                    var rtrn = base.OnIdentifier(sym, tArgs);

                    // Check if this is a recursive identifier
                    // In this context, that is a call back to the original callable from the newly generated operation
                    if (sym is Identifier.GlobalCallable callable && this.SharedState.OldName.Equals(callable.Item))
                    {
                        // Setting this flag will prevent the rerouting logic from processing the resolved type of the recursive identifier expression.
                        // This is necessary because we don't want any type parameters from the original callable from being rerouted to the new generated
                        // operation's type parameters in the definition of the identifier.
                        this.SharedState.IsRecursiveIdentifier = true;
                    }
                    return(rtrn);
                }
                /// <summary>
                /// Creates an operation call from the conditional control API, given information
                /// about which operation to call and with what arguments.
                /// </summary>
                private TypedExpression CreateControlCall(BuiltIn opInfo, IEnumerable <OpProperty> properties, TypedExpression args, IEnumerable <ResolvedType> typeArgs)
                {
                    var characteristics = new CallableInformation(
                        ResolvedCharacteristics.FromProperties(properties),
                        new InferredCallableInformation(((BuiltInKind.Operation)opInfo.Kind).IsSelfAdjoint, false));

                    var unitType      = ResolvedType.New(ResolvedTypeKind.UnitType);
                    var operationType = ResolvedType.New(ResolvedTypeKind.NewOperation(
                                                             Tuple.Create(args.ResolvedType, unitType),
                                                             characteristics));

                    // Build the surrounding control call
                    var identifier = new TypedExpression(
                        ExpressionKind.NewIdentifier(
                            Identifier.NewGlobalCallable(opInfo.FullName),
                            typeArgs.Any()
                            ? QsNullable <ImmutableArray <ResolvedType> > .NewValue(typeArgs.ToImmutableArray())
                            : QsNullable <ImmutableArray <ResolvedType> > .Null),
                        typeArgs
                        .Zip(((BuiltInKind.Operation)opInfo.Kind).TypeParameters, (type, param) => Tuple.Create(opInfo.FullName, param, type))
                        .ToImmutableArray(),
                        operationType,
                        new InferredExpressionInformation(false, false),
                        QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null);

                    // Creates type resolutions for the call expression
                    var opTypeArgResolutions = typeArgs
                                               .SelectMany(x =>
                                                           x.Resolution is ResolvedTypeKind.TupleType tup
                            ? tup.Item
                            : ImmutableArray.Create(x))
                                               .Where(x => x.Resolution.IsTypeParameter)
                                               .Select(x => (x.Resolution as ResolvedTypeKind.TypeParameter).Item)
                                               .GroupBy(x => (x.Origin, x.TypeName))
                                               .Select(group =>
                    {
                        var typeParam = group.First();
                        return(Tuple.Create(typeParam.Origin, typeParam.TypeName, ResolvedType.New(ResolvedTypeKind.NewTypeParameter(typeParam))));
                    })
                                               .ToImmutableArray();

                    return(new TypedExpression(
                               ExpressionKind.NewCallLikeExpression(identifier, args),
                               opTypeArgResolutions,
                               unitType,
                               new InferredExpressionInformation(false, true),
                               QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null));
                }
 internal static TypedExpression CreateIdentifierExpression(Identifier id,
                                                            TypeArgsResolution typeArgsMapping, ResolvedType resolvedType) =>
 new TypedExpression
 (
     ExpressionKind.NewIdentifier(
         id,
         typeArgsMapping.Any()
             ? QsNullable <ImmutableArray <ResolvedType> > .NewValue(typeArgsMapping
                                                                     .Select(argMapping => argMapping.Item3) // This should preserve the order of the type args
                                                                     .ToImmutableArray())
             : QsNullable <ImmutableArray <ResolvedType> > .Null),
     typeArgsMapping,
     resolvedType,
     new InferredExpressionInformation(false, false),
     QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null
 );
        // routines related to "reconstructing" the syntax tree from the saved tokens to do context checks

        /// <summary>
        /// Returns the context object for the given token index, ignoring empty fragments.
        /// </summary>
        private static Context.SyntaxTokenContext GetContext(this CodeFragment.TokenIndex tokenIndex)
        {
            QsNullable <QsFragmentKind> Nullable(CodeFragment?token, bool precedesSelf) =>
            token?.Kind == null
                ? QsNullable <QsFragmentKind> .Null
                : precedesSelf && !token.IncludeInCompilation // fragments that *follow * self need to be re-evaluated first
                    ? QsNullable <QsFragmentKind> .NewValue(QsFragmentKind.InvalidFragment)
                    : QsNullable <QsFragmentKind> .NewValue(token.Kind);

            var fragment    = tokenIndex.GetFragment();
            var headerRange = fragment?.HeaderRange ?? Range.Zero;

            var self     = Nullable(fragment, false);                                   // making sure that errors for fragments excluded from compilation still get logged
            var previous = Nullable(tokenIndex.PreviousOnScope()?.GetFragment(), true); // excludes empty tokens
            var next     = Nullable(tokenIndex.NextOnScope()?.GetFragment(), false);    // excludes empty tokens
            var parents  = tokenIndex.GetNonEmptyParents().Select(tIndex => Nullable(tIndex.GetFragment(), true)).ToArray();

            return(new Context.SyntaxTokenContext(headerRange, self, previous, next, parents));
        }
Пример #16
0
 internal CallableDetails(QsCallable callable)
 {
     this.Callable = callable;
     // ToDo: this may need to be adapted once we support type specializations
     this.Adjoint           = callable.Specializations.FirstOrDefault(spec => spec.Kind == QsSpecializationKind.QsAdjoint);
     this.Controlled        = callable.Specializations.FirstOrDefault(spec => spec.Kind == QsSpecializationKind.QsControlled);
     this.ControlledAdjoint = callable.Specializations.FirstOrDefault(spec => spec.Kind == QsSpecializationKind.QsControlledAdjoint);
     // ToDo: this may need to be per-specialization
     this.TypeParameters = callable.Signature.TypeParameters.Any(param => param.IsValidName)
     ? QsNullable <ImmutableArray <ResolvedType> > .NewValue(callable.Signature.TypeParameters
                                                             .Where(param => param.IsValidName)
                                                             .Select(param =>
                                                                     ResolvedType.New(ResolvedTypeKind.NewTypeParameter(new QsTypeParameter(
                                                                                                                            callable.FullName,
                                                                                                                            ((QsLocalSymbol.ValidName)param).Item,
                                                                                                                            QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null))))
                                                             .ToImmutableArray())
     : QsNullable <ImmutableArray <ResolvedType> > .Null;
 }
                /// <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));
                }
Пример #18
0
            public override QsExpressionKind <TypedExpression, Identifier, ResolvedType> onIdentifier(Identifier sym, QsNullable <ImmutableArray <ResolvedType> > tArgs)
            {
                if (sym is Identifier.GlobalCallable global)
                {
                    ImmutableConcretion applicableParams = CurrentParamTypes
                                                           .Where(kvp => kvp.Key.Item1.Equals(global.Item))
                                                           .ToImmutableDictionary(kvp => kvp.Key, kvp => kvp.Value);

                    // Create a new identifier
                    sym   = GetConcreteIdentifier(global, applicableParams);
                    tArgs = QsNullable <ImmutableArray <ResolvedType> > .Null;

                    // Remove Type Params used from the CurrentParamTypes
                    foreach (var key in applicableParams.Keys)
                    {
                        CurrentParamTypes.Remove(key);
                    }
                }
                else if (sym is Identifier.LocalVariable && tArgs.IsValue && tArgs.Item.Any())
                {
                    throw new ArgumentException($"Local variables cannot have type arguments.");
                }

                return(base.onIdentifier(sym, tArgs));
            }
Пример #19
0
 public override QsNullable <QsLocation> onLocation(QsNullable <QsLocation> loc) =>
 QsNullable <QsLocation> .Null;
Пример #20
0
 public override QsNullable <QsLocation> onLocation(QsNullable <QsLocation> l)
 {
     this._Scope.DeclarationOffset = l.IsValue? l.Item.Offset : null;
     return(l);
 }
Пример #21
0
                public override QsExpressionKind <TypedExpression, Identifier, ResolvedType> OnIdentifier(Identifier sym, QsNullable <ImmutableArray <ResolvedType> > tArgs)
                {
                    if (sym is Identifier.GlobalCallable global)
                    {
                        ImmutableConcretion applicableParams = this.SharedState.CurrentParamTypes
                                                               .Where(kvp => kvp.Key.Item1.Equals(global.Item))
                                                               .ToImmutableDictionary(kvp => kvp.Key, kvp => kvp.Value);

                        // We want to skip over intrinsic callables. They will not be monomorphized.
                        if (!this.SharedState.IntrinsicCallableSet.Contains(global.Item))
                        {
                            // Create a new identifier
                            sym   = this.SharedState.GetConcreteIdentifier(global, applicableParams);
                            tArgs = QsNullable <ImmutableArray <ResolvedType> > .Null;
                        }

                        // Remove Type Params used from the CurrentParamTypes
                        foreach (var key in applicableParams.Keys)
                        {
                            this.SharedState.CurrentParamTypes.Remove(key);
                        }
                    }
                    else if (sym is Identifier.LocalVariable && tArgs.IsValue && tArgs.Item.Any())
                    {
                        throw new ArgumentException($"Local variables cannot have type arguments.");
                    }

                    return(base.OnIdentifier(sym, tArgs));
                }
                public override QsExpressionKind <TypedExpression, Identifier, ResolvedType> OnIdentifier(Identifier sym, QsNullable <ImmutableArray <ResolvedType> > tArgs)
                {
                    if (sym is Identifier.GlobalCallable global)
                    {
                        // We want to skip over intrinsic callables. They will not be monomorphized.
                        if (!this.SharedState.IntrinsicCallableSet.Contains(global.Item))
                        {
                            var combination = new TypeResolutionCombination(this.SharedState.CurrentTypeParamResolutions);
                            this.SharedState.LastCalculatedTypeResolutions = combination.CombinedResolutionDictionary;
                            var typeRes = combination.CombinedResolutionDictionary.FilterByOrigin(global.Item);

                            // Create a new identifier
                            sym   = this.SharedState.GetConcreteIdentifier(global, typeRes);
                            tArgs = QsNullable <ImmutableArray <ResolvedType> > .Null;
                        }
                        this.SharedState.CurrentTypeParamResolutions.Clear();
                    }
                    else if (sym is Identifier.LocalVariable && tArgs.IsValue && tArgs.Item.Any())
                    {
                        throw new ArgumentException($"Local variables cannot have type arguments.");
                    }

                    return(base.OnIdentifier(sym, tArgs));
                }