// 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> /// 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); } }
/// <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> /// 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); }
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)); }
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); }
/// <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)); }
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)); }