From 5ee9115b75cb7ec84f85220d655dea2a24017033 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 20 Apr 2024 15:58:34 +0800 Subject: [PATCH] cl: TestVar --- cl/compile.go | 131 ++++++++++++++++++++++++++++++++++++++++++++- cl/compile_test.go | 65 ++++++++++++++++++++++ 2 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 cl/compile_test.go diff --git a/cl/compile.go b/cl/compile.go index 806fafd0..825b05fb 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 The GoPlus Authors (goplus.org). All rights reserved. + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,135 @@ package cl +import ( + "sort" + + llssa "github.com/goplus/llgo/ssa" + "golang.org/x/tools/go/ssa" +) + +type Config struct { +} + +type context struct { +} + +// Global variable. +func (p *context) compileGlobal(ret llssa.Package, member *ssa.Global) { + ret.NewVar(member.Name(), member.Type()) +} + +func (p *context) compileType(ret llssa.Package, member *ssa.Type) { + panic("todo") + /* + if types.IsInterface(member.Type()) { + // Interfaces don't have concrete methods. + continue + } + + // Named type. We should make sure all methods are created. + // This includes both functions with pointer receivers and those + // without. + methods := getAllMethods(pkg.Prog, member.Type()) + methods = append(methods, getAllMethods(pkg.Prog, types.NewPointer(member.Type()))...) + for _, method := range methods { + // Parse this method. + fn := pkg.Prog.MethodValue(method) + if fn == nil { + continue // probably a generic method + } + if member.Type().String() != member.String() { + // This is a member on a type alias. Do not build such a + // function. + continue + } + if fn.Blocks == nil { + continue // external function + } + if fn.Synthetic != "" && fn.Synthetic != "package initializer" { + // This function is a kind of wrapper function (created by + // the ssa package, not appearing in the source code) that + // is created by the getFunction method as needed. + // Therefore, don't build it here to avoid "function + // redeclared" errors. + continue + } + // Create the function definition. + b := newBuilder(c, irbuilder, fn) + b.createFunction() + } + */ +} + +func (p *context) compileFunc(ret llssa.Package, member *ssa.Function) { + // panic("todo") + /* + // Create the function definition. + b := newBuilder(c, irbuilder, member) + if _, ok := mathToLLVMMapping[member.RelString(nil)]; ok { + // The body of this function (if there is one) is ignored and + // replaced with a LLVM intrinsic call. + b.defineMathOp() + continue + } + if ok := b.defineMathBitsIntrinsic(); ok { + // Like a math intrinsic, the body of this function was replaced + // with a LLVM intrinsic. + continue + } + if member.Blocks == nil { + // Try to define this as an intrinsic function. + b.defineIntrinsicFunction() + // It might not be an intrinsic function but simply an external + // function (defined via //go:linkname). Leave it undefined in + // that case. + continue + } + b.createFunction() + */ +} + +func NewPackage(prog llssa.Program, pkg *ssa.Package, conf *Config) (ret llssa.Package, err error) { + type namedMember struct { + name string + val ssa.Member + } + + // Sort by position, so that the order of the functions in the IR matches + // the order of functions in the source file. This is useful for testing, + // for example. + var members []*namedMember + for name, v := range pkg.Members { + members = append(members, &namedMember{name, v}) + } + sort.Slice(members, func(i, j int) bool { + iPos := members[i].val.Pos() + jPos := members[j].val.Pos() + return iPos < jPos + }) + + pkgTypes := pkg.Pkg + ret = prog.NewPackage(pkgTypes.Name(), pkgTypes.Path()) + + ctx := &context{} + for _, m := range members { + member := m.val + switch member := member.(type) { + case *ssa.Function: + if member.TypeParams() != nil { + // Do not try to build generic (non-instantiated) functions. + continue + } + ctx.compileFunc(ret, member) + case *ssa.Type: + ctx.compileType(ret, member) + case *ssa.Global: + ctx.compileGlobal(ret, member) + } + } + return +} + /* import ( "go/types" diff --git a/cl/compile_test.go b/cl/compile_test.go new file mode 100644 index 00000000..7a9e8abf --- /dev/null +++ b/cl/compile_test.go @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cl + +import ( + "go/ast" + "go/importer" + "go/parser" + "go/token" + "go/types" + "testing" + + llssa "github.com/goplus/llgo/ssa" + "golang.org/x/tools/go/ssa" + "golang.org/x/tools/go/ssa/ssautil" +) + +func testCompile(t *testing.T, src, expected string) { + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, "foo.go", src, parser.ParseComments) + if err != nil { + t.Fatal("ParseFile failed:", err) + } + files := []*ast.File{f} + pkg := types.NewPackage("foo", "foo") + foo, _, err := ssautil.BuildPackage( + &types.Config{Importer: importer.Default()}, fset, pkg, files, ssa.SanityCheckFunctions) + if err != nil { + t.Fatal("BuildPackage failed:", err) + } + prog := llssa.NewProgram(nil) + ret, err := NewPackage(prog, foo, nil) + if err != nil { + t.Fatal("cl.NewPackage failed:", err) + } + if v := ret.String(); v != expected { + t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected) + } +} + +func TestVar(t *testing.T) { + testCompile(t, `package foo + +var a int +`, `; ModuleID = 'foo' +source_filename = "foo" + +@"init$guard" = external global ptr +@a = external global ptr +`) +}