public override bool UpdateDataQuerySelects(CallNode callNode, TexlBinding binding, DataSourceToQueryOptionsMap dataSourceToQueryOptionsMap) { Contracts.AssertValue(callNode); Contracts.AssertValue(binding); if (!CheckArgsCount(callNode, binding)) { return(false); } TexlNode[] args = callNode.Args.Children.VerifyValue(); DType dsType = binding.GetType(args[0]); if (dsType.AssociatedDataSources == null) { return(false); } var resultType = binding.GetType(callNode).VerifyValue(); bool retval = false; foreach (var typedName in resultType.GetNames(DPath.Root)) { DType columnType = typedName.Type; string columnName = typedName.Name.Value; Contracts.Assert(dsType.Contains(new DName(columnName))); retval |= dsType.AssociateDataSourcesToSelect(dataSourceToQueryOptionsMap, columnName, columnType, true); } return(retval); }
private bool IsColumnNode(TexlNode node, TexlBinding binding) { Contracts.AssertValue(node); Contracts.AssertValue(binding); return((node.Kind == NodeKind.FirstName) && binding.IsRowScope(node)); }
public override bool SupportsPaging(CallNode callNode, TexlBinding binding) { IList <FirstNameNode> dsNodes; if (!TryGetDataSourceNodes(callNode, binding, out dsNodes)) { return(false); } var args = callNode.Args.Children.VerifyValue(); var count = args.Count(); for (int i = 1; i < count;) { if (!binding.IsPageable(args[i])) { return(false); } // If there are an odd number of args, the last arg also participates. i += 2; if (i == count) { i--; } } return(true); }
public static bool FindCurFuncAndArgs(TexlNode curNode, int cursorPos, TexlBinding binding, out TexlFunction curFunc, out int argIndex, out int argCount, out DType expectedType) { Contracts.AssertValue(curNode); Contracts.AssertValue(binding); if (curNode.Kind == NodeKind.Call) { CallNode callNode = curNode.CastCall(); if (callNode.Token.Span.Lim <= cursorPos && callNode.ParenClose != null && cursorPos <= callNode.ParenClose.Span.Min) { CallInfo info = binding.GetInfo(callNode); if (info.Function != null) { curFunc = info.Function; argIndex = 0; argCount = callNode.Args.Count; expectedType = curFunc.ParamTypes.Length > 0 ? curFunc.ParamTypes[0] : DType.Error; return(true); } } } if (IntellisenseHelper.TryGetInnerMostFunction(curNode, binding, out curFunc, out argIndex, out argCount)) { expectedType = curFunc.ParamTypes.Length > argIndex ? curFunc.ParamTypes[argIndex] : DType.Error; return(true); } expectedType = DType.Error; return(false); }
public override bool CheckInvocation(TexlBinding binding, TexlNode[] args, DType[] argTypes, IErrorContainer errors, out DType returnType, out Dictionary <TexlNode, DType> nodeToCoercedTypeMap) { Contracts.AssertValue(args); Contracts.AssertAllValues(args); Contracts.AssertValue(argTypes); Contracts.Assert(args.Length == argTypes.Length); Contracts.AssertValue(errors); Contracts.Assert(MinArity <= args.Length && args.Length <= MaxArity); bool fValid = base.CheckInvocation(args, argTypes, errors, out returnType, out nodeToCoercedTypeMap); // The argument should be a table of one column. DType argType = argTypes[0]; if (!argType.IsTable) { fValid = false; errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrNeedTable_Func, Name); } else if (argType.GetNames(DPath.Root).Count() != 1) { fValid = false; errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrNeedTableCol_Func, Name); } return(fValid); }
public override bool UpdateDataQuerySelects(CallNode callNode, TexlBinding binding, DataSourceToQueryOptionsMap dataSourceToQueryOptionsMap) { Contracts.AssertValue(callNode); Contracts.AssertValue(binding); // Ignore delegation warning if (!CheckArgsCount(callNode, binding, DocumentErrorSeverity.Moderate)) { return(false); } TexlNode[] args = callNode.Args.Children.VerifyValue(); DType dsType = binding.GetType(args[0]); if (dsType.AssociatedDataSources == null) { return(false); } DType columnType = binding.GetType(args[1]); StrLitNode columnNode = args[1].AsStrLit(); if (columnType.Kind != DKind.String || columnNode == null) { return(false); } string columnName = columnNode.Value; Contracts.Assert(dsType.Contains(new DName(columnName))); return(dsType.AssociateDataSourcesToSelect(dataSourceToQueryOptionsMap, columnName, columnType, true)); }
internal IIntellisenseResult Suggest(string expression, FormulaType parameterType, int cursorPosition) { var formula = new Formula(expression); formula.EnsureParsed(TexlParser.Flags.None); var binding = TexlBinding.Run( new Glue2DocumentBinderGlue(), formula.ParseTree, new SimpleResolver(EnumStore.EnumSymbols), ruleScope: parameterType._type, useThisRecordForRuleScope: false ); var context = new IntellisenseContext(expression, cursorPosition); var intellisense = IntellisenseProvider.GetIntellisense(); var suggestions = intellisense.Suggest(context, binding, formula); if (suggestions.Exception != null) { throw suggestions.Exception; } return(suggestions); }
public bool TryGetValidValue(TexlNode argNode, TexlBinding binding, out IList <FirstNameNode> dsNodes) { Contracts.AssertValue(argNode); Contracts.AssertValue(binding); dsNodes = new List <FirstNameNode>(); FirstNameNode dsNode; switch (argNode.Kind) { case NodeKind.FirstName: if (TryGetDsNode(argNode.AsFirstName(), binding, out dsNode)) { dsNodes.Add(dsNode); } break; case NodeKind.Call: return(TryGetDsNodes(argNode.AsCall(), binding, out dsNodes)); case NodeKind.DottedName: return(TryGetDsNode(argNode.AsDottedName(), binding, out dsNodes)); } return(dsNodes.Count > 0); }
private bool TryGetDsNodes(CallNode callNode, TexlBinding binding, out IList <FirstNameNode> dsInfos) { Contracts.AssertValueOrNull(callNode); Contracts.AssertValue(binding); dsInfos = new List <FirstNameNode>(); if (callNode == null || !(binding.GetType(callNode).IsAggregate)) { return(false); } var callInfo = binding.GetInfo(callNode); if (callInfo == null) { return(false); } var function = callInfo.Function; if (function == null) { return(false); } return(function.TryGetDataSourceNodes(callNode, binding, out dsInfos)); }
public override bool CheckInvocation(TexlBinding binding, TexlNode[] args, DType[] argTypes, IErrorContainer errors, out DType returnType, out Dictionary <TexlNode, DType> nodeToCoercedTypeMap) { Contracts.AssertValue(args); Contracts.AssertAllValues(args); Contracts.AssertValue(argTypes); Contracts.Assert(args.Length == argTypes.Length); Contracts.AssertValue(errors); Contracts.Assert(MinArity <= args.Length && args.Length <= MaxArity); bool fValid = base.CheckInvocation(args, argTypes, errors, out returnType, out nodeToCoercedTypeMap); Contracts.Assert(returnType.IsTable); returnType = argTypes[0]; DType exprType = argTypes[1]; if (!exprType.IsPrimitive || exprType.IsOptionSet) { fValid = false; errors.EnsureError(args[1], TexlStrings.ErrSortWrongType); } if (args.Length == 3 && argTypes[2] != DType.String) { fValid = false; errors.EnsureError(args[2], TexlStrings.ErrSortIncorrectOrder); } return(fValid); }
public BinderNodesMetadataArgTypeVisitor(TexlBinding binding, INameResolver resolver, DType topScope, bool useThisRecordForRuleScope) : base(binding, resolver, topScope, useThisRecordForRuleScope) { Contracts.AssertValue(binding); _txb = binding; }
private bool TryGetDsInfo(CallNode callNode, TexlBinding binding, out IExternalDataSource dsInfo) { Contracts.AssertValueOrNull(callNode); Contracts.AssertValue(binding); dsInfo = null; if (callNode == null || !binding.IsDelegatable(callNode) || !binding.GetType(callNode).IsTable) { return(false); } var callInfo = binding.GetInfo(callNode); if (callInfo == null) { return(false); } var function = callInfo.Function; if (function == null) { return(false); } bool success = function.TryGetDataSource(callNode, binding, out var external); dsInfo = (IExternalDataSource)external; return(success); }
public override bool TryGetDelegationMetadata(CallNode node, TexlBinding binding, out IDelegationMetadata metadata) { Contracts.AssertValue(node); Contracts.AssertValue(binding); metadata = null; // Get metadata if it's an entity. IExpandInfo entityInfo; if (binding.TryGetEntityInfo(node.Args.Children[0], out entityInfo)) { Contracts.AssertValue(entityInfo.ParentDataSource); Contracts.AssertValue(entityInfo.ParentDataSource.DataEntityMetadataProvider); var metadataProvider = entityInfo.ParentDataSource.DataEntityMetadataProvider; IDataEntityMetadata entityMetadata; if (!metadataProvider.TryGetEntityMetadata(entityInfo.Identity, out entityMetadata)) { return(false); } metadata = entityMetadata.DelegationMetadata.VerifyValue(); return(true); } if (!TryGetValidDataSourceForDelegation(node, binding, FunctionDelegationCapability, out var ds)) { return(false); } metadata = ds.DelegationMetadata; return(true); }
public override bool CheckInvocation(TexlBinding binding, TexlNode[] args, DType[] argTypes, IErrorContainer errors, out DType returnType, out Dictionary <TexlNode, DType> nodeToCoercedTypeMap) { Contracts.AssertValue(args); Contracts.AssertAllValues(args); Contracts.AssertValue(argTypes); Contracts.Assert(args.Length == argTypes.Length); Contracts.Assert(args.Length == 1); Contracts.AssertValue(errors); bool fValid = base.CheckInvocation(args, argTypes, errors, out returnType, out nodeToCoercedTypeMap); Contracts.Assert(returnType.IsTable); // Typecheck the input table fValid &= CheckStringColumnType(argTypes[0], args[0], errors, ref nodeToCoercedTypeMap); if (nodeToCoercedTypeMap?.Any() ?? false) { // Now set the coerced type to a table with numeric column type with the same name as in the argument. returnType = nodeToCoercedTypeMap[args[0]]; } else { returnType = argTypes[0]; } return(fValid); }
public override bool CheckInvocation(TexlBinding binding, TexlNode[] args, DType[] argTypes, IErrorContainer errors, out DType returnType, out Dictionary <TexlNode, DType> nodeToCoercedTypeMap) { Contracts.AssertValue(args); Contracts.AssertAllValues(args); Contracts.AssertValue(argTypes); Contracts.Assert(args.Length == argTypes.Length); Contracts.AssertValue(errors); Contracts.Assert(MinArity <= args.Length && args.Length <= MaxArity); bool fValid = base.CheckInvocation(args, argTypes, errors, out returnType, out nodeToCoercedTypeMap); DType type0 = argTypes[0]; DType type1 = argTypes[1]; DType otherType = DType.Invalid; TexlNode otherArg = null; // At least one of the arguments has to be a table. if (type0.IsTable) { // Ensure we have a one-column table of colors. fValid &= CheckColorColumnType(type0, args[0], errors, ref nodeToCoercedTypeMap); // Borrow the return type from the 1st arg. returnType = type0; // Check arg1 below. otherArg = args[1]; otherType = type1; fValid &= CheckOtherType(otherType, otherArg, DType.Number, errors, ref nodeToCoercedTypeMap); Contracts.Assert(returnType.IsTable); Contracts.Assert(!fValid || returnType.IsColumn); } else if (type1.IsTable) { // Ensure we have a one-column table of numerics. fValid &= CheckNumericColumnType(type1, args[1], errors, ref nodeToCoercedTypeMap); // Since the 1st arg is not a table, make a new table return type *[Result:c] returnType = DType.CreateTable(new TypedName(DType.Color, OneColumnTableResultName)); // Check arg0 below. otherArg = args[0]; otherType = type0; fValid &= CheckOtherType(otherType, otherArg, DType.Color, errors, ref nodeToCoercedTypeMap); Contracts.Assert(returnType.IsTable); Contracts.Assert(!fValid || returnType.IsColumn); } else { Contracts.Assert(returnType.IsTable); errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrTypeError_Ex1_Ex2_Found, TableKindString, DType.Color.GetKindString(), type0.GetKindString()); errors.EnsureError(DocumentErrorSeverity.Severe, args[1], TexlStrings.ErrTypeError_Ex1_Ex2_Found, TableKindString, DType.Number.GetKindString(), type1.GetKindString()); // Both args are invalid. No need to continue. return(false); } return(fValid); }
private bool TryGetDsNode(FirstNameNode firstName, TexlBinding binding, out FirstNameNode dsNode) { Contracts.AssertValueOrNull(firstName); Contracts.AssertValue(binding); dsNode = null; if (firstName == null || !binding.GetType(firstName).IsTable) { return(false); } var firstNameInfo = binding.GetInfo(firstName); if (firstNameInfo == null || firstNameInfo.Kind != BindKind.Data) { return(false); } if (binding.EntityScope == null || !binding.EntityScope.TryGetEntity(firstNameInfo.Name, out IExternalDataSource _)) { return(false); } dsNode = firstName; return(true); }
public override bool IsServerDelegatable(CallNode callNode, TexlBinding binding) { Contracts.AssertValue(callNode); Contracts.AssertValue(binding); IExternalDataSource dataSource = null; // Only delegate First, not last if (!_isFirst) { return(false); } // If has top capability (e.g. Dataverse) if (TryGetValidDataSourceForDelegation(callNode, binding, FunctionDelegationCapability, out dataSource)) { return(true); } // If is a client-side pageable data source if (TryGetDataSource(callNode, binding, out dataSource) && dataSource.Kind == DataSourceKind.Connected && dataSource.IsPageable) { return(true); } if (dataSource != null && dataSource.IsDelegatable) { binding.ErrorContainer.EnsureError(DocumentErrorSeverity.Warning, callNode, TexlStrings.OpNotSupportedByServiceSuggestionMessage_OpNotSupportedByService, Name); } return(false); }
private bool TryGetValidSortOrder(TexlNode argNode, TexlBinding binding, out string validatedOrder) { Contracts.AssertValue(argNode); Contracts.AssertValue(binding); validatedOrder = ""; if (binding.ErrorContainer.HasErrors(argNode)) { return(false); } switch (argNode.Kind) { case NodeKind.FirstName: return(TryGetValidSortOrderNode(argNode.AsFirstName(), binding, out validatedOrder)); case NodeKind.DottedName: return(TryGetValidSortOrderNode(argNode.AsDottedName(), binding, out validatedOrder)); case NodeKind.StrLit: return(TryGetValidSortOrderNode(argNode.AsStrLit(), out validatedOrder)); default: TrackingProvider.Instance.AddSuggestionMessage("Invalid sortorder node type", argNode, binding); return(false); } }
private bool TryGetEntityInfo(CallNode callNode, TexlBinding binding, out IExpandInfo entityInfo) { Contracts.AssertValueOrNull(callNode); Contracts.AssertValue(binding); entityInfo = null; if (callNode == null || !binding.GetType(callNode).IsTable) { return(false); } var callInfo = binding.GetInfo(callNode); if (callInfo == null) { return(false); } var function = callInfo.Function; if (function == null) { return(false); } return(function.TryGetEntityInfo(callNode, binding, out entityInfo)); }
public bool IsValidCallNode(CallNode node, TexlBinding binding, OperationCapabilityMetadata metadata) { Contracts.AssertValue(node); Contracts.AssertValue(binding); Contracts.AssertValue(metadata); if (!IsValidNode(node, binding)) { SuggestDelegationHint(node, binding); return(false); } // If the node is not row scoped and it's valid then it can be delegated. var isRowScoped = binding.IsRowScope(node); if (!isRowScoped) { return(true); } CallInfo callInfo = binding.GetInfo(node); if (callInfo?.Function != null && ((TexlFunction)callInfo.Function).IsRowScopedServerDelegatable(node, binding, metadata)) { return(true); } var telemetryMessage = string.Format("Kind:{0}, isRowScoped:{1}", node.Kind, isRowScoped); SuggestDelegationHintAndAddTelemetryMessage(node, binding, telemetryMessage); TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.UndelegatableFunction, node, binding, _function, DelegationTelemetryInfo.CreateUndelegatableFunctionTelemetryInfo((TexlFunction)callInfo?.Function)); return(false); }
public override bool CheckInvocation(TexlBinding binding, TexlNode[] args, DType[] argTypes, IErrorContainer errors, out DType returnType, out Dictionary <TexlNode, DType> nodeToCoercedTypeMap) { Contracts.AssertValue(args); Contracts.AssertValue(argTypes); Contracts.Assert(args.Length == argTypes.Length); Contracts.Assert(args.Length >= 2); Contracts.AssertValue(errors); nodeToCoercedTypeMap = null; int count = args.Length; bool hasTableArg = false; bool fArgsValid = true; // Type check the args // If any one input argument is of table type, then the returnType will be table type. for (int i = 0; i < count; i++) { bool isTable; fArgsValid &= CheckParamIsTypeOrSingleColumnTable(DType.String, args[i], argTypes[i], errors, out isTable, ref nodeToCoercedTypeMap); hasTableArg |= isTable; } returnType = hasTableArg ? DType.CreateTable(new TypedName(DType.String, OneColumnTableResultName)) : DType.String; return(fArgsValid); }
protected void SuggestDelegationHintAndAddTelemetryMessage(TexlNode node, TexlBinding binding, string telemetryMessage, ErrorResourceKey?suggestionKey = null, params object[] args) { Contracts.Assert(suggestionKey == null || suggestionKey?.Key != string.Empty); SuggestDelegationHint(node, binding, suggestionKey, args); AddSuggestionMessageToTelemetry(telemetryMessage, node, binding); }
public static bool TryGetExpectedTypeForBinaryOp(TexlBinding binding, TexlNode curNode, int cursorPos, out DType expectedType) { // If we are in a binary operation context, the expected type is relative to the binary operation. if (curNode != null && curNode.Parent != null && curNode.Parent.Kind == NodeKind.BinaryOp) { BinaryOpNode binaryOpNode = curNode.Parent.CastBinaryOp(); DType coercedType; TexlNode expectedNode = null; if (cursorPos < binaryOpNode.Token.Span.Min) { // Cursor is before the binary operator. Expected type is equal to the type of right side. expectedNode = binaryOpNode.Right; } else if (cursorPos > binaryOpNode.Token.Span.Lim) { // Cursor is after the binary operator. Expected type is equal to the type of left side. expectedNode = binaryOpNode.Left; } if (expectedNode != null) { expectedType = binding.TryGetCoercedType(expectedNode, out coercedType) ? coercedType : binding.GetType(expectedNode); return(true); } } expectedType = DType.Error; return(false); }
protected void SuggestDelegationHint(TexlNode node, TexlBinding binding) { Contracts.AssertValue(node); Contracts.AssertValue(binding); SuggestDelegationHint(node, binding, null); }
public override bool CheckInvocation(TexlBinding binding, TexlNode[] args, DType[] argTypes, IErrorContainer errors, out DType returnType, out Dictionary <TexlNode, DType> nodeToCoercedTypeMap) { Contracts.AssertValue(args); Contracts.AssertAllValues(args); Contracts.AssertValue(argTypes); Contracts.Assert(args.Length == argTypes.Length); Contracts.AssertValue(errors); bool fArgsValid = base.CheckInvocation(args, argTypes, errors, out returnType, out nodeToCoercedTypeMap); if (argTypes[1].IsRecord) { returnType = argTypes[1].ToTable(); } else if (argTypes[1].IsPrimitive || argTypes[1].IsTable) { returnType = DType.CreateTable(new TypedName(argTypes[1], ColumnName_Value)); } else { returnType = DType.Error; fArgsValid = false; } return(fArgsValid); }
private bool IsValidRowScopedDottedNameNode(DottedNameNode node, TexlBinding binding, OperationCapabilityMetadata metadata, out bool isRowScopedDelegationExempted) { Contracts.AssertValue(node); Contracts.AssertValue(binding); isRowScopedDelegationExempted = false; if (node.Left.Kind == NodeKind.FirstName && binding.IsDelegationExempted(node.Left as FirstNameNode) && binding.IsLambdaScoped(node.Left as FirstNameNode)) { isRowScopedDelegationExempted = true; return(true); } if (node.Left.Kind == NodeKind.DottedName) { return(IsValidRowScopedDottedNameNode(node.Left.AsDottedName(), binding, metadata, out isRowScopedDelegationExempted)); } if (node.Left.Kind == NodeKind.Call && binding.GetInfo(node.Left as CallNode).Function is AsTypeFunction) { return(IsValidCallNode(node.Left as CallNode, binding, metadata)); } // We only allow dotted or firstname node on LHS for now, with exception of AsType. return(node.Left.Kind == NodeKind.FirstName); }
private bool TryGetDSNodes(TexlBinding binding, TexlNode[] args, out IList <FirstNameNode> dsNodes) { dsNodes = new List <FirstNameNode>(); var count = args.Count(); for (int i = 1; i < count;) { TexlNode nodeArg = args[i]; IList <FirstNameNode> tmpDsNodes; if (ArgValidators.DataSourceArgNodeValidator.TryGetValidValue(nodeArg, binding, out tmpDsNodes)) { foreach (var node in tmpDsNodes) { dsNodes.Add(node); } } // If there are an odd number of args, the last arg also participates. i += 2; if (i == count) { i--; } } return(dsNodes.Any()); }
public IntellisenseData(IIntellisenseContext context, DType expectedType, TexlBinding binding, TexlFunction curFunc, TexlNode curNode, int argIndex, int argCount, IsValidSuggestion isValidSuggestionFunc, IList <DType> missingTypes, List <CommentToken> comments) { Contracts.AssertValue(context); Contracts.AssertValid(expectedType); Contracts.AssertValue(binding); Contracts.AssertValue(curNode); Contracts.Assert(0 <= context.CursorPosition && context.CursorPosition <= context.InputText.Length); Contracts.AssertValue(isValidSuggestionFunc); Contracts.AssertValueOrNull(missingTypes); Contracts.AssertValueOrNull(comments); _expectedType = expectedType; _suggestions = new IntellisenseSuggestionList(); _substringSuggestions = new IntellisenseSuggestionList(); _binding = binding; _comments = comments; _curFunc = curFunc; _curNode = curNode; _script = context.InputText; _cursorPos = context.CursorPosition; _argIndex = argIndex; _argCount = argCount; _isValidSuggestionFunc = isValidSuggestionFunc; _matchingStr = string.Empty; _matchingLength = 0; _replacementStartIndex = context.CursorPosition; _missingTypes = missingTypes; BoundTo = string.Empty; _cleanupHandlers = new List <ISpecialCaseHandler>(); }
// Does the CallNode have an argument/expression that is async without side effects // Check 1..N arguments to identify if there is an AsyncWithNoSideEffects expression. public bool HasArgumentAsyncWithNoSideEffects(TexlBinding binding, int firstArgument = 0) { // check if the CallNode has any async arguments. // some functions don't need to look at all // arguments (e.g. Filter and LookUp where the first arg is a data source) return(Args.Children.Skip(firstArgument).Any(x => binding.IsAsyncWithNoSideEffects(x))); }
public override bool CheckInvocation(TexlBinding binding, TexlNode[] args, DType[] argTypes, IErrorContainer errors, out DType returnType, out Dictionary <TexlNode, DType> nodeToCoercedTypeMap) { Contracts.AssertValue(binding); Contracts.AssertValue(args); Contracts.AssertAllValues(args); Contracts.AssertValue(argTypes); Contracts.Assert(args.Length == argTypes.Length); Contracts.AssertValue(errors); // Base call yields unknown return type, so we set it accordingly below bool fArgsValid = base.CheckInvocation(args, argTypes, errors, out returnType, out nodeToCoercedTypeMap); // Return type determined by second argument (function) // Since CheckInvocation is called on partial functions, return type should be error when a second argument is undefined if (argTypes.Length >= 2) { returnType = argTypes[1]; } else { returnType = DType.Error; } return(fArgsValid); }