github.com/gotranspile/cxgo@v0.3.7/c_decl.go (about)

     1  package cxgo
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  	"go/token"
     7  
     8  	"github.com/gotranspile/cxgo/types"
     9  )
    10  
    11  type Range struct {
    12  	Start     int
    13  	StartLine int
    14  	End       int
    15  }
    16  
    17  type CDecl interface {
    18  	Node
    19  	AsDecl() []GoDecl
    20  	Uses() []types.Usage
    21  }
    22  
    23  type CVarSpec struct {
    24  	g     *translator
    25  	Type  types.Type
    26  	Names []*types.Ident
    27  	Inits []Expr
    28  }
    29  
    30  func (d *CVarSpec) Visit(v Visitor) {
    31  	for _, name := range d.Names {
    32  		v(IdentExpr{name})
    33  	}
    34  	for _, x := range d.Inits {
    35  		v(x)
    36  	}
    37  }
    38  
    39  func (d *CVarSpec) GoSpecs(isConst bool) *ast.ValueSpec {
    40  	var (
    41  		names []*ast.Ident
    42  		init  []GoExpr
    43  	)
    44  	var typ GoType
    45  	if d.Type != nil {
    46  		typ = d.Type.GoType()
    47  	}
    48  	dropType := 0
    49  	for i, name := range d.Names {
    50  		if name.Name == "__func__" {
    51  			continue
    52  		}
    53  		names = append(names, name.GoIdent())
    54  		if len(d.Inits) != 0 {
    55  			v := d.Inits[i]
    56  			if d.Type != nil && v != nil {
    57  				v = d.g.cCast(d.Type, v)
    58  			}
    59  			var e GoExpr
    60  			if v != nil {
    61  				e = v.AsExpr()
    62  			}
    63  			if ci, ok := e.(*ast.CompositeLit); ok && ci.Type == nil {
    64  				ci.Type = typ
    65  				dropType++
    66  			} else if _, ok = e.(*ast.BasicLit); ok && isConst {
    67  				if _, ok := d.Type.(types.Named); !ok || d.g.env.Go().IsBuiltinType(d.Type) {
    68  					dropType++
    69  				}
    70  			}
    71  			init = append(init, e)
    72  		}
    73  	}
    74  	if dropType == len(names) {
    75  		typ = nil
    76  	}
    77  	if len(init) != 0 && len(init) < len(names) {
    78  		panic("partial init")
    79  	}
    80  	return &ast.ValueSpec{
    81  		Type:   typ,
    82  		Names:  names,
    83  		Values: init,
    84  	}
    85  }
    86  
    87  func (d *CVarSpec) Uses() []types.Usage {
    88  	var list []types.Usage
    89  	for i, name := range d.Names {
    90  		acc := types.AccessDefine
    91  		if i < len(d.Inits) {
    92  			acc = types.AccessWrite
    93  		}
    94  		list = append(list, types.Usage{Ident: name, Access: acc})
    95  	}
    96  	for _, e := range d.Inits {
    97  		list = append(list, types.UseRead(e)...)
    98  	}
    99  	return list
   100  }
   101  
   102  type CVarDecl struct {
   103  	Const  bool
   104  	Single bool
   105  	CVarSpec
   106  }
   107  
   108  func (d *CVarDecl) Visit(v Visitor) {
   109  	v(&d.CVarSpec)
   110  }
   111  
   112  func (d *CVarDecl) GoField() *GoField {
   113  	if len(d.Names) > 1 {
   114  		panic("too large")
   115  	}
   116  	if len(d.Inits) != 0 {
   117  		panic("FIXME")
   118  	}
   119  	var names []*ast.Ident
   120  	if len(d.Names) != 0 {
   121  		names = append(names, d.Names[0].GoIdent())
   122  	}
   123  	return &GoField{
   124  		Names: names,
   125  		Type:  d.Type.GoType(),
   126  		// FIXME: init
   127  	}
   128  }
   129  
   130  func (d *CVarDecl) AsDecl() []GoDecl {
   131  	sp := d.GoSpecs(d.Const)
   132  	if sp == nil || len(sp.Names) == 0 {
   133  		return nil
   134  	}
   135  	single := d.Single
   136  	tok := token.VAR
   137  	if d.Const {
   138  		tok = token.CONST
   139  		// no complex consts in Go
   140  		if d.Type != nil && (d.Type.Kind().Is(types.Array) || d.Type.Kind().Is(types.Struct)) {
   141  			tok = token.VAR
   142  		} else {
   143  			for _, v := range d.Inits {
   144  				if v == nil {
   145  					single = false
   146  					continue
   147  				}
   148  				if vk := v.CType(nil).Kind(); vk.Is(types.Array) || vk.Is(types.Struct) {
   149  					tok = token.VAR
   150  					break
   151  				}
   152  			}
   153  		}
   154  	}
   155  	var specs []ast.Spec
   156  	if single {
   157  		specs = []ast.Spec{sp}
   158  	} else {
   159  		for i, name := range sp.Names {
   160  			var vals []ast.Expr
   161  			if len(sp.Values) != 0 && sp.Values[i] != nil {
   162  				vals = []ast.Expr{sp.Values[i]}
   163  			}
   164  			specs = append(specs, &ast.ValueSpec{
   165  				Names:  []*ast.Ident{name},
   166  				Type:   sp.Type,
   167  				Values: vals,
   168  			})
   169  		}
   170  	}
   171  	return []GoDecl{&ast.GenDecl{
   172  		Tok:   tok,
   173  		Specs: specs,
   174  	}}
   175  }
   176  
   177  type CTypeDef struct {
   178  	types.Named
   179  }
   180  
   181  func (d *CTypeDef) Visit(v Visitor) {
   182  	v(IdentExpr{d.Name()})
   183  }
   184  
   185  func (d *CTypeDef) AsDecl() []GoDecl {
   186  	var decls []GoDecl
   187  	if false && d.Kind().Is(types.Struct) {
   188  		decls = append(decls, &ast.GenDecl{
   189  			Tok: token.VAR,
   190  			Specs: []ast.Spec{
   191  				&ast.ValueSpec{
   192  					Names:  []*ast.Ident{ident("_")},
   193  					Values: []GoExpr{ident(fmt.Sprintf("([1]struct{}{})[%d-unsafe.Sizeof(%s{})]", d.Sizeof(), d.Name().Name))},
   194  				},
   195  			},
   196  		})
   197  	}
   198  	decls = append(decls, &ast.GenDecl{
   199  		Tok: token.TYPE,
   200  		Specs: []ast.Spec{
   201  			&ast.TypeSpec{
   202  				Name: d.Name().GoIdent(),
   203  				Type: d.Underlying().GoType(),
   204  			},
   205  		},
   206  	})
   207  	return decls
   208  }
   209  
   210  func (d *CTypeDef) Uses() []types.Usage {
   211  	// TODO: use type
   212  	return nil
   213  }
   214  
   215  type CFuncDecl struct {
   216  	Name  *types.Ident
   217  	Type  *types.FuncType
   218  	Body  *BlockStmt
   219  	Range *Range
   220  }
   221  
   222  func (d *CFuncDecl) Visit(v Visitor) {
   223  	v(IdentExpr{d.Name})
   224  	v(d.Body)
   225  }
   226  
   227  func (d *CFuncDecl) AsDecl() []GoDecl {
   228  	return []GoDecl{
   229  		&ast.FuncDecl{
   230  			Name: d.Name.GoIdent(),
   231  			Type: d.Type.GoFuncType(),
   232  			Body: d.Body.GoBlockStmt(),
   233  		},
   234  	}
   235  }
   236  
   237  func (d *CFuncDecl) Uses() []types.Usage {
   238  	var list []types.Usage
   239  	list = append(list, types.Usage{Ident: d.Name, Access: types.AccessDefine})
   240  	if d.Body != nil {
   241  		list = append(list, d.Body.Uses()...)
   242  	}
   243  	// TODO: use type
   244  	return nil
   245  }