393 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			393 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package golang
 | 
						|
 | 
						|
import (
 | 
						|
	"go/ast"
 | 
						|
	"go/parser"
 | 
						|
	"go/token"
 | 
						|
 | 
						|
	"github.com/mibk/dupl/syntax"
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	BadNode = iota
 | 
						|
	File
 | 
						|
	ArrayType
 | 
						|
	AssignStmt
 | 
						|
	BasicLit
 | 
						|
	BinaryExpr
 | 
						|
	BlockStmt
 | 
						|
	BranchStmt
 | 
						|
	CallExpr
 | 
						|
	CaseClause
 | 
						|
	ChanType
 | 
						|
	CommClause
 | 
						|
	CompositeLit
 | 
						|
	DeclStmt
 | 
						|
	DeferStmt
 | 
						|
	Ellipsis
 | 
						|
	EmptyStmt
 | 
						|
	ExprStmt
 | 
						|
	Field
 | 
						|
	FieldList
 | 
						|
	ForStmt
 | 
						|
	FuncDecl
 | 
						|
	FuncLit
 | 
						|
	FuncType
 | 
						|
	GenDecl
 | 
						|
	GoStmt
 | 
						|
	Ident
 | 
						|
	IfStmt
 | 
						|
	IncDecStmt
 | 
						|
	IndexExpr
 | 
						|
	InterfaceType
 | 
						|
	KeyValueExpr
 | 
						|
	LabeledStmt
 | 
						|
	MapType
 | 
						|
	ParenExpr
 | 
						|
	RangeStmt
 | 
						|
	ReturnStmt
 | 
						|
	SelectStmt
 | 
						|
	SelectorExpr
 | 
						|
	SendStmt
 | 
						|
	SliceExpr
 | 
						|
	StarExpr
 | 
						|
	StructType
 | 
						|
	SwitchStmt
 | 
						|
	TypeAssertExpr
 | 
						|
	TypeSpec
 | 
						|
	TypeSwitchStmt
 | 
						|
	UnaryExpr
 | 
						|
	ValueSpec
 | 
						|
)
 | 
						|
 | 
						|
// Parse the given file and return uniform syntax tree.
 | 
						|
func Parse(filename string) (*syntax.Node, error) {
 | 
						|
	fset := token.NewFileSet()
 | 
						|
	file, err := parser.ParseFile(fset, filename, nil, 0)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	t := &transformer{
 | 
						|
		fileset:  fset,
 | 
						|
		filename: filename,
 | 
						|
	}
 | 
						|
	return t.trans(file), nil
 | 
						|
}
 | 
						|
 | 
						|
type transformer struct {
 | 
						|
	fileset  *token.FileSet
 | 
						|
	filename string
 | 
						|
}
 | 
						|
 | 
						|
// trans transforms given golang AST to uniform tree structure.
 | 
						|
