From 72d6e62186749b0dcfc48a926c09238912cbe1b1 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 12 Sep 2026 09:29:35 +0800 Subject: [PATCH] cl: compileFunc; clang: FileContents --- cl/blockctx.go | 73 ++++++++++++++++++++++++++++++++++------------ cl/compile.go | 27 +++++------------ cl/compile_test.go | 12 ++++++-- cl/type_and_var.go | 6 +++- clang/clang.go | 19 ++++++++++++ lib/clang/clang.go | 5 ++++ 6 files changed, 99 insertions(+), 43 deletions(-) diff --git a/cl/blockctx.go b/cl/blockctx.go index 7b1e5919..8f79adf8 100644 --- a/cl/blockctx.go +++ b/cl/blockctx.go @@ -17,40 +17,75 @@ package cl import ( + "go/ast" "go/token" "github.com/goplus/gogen" + "github.com/goplus/lib/c" "github.com/goplus/llcppg/clang" ) // ----------------------------------------------------------------------------- +type node struct { + pos token.Pos + end token.Pos + ctx *blockCtx +} + +func (p *node) Pos() token.Pos { + return p.pos +} + +func (p *node) End() token.Pos { + return p.end +} + +/* TODO(xsw): +func goNode(ctx *blockCtx, v clang.Cursor) ast.Node { + var pos, end c.Uint + rg := v.Extent() + rg.RangeStart().SpellingLocation(nil, nil, nil, &pos) + rg.RangeEnd().SpellingLocation(nil, nil, nil, &end) + base := ctx.file.Base() + return &node{pos: token.Pos(int(pos) + base), end: token.Pos(int(end) + base), ctx: ctx} +} +*/ + +func goNodePos(ctx *blockCtx, v clang.Cursor) token.Pos { + var pos c.Uint + v.Extent().RangeStart().SpellingLocation(nil, nil, nil, &pos) + return token.Pos(int(pos) + ctx.file.Base()) +} + +// ----------------------------------------------------------------------------- + +type nodeInterp struct { + fset *token.FileSet +} + +func (p *nodeInterp) Position(start token.Pos) token.Position { + return p.fset.Position(start) +} + +func (p *nodeInterp) LoadExpr(v ast.Node) string { + panic("todo: nodeInterp.LoadExpr") +} + +// ----------------------------------------------------------------------------- + type blockCtx struct { pkg *gogen.Package cb *gogen.CodeBuilder fset *token.FileSet + file *token.File c gogen.PkgRef } -/* -func (ctx *blockCtx) goNode(v clang.Cursor) ast.Node { - if rg := v.Range; rg != nil && ctx.file != nil { - base := ctx.file.Base() - pos := token.Pos(int(rg.Begin.Offset) + base) - end := token.Pos(int(rg.End.Offset) + rg.End.TokLen + base) - return &node{pos: pos, end: end, ctx: ctx} - } - return nil -} -*/ - -func (ctx *blockCtx) goNodePos(v clang.Cursor) token.Pos { - /* if rg := v.Range; rg != nil && ctx.file != nil { - base := ctx.file.Base() - return token.Pos(int(rg.Begin.Offset) + base) - } - return token.NoPos */ - panic("todo: goNodePos") +func (p *blockCtx) initFile(file Source) { + src := file.TU.FileContents(file.Handle) + p.file = p.fset.AddFile("", -1, len(src)) + p.file.SetLinesForContent(src) } func (p *blockCtx) getPubName(pfnName *string) (rewritten bool) { diff --git a/cl/compile.go b/cl/compile.go index d13a4050..1227d5b3 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -17,7 +17,6 @@ package cl import ( - "go/ast" "go/token" "go/types" "log" @@ -47,20 +46,6 @@ func SetDebug(flags int) { // ----------------------------------------------------------------------------- -type nodeInterp struct { - fset *token.FileSet -} - -func (p *nodeInterp) Position(start token.Pos) token.Position { - return p.fset.Position(start) -} - -func (p *nodeInterp) LoadExpr(v ast.Node) string { - panic("todo: nodeInterp.LoadExpr") -} - -// ----------------------------------------------------------------------------- - type PkgInfo struct { } @@ -101,6 +86,7 @@ type Config struct { // Source represents a C/C++ header to compile. type Source struct { TU clang.TranslationUnit + Handle clang.File PresumedFile *c.Char } @@ -138,10 +124,11 @@ func NewPackage(pkgPath, pkgName string, file Source, conf *Config) (pkg Package // ----------------------------------------------------------------------------- func loadFile(p *gogen.Package, conf *Config, file Source) (pi *PkgInfo, err error) { - c := p.Import("github.com/lib/c") + c := p.Import("github.com/goplus/lib/c") ctx := &blockCtx{ pkg: p, cb: p.CB(), fset: p.Fset, c: c, } + ctx.initFile(file) _ = conf clang.VisitChildren(file.TU.Cursor(), func(decl, parent clang.Cursor) clang.ChildVisitResult { compileDecl(ctx, decl) @@ -243,9 +230,9 @@ func compileFunc(ctx *blockCtx, fn clang.Cursor) { results = types.NewTuple(pkg.NewParam(token.NoPos, "", tyRet, false)) } sig := types.NewSignatureType(nil, nil, nil, types.NewTuple(params...), results, variadic) - f := types.NewFunc(ctx.goNodePos(fn), pkg.Types, fnName, sig) - if old := pkg.Types.Scope().Insert(f); old != nil { - log.Panicln("Go func", fnName, "redefined") + f, err := pkg.NewFuncWith(goNodePos(ctx, fn), fnName, sig, nil) + if err != nil { + log.Panicln("compileFunc:", fnName, err) } // ctx.addExternFunc(fnName) if rewritten { @@ -356,7 +343,7 @@ func newParam(ctx *blockCtx, decl clang.Cursor, i c.Int) *types.Var { } else { declName = "__llcppg_param" + strconv.Itoa(int(i)+1) } - return types.NewParam(ctx.goNodePos(decl), ctx.pkg.Types, declName, typ) + return types.NewParam(goNodePos(ctx, decl), ctx.pkg.Types, declName, typ) } // ----------------------------------------------------------------------------- diff --git a/cl/compile_test.go b/cl/compile_test.go index cb9b1ab1..2ee892b2 100644 --- a/cl/compile_test.go +++ b/cl/compile_test.go @@ -18,6 +18,7 @@ package cl_test import ( "bytes" + "log" "os" "testing" @@ -43,11 +44,13 @@ func testDiff(t *testing.T, dir string, outfname string, b *bytes.Buffer, exp an } func testGenGo(t *testing.T, pkg *gogen.Package, dir string, exp any) { + log.Println("==> testGenGo", dir) var b bytes.Buffer err := pkg.WriteTo(&b) if err != nil { t.Fatal("gogen.WriteTo failed:", err) } + log.Println("==> testGenGo", dir, "len:", b.Len()) testDiff(t, dir, "/result.txt", &b, exp) } @@ -56,11 +59,13 @@ func testFromDir(t *testing.T, sel, relDir, lang string) { idx := clang.CreateIndex(0, 0) defer idx.Dispose() - u := idx.ParseTranslationUnit(0, pkgDir+"/in.h", "-x", lang) + filename := pkgDir + "/in.h" + u := idx.ParseTranslationUnit(0, filename, "-x", lang) defer u.Dispose() - imp := packages.NewImporter(nil, "./_mod") - pkg, err := cl.NewPackage("", "foo", cl.Source{TU: u}, &cl.Config{ + imp := packages.NewImporter(nil) + file := u.File(filename) + pkg, err := cl.NewPackage("", "foo", cl.Source{TU: u, Handle: file}, &cl.Config{ Importer: imp, NameLookup: cltest.MockNameLookup, }) @@ -74,6 +79,7 @@ func testFromDir(t *testing.T, sel, relDir, lang string) { } func _TestMockC(t *testing.T) { + cl.SetDebug(cl.DbgFlagAll) testFromDir(t, "", "./_testmockc", "c") } diff --git a/cl/type_and_var.go b/cl/type_and_var.go index 89f03f6d..3b348136 100644 --- a/cl/type_and_var.go +++ b/cl/type_and_var.go @@ -62,13 +62,17 @@ func newPointer(typ types.Type) types.Type { func toType(ctx *blockCtx, typ lc.Type, flags int) types.Type { switch typ.Kind { + case lc.TypeCharS: + return ctx.c.Ref("Char").Type() case lc.TypeInt: return ctx.c.Ref("Int").Type() case lc.TypeUInt: - return ctx.c.Ref("UInt").Type() + return ctx.c.Ref("Uint").Type() case lc.TypePointer: pointee := toType(ctx, typ.PointeeType(), flags) return newPointer(pointee) + default: + log.Println("==> toType: unknown Kind -", typ.Kind) } panic("todo: toType " + clang.String(typ)) } diff --git a/clang/clang.go b/clang/clang.go index e10e6c2f..7c566b2c 100644 --- a/clang/clang.go +++ b/clang/clang.go @@ -90,6 +90,13 @@ func (i Index) ParseTranslationUnit(options uint, filename string, args ...strin // ----------------------------------------------------------------------------- +/** + * A particular source file that is part of a translation unit. + */ +type File = clang.File + +// ----------------------------------------------------------------------------- + /** * A single translation unit, which resides in an index. */ @@ -104,6 +111,18 @@ func (u TranslationUnit) Dispose() { u.impl.Dispose() } +// File returns the File object corresponding to the given filename in the translation unit. +func (u TranslationUnit) File(filename string) File { + return u.impl.File(c.AllocaCStr(filename)) +} + +// FileContents returns the contents of the specified file in the translation unit. +func (u TranslationUnit) FileContents(file File) []byte { + var size c.SizeT + data := u.impl.FileContents(file, &size) + return unsafe.Slice((*byte)(unsafe.Pointer(data)), int(size)) +} + /** * Retrieve the cursor that represents the given translation unit. * diff --git a/lib/clang/clang.go b/lib/clang/clang.go index 1f11fa03..45667d7f 100644 --- a/lib/clang/clang.go +++ b/lib/clang/clang.go @@ -1302,6 +1302,11 @@ func (t *TranslationUnit) File(filename *c.Char) (ret File) { return } +// llgo:link (*TranslationUnit).FileContents C.clang_getFileContents +func (t *TranslationUnit) FileContents(file File, size *c.SizeT) (ret *c.Char) { + return +} + // llgo:link (*TranslationUnit).Spelling C.clang_getTranslationUnitSpelling func (t *TranslationUnit) Spelling() (ret String) { return