mirror of
https://gitee.com/wa-lang/wa.git
synced 2025-12-06 09:18:53 +08:00
修复 wz 准备函数不能工作的问题
This commit is contained in:
1
.github/workflows/publish.yml
vendored
1
.github/workflows/publish.yml
vendored
@@ -38,6 +38,7 @@ jobs:
|
||||
- run: make -C waroot/examples/w4-rocket publish
|
||||
- run: make -C waroot/examples/w4-magnifying-glass publish
|
||||
- run: make -C waroot/examples/brainfuck publish
|
||||
- run: make -C waroot/examples/p5-hello-wz publish
|
||||
|
||||
- name: Deploy
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
|
||||
@@ -76,7 +76,11 @@ func (p *Compiler) Compile(prog *loader.Program) (output string, err error) {
|
||||
var f wir.Function
|
||||
f.InternalName, f.ExternalName = "_start", "_start"
|
||||
n, _ := wir.GetPkgMangleName(prog.SSAMainPkg.Pkg.Path())
|
||||
n += ".init"
|
||||
if prog.SSAMainPkg.Pkg.W2Mode {
|
||||
n += "." + token.K_准备
|
||||
} else {
|
||||
n += "." + token.K_init
|
||||
}
|
||||
f.Insts = append(f.Insts, wat.NewInstCall(n))
|
||||
|
||||
//if mainFunc != "" {
|
||||
|
||||
@@ -6,6 +6,7 @@ package compiler_wat
|
||||
import (
|
||||
"wa-lang.org/wa/internal/backends/compiler_wat/wir"
|
||||
"wa-lang.org/wa/internal/ssa"
|
||||
"wa-lang.org/wa/internal/token"
|
||||
"wa-lang.org/wa/internal/types"
|
||||
)
|
||||
|
||||
@@ -14,7 +15,13 @@ func (p *Compiler) compileGlobal(g *ssa.Global) {
|
||||
p.module.AddGlobal(g.LinkName(), "", p.tLib.compile(g.Type().(*types.Pointer).Elem()), false, g)
|
||||
} else {
|
||||
pkg_name, _ := wir.GetPkgMangleName(g.Pkg.Pkg.Path())
|
||||
if g.Name() == "init$guard" || g.ForceRegister() {
|
||||
var initGuard string
|
||||
if g.Pkg.Pkg.W2Mode {
|
||||
initGuard = token.K_准备 + "$guard"
|
||||
} else {
|
||||
initGuard = token.K_init + "$guard"
|
||||
}
|
||||
if g.Name() == initGuard || g.ForceRegister() {
|
||||
p.module.AddGlobal(pkg_name+"."+g.Name(), "", p.tLib.compile(g.Type().(*types.Pointer).Elem()), false, g)
|
||||
} else {
|
||||
name_exp := ""
|
||||
|
||||
@@ -2083,11 +2083,20 @@ func (b *builder) buildFuncDecl(pkg *Package, decl *ast.FuncDecl) {
|
||||
return // discard
|
||||
}
|
||||
fn := pkg.values[pkg.info.Defs[id]].(*Function)
|
||||
if decl.Recv == nil && id.Name == "init" {
|
||||
var v Call
|
||||
v.Call.Value = fn
|
||||
v.setType(types.NewTuple())
|
||||
pkg.init.emit(&v)
|
||||
if pkg.Pkg.W2Mode {
|
||||
if decl.Recv == nil && id.Name == token.K_准备 {
|
||||
var v Call
|
||||
v.Call.Value = fn
|
||||
v.setType(types.NewTuple())
|
||||
pkg.init.emit(&v)
|
||||
}
|
||||
} else {
|
||||
if decl.Recv == nil && id.Name == token.K_init {
|
||||
var v Call
|
||||
v.Call.Value = fn
|
||||
v.setType(types.NewTuple())
|
||||
pkg.init.emit(&v)
|
||||
}
|
||||
}
|
||||
b.buildFunction(fn)
|
||||
}
|
||||
@@ -2147,9 +2156,16 @@ func (p *Package) build() {
|
||||
|
||||
if p.Prog.mode&BareInits == 0 {
|
||||
// Make init() skip if package is already initialized.
|
||||
initguard := p.Var("init$guard")
|
||||
var initguard *Global
|
||||
if p.Pkg.W2Mode {
|
||||
initguard = p.Var(token.K_准备 + "$guard")
|
||||
} else {
|
||||
initguard = p.Var(token.K_init + "$guard")
|
||||
}
|
||||
|
||||
doinit := init.newBasicBlock("init.start")
|
||||
done = init.newBasicBlock("init.done")
|
||||
|
||||
emitIf(init, emitLoad(init, initguard), done, doinit)
|
||||
init.currentBlock = doinit
|
||||
emitStore(init, initguard, vTrue, token.NoPos)
|
||||
|
||||
@@ -80,9 +80,16 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
|
||||
|
||||
case *types.Func:
|
||||
sig := obj.Type().(*types.Signature)
|
||||
if sig.Recv() == nil && name == "init" {
|
||||
pkg.ninit++
|
||||
name = fmt.Sprintf("init#%d", pkg.ninit)
|
||||
if pkg.Pkg.W2Mode {
|
||||
if sig.Recv() == nil && name == token.K_准备 {
|
||||
pkg.ninit++
|
||||
name = fmt.Sprintf(token.K_准备+"#%d", pkg.ninit)
|
||||
}
|
||||
} else {
|
||||
if sig.Recv() == nil && name == token.K_init {
|
||||
pkg.ninit++
|
||||
name = fmt.Sprintf(token.K_init+"#%d", pkg.ninit)
|
||||
}
|
||||
}
|
||||
fn := &Function{
|
||||
name: name,
|
||||
@@ -169,14 +176,25 @@ func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *
|
||||
}
|
||||
|
||||
// Add init() function.
|
||||
p.init = &Function{
|
||||
name: "init",
|
||||
Signature: new(types.Signature),
|
||||
Synthetic: "package initializer",
|
||||
Pkg: p,
|
||||
Prog: prog,
|
||||
if pkg.W2Mode {
|
||||
p.init = &Function{
|
||||
name: token.K_准备,
|
||||
Signature: new(types.Signature),
|
||||
Synthetic: "package initializer",
|
||||
Pkg: p,
|
||||
Prog: prog,
|
||||
}
|
||||
p.Members[p.init.name] = p.init
|
||||
} else {
|
||||
p.init = &Function{
|
||||
name: token.K_init,
|
||||
Signature: new(types.Signature),
|
||||
Synthetic: "package initializer",
|
||||
Pkg: p,
|
||||
Prog: prog,
|
||||
}
|
||||
p.Members[p.init.name] = p.init
|
||||
}
|
||||
p.Members[p.init.name] = p.init
|
||||
|
||||
// CREATE phase.
|
||||
// Allocate all package members: vars, funcs, consts and types.
|
||||
@@ -207,12 +225,21 @@ func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *
|
||||
|
||||
if prog.mode&BareInits == 0 {
|
||||
// Add initializer guard variable.
|
||||
initguard := &Global{
|
||||
Pkg: p,
|
||||
name: "init$guard",
|
||||
typ: types.NewPointer(tBool),
|
||||
if pkg.W2Mode {
|
||||
initguard := &Global{
|
||||
Pkg: p,
|
||||
name: token.K_准备 + "$guard",
|
||||
typ: types.NewPointer(tBool),
|
||||
}
|
||||
p.Members[initguard.Name()] = initguard
|
||||
} else {
|
||||
initguard := &Global{
|
||||
Pkg: p,
|
||||
name: token.K_init + "$guard",
|
||||
typ: types.NewPointer(tBool),
|
||||
}
|
||||
p.Members[initguard.Name()] = initguard
|
||||
}
|
||||
p.Members[initguard.Name()] = initguard
|
||||
}
|
||||
|
||||
if prog.mode&GlobalDebug != 0 {
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"wa-lang.org/wa/internal/token"
|
||||
"wa-lang.org/wa/internal/types"
|
||||
)
|
||||
|
||||
@@ -31,7 +32,6 @@ type sanity struct {
|
||||
//
|
||||
// Sanity-checking is intended to facilitate the debugging of code
|
||||
// transformation passes.
|
||||
//
|
||||
func sanityCheck(fn *Function, reporter io.Writer) bool {
|
||||
if reporter == nil {
|
||||
reporter = os.Stderr
|
||||
@@ -41,7 +41,6 @@ func sanityCheck(fn *Function, reporter io.Writer) bool {
|
||||
|
||||
// mustSanityCheck is like sanityCheck but panics instead of returning
|
||||
// a negative result.
|
||||
//
|
||||
func mustSanityCheck(fn *Function, reporter io.Writer) {
|
||||
if !sanityCheck(fn, reporter) {
|
||||
fn.WriteTo(os.Stderr)
|
||||
@@ -516,12 +515,22 @@ func sanityCheckPackage(pkg *Package) {
|
||||
continue // not all members have typechecker objects
|
||||
}
|
||||
if obj.Name() != name {
|
||||
if obj.Name() == "init" && strings.HasPrefix(mem.Name(), "init#") {
|
||||
// Ok. The name of a declared init function varies between
|
||||
// its types.Func ("init") and its ssa.Function ("init#%d").
|
||||
if pkg.Pkg.W2Mode {
|
||||
if obj.Name() == token.K_准备 && strings.HasPrefix(mem.Name(), token.K_准备+"#") {
|
||||
// Ok. The name of a declared 准备 function varies between
|
||||
// its types.Func ("准备") and its ssa.Function ("准备#%d").
|
||||
} else {
|
||||
panic(fmt.Sprintf("%s: %T.Object().Name() = %s, want %s",
|
||||
pkg.Pkg.Path(), mem, obj.Name(), name))
|
||||
}
|
||||
} else {
|
||||
panic(fmt.Sprintf("%s: %T.Object().Name() = %s, want %s",
|
||||
pkg.Pkg.Path(), mem, obj.Name(), name))
|
||||
if obj.Name() == token.K_init && strings.HasPrefix(mem.Name(), token.K_init+"#") {
|
||||
// Ok. The name of a declared init function varies between
|
||||
// its types.Func ("init") and its ssa.Function ("init#%d").
|
||||
} else {
|
||||
panic(fmt.Sprintf("%s: %T.Object().Name() = %s, want %s",
|
||||
pkg.Pkg.Path(), mem, obj.Name(), name))
|
||||
}
|
||||
}
|
||||
}
|
||||
if obj.Pos() != mem.Pos() {
|
||||
|
||||
@@ -80,20 +80,38 @@ func findEnclosingPackageLevelFunction(pkg *Package, path []ast.Node) *Function
|
||||
}
|
||||
|
||||
case *ast.FuncDecl:
|
||||
if decl.Recv == nil && decl.Name.Name == "init" {
|
||||
// Explicit init() function.
|
||||
for _, b := range pkg.init.Blocks {
|
||||
for _, instr := range b.Instrs {
|
||||
if instr, ok := instr.(*Call); ok {
|
||||
if callee, ok := instr.Call.Value.(*Function); ok && callee.Pkg == pkg && callee.Pos() == decl.Name.NamePos {
|
||||
return callee
|
||||
if pkg.Pkg.W2Mode {
|
||||
if decl.Recv == nil && decl.Name.Name == token.K_准备 {
|
||||
// Explicit init() function.
|
||||
for _, b := range pkg.init.Blocks {
|
||||
for _, instr := range b.Instrs {
|
||||
if instr, ok := instr.(*Call); ok {
|
||||
if callee, ok := instr.Call.Value.(*Function); ok && callee.Pkg == pkg && callee.Pos() == decl.Name.NamePos {
|
||||
return callee
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Hack: return non-nil when SSA is not yet
|
||||
// built so that HasEnclosingFunction works.
|
||||
return pkg.init
|
||||
}
|
||||
} else {
|
||||
if decl.Recv == nil && decl.Name.Name == token.K_init {
|
||||
// Explicit init() function.
|
||||
for _, b := range pkg.init.Blocks {
|
||||
for _, instr := range b.Instrs {
|
||||
if instr, ok := instr.(*Call); ok {
|
||||
if callee, ok := instr.Call.Value.(*Function); ok && callee.Pkg == pkg && callee.Pos() == decl.Name.NamePos {
|
||||
return callee
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Hack: return non-nil when SSA is not yet
|
||||
// built so that HasEnclosingFunction works.
|
||||
return pkg.init
|
||||
}
|
||||
// Hack: return non-nil when SSA is not yet
|
||||
// built so that HasEnclosingFunction works.
|
||||
return pkg.init
|
||||
}
|
||||
// Declared function/method.
|
||||
return findNamedFunc(pkg, decl.Name.NamePos)
|
||||
|
||||
@@ -46,9 +46,9 @@ type Program struct {
|
||||
type Package struct {
|
||||
Prog *Program // the owning program
|
||||
Pkg *types.Package // the corresponding go/types.Package
|
||||
Members map[string]Member // all package members keyed by name (incl. init and init#%d)
|
||||
Members map[string]Member // all package members keyed by name (incl. init/准备 and init#%d/准备#%d)
|
||||
values map[types.Object]Value // package members (incl. types and methods), keyed by object
|
||||
init *Function // Func("init"); the package's init function
|
||||
init *Function // Func("init") or Func("准备"); the package's init function
|
||||
debug bool // include full debug info in this package
|
||||
|
||||
// The following fields are set transiently, then cleared
|
||||
|
||||
@@ -550,9 +550,17 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
|
||||
obj.typ = sig // guard against cycles
|
||||
fdecl := decl.fdecl
|
||||
check.funcType(sig, fdecl.Recv, fdecl.Type)
|
||||
if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) {
|
||||
check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
|
||||
// ok to continue
|
||||
|
||||
if check.pkg.W2Mode {
|
||||
if sig.recv == nil && obj.name == token.K_准备 && (sig.params.Len() > 0 || sig.results.Len() > 0) {
|
||||
check.errorf(fdecl.Pos(), "func %s must have no arguments and no return values", token.K_准备)
|
||||
// ok to continue
|
||||
}
|
||||
} else {
|
||||
if sig.recv == nil && obj.name == token.K_init && (sig.params.Len() > 0 || sig.results.Len() > 0) {
|
||||
check.errorf(fdecl.Pos(), "func %s must have no arguments and no return values", token.K_init)
|
||||
// ok to continue
|
||||
}
|
||||
}
|
||||
|
||||
// function body must be type-checked after global declarations
|
||||
|
||||
@@ -7,6 +7,7 @@ package types
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"wa-lang.org/wa/internal/ast"
|
||||
"wa-lang.org/wa/internal/constant"
|
||||
@@ -153,7 +154,19 @@ func (obj *object) Type() Type { return obj.typ }
|
||||
// Exported reports whether the object is exported (starts with a capital letter).
|
||||
// It doesn't take into account whether the object is in a local (function) scope
|
||||
// or not.
|
||||
func (obj *object) Exported() bool { return token.IsExported(obj.name) }
|
||||
func (obj *object) Exported() bool {
|
||||
if obj.pkg != nil && obj.pkg.W2Mode {
|
||||
if obj.name == token.K_准备 {
|
||||
return false
|
||||
}
|
||||
if strings.HasPrefix(obj.name, token.K_准备+"#") {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
// init 小写字母开头, 属于未导出
|
||||
}
|
||||
return token.IsExported(obj.name)
|
||||
}
|
||||
|
||||
// Id is a wrapper for Id(obj.Pkg(), obj.Name()).
|
||||
func (obj *object) Id() string { return Id(obj.pkg, obj.name) }
|
||||
|
||||
@@ -112,14 +112,14 @@ func (check *Checker) declarePkgObj(ident *ast.Ident, obj Object, d *declInfo) {
|
||||
// spec: "A package-scope or file-scope identifier with name init
|
||||
// may only be declared to be a function with this (func()) signature."
|
||||
if ident.Name == token.K_准备 {
|
||||
check.errorf(ident.Pos(), "cannot declare init - must be func")
|
||||
check.errorf(ident.Pos(), "cannot declare %s - must be func", token.K_准备)
|
||||
return
|
||||
}
|
||||
|
||||
// spec: "The main package must have package name main and declare
|
||||
// a function main that takes no arguments and returns no value."
|
||||
if ident.Name == token.K_主控 && check.pkg.name == token.K_pkg_主包 {
|
||||
check.errorf(ident.Pos(), "cannot declare main - must be func")
|
||||
check.errorf(ident.Pos(), "cannot declare %s - must be func", token.K_主控)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -127,14 +127,14 @@ func (check *Checker) declarePkgObj(ident *ast.Ident, obj Object, d *declInfo) {
|
||||
// spec: "A package-scope or file-scope identifier with name init
|
||||
// may only be declared to be a function with this (func()) signature."
|
||||
if ident.Name == token.K_init {
|
||||
check.errorf(ident.Pos(), "cannot declare init - must be func")
|
||||
check.errorf(ident.Pos(), "cannot declare %s - must be func", token.K_init)
|
||||
return
|
||||
}
|
||||
|
||||
// spec: "The main package must have package name main and declare
|
||||
// a function main that takes no arguments and returns no value."
|
||||
if ident.Name == token.K_main && check.pkg.name == token.K_main {
|
||||
check.errorf(ident.Pos(), "cannot declare main - must be func")
|
||||
if ident.Name == token.K_main && check.pkg.name == token.K_pkg_main {
|
||||
check.errorf(ident.Pos(), "cannot declare %s - must be func", token.K_main)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -306,9 +306,17 @@ func (check *Checker) collectObjects() {
|
||||
check.errorf(s.Name.Pos(), `cannot rename import "C"`)
|
||||
continue
|
||||
}
|
||||
if name == "init" {
|
||||
check.errorf(s.Name.Pos(), "cannot declare init - must be func")
|
||||
continue
|
||||
|
||||
if check.pkg.W2Mode {
|
||||
if name == token.K_准备 {
|
||||
check.errorf(s.Name.Pos(), "cannot declare %s - must be func", token.K_准备)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if name == token.K_init {
|
||||
check.errorf(s.Name.Pos(), "cannot declare %s - must be func", token.K_init)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,16 +467,30 @@ func (check *Checker) collectObjects() {
|
||||
obj.setNode(d)
|
||||
if d.Recv == nil {
|
||||
// regular function
|
||||
if name == "init" {
|
||||
// don't declare init functions in the package scope - they are invisible
|
||||
obj.parent = pkg.scope
|
||||
check.recordDef(d.Name, obj)
|
||||
// init functions must have a body
|
||||
if d.Body == nil {
|
||||
check.softErrorf(obj.pos, "missing function body")
|
||||
if check.pkg.W2Mode {
|
||||
if name == token.K_准备 {
|
||||
// don't declare init functions in the package scope - they are invisible
|
||||
obj.parent = pkg.scope
|
||||
check.recordDef(d.Name, obj)
|
||||
// init functions must have a body
|
||||
if d.Body == nil {
|
||||
check.softErrorf(obj.pos, "missing function body")
|
||||
}
|
||||
} else {
|
||||
check.declare(pkg.scope, d.Name, obj, token.NoPos)
|
||||
}
|
||||
} else {
|
||||
check.declare(pkg.scope, d.Name, obj, token.NoPos)
|
||||
if name == token.K_init {
|
||||
// don't declare init functions in the package scope - they are invisible
|
||||
obj.parent = pkg.scope
|
||||
check.recordDef(d.Name, obj)
|
||||
// init functions must have a body
|
||||
if d.Body == nil {
|
||||
check.softErrorf(obj.pos, "missing function body")
|
||||
}
|
||||
} else {
|
||||
check.declare(pkg.scope, d.Name, obj, token.NoPos)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// method
|
||||
|
||||
@@ -6,4 +6,10 @@ dev:
|
||||
run:
|
||||
go run ../../../main.go run .
|
||||
|
||||
publish:
|
||||
go run ../../../main.go build .
|
||||
-rm -rf ../../../docs/p5-hello-wz/
|
||||
mkdir -p ../../../docs/p5-hello-wz
|
||||
cp ./output/* ../../../docs/p5-hello-wz/
|
||||
|
||||
clean:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
引入 "小画家"
|
||||
|
||||
函数·init:
|
||||
函数·准备:
|
||||
小画家·准备画纸(400)
|
||||
小画家·涂背景色(220)
|
||||
小画家·设置画笔颜色(小画家·红色)
|
||||
|
||||
Reference in New Issue
Block a user