// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package ast

func (desc *Description) Clone() *Description {
	desc1 := &Description{}
	for _, n := range desc.Nodes {
		desc1.Nodes = append(desc1.Nodes, n.Clone())
	}
	return desc1
}

func (n *NewLine) Clone() Node {
	return &NewLine{
		Pos: n.Pos,
	}
}

func (n *Comment) Clone() Node {
	return &Comment{
		Pos:  n.Pos,
		Text: n.Text,
	}
}

func (n *Include) Clone() Node {
	return &Include{
		Pos:  n.Pos,
		File: n.File.Clone().(*String),
	}
}

func (n *Incdir) Clone() Node {
	return &Incdir{
		Pos: n.Pos,
		Dir: n.Dir.Clone().(*String),
	}
}

func (n *Define) Clone() Node {
	return &Define{
		Pos:   n.Pos,
		Name:  n.Name.Clone().(*Ident),
		Value: n.Value.Clone().(*Int),
	}
}

func (n *Resource) Clone() Node {
	return &Resource{
		Pos:    n.Pos,
		Name:   n.Name.Clone().(*Ident),
		Base:   n.Base.Clone().(*Type),
		Values: cloneInts(n.Values),
	}
}

func (n *TypeDef) Clone() Node {
	var args []*Ident
	for _, v := range n.Args {
		args = append(args, v.Clone().(*Ident))
	}
	var typ *Type
	if n.Type != nil {
		typ = n.Type.Clone().(*Type)
	}
	var str *Struct
	if n.Struct != nil {
		str = n.Struct.Clone().(*Struct)
	}
	return &TypeDef{
		Pos:    n.Pos,
		Name:   n.Name.Clone().(*Ident),
		Args:   args,
		Type:   typ,
		Struct: str,
	}
}

func (n *Call) Clone() Node {
	var ret *Type
	if n.Ret != nil {
		ret = n.Ret.Clone().(*Type)
	}
	return &Call{
		Pos:      n.Pos,
		Name:     n.Name.Clone().(*Ident),
		CallName: n.CallName,
		NR:       n.NR,
		Args:     cloneFields(n.Args),
		Ret:      ret,
	}
}

func (n *Struct) Clone() Node {
	return &Struct{
		Pos:      n.Pos,
		Name:     n.Name.Clone().(*Ident),
		Fields:   cloneFields(n.Fields),
		Attrs:    cloneTypes(n.Attrs),
		Comments: cloneComments(n.Comments),
		IsUnion:  n.IsUnion,
	}
}

func (n *IntFlags) Clone() Node {
	return &IntFlags{
		Pos:    n.Pos,
		Name:   n.Name.Clone().(*Ident),
		Values: cloneInts(n.Values),
	}
}

func (n *StrFlags) Clone() Node {
	var values []*String
	for _, v := range n.Values {
		values = append(values, v.Clone().(*String))
	}
	return &StrFlags{
		Pos:    n.Pos,
		Name:   n.Name.Clone().(*Ident),
		Values: values,
	}
}

func (n *Ident) Clone() Node {
	return &Ident{
		Pos:  n.Pos,
		Name: n.Name,
	}
}

func (n *String) Clone() Node {
	return &String{
		Pos:   n.Pos,
		Value: n.Value,
	}
}

func (n *Int) Clone() Node {
	return &Int{
		Pos:      n.Pos,
		Value:    n.Value,
		ValueFmt: n.ValueFmt,
		Ident:    n.Ident,
		CExpr:    n.CExpr,
	}
}

func (n *Type) Clone() Node {
	return &Type{
		Pos:       n.Pos,
		Value:     n.Value,
		ValueFmt:  n.ValueFmt,
		Ident:     n.Ident,
		String:    n.String,
		HasString: n.HasString,
		HasColon:  n.HasColon,
		Pos2:      n.Pos2,
		Value2:    n.Value2,
		Value2Fmt: n.Value2Fmt,
		Ident2:    n.Ident2,
		Args:      cloneTypes(n.Args),
	}
}

func (n *Field) Clone() Node {
	return &Field{
		Pos:      n.Pos,
		Name:     n.Name.Clone().(*Ident),
		Type:     n.Type.Clone().(*Type),
		NewBlock: n.NewBlock,
		Comments: cloneComments(n.Comments),
	}
}

func cloneFields(list []*Field) (res []*Field) {
	for _, n := range list {
		res = append(res, n.Clone().(*Field))
	}
	return
}

func cloneInts(list []*Int) (res []*Int) {
	for _, n := range list {
		res = append(res, n.Clone().(*Int))
	}
	return
}

func cloneTypes(list []*Type) (res []*Type) {
	for _, n := range list {
		res = append(res, n.Clone().(*Type))
	}
	return
}

func cloneComments(list []*Comment) (res []*Comment) {
	for _, n := range list {
		res = append(res, n.Clone().(*Comment))
	}
	return
}