func (t *transformer) trans(node ast.Node) (o *syntax.Node) {
 | 
						|
	o = syntax.NewNode()
 | 
						|
	o.Filename = t.filename
 | 
						|
	st, end := node.Pos(), node.End()
 | 
						|
	o.Pos, o.End = t.fileset.File(st).Offset(st), t.fileset.File(end).Offset(end)
 | 
						|
 | 
						|
	switch n := node.(type) {
 | 
						|
	case *ast.ArrayType:
 | 
						|
		o.Type = ArrayType
 | 
						|
		if n.Len != nil {
 | 
						|
			o.AddChildren(t.trans(n.Len))
 | 
						|
		}
 | 
						|
		o.AddChildren(t.trans(n.Elt))
 | 
						|
 | 
						|
	case *ast.AssignStmt:
 | 
						|
		o.Type = AssignStmt
 | 
						|
		for _, e := range n.Rhs {
 | 
						|
			o.AddChildren(t.trans(e))
 | 
						|
		}
 | 
						|
 | 
						|
		for _, e := range n.Lhs {
 | 
						|
			o.AddChildren(t.trans(e))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.BasicLit:
 | 
						|
		o.Type = BasicLit
 | 
						|
 | 
						|
	case *ast.BinaryExpr:
 | 
						|
		o.Type = BinaryExpr
 | 
						|
		o.AddChildren(t.trans(n.X), t.trans(n.Y))
 | 
						|
 | 
						|
	case *ast.BlockStmt:
 | 
						|
		o.Type = BlockStmt
 | 
						|
		for _, stmt := range n.List {
 | 
						|
			o.AddChildren(t.trans(stmt))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.BranchStmt:
 | 
						|
		o.Type = BranchStmt
 | 
						|
		if n.Label != nil {
 | 
						|
			o.AddChildren(t.trans(n.Label))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.CallExpr:
 | 
						|
		o.Type = CallExpr
 | 
						|
		o.AddChildren(t.trans(n.Fun))
 | 
						|
		for _, arg := range n.Args {
 | 
						|
			o.AddChildren(t.trans(arg))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.CaseClause:
 | 
						|
		o.Type = CaseClause
 | 
						|
		for _, e := range n.List {
 | 
						|
			o.AddChildren(t.trans(e))
 | 
						|
		}
 | 
						|
		for _, stmt := range n.Body {
 | 
						|
			o.AddChildren(t.trans(stmt))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.ChanType:
 | 
						|
		o.Type = ChanType
 | 
						|
		o.AddChildren(t.trans(n.Value))
 | 
						|
 | 
						|
	case *ast.CommClause:
 | 
						|
		o.Type = CommClause
 | 
						|
		if n.Comm != nil {
 | 
						|
			o.AddChildren(t.trans(n.Comm))
 | 
						|
		}
 | 
						|
		for _, stmt := range n.Body {
 | 
						|
			o.AddChildren(t.trans(stmt))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.CompositeLit:
 | 
						|
		o.Type = CompositeLit
 | 
						|
		if n.Type != nil {
 | 
						|
			o.AddChildren(t.trans(n.Type))
 | 
						|
		}
 | 
						|
		for _, e := range n.Elts {
 | 
						|
			o.AddChildren(t.trans(e))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.DeclStmt:
 | 
						|
		o.Type = DeclStmt
 | 
						|
		o.AddChildren(t.trans(n.Decl))
 | 
						|
 | 
						|
	case *ast.DeferStmt:
 | 
						|
		o.Type = DeferStmt
 | 
						|
		o.AddChildren(t.trans(n.Call))
 | 
						|
 | 
						|
	case *ast.Ellipsis:
 | 
						|
		o.Type = Ellipsis
 | 
						|
		if n.Elt != nil {
 | 
						|
			o.AddChildren(t.trans(n.Elt))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.EmptyStmt:
 | 
						|
		o.Type = EmptyStmt
 | 
						|
 | 
						|
	case *ast.ExprStmt:
 | 
						|
		o.Type = ExprStmt
 | 
						|
		o.AddChildren(t.trans(n.X))
 | 
						|
 | 
						|
	case *ast.Field:
 | 
						|
		o.Type = Field
 | 
						|
		for _, name := range n.Names {
 | 
						|
			o.AddChildren(t.trans(name))
 | 
						|
		}
 | 
						|
		o.AddChildren(t.trans(n.Type))
 | 
						|
 | 
						|
	case *ast.FieldList:
 | 
						|
		o.Type = FieldList
 | 
						|
		for _, field := range n.List {
 | 
						|
			o.AddChildren(t.trans(field))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.File:
 | 
						|
		o.Type = File
 | 
						|
		for _, decl := range n.Decls {
 | 
						|
			if genDecl, ok := decl.(*ast.GenDecl); ok && genDecl.Tok == token.IMPORT {
 | 
						|
				// skip import declarations
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			o.AddChildren(t.trans(decl))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.ForStmt:
 | 
						|
		o.Type = ForStmt
 | 
						|
		if n.Init != nil {
 | 
						|
			o.AddChildren(t.trans(n.Init))
 | 
						|
		}
 | 
						|
		if n.Cond != nil {
 | 
						|
			o.AddChildren(t.trans(n.Cond))
 | 
						|
		}
 | 
						|
		if n.Post != nil {
 | 
						|
			o.AddChildren(t.trans(n.Post))
 | 
						|
		}
 | 
						|
		o.AddChildren(t.trans(n.Body))
 | 
						|
 | 
						|
	case *ast.FuncDecl:
 | 
						|
		o.Type = FuncDecl
 | 
						|
		if n.Recv != nil {
 | 
						|
			o.AddChildren(t.trans(n.Recv))
 | 
						|
		}
 | 
						|
		o.AddChildren(t.trans(n.Name), t.trans(n.Type))
 | 
						|
		if n.Body != nil {
 | 
						|
			o.AddChildren(t.trans(n.Body))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.FuncLit:
 | 
						|
		o.Type = FuncLit
 | 
						|
		o.AddChildren(t.trans(n.Type), t.trans(n.Body))
 | 
						|
 | 
						|
	case *ast.FuncType:
 | 
						|
		o.Type = FuncType
 | 
						|
		o.AddChildren(t.trans(n.Params))
 | 
						|
		if n.Results != nil {
 | 
						|
			o.AddChildren(t.trans(n.Results))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.GenDecl:
 | 
						|
		o.Type = GenDecl
 | 
						|
		for _, spec := range n.Specs {
 | 
						|
			o.AddChildren(t.trans(spec))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.GoStmt:
 | 
						|
		o.Type = GoStmt
 | 
						|
		o.AddChildren(t.trans(n.Call))
 | 
						|
 | 
						|
	case *ast.Ident:
 | 
						|
		o.Type = Ident
 | 
						|
 | 
						|
	case *ast.IfStmt:
 | 
						|
		o.Type = IfStmt
 | 
						|
		if n.Init != nil {
 | 
						|
			o.AddChildren(t.trans(n.Init))
 | 
						|
		}
 | 
						|
		o.AddChildren(t.trans(n.Cond), t.trans(n.Body))
 | 
						|
		if n.Else != nil {
 | 
						|
			o.AddChildren(t.trans(n.Else))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.IncDecStmt:
 | 
						|
		o.Type = IncDecStmt
 | 
						|
		o.AddChildren(t.trans(n.X))
 | 
						|
 | 
						|
	case *ast.IndexExpr:
 | 
						|
		o.Type = IndexExpr
 | 
						|
		o.AddChildren(t.trans(n.X), t.trans(n.Index))
 | 
						|
 | 
						|
	case *ast.InterfaceType:
 | 
						|
		o.Type = InterfaceType
 | 
						|
		o.AddChildren(t.trans(n.Methods))
 | 
						|
 | 
						|
	case *ast.KeyValueExpr:
 | 
						|
		o.Type = KeyValueExpr
 | 
						|
		o.AddChildren(t.trans(n.Key), t.trans(n.Value))
 | 
						|
 | 
						|
	case *ast.LabeledStmt:
 | 
						|
		o.Type = LabeledStmt
 | 
						|
		o.AddChildren(t.trans(n.Label), t.trans(n.Stmt))
 | 
						|
 | 
						|
	case *ast.MapType:
 | 
						|
		o.Type = MapType
 | 
						|
		o.AddChildren(t.trans(n.Key), t.trans(n.Value))
 | 
						|
 | 
						|
	case *ast.ParenExpr:
 | 
						|
		o.Type = ParenExpr
 | 
						|
		o.AddChildren(t.trans(n.X))
 | 
						|
 | 
						|
	case *ast.RangeStmt:
 | 
						|
		o.Type = RangeStmt
 | 
						|
		if n.Key != nil {
 | 
						|
			o.AddChildren(t.trans(n.Key))
 | 
						|
		}
 | 
						|
		if n.Value != nil {
 | 
						|
			o.AddChildren(t.trans(n.Value))
 | 
						|
		}
 | 
						|
		o.AddChildren(t.trans(n.X), t.trans(n.Body))
 | 
						|
 | 
						|
	case *ast.ReturnStmt:
 | 
						|
		o.Type = ReturnStmt
 | 
						|
		for _, e := range n.Results {
 | 
						|
			o.AddChildren(t.trans(e))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.SelectStmt:
 | 
						|
		o.Type = SelectStmt
 | 
						|
		o.AddChildren(t.trans(n.Body))
 | 
						|
 | 
						|
	case *ast.SelectorExpr:
 | 
						|
		o.Type = SelectorExpr
 | 
						|
		o.AddChildren(t.trans(n.X), t.trans(n.Sel))
 | 
						|
 | 
						|
	case *ast.SendStmt:
 | 
						|
		o.Type = SendStmt
 | 
						|
		o.AddChildren(t.trans(n.Chan), t.trans(n.Value))
 | 
						|
 | 
						|
	case *ast.SliceExpr:
 | 
						|
		o.Type = SliceExpr
 | 
						|
		o.AddChildren(t.trans(n.X))
 | 
						|
		if n.Low != nil {
 | 
						|
			o.AddChildren(t.trans(n.Low))
 | 
						|
		}
 | 
						|
		if n.High != nil {
 | 
						|
			o.AddChildren(t.trans(n.High))
 | 
						|
		}
 | 
						|
		if n.Max != nil {
 | 
						|
			o.AddChildren(t.trans(n.Max))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.StarExpr:
 | 
						|
		o.Type = StarExpr
 | 
						|
		o.AddChildren(t.trans(n.X))
 | 
						|
 | 
						|
	case *ast.StructType:
 | 
						|
		o.Type = StructType
 | 
						|
		o.AddChildren(t.trans(n.Fields))
 | 
						|
 | 
						|
	case *ast.SwitchStmt:
 | 
						|
		o.Type = SwitchStmt
 | 
						|
		if n.Init != nil {
 | 
						|
			o.AddChildren(t.trans(n.Init))
 | 
						|
		}
 | 
						|
		if n.Tag != nil {
 | 
						|
			o.AddChildren(t.trans(n.Tag))
 | 
						|
		}
 | 
						|
		o.AddChildren(t.trans(n.Body))
 | 
						|
 | 
						|
	case *ast.TypeAssertExpr:
 | 
						|
		o.Type = TypeAssertExpr
 | 
						|
		o.AddChildren(t.trans(n.X))
 | 
						|
		if n.Type != nil {
 | 
						|
			o.AddChildren(t.trans(n.Type))
 | 
						|
		}
 | 
						|
 | 
						|
	case *ast.TypeSpec:
 | 
						|
		o.Type = TypeSpec
 | 
						|
		o.AddChildren(t.trans(n.Name), t.trans(n.Type))
 | 
						|
 | 
						|
	case *ast.TypeSwitchStmt:
 | 
						|
		o.Type = TypeSwitchStmt
 | 
						|
		if n.Init != nil {
 | 
						|
			o.AddChildren(t.trans(n.Init))
 | 
						|
		}
 | 
						|
		o.AddChildren(t.trans(n.Assign), t.trans(n.Body))
 | 
						|
 | 
						|
	case *ast.UnaryExpr:
 | 
						|
		o.Type = UnaryExpr
 | 
						|
		o.AddChildren(t.trans(n.X))
 | 
						|
 | 
						|
	case *ast.ValueSpec:
 | 
						|
		o.Type = ValueSpec
 | 
						|
		for _, name := range n.Names {
 | 
						|
			o.AddChildren(t.trans(name))
 | 
						|
		}
 | 
						|
		if n.Type != nil {
 | 
						|
			o.AddChildren(t.trans(n.Type))
 | 
						|
		}
 | 
						|
		for _, val := range n.Values {
 | 
						|
			o.AddChildren(t.trans(val))
 | 
						|
		}
 | 
						|
 | 
						|
	default:
 | 
						|
		o.Type = BadNode
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
	return o
 | 
						|
}
 |