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

     1  package types
     2  
     3  import (
     4  	"os"
     5  	"sort"
     6  	"unsafe"
     7  )
     8  
     9  // Default returns a default config.
    10  func Default() Config {
    11  	var c Config
    12  	c.setDefaults()
    13  	return c
    14  }
    15  
    16  // Config32 returns a default types config for 32 bit systems.
    17  func Config32() Config {
    18  	c := Config{PtrSize: 4, IntSize: 4}
    19  	c.setDefaults()
    20  	return c
    21  }
    22  
    23  // Config64 returns a default types config for 64 bit systems.
    24  func Config64() Config {
    25  	c := Config{PtrSize: 8, IntSize: 8}
    26  	c.setDefaults()
    27  	return c
    28  }
    29  
    30  // Config stores configuration for base types.
    31  type Config struct {
    32  	PtrSize     int  // size of pointers in bytes
    33  	IntSize     int  // default int size in bytes
    34  	WCharSize   int  // wchar_t size
    35  	WCharSigned bool // is wchar_t signed?
    36  	UseGoInt    bool // use Go int for C int and long
    37  }
    38  
    39  func (c *Config) setDefaults() {
    40  	if c.WCharSize == 0 {
    41  		c.WCharSize = 2
    42  	}
    43  	if c.PtrSize == 0 {
    44  		switch os.Getenv("GOARCH") {
    45  		case "386":
    46  			c.PtrSize = 4
    47  		case "amd64":
    48  			c.PtrSize = 8
    49  		default:
    50  			c.PtrSize = int(unsafe.Sizeof((*int)(nil)))
    51  		}
    52  	}
    53  	if c.IntSize == 0 {
    54  		switch os.Getenv("GOARCH") {
    55  		case "386":
    56  			c.IntSize = 4
    57  		case "amd64":
    58  			c.IntSize = 8
    59  		default:
    60  			c.IntSize = int(unsafe.Sizeof(int(0)))
    61  		}
    62  	}
    63  }
    64  
    65  func NewEnv(c Config) *Env {
    66  	e := &Env{
    67  		conf: c,
    68  		pkgs: make(map[string]*Package),
    69  	}
    70  	e.conf.setDefaults()
    71  	// Go must be first, because C definitions may depend on it
    72  	e.initGo()
    73  	e.initC()
    74  
    75  	// conversion functions
    76  	e.stringGo2C = NewIdent("libc.CString", e.FuncTT(
    77  		e.C().String(),
    78  		e.Go().String(),
    79  	))
    80  	e.wstringGo2C = NewIdent("libc.CWString", e.FuncTT(
    81  		e.C().WString(),
    82  		e.Go().String(),
    83  	))
    84  	e.stringC2Go = NewIdent("libc.GoString", e.FuncTT(
    85  		e.Go().String(),
    86  		e.C().String(),
    87  	))
    88  	e.wstringC2Go = NewIdent("libc.GoWString", e.FuncTT(
    89  		e.Go().String(),
    90  		e.C().WString(),
    91  	))
    92  	return e
    93  }
    94  
    95  type Env struct {
    96  	conf Config
    97  
    98  	c           C
    99  	g           *Go
   100  	pkgs        map[string]*Package
   101  	stringGo2C  *Ident
   102  	wstringGo2C *Ident
   103  	stringC2Go  *Ident
   104  	wstringC2Go *Ident
   105  }
   106  
   107  // PtrSize returns size of the pointer.
   108  func (e *Env) PtrSize() int {
   109  	return e.conf.PtrSize
   110  }
   111  
   112  // IntSize returns default size of the integer.
   113  func (e *Env) IntSize() int {
   114  	return e.conf.IntSize
   115  }
   116  
   117  // PtrT returns a pointer type with a specified element.
   118  func (e *Env) PtrT(t Type) PtrType {
   119  	return PtrT(e.conf.PtrSize, t)
   120  }
   121  
   122  // IntPtrT returns a signed int type that can hold a pointer diff.
   123  func (e *Env) IntPtrT() IntType {
   124  	return IntT(e.conf.PtrSize)
   125  }
   126  
   127  // UintPtrT returns a unsigned int type that can hold a pointer.
   128  // It is different from Go().Uintptr(), since it returns uint32/uint64 type directly.
   129  func (e *Env) UintPtrT() IntType {
   130  	return UintT(e.conf.PtrSize)
   131  }
   132  
   133  // DefIntT returns a default signed int type.
   134  // It is different from Go().Int(), since it returns int32/int64 type directly.
   135  func (e *Env) DefIntT() Type {
   136  	if e.conf.UseGoInt {
   137  		return e.g.Int()
   138  	}
   139  	return IntT(e.conf.IntSize)
   140  }
   141  
   142  // DefUintT returns a default unsigned int type.
   143  // It is different from Go().Uint(), since it returns uint32/uint64 type directly.
   144  func (e *Env) DefUintT() Type {
   145  	if e.conf.UseGoInt {
   146  		return e.g.Uint()
   147  	}
   148  	return UintT(e.conf.IntSize)
   149  }
   150  
   151  // FuncT returns a function type with a given return type and named arguments.
   152  // It's mostly useful for function declarations. See FuncTT for simplified version.
   153  func (e *Env) FuncT(ret Type, args ...*Field) *FuncType {
   154  	return FuncT(e.conf.PtrSize, ret, args...)
   155  }
   156  
   157  // FuncTT returns a function type with a given return type and arguments.
   158  // To name arguments, use FuncT.
   159  func (e *Env) FuncTT(ret Type, args ...Type) *FuncType {
   160  	return FuncTT(e.conf.PtrSize, ret, args...)
   161  }
   162  
   163  // VarFuncT returns a variadic function type with a given return type and named arguments.
   164  // It's mostly useful for function declarations. See VarFuncTT for simplified version.
   165  func (e *Env) VarFuncT(ret Type, args ...*Field) *FuncType {
   166  	return VarFuncT(e.conf.PtrSize, ret, args...)
   167  }
   168  
   169  // VarFuncTT returns a variadic function type with a given return type and arguments.
   170  // To name arguments, use VarFuncT.
   171  func (e *Env) VarFuncTT(ret Type, args ...Type) *FuncType {
   172  	return VarFuncTT(e.conf.PtrSize, ret, args...)
   173  }
   174  
   175  func (e *Env) MethStructT(meth map[string]*FuncType) *StructType {
   176  	fields := make([]*Field, 0, len(meth))
   177  	for name, ft := range meth {
   178  		id := NewIdent(name, ft)
   179  		fields = append(fields, &Field{
   180  			Name: id,
   181  		})
   182  	}
   183  	return StructT(fields)
   184  }
   185  
   186  // StringGo2C is a builtin function that converts Go string to C string.
   187  func (e *Env) StringGo2C() *Ident {
   188  	return e.stringGo2C
   189  }
   190  
   191  // WStringGo2C is a builtin function that converts Go string to C wchar_t string.
   192  func (e *Env) WStringGo2C() *Ident {
   193  	return e.wstringGo2C
   194  }
   195  
   196  // StringC2Go is a builtin function that converts C string to Go string.
   197  func (e *Env) StringC2Go() *Ident {
   198  	return e.stringC2Go
   199  }
   200  
   201  // WStringC2Go is a builtin function that converts C wchar_t string to Go string.
   202  func (e *Env) WStringC2Go() *Ident {
   203  	return e.wstringC2Go
   204  }
   205  
   206  func newPackage(name, path string) *Package {
   207  	return &Package{name: name, path: path}
   208  }
   209  
   210  func (e *Env) NewPackage(name, path string) *Package {
   211  	if path == "" {
   212  		path = name
   213  	}
   214  	p := newPackage(name, path)
   215  	e.pkgs[path] = p
   216  	return p
   217  }
   218  
   219  func (e *Env) PackageByPath(path string) *Package {
   220  	return e.pkgs[path]
   221  }
   222  
   223  func (e *Env) Packages() []*Package {
   224  	out := make([]*Package, 0, len(e.pkgs))
   225  	for _, p := range e.pkgs {
   226  		out = append(out, p)
   227  	}
   228  	sort.Slice(out, func(i, j int) bool {
   229  		return out[i].path < out[j].path
   230  	})
   231  	return out
   232  }
   233  
   234  type Package struct {
   235  	name string
   236  	path string
   237  
   238  	idents  map[*Ident]struct{}
   239  	cnames  map[string]Type
   240  	gonames map[string]Type
   241  }
   242  
   243  func (p *Package) checkNames(cname, goname string) string {
   244  	if cname != "" {
   245  		if _, ok := p.cnames[cname]; ok {
   246  			panic("type already exists: " + cname)
   247  		}
   248  	}
   249  	if goname == "" {
   250  		goname = goName(cname)
   251  	}
   252  	if goname != "" {
   253  		if _, ok := p.gonames[goname]; ok {
   254  			panic("type already exists: " + goname)
   255  		}
   256  	}
   257  	return goname
   258  }
   259  
   260  func (p *Package) setNames(cname, goname string, t Type) {
   261  	if cname != "" {
   262  		if p.cnames == nil {
   263  			p.cnames = make(map[string]Type)
   264  		}
   265  		p.cnames[cname] = t
   266  	}
   267  	if goname != "" {
   268  		if p.gonames == nil {
   269  			p.gonames = make(map[string]Type)
   270  		}
   271  		p.gonames[goname] = t
   272  	}
   273  }
   274  
   275  func (p *Package) NewAlias(cname, goname string, t Type) Type {
   276  	_ = p.checkNames(cname, goname)
   277  	p.setNames(cname, goname, t)
   278  	return t
   279  }
   280  
   281  func (p *Package) NewTypeC(cname string, t Type) Named {
   282  	return p.NewTypeGo(cname, "", t)
   283  }
   284  
   285  func (p *Package) NewTypeGo(cname, goname string, t Type) Named {
   286  	goname = p.checkNames(cname, goname)
   287  
   288  	nt := NamedTGo(cname, goname, t)
   289  	if p.idents == nil {
   290  		p.idents = make(map[*Ident]struct{})
   291  	}
   292  	p.idents[nt.Name()] = struct{}{}
   293  	if cname != "" {
   294  		if p.cnames == nil {
   295  			p.cnames = make(map[string]Type)
   296  		}
   297  		p.cnames[cname] = nt
   298  	}
   299  	if goname != "" {
   300  		if p.gonames == nil {
   301  			p.gonames = make(map[string]Type)
   302  		}
   303  		p.gonames[goname] = nt
   304  	}
   305  	return nt
   306  }
   307  
   308  func (p *Package) CType(name string) Type {
   309  	return p.cnames[name]
   310  }
   311  
   312  func (p *Package) GoType(name string) Type {
   313  	return p.gonames[name]
   314  }
   315  
   316  func (p *Package) CNamedType(name string) Named {
   317  	t := p.cnames[name]
   318  	if t == nil {
   319  		return nil
   320  	}
   321  	nt, _ := t.(Named)
   322  	return nt
   323  }
   324  
   325  func (p *Package) GoNamedType(name string) Named {
   326  	t := p.gonames[name]
   327  	if t == nil {
   328  		return nil
   329  	}
   330  	nt, _ := t.(Named)
   331  	return nt
   332  }