Public API to get list of functions call (#2474)

Issue https://github.com/microsoft/Power-Fx/issues/2455.
This commit is contained in:
Anderson Silva 2024-06-12 18:48:10 -05:00 коммит произвёл GitHub
Родитель 5126fb4b11
Коммит c240146620
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
3 изменённых файлов: 103 добавлений и 0 удалений

Просмотреть файл

@ -706,6 +706,11 @@ namespace Microsoft.PowerFx
return summary;
}
public IEnumerable<string> GetFunctionNames()
{
return ListFunctionVisitor.Run(ApplyParse());
}
}
// Internal interface to ensure that Result objects have a common contract

Просмотреть файл

@ -0,0 +1,35 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System.Collections.Generic;
namespace Microsoft.PowerFx.Syntax
{
internal class ListFunctionVisitor : IdentityTexlVisitor
{
// FullName --> Name
// Use Fullname as key because it's unique.
private readonly HashSet<string> _functionNames = new HashSet<string>();
public static IEnumerable<string> Run(ParseResult parse)
{
var visitor = new ListFunctionVisitor();
parse.Root.Accept(visitor);
return visitor._functionNames;
}
public override bool PreVisit(CallNode node)
{
var hasNamespace = node.Head.Namespace.Length > 0;
var name = node.Head.Name;
var fullName = hasNamespace ?
node.Head.Namespace + "." + name :
name;
_functionNames.Add(fullName);
return base.PreVisit(node);
}
}
}

Просмотреть файл

@ -0,0 +1,63 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using Xunit;
namespace Microsoft.PowerFx.Core.Tests
{
public class ListFunctionVisitorTests : PowerFxTest
{
[Theory]
[InlineData("Abs(1)", "Abs")]
[InlineData("Abs(Abs(Abs(Abs(Abs(1)))))", "Abs")]
[InlineData("With({x:Today()}, x+1)", "With,Today")]
[InlineData("SomeNameSpace.Foo() + SomeNameSpace.Bar()", "SomeNameSpace.Foo,SomeNameSpace.Bar")]
[InlineData("true And true", "")]
[InlineData("If(true, Blank(),Error())", "If,Blank,Error")]
public void ListFunctionNamesTest(string expression, string expectedNames)
{
foreach (var textFirst in new bool[] { false, true })
{
if (textFirst)
{
expression = $"={expression}";
}
CheckFunctionNames(textFirst, expression, expectedNames);
}
}
[Theory]
[InlineData("Hello ${Sum(1,Sqrt(2))} world", "Sum,Sqrt")]
[InlineData("3 ' {} ${Upper(3+3)} \" ${Lower($\"{7+7}\")}", "Upper,Lower")]
public void ListFunctionNamesTextFirstTest(string expression, string expectedNames)
{
CheckFunctionNames(true, expression, expectedNames);
}
[Fact]
public void ListFunctionNamesErrorTest()
{
var checkResult = new CheckResult(new Engine());
Assert.Throws<InvalidOperationException>(() => checkResult.GetFunctionNames());
}
private static void CheckFunctionNames(bool textFirst, string expression, string expectedNames)
{
var options = new ParserOptions() { TextFirst = textFirst };
var engine = new Engine();
var check = engine.Check(expression, options);
var checkResult = new CheckResult(engine).SetText(expression, options);
var functionsNames1 = check.GetFunctionNames();
var functionsNames2 = checkResult.GetFunctionNames();
var actualNames1 = string.Join(",", functionsNames1);
var actualNames2 = string.Join(",", functionsNames2);
Assert.Equal(expectedNames, actualNames1);
Assert.Equal(expectedNames, actualNames2);
}
}
}