Skip to content
This repository has been archived by the owner on May 18, 2024. It is now read-only.

pub struct/union fields #137

Merged
merged 13 commits into from
Jul 26, 2022
49 changes: 34 additions & 15 deletions cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"github.com/goplus/c2go/clang/cmod"
"github.com/goplus/c2go/clang/types/parser"
"github.com/goplus/gox"
"github.com/goplus/gox/cpackages"

ctypes "github.com/goplus/c2go/clang/types"
)
Expand Down Expand Up @@ -295,6 +294,15 @@ func loadFile(p *gox.Package, conf *Config, file *ast.Node) (pi *PkgInfo, err er
return
}

// NOTE: call isPubTypedef only in global scope
func isPubTypedef(ctx *blockCtx, decl *ast.Node) bool {
if decl.Kind == ast.TypedefDecl {
name := decl.Name
return ctx.getPubName(&name)
}
return false
}

func compileDeclStmt(ctx *blockCtx, node *ast.Node, global bool) {
scope := ctx.cb.Scope()
n := len(node.Inner)
Expand All @@ -310,26 +318,37 @@ func compileDeclStmt(ctx *blockCtx, node *ast.Node, global bool) {
case ast.VarDecl:
compileVarDecl(ctx, decl, global)
case ast.TypedefDecl:
if typ := compileTypedef(ctx, decl, global); typ != nil && global {
name := decl.Name
if ctx.getPubName(&name) {
ctx.pkg.AliasType(name, typ, ctx.goNodePos(decl))
}
origName, pub := decl.Name, false
if global {
pub = ctx.getPubName(&decl.Name)
}
compileTypedef(ctx, decl, global, pub)
if pub {
substObj(ctx.pkg.Types, scope, origName, scope, decl.Name)
}
case ast.RecordDecl:
pub := false
name, suKind := ctx.getSuName(decl, decl.TagUsed)
if global && suKind != suAnonymous && decl.CompleteDefinition && ctx.checkExists(name) {
continue
origName := name
if global {
if suKind == suAnonymous {
// pub = true if this is a public typedef
pub = i+1 < n && isPubTypedef(ctx, node.Inner[i+1])
} else {
pub = ctx.getPubName(&name)
if decl.CompleteDefinition && ctx.checkExists(name) {
continue
}
}
}
typ, del := compileStructOrUnion(ctx, name, decl)
typ, del := compileStructOrUnion(ctx, name, decl, pub)
if suKind != suAnonymous {
if decl.CompleteDefinition && ctx.getPubName(&name) {
ctx.pkg.AliasType(name, typ, ctx.goNodePos(decl))
if pub {
substObj(ctx.pkg.Types, scope, origName, scope, name)
}
break
} else {
ctx.unnameds[decl.ID] = unnamedType{typ: typ, del: del}
}
ctx.unnameds[decl.ID] = unnamedType{typ: typ, del: del}
for i+1 < n {
next := node.Inner[i+1]
if next.Kind == ast.VarDecl {
Expand Down Expand Up @@ -483,11 +502,11 @@ func (p *blockCtx) getPubName(pfnName *string) (ok bool) {
goName, ok := p.public[name]
if ok {
if goName == "" {
goName = cpackages.PubName(name)
goName = gox.CPubName(name)
}
} else if _, ok = p.autopub[name]; ok {
p.public[name] = ""
goName = cpackages.PubName(name)
goName = gox.CPubName(name)
} else {
return
}
Expand Down
2 changes: 1 addition & 1 deletion cl/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func compileCompoundLiteralExpr(ctx *blockCtx, expr *ast.Node) {
if fld := inner.Field; fld != nil {
tyAnonym = toAnonymType(ctx, ctx.goNodePos(expr), fld)
}
typ, _ := toTypeEx(ctx, ctx.cb.Scope(), tyAnonym, inner.Type, 0)
typ, _ := toTypeEx(ctx, ctx.cb.Scope(), tyAnonym, inner.Type, 0, false)
initLit(ctx, typ, inner)
default:
log.Panicln("compileCompoundLiteralExpr unexpected:", inner.Kind)
Expand Down
14 changes: 3 additions & 11 deletions cl/pkginfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (

"github.com/goplus/c2go/clang/ast"
"github.com/goplus/gox"
"github.com/goplus/gox/cpackages"
)

// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -97,7 +96,7 @@ func loadPubFile(pubfile string) (pubs []pubName) {
goName := ""
switch len(flds) {
case 1:
goName = cpackages.PubName(flds[0])
goName = gox.CPubName(flds[0])
case 2:
goName = flds[1]
case 0:
Expand Down Expand Up @@ -126,10 +125,8 @@ func (p *blockCtx) initPublicFrom(baseDir string, conf *Config, node *ast.Node)
}
if isPub {
switch decl.Kind {
case ast.VarDecl, ast.TypedefDecl, ast.FunctionDecl:
if canPub(decl.Name) {
p.autopub[decl.Name] = none{}
}
case ast.FunctionDecl, ast.TypedefDecl, ast.VarDecl:
p.autopub[decl.Name] = none{}
case ast.RecordDecl:
if decl.Name != "" {
suName := ctypes.MangledName(decl.TagUsed, decl.Name)
Expand All @@ -140,11 +137,6 @@ func (p *blockCtx) initPublicFrom(baseDir string, conf *Config, node *ast.Node)
}
}

func canPub(name string) bool {
r := name[0]
return 'a' <= r && r <= 'z'
}

// f, pubFrom are absolute paths
func isPublicFrom(f string, pubFrom []string) bool {
for _, from := range pubFrom {
Expand Down
100 changes: 65 additions & 35 deletions cl/type_and_var.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,34 @@ import (
// -----------------------------------------------------------------------------

func toType(ctx *blockCtx, typ *ast.Type, flags int) types.Type {
t, _ := toTypeEx(ctx, ctx.cb.Scope(), nil, typ, flags)
t, _ := toTypeEx(ctx, ctx.cb.Scope(), nil, typ, flags, false)
return t
}

func toTypeEx(ctx *blockCtx, scope *types.Scope, tyAnonym types.Type, typ *ast.Type, flags int) (t types.Type, kind int) {
t, kind, err := parseType(ctx, scope, tyAnonym, typ, flags)
func toTypeEx(ctx *blockCtx, scope *types.Scope, tyAnonym types.Type, typ *ast.Type, flags int, pub bool) (t types.Type, kind int) {
t, kind, err := parseType(ctx, scope, tyAnonym, typ, flags, pub)
if err != nil {
log.Panicln("toType:", err, "-", typ.QualType)
}
return
}

func parseType(ctx *blockCtx, scope *types.Scope, tyAnonym types.Type, typ *ast.Type, flags int) (t types.Type, kind int, err error) {
func parseType(ctx *blockCtx, scope *types.Scope, tyAnonym types.Type, typ *ast.Type, flags int, pub bool) (t types.Type, kind int, err error) {
conf := &parser.Config{
Scope: scope, Flags: flags, Anonym: tyAnonym, ParseEnv: ctx,
}
retry:
t, kind, err = parser.ParseType(typ.QualType, conf)
if err != nil {
if e, ok := err.(*parser.TypeNotFound); ok && e.StructOrUnion {
ctx.typdecls[e.Literal] = ctx.cb.NewType(e.Literal)
name := e.Literal
if pub {
name = gox.CPubName(name)
}
newStructOrUnionType(ctx, token.NoPos, name)
if pub {
substObj(ctx.pkg.Types, scope, e.Literal, scope, name)
}
goto retry
}
}
Expand All @@ -49,7 +56,7 @@ func toAnonymType(ctx *blockCtx, pos token.Pos, decl *ast.Node) (ret *types.Name
switch decl.Kind {
case ast.FieldDecl:
pkg := ctx.pkg
typ, _ := toTypeEx(ctx, scope, nil, decl.Type, 0)
typ, _ := toTypeEx(ctx, scope, nil, decl.Type, 0, false)
fld := types.NewField(ctx.goNodePos(decl), pkg.Types, decl.Name, typ, false)
struc := types.NewStruct([]*types.Var{fld}, nil)
ret = pkg.NewType(ctx.getAnonyName(), pos).InitType(pkg, struc)
Expand All @@ -59,28 +66,39 @@ func toAnonymType(ctx *blockCtx, pos token.Pos, decl *ast.Node) (ret *types.Name
return
}

func toStructType(ctx *blockCtx, t *types.Named, struc *ast.Node) (ret *types.Struct, dels delfunc) {
func checkFieldName(pname *string, pub bool) {
if pub {
*pname = gox.CPubName(*pname)
} else {
avoidKeyword(pname)
}
}

func toStructType(ctx *blockCtx, t *types.Named, struc *ast.Node, pub bool) (ret *types.Struct, dels delfunc) {
b := newStructBuilder()
scope := types.NewScope(ctx.cb.Scope(), token.NoPos, token.NoPos, "")
n := len(struc.Inner)
for i := 0; i < n; i++ {
decl := struc.Inner[i]
switch decl.Kind {
case ast.FieldDecl:
name := decl.Name
if debugCompileDecl {
log.Println(" => field", decl.Name, "-", decl.Type.QualType)
log.Println(" => field", name, "-", decl.Type.QualType)
}
if name != "" {
checkFieldName(&name, pub)
}
avoidKeyword(&decl.Name)
typ, _ := toTypeEx(ctx, scope, nil, decl.Type, parser.FlagIsField)
typ, _ := toTypeEx(ctx, scope, nil, decl.Type, parser.FlagIsStructField, false)
if decl.IsBitfield {
bits := toInt64(ctx, decl.Inner[0], "non-constant bit field")
b.BitField(ctx, typ, decl.Name, int(bits))
b.BitField(ctx, typ, name, int(bits))
} else {
b.Field(ctx, ctx.goNodePos(decl), typ, decl.Name, false)
b.Field(ctx, ctx.goNodePos(decl), typ, name, false)
}
case ast.RecordDecl:
name, suKind := ctx.getSuName(decl, decl.TagUsed)
typ, del := compileStructOrUnion(ctx, name, decl)
typ, del := compileStructOrUnion(ctx, name, decl, pub)
if suKind != suAnonymous {
break
}
Expand All @@ -93,6 +111,7 @@ func toStructType(ctx *blockCtx, t *types.Named, struc *ast.Node) (ret *types.St
b.Field(ctx, ctx.goNodePos(decl), typ, name, true)
i++
} else if ret, ok := checkAnonymous(ctx, scope, typ, next); ok {
checkFieldName(&next.Name, pub)
b.Field(ctx, ctx.goNodePos(next), ret, next.Name, false)
i++
continue
Expand All @@ -109,22 +128,24 @@ func toStructType(ctx *blockCtx, t *types.Named, struc *ast.Node) (ret *types.St
return
}

func toUnionType(ctx *blockCtx, t *types.Named, unio *ast.Node) (ret types.Type, dels delfunc) {
func toUnionType(ctx *blockCtx, t *types.Named, unio *ast.Node, pub bool) (ret types.Type, dels delfunc) {
b := newUnionBuilder()
scope := types.NewScope(ctx.cb.Scope(), token.NoPos, token.NoPos, "")
n := len(unio.Inner)
for i := 0; i < n; i++ {
decl := unio.Inner[i]
switch decl.Kind {
case ast.FieldDecl:
name := decl.Name
if debugCompileDecl {
log.Println(" => field", decl.Name, "-", decl.Type.QualType)
log.Println(" => field", name, "-", decl.Type.QualType)
}
typ, _ := toTypeEx(ctx, scope, nil, decl.Type, 0)
b.Field(ctx, ctx.goNodePos(decl), typ, decl.Name, false)
checkFieldName(&name, pub)
typ, _ := toTypeEx(ctx, scope, nil, decl.Type, 0, false)
b.Field(ctx, ctx.goNodePos(decl), typ, name, false)
case ast.RecordDecl:
name, suKind := ctx.getSuName(decl, decl.TagUsed)
typ, del := compileStructOrUnion(ctx, name, decl)
typ, del := compileStructOrUnion(ctx, name, decl, pub)
if suKind != suAnonymous {
break
}
Expand All @@ -137,6 +158,7 @@ func toUnionType(ctx *blockCtx, t *types.Named, unio *ast.Node) (ret types.Type,
b.Field(ctx, ctx.goNodePos(decl), typ, name, true)
i++
} else if ret, ok := checkAnonymous(ctx, scope, typ, next); ok {
checkFieldName(&next.Name, pub)
b.Field(ctx, ctx.goNodePos(next), ret, next.Name, false)
i++
continue
Expand All @@ -154,14 +176,14 @@ func toUnionType(ctx *blockCtx, t *types.Named, unio *ast.Node) (ret types.Type,
}

func checkAnonymous(ctx *blockCtx, scope *types.Scope, typ types.Type, v *ast.Node) (ret types.Type, ok bool) {
ret, kind := toTypeEx(ctx, scope, typ, v.Type, 0)
ret, kind := toTypeEx(ctx, scope, typ, v.Type, 0, false)
ok = (kind & parser.KindFAnonymous) != 0
return
}

// -----------------------------------------------------------------------------

func compileTypedef(ctx *blockCtx, decl *ast.Node, global bool) types.Type {
func compileTypedef(ctx *blockCtx, decl *ast.Node, global, pub bool) types.Type {
name, qualType := decl.Name, decl.Type.QualType
if debugCompileDecl {
log.Println("typedef", name, "-", qualType)
Expand Down Expand Up @@ -195,7 +217,7 @@ func compileTypedef(ctx *blockCtx, decl *ast.Node, global bool) types.Type {
}
}
}
typ := toType(ctx, decl.Type, parser.FlagIsTypedef)
typ, _ := toTypeEx(ctx, scope, nil, decl.Type, parser.FlagIsTypedef, pub)
if isArrayUnknownLen(typ) || typ == ctypes.Void {
aliasType(scope, ctx.pkg.Types, name, typ)
return nil
Expand All @@ -211,36 +233,44 @@ func compileTypedef(ctx *blockCtx, decl *ast.Node, global bool) types.Type {
return typ
}

func compileStructOrUnion(ctx *blockCtx, name string, decl *ast.Node) (*types.Named, delfunc) {
func newStructOrUnionType(ctx *blockCtx, pos token.Pos, name string) (t *gox.TypeDecl) {
t, decled := ctx.typdecls[name]
if !decled {
t = ctx.cb.NewType(name, pos)
ctx.typdecls[name] = t
}
return
}

func compileStructOrUnion(ctx *blockCtx, name string, decl *ast.Node, pub bool) (*types.Named, delfunc) {
if debugCompileDecl {
log.Println(decl.TagUsed, name, "-", decl.Loc.PresumedLine)
}
var t *gox.TypeDecl
pos := ctx.goNodePos(decl)
realName := name
pkg := ctx.pkg
if ctx.inSrcFile() && decl.Name != "" {
realName = ctx.autoStaticName(decl.Name)
realName := ctx.autoStaticName(decl.Name)
var scope = ctx.cb.Scope()
t = ctx.cb.NewType(realName, pos)
substObj(ctx.pkg.Types, scope, name, scope, realName)
substObj(pkg.Types, scope, name, scope, realName)
} else {
var decled bool
t, decled = ctx.typdecls[name]
if !decled {
t = ctx.cb.NewType(realName, pos)
ctx.typdecls[name] = t
}
t = newStructOrUnionType(ctx, pos, name)
}
if decl.CompleteDefinition {
var inner types.Type
var del delfunc
switch decl.TagUsed {
case "struct":
inner, del = toStructType(ctx, t.Type(), decl)
inner, del = toStructType(ctx, t.Type(), decl, pub)
default:
inner, del = toUnionType(ctx, t.Type(), decl)
inner, del = toUnionType(ctx, t.Type(), decl, pub)
}
ret := t.InitType(pkg, inner)
if pub {
pkg.ExportFields(ret)
}
return t.InitType(ctx.pkg, inner), del
return ret, del
}
return t.Type(), nil
}
Expand Down Expand Up @@ -302,7 +332,7 @@ func compileVarDecl(ctx *blockCtx, decl *ast.Node, global bool) {
}
decl.Name, rewritten = ctx.autoStaticName(origName), true
}
typ, kind, err := parseType(ctx, scope, nil, decl.Type, flags)
typ, kind, err := parseType(ctx, scope, nil, decl.Type, flags, false)
if err != nil {
if gblStatic && parser.IsArrayWithoutLen(err) {
return
Expand Down
4 changes: 2 additions & 2 deletions clang/types/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func IsArrayWithoutLen(err error) bool {

const (
FlagIsParam = 1 << iota
FlagIsField
FlagIsStructField
FlagIsExtern
FlagIsTypedef
FlagGetRetType
Expand Down Expand Up @@ -263,7 +263,7 @@ func (p *parser) parseArray(t types.Type, inFlags int) (types.Type, error) {
p.next()
switch p.tok {
case token.RBRACK: // ]
if (inFlags & FlagIsField) != 0 {
if (inFlags & FlagIsStructField) != 0 {
n = 0
} else {
n = -1
Expand Down