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); }
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 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); }
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 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); }
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)); }
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); }
// Gets the inner most function and the current arg index from the current node, if any. // If there is no inner most function, current arg index will be -1 // and argument count will be -1. internal static bool TryGetInnerMostFunction(TexlNode nodeCur, TexlBinding bind, out TexlFunction funcCur, out int iarg, out int carg) { Contracts.AssertValue(nodeCur); Contracts.AssertValue(bind); TexlNode nodeParent = nodeCur.Parent; TexlNode nodeCallArg = nodeCur; CallNode callNode = null; while (nodeParent != null) { if (nodeParent.Kind == NodeKind.Call) { callNode = nodeParent.AsCall(); break; } // The last node before a call's list node is the call arg. if (nodeParent.Kind != NodeKind.List) { nodeCallArg = nodeParent; } nodeParent = nodeParent.Parent; } if (callNode == null) { iarg = -1; carg = -1; funcCur = null; return(false); } Contracts.AssertValue(nodeCallArg); CallInfo info = bind.GetInfo(callNode); if (info.Function != null) { carg = callNode.Args.Count; for (iarg = 0; iarg < carg; iarg++) { if (callNode.Args.Children[iarg] == nodeCallArg) { break; } } Contracts.Assert(iarg < carg); funcCur = (TexlFunction)info.Function; return(true); } iarg = -1; carg = -1; funcCur = null; return(false); }
private bool IsUserCallNodeDelegable(TexlNode node, TexlBinding binding) { if ((node is DottedNameNode) && (node.AsDottedName().Left is CallNode) && (binding.GetInfo(node.AsDottedName().Left.AsCall()).Function is ICustomDelegationFunction customDelFunc) && customDelFunc.IsUserCallNodeDelegable()) { return(true); } return(false); }
// Verifies if provided column node supports delegation. protected bool IsDelegatableColumnNode(FirstNameNode node, TexlBinding binding, IOpDelegationStrategy opDelStrategy, DelegationCapability capability) { Contracts.AssertValue(node); Contracts.AssertValue(binding); Contracts.AssertValueOrNull(opDelStrategy); Contracts.Assert(binding.IsRowScope(node)); FirstNameInfo firstNameInfo = binding.GetInfo(node.AsFirstName()); if (firstNameInfo == null) { return(false); } IDelegationMetadata metadata = GetCapabilityMetadata(firstNameInfo); // This means that this row scoped field is from some parent scope which is non-delegatable. That should deny delegation at that point. // For this scope, this means that value will be provided from some other source. // For example, AddColumns(CDS, "Column1", LookUp(CDS1, Name in FirstName)) // CDS - *[Name:s], CDS1 - *[FirstName:s] if (metadata == null) { return(true); } var columnName = firstNameInfo.Name; Contracts.AssertValid(columnName); var columnPath = DPath.Root.Append(columnName); if (!metadata.FilterDelegationMetadata.IsDelegationSupportedByColumn(columnPath, capability)) { var safeColumnName = CharacterUtils.MakeSafeForFormatString(columnName.Value); var message = string.Format(StringResources.Get(TexlStrings.OpNotSupportedByColumnSuggestionMessage_OpNotSupportedByColumn), safeColumnName); SuggestDelegationHintAndAddTelemetryMessage(node, binding, message, TexlStrings.OpNotSupportedByColumnSuggestionMessage_OpNotSupportedByColumn, safeColumnName); TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.NoDelSupportByColumn, node, binding, _function, DelegationTelemetryInfo.CreateNoDelSupportByColumnTelemetryInfo(firstNameInfo)); return(false); } // If there is any operator applied on this node then check if column supports operation. if (opDelStrategy != null && !opDelStrategy.IsOpSupportedByColumn(metadata.FilterDelegationMetadata, node.AsFirstName(), columnPath, binding)) { return(false); } return(true); }
public static DelegationTelemetryInfo CreateImpureNodeTelemetryInfo(TexlNode node, TexlBinding binding = null) { Contracts.AssertValue(node); Contracts.AssertValueOrNull(binding); switch (node.Kind) { case NodeKind.Call: var callNode = node.AsCall(); var funcName = binding?.GetInfo(callNode)?.Function?.Name ?? string.Empty; return(new DelegationTelemetryInfo(funcName)); default: return(new DelegationTelemetryInfo(node.ToString())); } }
protected bool IsValidNode(TexlNode node, TexlBinding binding) { Contracts.AssertValue(node); Contracts.AssertValue(binding); bool isAsync = binding.IsAsync(node); bool isPure = binding.IsPure(node); if (node is DottedNameNode && ((binding.GetType(node.AsDottedName().Left).Kind == DKind.OptionSet && binding.GetType(node).Kind == DKind.OptionSetValue) || (binding.GetType(node.AsDottedName().Left).Kind == DKind.View && binding.GetType(node).Kind == DKind.ViewValue))) { // OptionSet and View Access are delegable despite being async return(true); } if (node is CallNode && (binding.IsBlockScopedConstant(node) || (binding.GetInfo(node as CallNode).Function is AsTypeFunction))) { // AsType is delegable despite being async return(true); } // Async predicates and impure nodes are not supported. // Let CallNodes for User() be marked as being Valid to allow // expressions with User() calls to be delegated if (!(IsUserCallNodeDelegable(node, binding)) && (isAsync || !isPure)) { var telemetryMessage = string.Format("Kind:{0}, isAsync:{1}, isPure:{2}", node.Kind, isAsync, isPure); SuggestDelegationHintAndAddTelemetryMessage(node, binding, telemetryMessage); if (isAsync) { TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.AsyncPredicate, node, binding, _function); } if (!isPure) { TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.ImpureNode, node, binding, _function, DelegationTelemetryInfo.CreateImpureNodeTelemetryInfo(node, binding)); } return(false); } return(true); }
public override void Visit(FirstNameNode node) { FirstNameInfo info = _binding.GetInfo(node); var name = node.Ident.Name.Value; // Only include dependencies from the incoming context (Fields) // defined at the top level (NestDst==1) if ((info.NestDst == 1 && info.Kind == BindKind.LambdaField) || (info.Kind == BindKind.ScopeVariable) || (info.Kind == BindKind.PowerFxResolvedObject)) { _vars.Add(name); } base.Visit(node); }
internal static bool TryConvertNodeToDPath(TexlBinding binding, DottedNameNode node, out DPath path) { Contracts.AssertValue(binding); Contracts.AssertValue(node); if (node.Left is DottedNameNode && TryConvertNodeToDPath(binding, node.Left as DottedNameNode, out path)) { DName rightNodeName = node.Right.Name; string possibleRename; if (binding.TryGetReplacedIdentName(node.Right, out possibleRename)) { rightNodeName = new DName(possibleRename); } path = path.Append(rightNodeName); return(true); } else if (node.Left is FirstNameNode firstName) { if (binding.GetInfo(firstName).Kind == BindKind.LambdaFullRecord) { DName rightNodeName = node.Right.Name; if (binding.TryGetReplacedIdentName(node.Right, out string rename)) { rightNodeName = new DName(rename); } path = DPath.Root.Append(rightNodeName); return(true); } // Check if the access was renamed: DName leftNodeName = firstName.Ident.Name; string possibleRename; if (binding.TryGetReplacedIdentName(firstName.Ident, out possibleRename)) { leftNodeName = new DName(possibleRename); } path = DPath.Root.Append(leftNodeName).Append(node.Right.Name); return(true); } path = DPath.Root; return(false); }
public override LazyList <string> Visit(FirstNameNode node, Precedence parentPrecedence) { Contracts.AssertValue(node); var info = _binding?.GetInfo(node); if (info != null && info.Kind != BindKind.Unknown) { return(LazyList <string> .Of($"#${Enum.GetName(typeof(BindKind), info.Kind)}$#")); } if (node.Ident.AtToken == null) { return(LazyList <string> .Of("#$firstname$#")); } else { return(LazyList <string> .Of("#$disambiguation$#")); } }
private static bool TryGetLocalScopeInfo(TexlNode node, TexlBinding binding, out ScopedNameLookupInfo info) { Contracts.AssertValue(node); Contracts.AssertValue(binding); if (node.Kind == NodeKind.FirstName) { FirstNameNode curNode = node.CastFirstName(); var firstNameInfo = binding.GetInfo(curNode); if (firstNameInfo.Kind == BindKind.ScopeArgument) { info = (ScopedNameLookupInfo)firstNameInfo.Data; return(true); } } info = new ScopedNameLookupInfo(); return(false); }
private bool VerifyFirstNameNodeIsValidSortOrderEnum(FirstNameNode node, TexlBinding binding) { Contracts.AssertValue(node); Contracts.AssertValue(binding); var firstNameInfo = binding.GetInfo(node); if (firstNameInfo == null || firstNameInfo.Kind != BindKind.Enum) { return(false); } if (!binding.NameResolver.TryLookupEnum(new DName(LanguageConstants.SortOrderEnumStringInvariant), out var lookupInfo)) { return(false); } DType type = binding.GetType(node); return(type == lookupInfo.Type); }
private bool TryGetValidSortOrderNode(FirstNameNode node, TexlBinding binding, out string sortOrder) { Contracts.AssertValue(node); Contracts.AssertValue(binding); sortOrder = ""; var info = binding.GetInfo(node).VerifyValue(); if (info.Kind != BindKind.Enum) { return(false); } string order = info.Data as string; if (order == null) { return(false); } return(IsValidOrderString(order, out sortOrder)); }
private static bool TryGetNamespaceFunctions(TexlNode node, TexlBinding binding, out IEnumerable <TexlFunction> functions) { Contracts.AssertValue(node); Contracts.AssertValue(binding); FirstNameNode curNode = node.AsFirstName(); if (curNode == null) { functions = EmptyEnumerator <TexlFunction> .Instance; return(false); } FirstNameInfo firstNameInfo = binding.GetInfo(curNode).VerifyValue(); Contracts.AssertValid(firstNameInfo.Name); DPath namespacePath = new DPath().Append(firstNameInfo.Name); functions = binding.NameResolver.LookupFunctionsInNamespace(namespacePath); return(functions.Any()); }
private static bool TryGetEnumInfo(IntellisenseData.IntellisenseData data, TexlNode node, TexlBinding binding, out EnumSymbol enumSymbol) { Contracts.AssertValue(node); Contracts.AssertValue(binding); FirstNameNode curNode = node.AsFirstName(); if (curNode == null) { enumSymbol = null; return(false); } FirstNameInfo firstNameInfo = binding.GetInfo(curNode).VerifyValue(); if (firstNameInfo.Kind != BindKind.Enum) { enumSymbol = null; return(false); } return(data.TryGetEnumSymbol(firstNameInfo.Name, binding, out enumSymbol)); }
public bool CheckForFullyQualifiedFieldAccess(bool isRHSDelegableTable, BinaryOpNode binaryOpNode, TexlBinding binding, TexlNode node, ref DName columnName, ref FirstNameInfo info) { Contracts.AssertValue(binaryOpNode); Contracts.AssertValue(binding); Contracts.AssertValue(node); // Check for fully qualified field access var firstNameNode = isRHSDelegableTable ? binaryOpNode.Left?.AsFirstName() : binaryOpNode.Right?.AsFirstName(); var dottedNameNode = isRHSDelegableTable ? binaryOpNode.Left?.AsDottedName() : binaryOpNode.Right?.AsDottedName(); if (dottedNameNode != null && dottedNameNode.Left is FirstNameNode possibleScopeAccess && (info = binding.GetInfo(possibleScopeAccess))?.Kind == BindKind.LambdaFullRecord) { columnName = dottedNameNode.Right.Name; }
public override bool IsServerDelegatable(CallNode callNode, TexlBinding binding) { Contracts.AssertValue(callNode); Contracts.AssertValue(binding); if (!CheckArgsCount(callNode, binding)) { return(false); } SortOpMetadata metadata = null; IDelegationMetadata delegationMetadata = null; IExternalDataSource dataSource; if (TryGetEntityMetadata(callNode, binding, out delegationMetadata)) { if (!binding.Document.Properties.EnabledFeatures.IsEnhancedDelegationEnabled || !TryGetValidDataSourceForDelegation(callNode, binding, DelegationCapability.ArrayLookup, out _)) { SuggestDelegationHint(callNode, binding); return(false); } metadata = delegationMetadata.SortDelegationMetadata.VerifyValue(); } else { if (!TryGetValidDataSourceForDelegation(callNode, binding, DelegationCapability.Sort, out dataSource)) { return(false); } metadata = dataSource.DelegationMetadata.SortDelegationMetadata; } TexlNode[] args = callNode.Args.Children.VerifyValue(); TexlNode arg1 = args[1].VerifyValue(); // For now, we are only supporting delegation for Sort operations where second argument is column name. // For example, Sort(CDS, Value) FirstNameNode firstName = arg1.AsFirstName(); if (firstName == null) { SuggestDelegationHint(arg1, binding); AddSuggestionMessageToTelemetry("Arg1 is not a FirstName node.", arg1, binding); DelegationTrackerCore.SetDelegationTrackerStatus(DelegationStatus.UnSupportedSortArg, arg1, binding, this, DelegationTelemetryInfo.CreateEmptyDelegationTelemetryInfo()); return(false); } FirstNameInfo firstNameInfo = binding.GetInfo(firstName); if (firstNameInfo == null) { return(false); } DPath columnName = DPath.Root.Append(firstNameInfo.Name); if (!metadata.IsDelegationSupportedByColumn(columnName, DelegationCapability.Sort)) { SuggestDelegationHint(firstName, binding); DelegationTrackerCore.SetDelegationTrackerStatus(DelegationStatus.NoDelSupportByColumn, firstName, binding, this, DelegationTelemetryInfo.CreateNoDelSupportByColumnTelemetryInfo(firstNameInfo)); return(false); } const string defaultSortOrder = LanguageConstants.AscendingSortOrderString; int cargs = args.Count(); // Verify that the third argument (If present) is an Enum or string literal. if (cargs < 3 && IsSortOrderSuppportedByColumn(callNode, binding, defaultSortOrder, metadata, columnName)) { return(true); } // TASK: 6237100 - Binder: Propagate errors in subtree of the callnode to the call node itself // Only FirstName, DottedName and StrLit non-async nodes are supported for arg2. TexlNode arg2 = args[2].VerifyValue(); if (!IsValidSortOrderNode(arg2, metadata, binding, columnName)) { SuggestDelegationHint(arg2, binding); return(false); } return(true); }
public override void PostVisit(DottedNameNode node) { Contracts.AssertValue(node); DType lhsType = _txb.GetType(node.Left); DType typeRhs = DType.Invalid; DName nameRhs = node.Right.Name; FirstNameInfo firstNameInfo; FirstNameNode firstNameNode; IExternalTableMetadata tableMetadata; DType nodeType = DType.Unknown; if (node.Left.Kind != NodeKind.FirstName && node.Left.Kind != NodeKind.DottedName) { SetDottedNameError(node, TexlStrings.ErrInvalidName); return; } nameRhs = GetLogicalNodeNameAndUpdateDisplayNames(lhsType, node.Right); if (!lhsType.TryGetType(nameRhs, out typeRhs)) { SetDottedNameError(node, TexlStrings.ErrInvalidName); return; } // There are two cases: // 1. RHS could be an option set. // 2. RHS could be a data entity. // 3. RHS could be a column name and LHS would be a datasource. if (typeRhs.IsOptionSet) { nodeType = typeRhs; } else if (typeRhs.IsExpandEntity) { var entityInfo = typeRhs.ExpandInfo; Contracts.AssertValue(entityInfo); string entityPath = string.Empty; if (lhsType.HasExpandInfo) { entityPath = lhsType.ExpandInfo.ExpandPath.ToString(); } DType expandedEntityType = GetExpandedEntityType(typeRhs, entityPath); var parentDataSource = entityInfo.ParentDataSource; var metadata = new DataTableMetadata(parentDataSource.Name, parentDataSource.Name); nodeType = DType.CreateMetadataType(new DataColumnMetadata(typeRhs.ExpandInfo.Name, expandedEntityType, metadata)); } else if ((firstNameNode = node.Left.AsFirstName()) != null && (firstNameInfo = _txb.GetInfo(firstNameNode)) != null) { var tabularDataSourceInfo = firstNameInfo.Data as IExternalTabularDataSource; tableMetadata = tabularDataSourceInfo?.TableMetadata; if (tableMetadata == null || !tableMetadata.TryGetColumn(nameRhs.Value, out var columnMetadata) || !IsColumnMultiChoice(columnMetadata)) { SetDottedNameError(node, TexlStrings.ErrInvalidName); return; } var metadata = new DataTableMetadata(tabularDataSourceInfo.Name, tableMetadata.DisplayName); nodeType = DType.CreateMetadataType(new DataColumnMetadata(columnMetadata, metadata)); } else { SetDottedNameError(node, TexlStrings.ErrInvalidName); return; } Contracts.AssertValid(nodeType); _txb.SetType(node, nodeType); _txb.SetInfo(node, new DottedNameInfo(node)); }