diff --git a/README-zh.md b/README-zh.md index fc561b7c695bd9709adc0085f5625afae2637938..abdac47ba598ce477f6cf8dc6721ce05d9b70d84 100644 --- a/README-zh.md +++ b/README-zh.md @@ -17,7 +17,7 @@ 凹语言™(凹读音“Wa”)是 针对 WASM 平台设计的通用编程语言,同时支持 Linux、macOS 和 Windows 等主流操作系统和 Chrome 等浏览器环境,同时也支持作为独立Shell脚本和被嵌入脚本模式执行。 -![](docs/images/logo/logo-animate1-blue.svg) +![](docs/images/logo/logo-animate1.svg) - 主页: [https://wa-lang.org](https://wa-lang.org) - 代码仓库 (Gitee): [https://gitee.com/wa-lang/wa](https://gitee.com/wa-lang/wa) @@ -128,7 +128,3 @@ func main() { ``` 注:作为脚本执行目前只支持本地环境。 - -## 版权(License) - -版权 @2019-2022 凹语言™ 作者。保留所有权利。 diff --git a/README.md b/README.md index 51b1b5383528f8a1fe71091b18551acb3c571c19..51a4a88b836bb3b2d8c2d30bbcca442225b2665f 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Wa is a general-purpose programming language designed for developing robustness and maintainability WebAssembly software. Instead of requiring complex toolchains to set up, you can simply go install it - or run it in a browser. -![](docs/images/logo/logo-animate1-blue.svg) +![](docs/images/logo/logo-animate1.svg) - Homepage: [https://wa-lang.org](https://wa-lang.org) - Github: [https://github.com/wa-lang/wa](https://github.com/wa-lang/wa) @@ -130,7 +130,3 @@ func main() { ``` Note: Executing as a script currently only supports native environments. - -## License - -Copyright @2019-2022 The Wa author. All rights reserved. diff --git a/_examples/llvm/internal_function.wa b/_examples/llvm/internal_function.wa index d9e80e216c41d44848b0b4d6ad3793f8da19c01c..dc857c0f1cca489d7667db88a630ec9052511a05 100644 --- a/_examples/llvm/internal_function.wa +++ b/_examples/llvm/internal_function.wa @@ -1,18 +1,30 @@ # Test the llvm backend. # Test anonymous functions and closure functions. +type pair struct { + i :f32 + j :f32 +} + fn main() { print("Hello, ") fn() { println("World!") }() - var i: int - show := fn() { - println("i = ", i) + var i: int = 31 + var j: [4]f32 = [4]f32{1, 2.2, 5.5, 9.8} + var k: pair = pair{3.14, 2.718} + show := fn(q: int) { + println(i, " + ", q, " = ", i+q) + println("{", j[0], ", ", j[1], ", ", j[2], ", ", j[3], "}") + println("{", k.i, ", ", k.j, "}") } - for i = 0; i < 10; i++ { - show() + for i := int(0); i < 4; i++ { + j[i] += 1.0 + k.i += 0.1 + k.j -= 0.1 + show(i) } } diff --git a/internal/backends/compiler_llvm/compile.go b/internal/backends/compiler_llvm/compile.go index 3fb3c7744202ee1ca986c851ee0ff27e9bec113d..cf08328129838a65ebe2707b4b4c63649e1173df 100644 --- a/internal/backends/compiler_llvm/compile.go +++ b/internal/backends/compiler_llvm/compile.go @@ -16,12 +16,22 @@ type FmtStr struct { size int } +type Argument struct { + AType string + AName string +} + +type InnerFunc struct { + fn *ssa.Function + args []Argument +} + type Compiler struct { target string output strings.Builder debug bool fmts []FmtStr - anofn []*ssa.Function + anofn []InnerFunc } func New(target string, debug bool) *Compiler { @@ -138,18 +148,18 @@ func (p *Compiler) compilePackage(pkg *ssa.Package) error { // Generate LLVM-IR for each global function. for _, v := range fns { - if err := p.compileFunction(v); err != nil { + if err := p.compileFunction(v, []Argument{}); err != nil { return err } } // Generate LLVM-IR for each internal function. for _, v := range p.anofn { - if err := p.compileFunction(v); err != nil { + if err := p.compileFunction(v.fn, v.args); err != nil { return err } } - p.anofn = []*ssa.Function{} + p.anofn = []InnerFunc{} return nil } diff --git a/internal/backends/compiler_llvm/compile_function.go b/internal/backends/compiler_llvm/compile_function.go index c7cb47134bdcef4350f4a7dfcd418242516bcf35..aafbdc6ecd6842670d1b5cb53be904f89a664841 100644 --- a/internal/backends/compiler_llvm/compile_function.go +++ b/internal/backends/compiler_llvm/compile_function.go @@ -11,7 +11,7 @@ import ( "github.com/wa-lang/wa/internal/types" ) -func (p *Compiler) compileFunction(fn *ssa.Function) error { +func (p *Compiler) compileFunction(fn *ssa.Function, extraArgs []Argument) error { if isTargetBuiltin(fn.LinkName(), p.target) || isTargetBuiltin(fn.Name(), p.target) { return nil } @@ -82,6 +82,14 @@ func (p *Compiler) compileFunction(fn *ssa.Function) error { p.output.WriteString(", ") } } + // Emit binded values as extra arguments for closure functions. + for _, v := range extraArgs { + p.output.WriteString(", ") + p.output.WriteString(v.AType) + p.output.WriteString(" ") + p.output.WriteString(v.AName) + } + // Finish emitting function header. if len(fn.Blocks) == 0 { p.output.WriteString(")\n\n") return nil diff --git a/internal/backends/compiler_llvm/compile_value.go b/internal/backends/compiler_llvm/compile_value.go index 36f20ec857518d86a578e85046fcc3c75adbc170..390aaf13d7255101578dd9c9c75bba26ccfbe008 100644 --- a/internal/backends/compiler_llvm/compile_value.go +++ b/internal/backends/compiler_llvm/compile_value.go @@ -114,6 +114,10 @@ func (p *Compiler) compileValue(val ssa.Value) error { p.output.WriteString(fmt.Sprintf("%d", val.Index)) p.output.WriteString("\n") + case *ssa.MakeClosure: + // We postpone the process of closure functions to the fist call of them. + break + default: p.output.WriteString(" ; " + val.Name() + " = " + val.String() + "\n") // panic("unsupported Value '" + val.Name() + " = " + val.String() + "'") @@ -359,7 +363,7 @@ func (p *Compiler) compileBinOp(val *ssa.BinOp) error { func (p *Compiler) compileCall(val *ssa.Call) error { switch val.Call.Value.(type) { - case *ssa.Function: + case *ssa.Function, *ssa.MakeClosure: // Special process for float32 constants. paf32 := map[int]string{} for i, v := range val.Call.Args { @@ -389,16 +393,42 @@ func (p *Compiler) compileCall(val *ssa.Call) error { callee := val.Call.StaticCallee() // This callee is an internal function, whose body will be genereated later. if callee.Parent() != nil { - p.anofn = append(p.anofn, callee) + found := false + for _, f := range p.anofn { + if f.fn == callee { + found = true + } + } + if !found { + inner := InnerFunc{callee, []Argument{}} + // Collect all binded values for closure functions, then emit them as implicit arguments. + if cl, ok := val.Call.Value.(*ssa.MakeClosure); ok { + for _, v := range cl.Bindings { + if al, ok := v.(*ssa.Alloc); ok { + arg := Argument{getTypeStr(v.Type(), p.target), "%" + al.Comment} + inner.args = append(inner.args, arg) + } + } + } + p.anofn = append(p.anofn, inner) + } } + // Emit link name for external functions. if len(callee.LinkName()) > 0 { p.output.WriteString(callee.LinkName()) } else { p.output.WriteString(getNormalName(callee.Pkg.Pkg.Path() + "." + callee.Name())) } p.output.WriteString("(") + // Collect all binded values for closure functions, then pass them as implicit parameters. + params := val.Call.Args[0:] + if cl, ok := val.Call.Value.(*ssa.MakeClosure); ok { + for _, v := range cl.Bindings { + params = append(params, v) + } + } // Emit parameters. - for i, v := range val.Call.Args { + for i, v := range params { ty := getRealType(v.Type()) tyStr := getTypeStr(ty, p.target) switch ty.(type) { @@ -414,7 +444,7 @@ func (p *Compiler) compileCall(val *ssa.Call) error { } else { p.output.WriteString(getValueStr(v)) } - if i < len(val.Call.Args)-1 { + if i < len(params)-1 { p.output.WriteString(", ") } }