修复 wz 准备函数不能工作的问题

This commit is contained in:
chai2010
2025-10-28 20:39:41 +08:00
parent f6c80e4a3c
commit 1f459ac937
13 changed files with 194 additions and 63 deletions

View File

@@ -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

View File

@@ -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 != "" {

View File

@@ -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 := ""

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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() {

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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) }

View File

@@ -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

View File

@@ -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:

View File

@@ -2,7 +2,7 @@
引入 "小画家"
函数·init:
函数·准备:
小画家·准备画纸(400)
小画家·涂背景色(220)
小画家·设置画笔颜色(小画家·红色)