From 55b310d2665550b5b79956a0bcf58c0d0d89b237 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Mon, 15 Apr 2024 00:48:04 +0800 Subject: [PATCH] basic structure --- .gitignore | 2 +- build/build.go | 22 ++++-- cl/alias.go | 2 + cl/builder.go | 2 + cl/compile.go | 9 ++- cl/intrinsics.go | 2 + cl/symbol.go | 10 ++- cmd/internal/build/build.go | 4 +- go.mod | 13 ++-- go.sum | 28 ++++---- loader/loader.go | 36 ---------- x/loader/loader.go | 130 ++++++++++++++++++++++++++++++++++++ x/parser/parser.go | 63 +++++++++++++++++ 13 files changed, 249 insertions(+), 74 deletions(-) delete mode 100644 loader/loader.go create mode 100644 x/loader/loader.go create mode 100644 x/parser/parser.go diff --git a/.gitignore b/.gitignore index 8a031168..238d50fe 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,4 @@ _tinygo/ # vendor/ # Go workspace file -go.work +go.work* diff --git a/build/build.go b/build/build.go index 816f63ad..13cba697 100644 --- a/build/build.go +++ b/build/build.go @@ -16,18 +16,21 @@ package build +import ( + "go/build" +) + // An ImportMode controls the behavior of the Import method. -type ImportMode uint +type ImportMode = build.ImportMode // A Package describes the Go package found in a directory. type Package struct { - Dir string // directory containing package sources - Name string // package name - ImportPath string // import path of package ("" if unknown) + *build.Package } // A Context specifies the supporting context for a build. type Context struct { + *build.Context } // Import returns details about the Go package named by the import path, @@ -38,12 +41,17 @@ type Context struct { // // If an error occurs, Import returns a non-nil error and a non-nil // *Package containing partial information. -func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) { - panic("todo") +func (ctxt Context) Import(path string, srcDir string, mode ImportMode) (ret Package, err error) { + pkg, err := build.Import(path, srcDir, mode) + if err != nil { + return + } + ret = Package{pkg} + return } // ImportDir is like Import but processes the Go package found in // the named directory. -func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) { +func (ctxt *Context) ImportDir(dir string, mode ImportMode) (Package, error) { return ctxt.Import(".", dir, mode) } diff --git a/cl/alias.go b/cl/alias.go index 7e20ddc1..ada3782e 100644 --- a/cl/alias.go +++ b/cl/alias.go @@ -16,6 +16,7 @@ package cl +/* import ( llvm "tinygo.org/x/go-llvm" ) @@ -42,3 +43,4 @@ var stdlibAliases = map[string]string{ func (b *builder) createAlias(alias llvm.Value) { panic("todo") } +*/ diff --git a/cl/builder.go b/cl/builder.go index 3591ffb1..98c51ddf 100644 --- a/cl/builder.go +++ b/cl/builder.go @@ -16,6 +16,7 @@ package cl +/* import ( "golang.org/x/tools/go/ssa" llvm "tinygo.org/x/go-llvm" @@ -35,3 +36,4 @@ func newBuilder(c *context, irbuilder llvm.Builder, f *ssa.Function) *builder { func (b *builder) createFunction() { panic("todo") } +*/ diff --git a/cl/compile.go b/cl/compile.go index fe54f3ce..806fafd0 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -16,6 +16,7 @@ package cl +/* import ( "go/types" "os" @@ -213,8 +214,8 @@ func NewPackage(moduleName string, pkg loader.Package, conf *Config) (ret Packag // Predeclare trackPointer, which is used everywhere we use runtime.alloc. c.getFunction(c.program.ImportedPackage("runtime").Members["trackPointer"].(*ssa.Function)) } - */ - +*/ +/* // Compile all functions, methods, and global variables in this package. irbuilder := c.ctx.NewBuilder() defer irbuilder.Dispose() @@ -232,7 +233,8 @@ func NewPackage(moduleName string, pkg loader.Package, conf *Config) (ret Packag }), ) } - */ +*/ +/* ret.Module = c.mod err = c.errs.ToError() return @@ -271,3 +273,4 @@ func (p Package) WriteTo(f *os.File) (err error) { } return } +*/ diff --git a/cl/intrinsics.go b/cl/intrinsics.go index a99f2e54..7f34e9e9 100644 --- a/cl/intrinsics.go +++ b/cl/intrinsics.go @@ -16,6 +16,7 @@ package cl +/* // Define unimplemented intrinsic functions. // // Some functions are either normally implemented in Go assembly (like @@ -58,3 +59,4 @@ func (b *builder) defineMathOp() { func (b *builder) defineMathBitsIntrinsic() bool { panic("todo") } +*/ diff --git a/cl/symbol.go b/cl/symbol.go index eb8e8d5f..89662863 100644 --- a/cl/symbol.go +++ b/cl/symbol.go @@ -16,6 +16,7 @@ package cl +/* import ( "go/types" @@ -40,7 +41,8 @@ type functionInfo struct { nobounds bool // go:nobounds variadic bool // go:variadic (CGo only) inline inlineType // go:inline - */ +*/ +/* linkName string // go:linkname, go:export - the IR function name } @@ -64,7 +66,7 @@ const ( inlineNone ) */ - +/* // getFunctionInfo returns information about a function that is not directly // present in *ssa.Function, such as the link name and whether it should be // exported. @@ -79,7 +81,8 @@ type globalInfo struct { /* linkName string // go:extern align int // go:align - */ +*/ +/* section string // go:section extern bool // go:extern } @@ -103,3 +106,4 @@ func (c *context) getGlobalInfo(g *ssa.Global) globalInfo { func getAllMethods(prog *ssa.Program, typ types.Type) []*types.Selection { panic("todo") } +*/ diff --git a/cmd/internal/build/build.go b/cmd/internal/build/build.go index e22d9f2a..0492f923 100644 --- a/cmd/internal/build/build.go +++ b/cmd/internal/build/build.go @@ -33,7 +33,7 @@ import ( // llgo build var Cmd = &base.Command{ - UsageLine: "llog build [flags] [packages]", + UsageLine: "llgo build [flags] [packages]", Short: "Build Go files", } @@ -87,7 +87,7 @@ func build(proj gopprojs.Proj, conf *llgo.Config, build *gocmd.BuildConfig) { err = llgo.BuildDir(obj, conf, build) case *gopprojs.PkgPathProj: obj = v.Path - err = llgo.BuildPkgPath("", v.Path, conf, build) + err = llgo.BuildPkgPath("", obj, conf, build) case *gopprojs.FilesProj: err = llgo.BuildFiles(v.Files, conf, build) default: diff --git a/go.mod b/go.mod index 0695abfa..ab2dd97d 100644 --- a/go.mod +++ b/go.mod @@ -5,14 +5,13 @@ go 1.18 require ( github.com/aykevl/go-wasm v0.0.1 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb - github.com/goplus/gop v1.1.13 - github.com/qiniu/x v1.13.1 - golang.org/x/tools v0.16.0 - tinygo.org/x/go-llvm v0.0.0-20231014233752-75a8a9fe6f74 + github.com/goplus/gop v1.2.6 + github.com/qiniu/x v1.13.10 ) require ( - github.com/goplus/gox v1.13.1 // indirect - github.com/goplus/mod v0.11.9 // indirect - golang.org/x/mod v0.14.0 // indirect + github.com/goplus/gogen v1.15.2 // indirect + github.com/goplus/mod v0.13.10 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/tools v0.19.0 // indirect ) diff --git a/go.sum b/go.sum index 0fc7f0bc..2872a2df 100644 --- a/go.sum +++ b/go.sum @@ -2,14 +2,14 @@ github.com/aykevl/go-wasm v0.0.1 h1:lPxy8l48P39W7I0tLrtCrLfZBOUq9IWZ7odGdyJP2AM= github.com/aykevl/go-wasm v0.0.1/go.mod h1:b4nggwg3lEkNKOU4wzhtLKz2q2sLxSHFnc98aGt6z/Y= github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4= github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= -github.com/goplus/gop v1.1.13 h1:Nnyzy7BeE25SbpGfOX/mHGBCpvVsmkr/9hW0FtUXZwY= -github.com/goplus/gop v1.1.13/go.mod h1:iRl6Rxc4bazQaDr4yUlxSpa9Wxs8J2nXG0ON8vcfh4g= -github.com/goplus/gox v1.13.1 h1:/X6Ja9R2hQuLVbN+PzLHRtaBcan+YmhASvGO3nMJsZw= -github.com/goplus/gox v1.13.1/go.mod h1:UNzOPlRyO/uQn+9iHelk6KelAFaaC7OBn5AxtSSsC9c= -github.com/goplus/mod v0.11.9 h1:XdWvSNi55fQ3KHnk0PVVHsXynG58lTbfXps/C9HjTVQ= -github.com/goplus/mod v0.11.9/go.mod h1:YxrBMhvWGcvLU14j8e7qyKSVnj5Loba7GgH1rNXJtDg= -github.com/qiniu/x v1.13.1 h1:hi7tkXFq6BWGbBpMoLV7kvA2elop69j6Kl7TlxnFAiU= -github.com/qiniu/x v1.13.1/go.mod h1:INZ2TSWSJVWO/RuELQROERcslBwVgFG7MkTfEdaQz9E= +github.com/goplus/gogen v1.15.2 h1:Q6XaSx/Zi5tWnjfAziYsQI6Jv6MgODRpFtOYqNkiiqM= +github.com/goplus/gogen v1.15.2/go.mod h1:92qEzVgv7y8JEFICWG9GvYI5IzfEkxYdsA1DbmnTkqk= +github.com/goplus/gop v1.2.6 h1:kog3c5Js+8EopqmI4+CwueXsqibnBwYVt5q5N7juRVY= +github.com/goplus/gop v1.2.6/go.mod h1:uREWbR1MrFaviZ4Mbx4ZCcAYDoqzO0iv1Qo6Np0Xx4E= +github.com/goplus/mod v0.13.10 h1:5Om6KOvo31daN7N30kWU1vC5zhsJPM+uPbcEN/FnlzE= +github.com/goplus/mod v0.13.10/go.mod h1:HDuPZgpWiaTp3PUolFgsiX+Q77cbUWB/mikVHfYND3c= +github.com/qiniu/x v1.13.10 h1:J4Z3XugYzAq85SlyAfqlKVrbf05glMbAOh+QncsDQpE= +github.com/qiniu/x v1.13.10/go.mod h1:INZ2TSWSJVWO/RuELQROERcslBwVgFG7MkTfEdaQz9E= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -17,8 +17,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -29,7 +29,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -54,8 +54,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= -golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= +golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -tinygo.org/x/go-llvm v0.0.0-20231014233752-75a8a9fe6f74 h1:tW8XhLI9gUZLL+2pG0HYb5dc6bpMj1aqtESpizXPnMY= -tinygo.org/x/go-llvm v0.0.0-20231014233752-75a8a9fe6f74/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0= diff --git a/loader/loader.go b/loader/loader.go deleted file mode 100644 index 89facef9..00000000 --- a/loader/loader.go +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023 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 loader - -import ( - "golang.org/x/tools/go/ssa" -) - -type Package struct { - SSA *ssa.Package - EmbedGlobals map[string][]*EmbedFile -} - -type EmbedFile struct { - /* - Name string - Size uint64 - Hash string // hash of the file (as a hex string) - NeedsData bool // true if this file is embedded as a byte slice - Data []byte // contents of this file (only if NeedsData is set) - */ -} diff --git a/x/loader/loader.go b/x/loader/loader.go new file mode 100644 index 00000000..15240a9c --- /dev/null +++ b/x/loader/loader.go @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2023 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 loader + +/* +import ( + "go/ast" + "go/token" + "go/types" + + "github.com/goplus/llgo/build" + "golang.org/x/tools/go/ssa" +) + +type Package struct { + SSA *ssa.Package + EmbedGlobals map[string][]*EmbedFile +} + +type EmbedFile struct { + /* + Name string + Size uint64 + Hash string // hash of the file (as a hex string) + NeedsData bool // true if this file is embedded as a byte slice + Data []byte // contents of this file (only if NeedsData is set) +*/ +/* +} + +type Context struct { + *ssa.Program +} + +func (ctx *Context) Load(pkg build.Package) (ret Package, err error) { + return +} + +// BuildPackage builds an SSA program with IR for a single package. +// +// It populates pkg by type-checking the specified file ASTs. All +// dependencies are loaded using the importer specified by tc, which +// typically loads compiler export data; SSA code cannot be built for +// those packages. BuildPackage then constructs an ssa.Program with all +// dependency packages created, and builds and returns the SSA package +// corresponding to pkg. +// +// The caller must have set pkg.Path() to the import path. +// +// The operation fails if there were any type-checking or import errors. +// +// See ../example_test.go for an example. +func BuildPackage(tc *types.Config, fset *token.FileSet, pkg *types.Package, files []*ast.File, mode ssa.BuilderMode) (*ssa.Package, *types.Info, error) { + if fset == nil { + panic("no token.FileSet") + } + if pkg.Path() == "" { + panic("package has no import path") + } + + info := &types.Info{ + Types: make(map[ast.Expr]types.TypeAndValue), + Defs: make(map[*ast.Ident]types.Object), + Uses: make(map[*ast.Ident]types.Object), + Implicits: make(map[ast.Node]types.Object), + Scopes: make(map[ast.Node]*types.Scope), + Selections: make(map[*ast.SelectorExpr]*types.Selection), + } + typeparams.InitInstanceInfo(info) + versions.InitFileVersions(info) + if err := types.NewChecker(tc, fset, pkg, info).Files(files); err != nil { + return nil, nil, err + } + + prog := ssa.NewProgram(fset, mode) + + // Create SSA packages for all imports. + // Order is not significant. + created := make(map[*types.Package]bool) + var createAll func(pkgs []*types.Package) + createAll = func(pkgs []*types.Package) { + for _, p := range pkgs { + if !created[p] { + created[p] = true + prog.CreatePackage(p, nil, nil, true) + createAll(p.Imports()) + } + } + } + createAll(pkg.Imports()) + + // TODO(adonovan): we could replace createAll with just: + // + // // Create SSA packages for all imports. + // for _, p := range pkg.Imports() { + // prog.CreatePackage(p, nil, nil, true) + // } + // + // (with minor changes to changes to ../builder_test.go as + // shown in CL 511715 PS 10.) But this would strictly violate + // the letter of the doc comment above, which says "all + // dependencies created". + // + // Tim makes the good point with some extra work we could + // remove the need for any CreatePackage calls except the + // ones with syntax (i.e. primary packages). Of course + // You wouldn't have ssa.Packages and Members for as + // many things but no-one really uses that anyway. + // I wish I had done this from the outset. + + // Create and build the primary package. + ssapkg := prog.CreatePackage(pkg, files, info, false) + ssapkg.Build() + return ssapkg, info, nil +} +*/ diff --git a/x/parser/parser.go b/x/parser/parser.go new file mode 100644 index 00000000..32c815cd --- /dev/null +++ b/x/parser/parser.go @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 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 parser + +/* +import ( + "go/ast" + "go/parser" + "go/token" + + "github.com/goplus/llgo/build" +) + +// A Mode value is a set of flags (or 0). +// They control the amount of source code parsed and other optional +// parser functionality. +type Mode = parser.Mode + +const ( + PackageClauseOnly = parser.PackageClauseOnly // stop parsing after package clause + ImportsOnly = parser.ImportsOnly // stop parsing after import declarations + ParseComments = parser.ParseComments // parse comments and add them to AST + Trace = parser.Trace // print a trace of parsed productions + DeclarationErrors = parser.DeclarationErrors // report declaration errors + SpuriousErrors = parser.SpuriousErrors // same as AllErrors, for backward-compatibility + SkipObjectResolution = parser.SkipObjectResolution // don't resolve identifiers to objects - see ParseFile + AllErrors = parser.AllErrors // report all errors (not just the first 10 on different lines) +) + +// A Package node represents a set of source files +// collectively building a Go package. +type Package struct { + *ast.Package +} + +func Parse(fset *token.FileSet, pkg build.Package, mode Mode) (_ Package, first error) { + ret := map[string]*ast.Package{} + for _, file := range pkg.GoFiles { + f, err := parser.ParseFile(fset, file, nil, mode) + if err != nil { + if first == nil { + first = err + } + continue + } + ret[file] = f + } +} +*/