diff options
author | Ayke van Laethem <[email protected]> | 2019-05-16 22:16:58 +0200 |
---|---|---|
committer | Ron Evans <[email protected]> | 2019-05-17 19:37:20 +0200 |
commit | dfa713040a7b3be012dc229996440005734aa9b4 (patch) | |
tree | b9e6085df2788c1c10e792739ea6d79b7adf2aa8 /cgo/cgo.go | |
parent | 82dc14b74174bc5114271773d6eb7d3858ad862d (diff) | |
download | tinygo-dfa713040a7b3be012dc229996440005734aa9b4.tar.gz tinygo-dfa713040a7b3be012dc229996440005734aa9b4.zip |
cgo: add support for enum types
Enum types are implemented as named types (with possible accompanying
typedefs as type aliases). The constants inside the enums are treated as
Go constants like in the Go toolchain.
Diffstat (limited to 'cgo/cgo.go')
-rw-r--r-- | cgo/cgo.go | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/cgo/cgo.go b/cgo/cgo.go index 0ef32127d..d31fe57a4 100644 --- a/cgo/cgo.go +++ b/cgo/cgo.go @@ -35,6 +35,7 @@ type cgoPackage struct { globals map[string]globalInfo typedefs map[string]*typedefInfo elaboratedTypes map[string]*elaboratedTypeInfo + enums map[string]enumInfo } // constantInfo stores some information about a CGo constant found by libclang @@ -71,6 +72,12 @@ type elaboratedTypeInfo struct { pos token.Pos } +// enumInfo contains information about an enum in the C. +type enumInfo struct { + typeExpr ast.Expr + pos token.Pos +} + // globalInfo contains information about a declared global variable in C. type globalInfo struct { typeExpr ast.Expr @@ -140,6 +147,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string globals: map[string]globalInfo{}, typedefs: map[string]*typedefInfo{}, elaboratedTypes: map[string]*elaboratedTypeInfo{}, + enums: map[string]enumInfo{}, } // Add a new location for the following file. @@ -243,6 +251,9 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string // Add elaborated types for C structs and unions. p.addElaboratedTypes() + // Add enum types and enum constants for C enums. + p.addEnumTypes() + // Patch the AST to use the declared types and functions. for _, f := range files { astutil.Apply(f, p.walker, nil) @@ -574,6 +585,54 @@ func (p *cgoPackage) addElaboratedTypes() { p.generated.Decls = append(p.generated.Decls, gen) } +// addEnumTypes adds C enums to the AST. For example, the following C code: +// +// enum option { +// optionA, +// optionB = 5, +// }; +// +// is translated to the following Go code equivalent: +// +// type C.enum_option int32 +// +// The constants are treated just like macros so are inserted into the AST by +// addConstDecls. +// See also: https://en.cppreference.com/w/c/language/enum +func (p *cgoPackage) addEnumTypes() { + if len(p.enums) == 0 { + return + } + gen := &ast.GenDecl{ + TokPos: token.NoPos, + Tok: token.TYPE, + } + names := make([]string, 0, len(p.enums)) + for name := range p.enums { + names = append(names, name) + } + sort.Strings(names) + for _, name := range names { + typ := p.enums[name] + typeName := "C.enum_" + name + obj := &ast.Object{ + Kind: ast.Typ, + Name: typeName, + } + typeSpec := &ast.TypeSpec{ + Name: &ast.Ident{ + NamePos: typ.pos, + Name: typeName, + Obj: obj, + }, + Type: typ.typeExpr, + } + obj.Decl = typeSpec + gen.Specs = append(gen.Specs, typeSpec) + } + p.generated.Decls = append(p.generated.Decls, gen) +} + // findMissingCGoNames traverses the AST and finds all C.something names. Only // these symbols are extracted from the parsed C AST and converted to the Go // equivalent. |