cl: TestVar
This commit is contained in:
131
cl/compile.go
131
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,6 +16,135 @@
|
|||||||
|
|
||||||
package cl
|
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 (
|
import (
|
||||||
"go/types"
|
"go/types"
|
||||||
|
|||||||
65
cl/compile_test.go
Normal file
65
cl/compile_test.go
Normal file
@@ -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
|
||||||
|
`)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user