亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何比較兩個源代碼文件/ ast 樹?

如何比較兩個源代碼文件/ ast 樹?

Go
皈依舞 2021-10-04 17:24:42
我正在使用模板包生成一些源代碼(有沒有更好的方法?)和測試的一部分,我需要檢查輸出是否與預期的源代碼匹配。我嘗試了字符串比較,但由于模板包生成的額外空格/新行而失敗。我也試過format.Source沒有成功。( 失?。┪以噲D解析兩個源的 ast(見下文),但即使除了新行/空格之外,代碼基本相同,但 ast 也不匹配。(失?。┌鱥mport (    "fmt"    "go/parser"    "go/token"    "reflect")func main() {    stub1 := `package main     func myfunc(s string) error {        return nil      }`    stub2 := `package main     func myfunc(s string) error {        return nil    }`    fset := token.NewFileSet()    r1, err := parser.ParseFile(fset, "", stub1, parser.AllErrors)    if err != nil {        panic(err)    }    fset = token.NewFileSet()    r2, err := parser.ParseFile(fset, "", stub2, parser.AllErrors)    if err != nil {        panic(err)    }    if !reflect.DeepEqual(r1, r2) {        fmt.Printf("e %v, r %s, ", r1, r2)    }}
查看完整描述

2 回答

?
有只小跳蛙

TA貢獻1824條經驗 獲得超8個贊

好吧,實現這一點的一種簡單方法是使用go/printer庫,它可以讓您更好地控制輸出格式,并且基本上就像gofmt在源代碼上運行一樣,規范化兩個樹:


package main

import (

    "fmt"

    "go/parser"

    "go/token"

    "go/printer"

    //"reflect"

    "bytes"

)


func main() {

    stub1 := `package main

     func myfunc(s string) error {

        return nil  

    }`

    stub2 := `package main


     func myfunc(s string) error {


        return nil


    }`


    fset1 := token.NewFileSet()

    r1, err := parser.ParseFile(fset1, "", stub1, parser.AllErrors)

    if err != nil {

        panic(err)

    }

    fset2 := token.NewFileSet()

    r2, err := parser.ParseFile(fset1, "", stub2, parser.AllErrors)

    if err != nil {

        panic(err)

    }


    // we create two output buffers for each source tree

    out1 := bytes.NewBuffer(nil)

    out2 := bytes.NewBuffer(nil)


    // we use the same printer config for both

    conf := &printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}


    // print to both outputs

    if err := conf.Fprint(out1, fset1, r1); err != nil {

        panic(err)

    }

    if err := conf.Fprint(out2, fset2, r2); err != nil {

        panic(err)

    }



    // they should be identical!

    if string(out1.Bytes()) != string(out2.Bytes()) {

        panic(string(out1.Bytes()) +"\n" + string(out2.Bytes()))

    } else {

        fmt.Println("A-OKAY!")

    }

}

當然,這段代碼需要重構才能看起來不那么愚蠢。另一種方法是不使用 DeepEqual,而是自己創建一個樹比較函數,跳過不相關的節點。


查看完整回答
反對 回復 2021-10-04
?
紅顏莎娜

TA貢獻1842條經驗 獲得超13個贊

這比我想象的要容易。我所要做的就是刪除空的新行(格式化后)。下面是代碼。


    package main


    import (

        "fmt"

        "go/format"

        "strings"

    )


    func main() {

        a, err := fmtSource(stub1)

        if err != nil {

            panic(err)

        }

        b, err := fmtSource(stub2)

        if err != nil {

            panic(err)

        }

        if a != b {

            fmt.Printf("a %v, \n b %v", a, b)

        }

    }


func fmtSource(source string) (string, error) {

    if !strings.Contains(source, "package") {

        source = "package main\n" + source

    }

    b, err := format.Source([]byte(source))

    if err != nil {

        return "", err

    }

    // cleanLine replaces double space with one space

    cleanLine := func(s string)string{

        sa := strings.Fields(s)

        return strings.Join(sa, " ")

    }

    lines := strings.Split(string(b), "\n")

    n := 0

    var startLn *int

    for _, line := range lines {

        if line != "" {

            line = cleanLine(line)

            lines[n] = line

            if startLn == nil {

                x := n

                startLn = &x

            }

            n++

        }

    }

    lines = lines[*startLn:n]

    // Add final "" entry to get trailing newline from Join.

    if n > 0 && lines[n-1] != "" {

        lines = append(lines, "")

    }



    // Make it pretty 

    b, err = format.Source([]byte(strings.Join(lines, "\n")))

    if err != nil {

        return "", err

    }

    return string(b), nil

}



查看完整回答
反對 回復 2021-10-04
  • 2 回答
  • 0 關注
  • 310 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號