F#编译器服务:获取范围中可见的名称列表

时间:2017-10-27 17:40:44

标签: f# f#-compiler-services

如何通过FSC获取范围内可见的名称列表? 我试过这个:

#r "../../packages/FSharp.Compiler.Service.16.0.2/lib/net45/FSharp.Compiler.Service.dll"
open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler.SourceCodeServices

do 
    let file = "TestFileName.fsx"
    let checker = SourceCodeServices.FSharpChecker.Create()

    let code = 
        """
let testStr = "x"
t
"""
    async{  
        let! options, _ = checker.GetProjectOptionsFromScript(file,code)
        let! parseRes,checkAnser = checker.ParseAndCheckFileInProject(file, 0, code, options)                               
        match checkAnser with
        | FSharpCheckFileAnswer.Succeeded checkRes ->
            let! decls =
                checkRes.GetDeclarationListInfo(
                    Some parseRes,  //ParsedFileResultsOpt
                    3 ,              //line
                    1 ,              //colAtEndOfPartialName
                    "t" ,            //lineText
                    [ "t" ] ,        //qualifyingNames
                    "" ,             //partialName
                    ( fun _ -> [] )  //getAllSymbols: (unit -> AssemblySymbol list) 
                    )

            if Seq.isEmpty decls.Items then 
                printfn "*no declarations found*" 
            else
                decls.Items 
                |> Seq.sortBy (fun d -> d.Name) 
                |> Seq.truncate 10 
                |> Seq.iter (fun d -> printfn "decl: %s" d.Name)

        | _ -> failwithf "*Parsing did not finish... "        
        } |> Async.RunSynchronously

但它只打印“未找到声明”。我不仅会期望testStr,还会期望默认情况下可用的所有其他名称。 我没有在documentation中找到示例。

2 个答案:

答案 0 :(得分:1)

qualifyingNames应该是一个空列表,它用于点分隔的前缀,不包括最后一个(可能是部分的)ident。但是,FCS中没有一个方法可以返回未筛选的范围名称列表,但添加一个名称很容易。

答案 1 :(得分:0)

回答了vasily-kirichenko并使用当前的FCS 17.0.1,我提出了这个解决方案:

#r "../../packages/FSharp.Compiler.Service.17.0.1/lib/net45/FSharp.Compiler.Service.dll"
open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler.SourceCodeServices

do 
    let file = "TestFileName.fsx"
    let checker = SourceCodeServices.FSharpChecker.Create()

    let code = 
        """
let testStr = "x"
testStr.
"""
    async{  
        let! options, _ = checker.GetProjectOptionsFromScript(file,code)
        let! parseRes,checkAnser = checker.ParseAndCheckFileInProject(file, 0, code, options)                               
        match checkAnser with
        | FSharpCheckFileAnswer.Succeeded checkRes ->
            let! decls =
                let partialName = PartialLongName.Empty 6 //use any location before before the dot to get all declarations in scope
                //let partialName = PartialLongName.Empty 7 //use the loacation of the dot (7) to get memebers of string
                checkRes.GetDeclarationListInfo(
                    Some parseRes,  // ParsedFileResultsOpt
                    3 ,             // line                   
                    "testStr." ,    // lineText
                    partialName,    // PartialLongName
                    ( fun _ -> [] ) // getAllSymbols: (unit -> AssemblySymbol list) 
                    )

            if Seq.isEmpty decls.Items then 
                printfn "*no declarations found*" 
            else
                decls.Items 
                |> Seq.sortBy (fun d -> d.Name) 
                |> Seq.truncate 10 
                |> Seq.iter (fun d -> printfn "decl: %s" d.Name)


        | _ -> failwithf "*Parsing did not finish... "        
        } |> Async.RunSynchronously