diff --git a/README-zh.md b/README-zh.md index 33180fa4bcac8ed2af0e2dda4d64aea744230844..7dba96051aff0910e6ce8defdfba76becaddc476 100644 --- a/README-zh.md +++ b/README-zh.md @@ -10,6 +10,7 @@ ![](docs/images/logo/logo-animate1.svg) - 主页: [https://wa-lang.org](https://wa-lang.org) +- 参考手册: [https://wa-lang.org/man/](https://wa-lang.org/man/) - 仓库(Gitee): [https://gitee.com/wa-lang/wa](https://gitee.com/wa-lang/wa) - 仓库(Github): [https://github.com/wa-lang/wa](https://github.com/wa-lang/wa) - Playground: [https://wa-lang.org/playground](https://wa-lang.org/playground) diff --git a/README.md b/README.md index 56bce67efd0fa197f19030b6f4dfafb6eac717c4..6736617106086fac2b2bdb237e588bdd79b73311 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Instead of requiring complex toolchains to set up, you can simply go install it ![](docs/images/logo/logo-animate1.svg) - Home: [https://wa-lang.org](https://wa-lang.org) +- Manual(Chinese): [https://wa-lang.org/man/](https://wa-lang.org/man/) - Github: [https://github.com/wa-lang/wa](https://github.com/wa-lang/wa) - Playground: [https://wa-lang.org/playground](https://wa-lang.org/playground) diff --git a/internal/app/apptest/apptest.go b/internal/app/apptest/apptest.go index e16b57455f8a601933aa607d045dc3502ac4e7e7..8d0289f977708e1087eb3d1cbd52ae79a56c19cc 100644 --- a/internal/app/apptest/apptest.go +++ b/internal/app/apptest/apptest.go @@ -98,8 +98,49 @@ func runTest(cfg *config.Config, pkgpath string, appArgs ...string) { // 执行测试函数 var firstError error - for _, t := range mainPkg.TestInfo.Tests { - _, stdout, stderr, err := m.RunFunc(mainPkg.Pkg.Path() + "." + t.Name) + for i := 0; i < len(mainPkg.TestInfo.Tests); i++ { + t := mainPkg.TestInfo.Tests[i] + + tFuncName := mainPkg.Pkg.Path() + "." + t.Name + tFuncName = strings.ReplaceAll(tFuncName, "/", "$") + _, stdout, stderr, err := m.RunFunc(tFuncName) + if t.OutputPanic { + stdout = bytes.TrimSpace(stdout) + expect, got := t.Output, string(stdout) + + if exitCode, _ := wazero.AsExitError(err); exitCode == 0 { + fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name) + fmt.Printf(" expect panic, got = nil\n") + + if firstError == nil { + firstError = fmt.Errorf("expect(panic) = %q, got = %q", expect, "nil") + } + continue + } + + if !strings.HasPrefix(got, "panic: "+expect) { // panic: ${expect} (pos) + fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name) + fmt.Printf(" expect(panic) = %q, got = %q\n", expect, got) + + if firstError == nil { + firstError = fmt.Errorf("expect(panic) = %q, got = %q", expect, got) + } + } + + // 重新加载 + { + m, err = wazero.BuildModule(cfg, wasmName, wasmBytes, wasmArgs...) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + // 临时方案: defer 太多 + defer m.Close() + } + + continue + } if err != nil { if len(stdout) > 0 { if s := sWithPrefix(string(stdout), " "); s != "" { @@ -110,7 +151,12 @@ func runTest(cfg *config.Config, pkgpath string, appArgs ...string) { if s := sWithPrefix(string(stderr), " "); s != "" { fmt.Println(s) } + } else { + if s := sWithPrefix(err.Error(), " "); s != "" { + fmt.Println(s) + } } + os.Exit(1) } @@ -146,8 +192,50 @@ func runTest(cfg *config.Config, pkgpath string, appArgs ...string) { } } } - for _, t := range mainPkg.TestInfo.Examples { - _, stdout, stderr, err := m.RunFunc(mainPkg.Pkg.Path() + "." + t.Name) + + for i := 0; i < len(mainPkg.TestInfo.Examples); i++ { + t := mainPkg.TestInfo.Examples[i] + + tFuncName := mainPkg.Pkg.Path() + "." + t.Name + tFuncName = strings.ReplaceAll(tFuncName, "/", "$") + _, stdout, stderr, err := m.RunFunc(tFuncName) + if t.OutputPanic { + stdout = bytes.TrimSpace(stdout) + expect, got := t.Output, string(stdout) + + if exitCode, _ := wazero.AsExitError(err); exitCode == 0 { + fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name) + fmt.Printf(" expect panic, got = nil\n") + + if firstError == nil { + firstError = fmt.Errorf("expect panic, got = nil") + } + continue + } + + if !strings.HasPrefix(got, "panic: "+expect) { // panic: ${expect} (pos) + fmt.Printf("---- %s.%s\n", prog.Manifest.MainPkg, t.Name) + fmt.Printf(" expect(panic) = %q, got = %q\n", expect, got) + + if firstError == nil { + firstError = fmt.Errorf("expect(panic) = %q, got = %q", expect, got) + } + } + + // 重新加载 + { + m, err = wazero.BuildModule(cfg, wasmName, wasmBytes, wasmArgs...) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + // 临时方案: defer 太多 + defer m.Close() + } + + continue + } if err != nil { if len(stdout) > 0 { if s := sWithPrefix(string(stdout), " "); s != "" { diff --git a/internal/loader/api.go b/internal/loader/api.go index 5fea1f9dd5ad6cbedd328e69550242b1f81ef196..6caeac91c751656c0f4313bf86282a2735157e9f 100644 --- a/internal/loader/api.go +++ b/internal/loader/api.go @@ -44,9 +44,10 @@ type TestInfo struct { // 测试函数信息 type TestFuncInfo struct { - FuncPos token.Pos // 函数位置 - Name string // 函数名, 不含包路径 - Output string // 期望输出, 为空表示不验证 + FuncPos token.Pos // 函数位置 + Name string // 函数名, 不含包路径 + Output string // 期望输出, 为空表示不验证 + OutputPanic bool // 异常信息 } // 汇编代码文件 diff --git a/internal/loader/loader.go b/internal/loader/loader.go index eea727e502abba75cb467c3631cbb9813220ab6a..dc0d5908fe1c7a8ead2a677237c6670d66c9cfbb 100644 --- a/internal/loader/loader.go +++ b/internal/loader/loader.go @@ -300,10 +300,12 @@ func (p *_Loader) parseTestInfo(pkg *Package, filenames []string) (*TestInfo, er switch { case strings.HasPrefix(name, "Test"): + output, isPanic := p.parseExampleOutputComment(file, fn) tInfo.Tests = append(tInfo.Tests, TestFuncInfo{ - FuncPos: obj.Pos(), - Name: name, - Output: p.parseExampleOutputComment(file, fn), + FuncPos: obj.Pos(), + Name: name, + Output: output, + OutputPanic: isPanic, }) case strings.HasPrefix(name, "Bench"): tInfo.Benchs = append(tInfo.Benchs, TestFuncInfo{ @@ -311,10 +313,12 @@ func (p *_Loader) parseTestInfo(pkg *Package, filenames []string) (*TestInfo, er Name: name, }) case strings.HasPrefix(name, "Example"): + output, isPanic := p.parseExampleOutputComment(file, fn) tInfo.Examples = append(tInfo.Examples, TestFuncInfo{ - FuncPos: obj.Pos(), - Name: name, - Output: p.parseExampleOutputComment(file, fn), + FuncPos: obj.Pos(), + Name: name, + Output: output, + OutputPanic: isPanic, }) } } @@ -324,7 +328,7 @@ func (p *_Loader) parseTestInfo(pkg *Package, filenames []string) (*TestInfo, er return tInfo, nil } -func (p *_Loader) parseExampleOutputComment(f *ast.File, fn *ast.FuncDecl) string { +func (p *_Loader) parseExampleOutputComment(f *ast.File, fn *ast.FuncDecl) (output string, isPanic bool) { for _, commentGroup := range f.Comments { if commentGroup.Pos() <= fn.Body.Pos() { continue @@ -334,23 +338,33 @@ func (p *_Loader) parseExampleOutputComment(f *ast.File, fn *ast.FuncDecl) strin } for j, comment := range commentGroup.List { - if comment.Text != "// Output:" { - continue - } + switch comment.Text { + case "// Output:": + var lineTexts []string + for _, x := range commentGroup.List[j+1:] { + if !strings.HasPrefix(x.Text, "//") { + break + } + lineTexts = append(lineTexts, strings.TrimSpace(x.Text[2:])) + } - var lineTexts []string - for _, x := range commentGroup.List[j+1:] { - if !strings.HasPrefix(x.Text, "//") { - break + return strings.Join(lineTexts, "\n"), false + + case "// Output(panic):": + var lineTexts []string + for _, x := range commentGroup.List[j+1:] { + if !strings.HasPrefix(x.Text, "//") { + break + } + lineTexts = append(lineTexts, strings.TrimSpace(x.Text[2:])) } - lineTexts = append(lineTexts, strings.TrimSpace(x.Text[2:])) - } - return strings.Join(lineTexts, "\n") + return strings.Join(lineTexts, "\n"), true + } } } - return "" + return "", false } func (p *_Loader) ParseDir_wsFiles(pkgpath string) (files []*WsFile, err error) { diff --git a/waroot/src/apple/apple_test.wa b/waroot/src/apple/apple_test.wa index 6942f10ca483ede4eb22290e326e6b62ffaa3796..6d673555cd5b1f9afdf8328e28b7f5367683dcf1 100644 --- a/waroot/src/apple/apple_test.wa +++ b/waroot/src/apple/apple_test.wa @@ -23,4 +23,11 @@ func ExampleApple { // Output: // apple-mvp -} \ No newline at end of file +} + +func ExamplePanic { + panic("fuck panic") + + // Output(panic): + // fuck panic +} diff --git a/waroot/src/builtin/builtin.wa b/waroot/src/builtin/builtin.wa index e191fdd016e4ed0e76aa0e3659205563ecc85a5d..52f2c9daaf9cfd6750210ff58409b2de2c179ce5 100644 --- a/waroot/src/builtin/builtin.wa +++ b/waroot/src/builtin/builtin.wa @@ -12,40 +12,32 @@ const ( // u8 is the set of all unsigned 8-bit integers. // Range: 0 through 255. type u8: u8 -type uint8: u8 // u16 is the set of all unsigned 16-bit integers. // Range: 0 through 65535. type u16: u16 -type uint16: u16 // u32 is the set of all unsigned 32-bit integers. // Range: 0 through 4294967295. type u32: u32 -type uint32: u32 // u64 is the set of all unsigned 64-bit integers. // Range: 0 through 18446744073709551615. type u64: u64 -type uint64: u64 // int32 is the set of all signed 32-bit integers. // Range: -2147483648 through 2147483647. type i32: i32 -type int32: i32 // int64 is the set of all signed 64-bit integers. // Range: -9223372036854775808 through 9223372036854775807. type i64: i64 -type int64: i64 // float32 is the set of all IEEE-754 32-bit floating-point numbers. type f32: f32 -type float32: f32 // float64 is the set of all IEEE-754 64-bit floating-point numbers. type f64: f64 -type float64: f64 // string is the set of all strings of 8-bit bytes, conventionally but not // necessarily representing UTF-8-encoded text. A string may be empty, but @@ -60,10 +52,6 @@ type int: int // distinct type, however, and not an alias for, say, u32. type uint: uint -// uintptr is an integer type that is large enough to hold the bit pattern of -// any pointer. -type uintptr uintptr - // byte is an alias for u8 and is equivalent to u8 in all ways. It is // used, by convention, to distinguish byte values from 8-bit unsigned // integer values. @@ -73,24 +61,14 @@ type byte = u8 // used, by convention, to distinguish character values from integer values. type rune = i32 -// iota is a predeclared identifier representing the untyped integer ordinal -// number of the current const specification in a (usually parenthesized) -// const declaration. It is zero-indexed. -const iota = 0 // Untyped int. - -// nil is a predeclared identifier representing the zero value for a -// pointer, channel, func, interface, map, or slice type. -global nil: Type // Type must be a pointer, channel, func, interface, map, or slice type - // Type is here for the purposes of documentation only. It is a stand-in -// for any Go type, but represents the same type for any given function +// for any Wa type, but represents the same type for any given function // invocation. type Type: int -// Type1 is here for the purposes of documentation only. It is a stand-in -// for any Go type, but represents the same type for any given function -// invocation. -type Type1: int +// nil is a predeclared identifier representing the zero value for a +// pointer, func, interface, map, or slice type. +global nil: Type // Type must be a pointer, func, interface, map, or slice type // IntegerType is here for the purposes of documentation only. It is a stand-in // for any integer type: int, uint, int8 etc. @@ -123,10 +101,8 @@ func copy(dst, src: []Type) => int // Pointer to array: the number of elements in *v (even if v is nil). // Slice, or map: the number of elements in v; if v is nil, len(v) is zero. // String: the number of bytes in v. -// Channel: the number of elements queued (unread) in the channel buffer; -// if v is nil, len(v) is zero. // For some arguments, such as a string literal or a simple array expression, the -// result can be a constant. See the Go language specification's "Length and +// result can be a constant. See the Wa language specification's "Length and // capacity" section for details. func len(v: Type) => int @@ -135,15 +111,13 @@ func len(v: Type) => int // Pointer to array: the number of elements in *v (same as len(v)). // Slice: the maximum length the slice can reach when resliced; // if v is nil, cap(v) is zero. -// Channel: the channel buffer capacity, in units of elements; -// if v is nil, cap(v) is zero. // For some arguments, such as a simple array expression, the result can be a -// constant. See the Go language specification's "Length and capacity" section for +// constant. See the Wa language specification's "Length and capacity" section for // details. func cap(v: Type) => int // The make built-in function allocates and initializes an object of type -// slice, map, or chan (only). Like new, the first argument is a type, not a +// slice, or map. Like new, the first argument is a type, not a // value. Unlike new, make's return type is the same as the type of its // argument, not a pointer to it. The specification of the result depends on // the type: @@ -156,9 +130,6 @@ func cap(v: Type) => int // Map: An empty map is allocated with enough space to hold the // specified number of elements. The size may be omitted, in which case // a small starting size is allocated. -// Channel: The channel's buffer is initialized with the specified -// buffer capacity. If zero, or the size is omitted, the channel is -// unbuffered. func make(t: Type, size: ...IntegerType) => Type // The new built-in function allocates memory. The first argument is a type, @@ -167,15 +138,7 @@ func make(t: Type, size: ...IntegerType) => Type func new(Type) => *Type // The panic built-in function stops normal execution of the current -// goroutine. When a function F calls panic, normal execution of F stops -// immediately. Any functions whose execution was deferred by F are run in -// the usual way, and then F returns to its caller. To the caller G, the -// invocation of F then behaves like a call to panic, terminating G's -// execution and running any deferred functions. This continues until all -// functions in the executing goroutine have stopped, in reverse order. At -// that point, the program is terminated with a non-zero exit code. This -// termination sequence is called panicking and can be controlled by the -// built-in function recover. +// application. func panic(msg: string) // The print built-in function formats its arguments in an diff --git a/waroot/src/math/bits/bits.wa b/waroot/src/math/bits/bits.wa index 61dcb8a4e6f5d34c429d340912257f4ef897f19b..e6d34c83fc6707aca62dda28460c5ecbf5719c8f 100644 --- a/waroot/src/math/bits/bits.wa +++ b/waroot/src/math/bits/bits.wa @@ -4,6 +4,11 @@ //go:generate go run make_tables.go +const ( + overflowError = "integer overflow" + divideError = "integer divide by zero" +) + const uintSize = 32 << (^uint(0) >> 63) // 32 or 64 // UintSize is the size of a uint in bits. @@ -21,24 +26,24 @@ func LeadingZeros8(x: uint8) => int { return 8 - Len8(x) } func LeadingZeros16(x: uint16) => int { return 16 - Len16(x) } // LeadingZeros32 returns the number of leading zero bits in x; the result is 32 for x == 0. -func LeadingZeros32(x: uint32) => int { return 32 - Len32(x) } +func LeadingZeros32(x: u32) => int { return 32 - Len32(x) } // LeadingZeros64 returns the number of leading zero bits in x; the result is 64 for x == 0. -func LeadingZeros64(x: uint64) => int { return 64 - Len64(x) } +func LeadingZeros64(x: u64) => int { return 64 - Len64(x) } // --- TrailingZeros --- // See http://supertech.csail.mit.edu/papers/debruijn.pdf const deBruijn32 = 0x077CB531 -var deBruijn32tab = [32]byte{ +global deBruijn32tab = [32]byte{ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9, } const deBruijn64 = 0x03f79d71b4ca8b09 -var deBruijn64tab = [64]byte{ +global deBruijn64tab = [64]byte{ 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4, 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5, 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11, @@ -48,9 +53,9 @@ var deBruijn64tab = [64]byte{ // TrailingZeros returns the number of trailing zero bits in x; the result is UintSize for x == 0. func TrailingZeros(x: uint) => int { if UintSize == 32 { - return TrailingZeros32(uint32(x)) + return TrailingZeros32(u32(x)) } - return TrailingZeros64(uint64(x)) + return TrailingZeros64(u64(x)) } // TrailingZeros8 returns the number of trailing zero bits in x; the result is 8 for x == 0. @@ -64,11 +69,11 @@ func TrailingZeros16(x: uint16) => int { return 16 } // see comment in TrailingZeros64 - return int(deBruijn32tab[uint32(x&-x)*deBruijn32>>(32-5)]) + return int(deBruijn32tab[u32(x&-x)*deBruijn32>>(32-5)]) } // TrailingZeros32 returns the number of trailing zero bits in x; the result is 32 for x == 0. -func TrailingZeros32(x: uint32) => int { +func TrailingZeros32(x: u32) => int { if x == 0 { return 32 } @@ -77,7 +82,7 @@ func TrailingZeros32(x: uint32) => int { } // TrailingZeros64 returns the number of trailing zero bits in x; the result is 64 for x == 0. -func TrailingZeros64(x: uint64) => int { +func TrailingZeros64(x: u64) => int { if x == 0 { return 64 } @@ -106,9 +111,9 @@ const m4 = 0x0000ffff0000ffff // OnesCount returns the number of one bits ("population count") in x. func OnesCount(x: uint) => int { if UintSize == 32 { - return OnesCount32(uint32(x)) + return OnesCount32(u32(x)) } - return OnesCount64(uint64(x)) + return OnesCount64(u64(x)) } // OnesCount8 returns the number of one bits ("population count") in x. @@ -122,12 +127,12 @@ func OnesCount16(x: uint16) => int { } // OnesCount32 returns the number of one bits ("population count") in x. -func OnesCount32(x: uint32) => int { +func OnesCount32(x: u32) => int { return int(pop8tab[x>>24] + pop8tab[x>>16&0xff] + pop8tab[x>>8&0xff] + pop8tab[x&0xff]) } // OnesCount64 returns the number of one bits ("population count") in x. -func OnesCount64(x: uint64) => int { +func OnesCount64(x: u64) => int { // Implementation: Parallel summing of adjacent bits. // See "Hacker's Delight", Chap. 5: Counting Bits. // The following pattern shows the general approach: @@ -165,9 +170,9 @@ func OnesCount64(x: uint64) => int { // This function's execution time does not depend on the inputs. func RotateLeft(x: uint, k: int) => uint { if UintSize == 32 { - return uint(RotateLeft32(uint32(x), k)) + return uint(RotateLeft32(u32(x), k)) } - return uint(RotateLeft64(uint64(x), k)) + return uint(RotateLeft64(u64(x), k)) } // RotateLeft8 returns the value of x rotated left by (k mod 8) bits. @@ -194,7 +199,7 @@ func RotateLeft16(x: uint16, k: int) => uint16 { // To rotate x right by k bits, call RotateLeft32(x, -k). // // This function's execution time does not depend on the inputs. -func RotateLeft32(x: uint32, k: int) => uint32 { +func RotateLeft32(x: u32, k: int) => u32 { const n = 32 s := uint(k) & (n - 1) return x<>(n-s) @@ -204,7 +209,7 @@ func RotateLeft32(x: uint32, k: int) => uint32 { // To rotate x right by k bits, call RotateLeft64(x, -k). // // This function's execution time does not depend on the inputs. -func RotateLeft64(x: uint64, k: int) => uint64 { +func RotateLeft64(x: u64, k: int) => u64 { const n = 64 s := uint(k) & (n - 1) return x<>(n-s) @@ -215,9 +220,9 @@ func RotateLeft64(x: uint64, k: int) => uint64 { // Reverse returns the value of x with its bits in reversed order. func Reverse(x: uint) => uint { if UintSize == 32 { - return uint(Reverse32(uint32(x))) + return uint(Reverse32(u32(x))) } - return uint(Reverse64(uint64(x))) + return uint(Reverse64(u64(x))) } // Reverse8 returns the value of x with its bits in reversed order. @@ -231,7 +236,7 @@ func Reverse16(x: uint16) => uint16 { } // Reverse32 returns the value of x with its bits in reversed order. -func Reverse32(x: uint32) => uint32 { +func Reverse32(x: u32) => u32 { const m = 1<<32 - 1 x = x>>1&(m0&m) | x&(m0&m)<<1 x = x>>2&(m1&m) | x&(m1&m)<<2 @@ -240,7 +245,7 @@ func Reverse32(x: uint32) => uint32 { } // Reverse64 returns the value of x with its bits in reversed order. -func Reverse64(x: uint64) => uint64 { +func Reverse64(x: u64) => u64 { const m = 1<<64 - 1 x = x>>1&(m0&m) | x&(m0&m)<<1 x = x>>2&(m1&m) | x&(m1&m)<<2 @@ -255,9 +260,9 @@ func Reverse64(x: uint64) => uint64 { // This function's execution time does not depend on the inputs. func ReverseBytes(x: uint) => uint { if UintSize == 32 { - return uint(ReverseBytes32(uint32(x))) + return uint(ReverseBytes32(u32(x))) } - return uint(ReverseBytes64(uint64(x))) + return uint(ReverseBytes64(u64(x))) } // ReverseBytes16 returns the value of x with its bytes in reversed order. @@ -270,7 +275,7 @@ func ReverseBytes16(x: uint16) => uint16 { // ReverseBytes32 returns the value of x with its bytes in reversed order. // // This function's execution time does not depend on the inputs. -func ReverseBytes32(x: uint32) => uint32 { +func ReverseBytes32(x: u32) => u32 { const m = 1<<32 - 1 x = x>>8&(m3&m) | x&(m3&m)<<8 return x>>16 | x<<16 @@ -279,7 +284,7 @@ func ReverseBytes32(x: uint32) => uint32 { // ReverseBytes64 returns the value of x with its bytes in reversed order. // // This function's execution time does not depend on the inputs. -func ReverseBytes64(x: uint64) => uint64 { +func ReverseBytes64(x: u64) => u64 { const m = 1<<64 - 1 x = x>>8&(m3&m) | x&(m3&m)<<8 x = x>>16&(m4&m) | x&(m4&m)<<16 @@ -291,9 +296,9 @@ func ReverseBytes64(x: uint64) => uint64 { // Len returns the minimum number of bits required to represent x; the result is 0 for x == 0. func Len(x: uint) => int { if UintSize == 32 { - return Len32(uint32(x)) + return Len32(u32(x)) } - return Len64(uint64(x)) + return Len64(u64(x)) } // Len8 returns the minimum number of bits required to represent x; the result is 0 for x == 0. @@ -311,7 +316,7 @@ func Len16(x: uint16) => (n: int) { } // Len32 returns the minimum number of bits required to represent x; the result is 0 for x == 0. -func Len32(x: uint32) => (n: int) { +func Len32(x: u32) => (n: int) { if x >= 1<<16 { x >>= 16 n = 16 @@ -324,7 +329,7 @@ func Len32(x: uint32) => (n: int) { } // Len64 returns the minimum number of bits required to represent x; the result is 0 for x == 0. -func Len64(x: uint64) => (n: int) { +func Len64(x: u64) => (n: int) { if x >= 1<<32 { x >>= 32 n = 32 @@ -349,10 +354,10 @@ func Len64(x: uint64) => (n: int) { // This function's execution time does not depend on the inputs. func Add(x, y, carry: uint) => (sum, carryOut: uint) { if UintSize == 32 { - s32, c32 := Add32(uint32(x), uint32(y), uint32(carry)) + s32, c32 := Add32(u32(x), u32(y), u32(carry)) return uint(s32), uint(c32) } - s64, c64 := Add64(uint64(x), uint64(y), uint64(carry)) + s64, c64 := Add64(u64(x), u64(y), u64(carry)) return uint(s64), uint(c64) } @@ -361,10 +366,10 @@ func Add(x, y, carry: uint) => (sum, carryOut: uint) { // The carryOut output is guaranteed to be 0 or 1. // // This function's execution time does not depend on the inputs. -func Add32(x, y, carry: uint32) => (sum, carryOut: uint32) { - sum64 := uint64(x) + uint64(y) + uint64(carry) - sum = uint32(sum64) - carryOut = uint32(sum64 >> 32) +func Add32(x, y, carry: u32) => (sum, carryOut: u32) { + sum64 := u64(x) + u64(y) + u64(carry) + sum = u32(sum64) + carryOut = u32(sum64 >> 32) return } @@ -373,7 +378,7 @@ func Add32(x, y, carry: uint32) => (sum, carryOut: uint32) { // The carryOut output is guaranteed to be 0 or 1. // // This function's execution time does not depend on the inputs. -func Add64(x, y, carry: uint64) => (sum, carryOut: uint64) { +func Add64(x, y, carry: u64) => (sum, carryOut: u64) { sum = x + y + carry // The sum will overflow if both top bits are set (x & y) or if one of them // is (x | y), and a carry from the lower place happened. If such a carry @@ -391,10 +396,10 @@ func Add64(x, y, carry: uint64) => (sum, carryOut: uint64) { // This function's execution time does not depend on the inputs. func Sub(x, y, borrow: uint) => (diff, borrowOut: uint) { if UintSize == 32 { - d32, b32 := Sub32(uint32(x), uint32(y), uint32(borrow)) + d32, b32 := Sub32(u32(x), u32(y), u32(borrow)) return uint(d32), uint(b32) } - d64, b64 := Sub64(uint64(x), uint64(y), uint64(borrow)) + d64, b64 := Sub64(u64(x), u64(y), u64(borrow)) return uint(d64), uint(b64) } @@ -403,7 +408,7 @@ func Sub(x, y, borrow: uint) => (diff, borrowOut: uint) { // The borrowOut output is guaranteed to be 0 or 1. // // This function's execution time does not depend on the inputs. -func Sub32(x, y, borrow: uint32) => (diff, borrowOut: uint32) { +func Sub32(x, y, borrow: u32) => (diff, borrowOut: u32) { diff = x - y - borrow // The difference will underflow if the top bit of x is not set and the top // bit of y is set (^x & y) or if they are the same (^(x ^ y)) and a borrow @@ -418,7 +423,7 @@ func Sub32(x, y, borrow: uint32) => (diff, borrowOut: uint32) { // The borrowOut output is guaranteed to be 0 or 1. // // This function's execution time does not depend on the inputs. -func Sub64(x, y, borrow: uint64) => (diff, borrowOut: uint64) { +func Sub64(x, y, borrow: u64) => (diff, borrowOut: u64) { diff = x - y - borrow // See Sub32 for the bit logic. borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63 @@ -434,10 +439,10 @@ func Sub64(x, y, borrow: uint64) => (diff, borrowOut: uint64) { // This function's execution time does not depend on the inputs. func Mul(x, y: uint) => (hi, lo: uint) { if UintSize == 32 { - h, l := Mul32(uint32(x), uint32(y)) + h, l := Mul32(u32(x), u32(y)) return uint(h), uint(l) } - h, l := Mul64(uint64(x), uint64(y)) + h, l := Mul64(u64(x), u64(y)) return uint(h), uint(l) } @@ -446,9 +451,9 @@ func Mul(x, y: uint) => (hi, lo: uint) { // half returned in lo. // // This function's execution time does not depend on the inputs. -func Mul32(x, y: uint32) => (hi, lo: uint32) { - tmp := uint64(x) * uint64(y) - hi, lo = uint32(tmp>>32), uint32(tmp) +func Mul32(x, y: u32) => (hi, lo: u32) { + tmp := u64(x) * u64(y) + hi, lo = u32(tmp>>32), u32(tmp) return } @@ -457,7 +462,7 @@ func Mul32(x, y: uint32) => (hi, lo: uint32) { // half returned in lo. // // This function's execution time does not depend on the inputs. -func Mul64(x, y: uint64) => (hi, lo: uint64) { +func Mul64(x, y: u64) => (hi, lo: u64) { const mask32 = 1<<32 - 1 x0 := x & mask32 x1 := x >> 32 @@ -481,10 +486,10 @@ func Mul64(x, y: uint64) => (hi, lo: uint64) { // Div panics for y == 0 (division by zero) or y <= hi (quotient overflow). func Div(hi, lo, y: uint) => (quo, rem: uint) { if UintSize == 32 { - q, r := Div32(uint32(hi), uint32(lo), uint32(y)) + q, r := Div32(u32(hi), u32(lo), u32(y)) return uint(q), uint(r) } - q, r := Div64(uint64(hi), uint64(lo), uint64(y)) + q, r := Div64(u64(hi), u64(lo), u64(y)) return uint(q), uint(r) } @@ -492,12 +497,15 @@ func Div(hi, lo, y: uint) => (quo, rem: uint) { // quo = (hi, lo)/y, rem = (hi, lo)%y with the dividend bits' upper // half in parameter hi and the lower half in parameter lo. // Div32 panics for y == 0 (division by zero) or y <= hi (quotient overflow). -func Div32(hi, lo, y: uint32) => (quo, rem: uint32) { +func Div32(hi, lo, y: u32) => (quo, rem: u32) { if y != 0 && y <= hi { - // panic(overflowError) + panic(overflowError) + } + if y == 0 { + panic(divideError) } - z := uint64(hi)<<32 | uint64(lo) - quo, rem = uint32(z/uint64(y)), uint32(z%uint64(y)) + z := u64(hi)<<32 | u64(lo) + quo, rem = u32(z/u64(y)), u32(z%u64(y)) return } @@ -505,16 +513,16 @@ func Div32(hi, lo, y: uint32) => (quo, rem: uint32) { // quo = (hi, lo)/y, rem = (hi, lo)%y with the dividend bits' upper // half in parameter hi and the lower half in parameter lo. // Div64 panics for y == 0 (division by zero) or y <= hi (quotient overflow). -func Div64(hi, lo, y: uint64) => (quo, rem: uint64) { +func Div64(hi, lo, y: u64) => (quo, rem: u64) { const ( two32 = 1 << 32 mask32 = two32 - 1 ) if y == 0 { - // panic(divideError) + panic(divideError) } if y <= hi { - // panic(overflowError) + panic(overflowError) } s := uint(LeadingZeros64(y)) @@ -557,22 +565,22 @@ func Div64(hi, lo, y: uint64) => (quo, rem: uint64) { // quotient overflow. func Rem(hi, lo, y: uint) => uint { if UintSize == 32 { - return uint(Rem32(uint32(hi), uint32(lo), uint32(y))) + return uint(Rem32(u32(hi), u32(lo), u32(y))) } - return uint(Rem64(uint64(hi), uint64(lo), uint64(y))) + return uint(Rem64(u64(hi), u64(lo), u64(y))) } // Rem32 returns the remainder of (hi, lo) divided by y. Rem32 panics // for y == 0 (division by zero) but, unlike Div32, it doesn't panic // on a quotient overflow. -func Rem32(hi, lo, y: uint32) => uint32 { - return uint32((uint64(hi)<<32 | uint64(lo)) % uint64(y)) +func Rem32(hi, lo, y: u32) => u32 { + return u32((u64(hi)<<32 | u64(lo)) % u64(y)) } // Rem64 returns the remainder of (hi, lo) divided by y. Rem64 panics // for y == 0 (division by zero) but, unlike Div64, it doesn't panic // on a quotient overflow. -func Rem64(hi, lo, y: uint64) => uint64 { +func Rem64(hi, lo, y: u64) => u64 { // We scale down hi so that hi < y, then use Div64 to compute the // rem with the guarantee that it won't panic on quotient overflow. // Given that diff --git a/waroot/src/math/bits/bits_errors_bootstrap.wa b/waroot/src/math/bits/bits_errors_bootstrap.wa deleted file mode 100644 index 0e639745c942f83e4d831317fb3173b40794c306..0000000000000000000000000000000000000000 --- a/waroot/src/math/bits/bits_errors_bootstrap.wa +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build compiler_bootstrap -// +build compiler_bootstrap - -// This version used only for bootstrap (on this path we want -// to avoid use of go:linkname as applied to variables). - -type errorString struct { - msg string -} - -func (e: errorString) RuntimeError {} - -func (e: errorString) Error => string { - return "runtime error: " + string(e.msg) -} - -var overflowError = error(&errorString{"integer overflow"}) - -var divideError = error(&errorString{"integer divide by zero"}) diff --git a/waroot/src/math/bits/bits_panic_test.wa b/waroot/src/math/bits/bits_panic_test.wa new file mode 100644 index 0000000000000000000000000000000000000000..d24f2e1e210bc3f56618f14f9b70c6bbb1b82e17 --- /dev/null +++ b/waroot/src/math/bits/bits_panic_test.wa @@ -0,0 +1,77 @@ +// 版权 @2023 凹语言 作者。保留所有权利。 + +const ( + divZeroError = "runtime error: integer divide by zero" +) + +func TestDivPanicOverflow { + // Output(panic): + // integer overflow + + assert(overflowError == "integer overflow") + + q, r := Div(1, 0, 1) + _, _= q, r + + assert(false, "should panic") +} + +func TestDiv32PanicOverflow { + // Output(panic): + // integer overflow + + assert(overflowError == "integer overflow") + + q, r := Div32(1, 0, 1) + _, _= q, r + + assert(false, "should panic") +} + +func TestDiv64PanicOverflow { + // Output(panic): + // integer overflow + + assert(overflowError == "integer overflow") + + q, r := Div64(1, 0, 1) + _, _= q, r + + assert(false, "should panic") +} + +func TestDivPanicZero { + // Output(panic): + // integer divide by zero + + assert(divideError == "integer divide by zero") + + q, r := Div(1, 1, 0) + _, _= q, r + + assert(false, "should panic") +} + +func TestDiv32PanicZero { + // Output(panic): + // integer divide by zero + + assert(divideError == "integer divide by zero") + + q, r := Div32(1, 1, 0) + _, _= q, r + + assert(false, "should panic") +} + +func TestDiv64PanicZero { + // Output(panic): + // integer divide by zero + + assert(divideError == "integer divide by zero") + + q, r := Div64(1, 1, 0) + _, _= q, r + + assert(false, "should panic") +} diff --git a/waroot/src/math/bits/bits_test.wa b/waroot/src/math/bits/bits_test.wa new file mode 100644 index 0000000000000000000000000000000000000000..f577807a38aa186c41bc6577be2e76df3523aaf1 --- /dev/null +++ b/waroot/src/math/bits/bits_test.wa @@ -0,0 +1,560 @@ +// 版权 @2023 凹语言 作者。保留所有权利。 + +// ---------------------------------------------------------------------------- +// Testing support + +const DeBruijn64 = deBruijn64 + +type entry = struct { + nlz, ntz, pop: int +} + +// tab contains results for all uint8 values +global tab: [256]entry + +func init() { + tab[0] = entry{8, 8, 0} + for i := 1; i < len(tab); i++ { + // nlz + x := i // x != 0 + n := 0 + for x&0x80 == 0 { + n++ + x <<= 1 + } + tab[i].nlz = n + + // ntz + x = i // x != 0 + n = 0 + for x&1 == 0 { + n++ + x >>= 1 + } + tab[i].ntz = n + + // pop + x = i // x != 0 + n = 0 + for x != 0 { + n += int(x & 1) + x >>= 1 + } + tab[i].pop = n + } +} + +// ---------------------------------------------------------------------------- + +func TestUintSize { + assert(UintSize == 32) +} + +func TestLeadingZeros { + for i := 0; i < 256; i++ { + nlz := tab[i].nlz + for k := 0; k < 64-8; k++ { + x := u64(i) << uint(k) + if x <= 1<<8-1 { + got := LeadingZeros8(uint8(x)) + want := nlz - k + (8 - 8) + if x == 0 { + want = 8 + } + assert(got == want, "LeadingZeros8 got != want") + } + + if x <= 1<<16-1 { + got := LeadingZeros16(uint16(x)) + want := nlz - k + (16 - 8) + if x == 0 { + want = 16 + } + assert(got == want, "LeadingZeros16 got != want") + } + + if x <= 1<<32-1 { + got := LeadingZeros32(uint32(x)) + want := nlz - k + (32 - 8) + if x == 0 { + want = 32 + } + + assert(got == want, "LeadingZeros32 got != want") + + if UintSize == 32 { + got = LeadingZeros(uint(x)) + if got != want { + assert(got == want, "LeadingZeros got != want") + } + } + } + + if x <= 1<<64-1 { + got := LeadingZeros64(u64(x)) + want := nlz - k + (64 - 8) + if x == 0 { + want = 64 + } + assert(got == want, "LeadingZeros64 got != want") + if UintSize == 64 { + got = LeadingZeros(uint(x)) + if got != want { + assert(got == want, "LeadingZeros got != want") + } + } + } + } + } +} + +func TestTrailingZeros { + for i := 0; i < 256; i++ { + ntz := tab[i].ntz + for k := 0; k < 64-8; k++ { + x := u64(i) << uint(k) + want := ntz + k + if x <= 1<<8-1 { + got := TrailingZeros8(u8(x)) + if x == 0 { + want = 8 + } + if got != want { + assert(got == want, "TrailingZeros8 got != want") + } + } + + if x <= 1<<16-1 { + got := TrailingZeros16(u16(x)) + if x == 0 { + want = 16 + } + if got != want { + assert(got == want, "TrailingZeros16 got != want") + } + } + + if x <= 1<<32-1 { + got := TrailingZeros32(u32(x)) + if x == 0 { + want = 32 + } + if got != want { + assert(got == want, "TrailingZeros32 got != want") + } + if UintSize == 32 { + got = TrailingZeros(uint(x)) + if got != want { + assert(got == want, "TrailingZeros got != want") + } + } + } + + if x <= 1<<64-1 { + got := TrailingZeros64(u64(x)) + if x == 0 { + want = 64 + } + if got != want { + assert(got == want, "TrailingZeros64 got != want") + } + if UintSize == 64 { + got = TrailingZeros(uint(x)) + if got != want { + assert(got == want, "TrailingZeros got != want") + } + } + } + } + } +} + +func TestOnesCount { + x: u64 + for i := 0; i <= 64; i++ { + testOnesCount(x, i) + x = x<<1 | 1 + } + + for i := 64; i >= 0; i-- { + testOnesCount(x, i) + x = x << 1 + } + + for i := 0; i < 256; i++ { + for k := 0; k < 64-8; k++ { + testOnesCount(u64(i)<>(8-k&0x7) + if got8 != want8 { + assert(got8 == want8, "RotateLeft8 got != want") + } + got8 = RotateLeft8(want8, -int(k)) + if got8 != x8 { + assert(got8 == x8, "RotateLeft8 got != want") + } + + x16 := u16(m) + got16 := RotateLeft16(x16, int(k)) + want16 := x16<<(k&0xf) | x16>>(16-k&0xf) + if got16 != want16 { + assert(got16 == want16, "RotateLeft16 got != want") + } + got16 = RotateLeft16(want16, -int(k)) + if got16 != x16 { + assert(got16 == x16, "RotateLeft16 got != want") + } + + x32 := uint32(m) + got32 := RotateLeft32(x32, int(k)) + want32 := x32<<(k&0x1f) | x32>>(32-k&0x1f) + if got32 != want32 { + assert(got32 == want32, "RotateLeft32 got != want") + } + got32 = RotateLeft32(want32, -int(k)) + if got32 != x32 { + assert(got32 == x32, "RotateLeft32 got != want") + } + if UintSize == 32 { + x := uint(m) + got := RotateLeft(x, int(k)) + want := x<<(k&0x1f) | x>>(32-k&0x1f) + if got != want { + assert(got == want, "RotateLeft got != want") + } + got = RotateLeft(want, -int(k)) + if got != x { + assert(got == x, "RotateLeft got != want") + } + } + + x64 := u64(m) + got64 := RotateLeft64(x64, int(k)) + want64 := x64<<(k&0x3f) | x64>>(64-k&0x3f) + if got64 != want64 { + assert(got64 == want64, "RotateLeft64 got != want") + } + got64 = RotateLeft64(want64, -int(k)) + if got64 != x64 { + assert(got64 == x64, "RotateLeft64 got != want") + } + if UintSize == 64 { + x := uint(m) + got := RotateLeft(x, int(k)) + want := x<<(k&0x3f) | x>>(64-k&0x3f) + if got != want { + assert(got == want, "RotateLeft got != want") + } + got = RotateLeft(want, -int(k)) + if got != x { + assert(got == x, "RotateLeft got != want") + } + } + } +} + +func TestReverse { + // test each bit + for i := uint(0); i < 64; i++ { + testReverse(u64(1)<> (64 - 8)) + if got8 != want8 { + assert(got8 == want8, "Reverse8 got != want") + } + + x16 := u16(x64) + got16 := Reverse16(x16) + want16 := u16(want64 >> (64 - 16)) + if got16 != want16 { + assert(got16 == want16, "Reverse16 got != want") + } + + x32 := u32(x64) + got32 := Reverse32(x32) + want32 := u32(want64 >> (64 - 32)) + if got32 != want32 { + assert(got32 == want32, "Reverse32 got != want") + } + if UintSize == 32 { + x := uint(x32) + got := Reverse(x) + want := uint(want32) + if got != want { + assert(got == want, "Reverse got != want") + } + } + + got64 := Reverse64(x64) + if got64 != want64 { + assert(got64 == want64, "Reverse64 got != want") + } + if UintSize == 64 { + x := uint(x64) + got := Reverse(x) + want := uint(want64) + if got != want { + assert(got == want, "Reverse got != want") + } + } +} + +func TestReverseBytes { + for _, test := range []struct { + x, r uint64 + }{ + {0, 0}, + {0x01, 0x01 << 56}, + {0x0123, 0x2301 << 48}, + {0x012345, 0x452301 << 40}, + {0x01234567, 0x67452301 << 32}, + {0x0123456789, 0x8967452301 << 24}, + {0x0123456789ab, 0xab8967452301 << 16}, + {0x0123456789abcd, 0xcdab8967452301 << 8}, + {0x0123456789abcdef, 0xefcdab8967452301 << 0}, + } { + testReverseBytes(test.x, test.r) + testReverseBytes(test.r, test.x) + } +} + +func testReverseBytes(x64, want64: u64) { + x16 := u16(x64) + got16 := ReverseBytes16(x16) + want16 := u16(want64 >> (64 - 16)) + if got16 != want16 { + assert(got16 == want16, "ReverseBytes16 got != want") + } + + x32 := u32(x64) + got32 := ReverseBytes32(x32) + want32 := u32(want64 >> (64 - 32)) + if got32 != want32 { + assert(got32 == want32, "ReverseBytes32 got != want") + } + if UintSize == 32 { + x := uint(x32) + got := ReverseBytes(x) + want := uint(want32) + if got != want { + assert(got == want, "ReverseBytes got != want") + } + } + + got64 := ReverseBytes64(x64) + if got64 != want64 { + assert(got64 == want64, "ReverseBytes64 got != want") + } + if UintSize == 64 { + x := uint(x64) + got := ReverseBytes(x) + want := uint(want64) + if got != want { + assert(got == want, "ReverseBytes got != want") + } + } +} + +func TestLen { + for i := 0; i < 256; i++ { + len := 8 - tab[i].nlz + for k := 0; k < 64-8; k++ { + x := u64(i) << uint(k) + want := 0 + if x != 0 { + want = len + k + } + if x <= 1<<8-1 { + got := Len8(u8(x)) + if got != want { + assert(got == want, "Len8 got != want") + } + } + + if x <= 1<<16-1 { + got := Len16(u16(x)) + if got != want { + assert(got == want, "Len16 got != want") + } + } + + if x <= 1<<32-1 { + got := Len32(u32(x)) + if got != want { + assert(got == want, "Len32 got != want") + } + if UintSize == 32 { + got := Len(uint(x)) + if got != want { + assert(got == want, "Len got != want") + } + } + } + + if x <= 1<<64-1 { + got := Len64(u64(x)) + if got != want { + assert(got == want, "Len64 got != want") + } + if UintSize == 64 { + got := Len(uint(x)) + if got != want { + assert(got == want, "Len got != want") + } + } + } + } + } +} + +func TestRem32 { + // Sanity check: for non-oveflowing dividends, the result is the + // same as the rem returned by Div32 + hi, lo, y := u32(510510), u32(9699690), u32(510510+1) // ensure hi < y + for i := 0; i < 1000; i++ { + r := Rem32(hi, lo, y) + _, r2 := Div32(hi, lo, y) + if r != r2 { + assert(false, "Rem32 failed") + } + y += 13 + } +} + +func TestRem32Overflow { + // To trigger a quotient overflow, we need y <= hi + hi, lo, y := u32(510510), u32(9699690), u32(7) + for i := 0; i < 1000; i++ { + r := Rem32(hi, lo, y) + _, r2 := Div64(0, u64(hi)<<32|u64(lo), u64(y)) + if r != u32(r2) { + assert(false, "Rem32 failed") + } + y += 13 + } +} + +func TestRem64 { + // Sanity check: for non-oveflowing dividends, the result is the + // same as the rem returned by Div64 + hi, lo, y := u64(510510), u64(9699690), u64(510510+1) // ensure hi < y + for i := 0; i < 1000; i++ { + r := Rem64(hi, lo, y) + _, r2 := Div64(hi, lo, y) + if r != r2 { + assert(false, "Rem64 failed") + } + y += 13 + } +} + +func TestRem64Overflow { + Rem64Tests := []struct { + hi, lo, y: u64 + rem: u64 + }{ + // Testcases computed using Python 3, as: + // >>> hi = 42; lo = 1119; y = 42 + // >>> ((hi<<64)+lo) % y + {42, 1119, 42, 27}, + {42, 1119, 38, 9}, + {42, 1119, 26, 23}, + {469, 0, 467, 271}, + {469, 0, 113, 58}, + {111111, 111111, 1171, 803}, + {3968194946088682615, 3192705705065114702, 1000037, 56067}, + } + + for _, rt := range Rem64Tests { + if rt.hi < rt.y { + assert(false, "Rem64 is not a test with quo overflow") + } + rem := Rem64(rt.hi, rt.lo, rt.y) + if rem != rt.rem { + assert(false, "Rem64 failed") + } + } +} diff --git a/waroot/src/math/bits/example_test.wa b/waroot/src/math/bits/example_test.wa new file mode 100644 index 0000000000000000000000000000000000000000..3d781cd481d2ae2f1237abb5c3d686de3bca2c5c --- /dev/null +++ b/waroot/src/math/bits/example_test.wa @@ -0,0 +1,141 @@ +// 版权 @2023 凹语言 作者。保留所有权利。 + +func TestLeadingZeros8 { + assert(0b00000001 == 1) + assert(7 == LeadingZeros8(1)) +} + +func TestLeadingZeros16 { + assert(0b0000000000000001 == 1) + assert(15 == LeadingZeros16(1)) +} + +func TestLeadingZeros32 { + assert(0b00000000000000000000000000000001 == 1) + assert(31 == LeadingZeros32(1)) +} + +func TestLeadingZeros64 { + assert(0b0000000000000000000000000000000000000000000000000000000000000001 == 1) + assert(63 == LeadingZeros64(1)) +} + +func TestTrailingZeros8 { + assert(0b00001110 == 14) + assert(1 == TrailingZeros8(14)) +} + +func TestTrailingZeros16 { + assert(0b0000000000001110 == 14) + assert(1 == TrailingZeros16(14)) +} + +func TestTrailingZeros32 { + assert(0b00000000000000000000000000001110 == 14) + assert(1 == TrailingZeros32(14)) +} + +func TestTrailingZeros64 { + assert(0b0000000000000000000000000000000000000000000000000000000000001110 == 14) + assert(1 == TrailingZeros64(14)) +} + +func TestOnesCount8 { + assert(0b00001110 == 14) + assert(3 == OnesCount8(14)) +} + +func TestOnesCount16 { + assert(0b0000000000001110 == 14) + assert(3 == OnesCount16(14)) +} + +func TestOnesCount32 { + assert(0b00000000000000000000000000001110 == 14) + assert(3 == OnesCount32(14)) +} + +func TestOnesCount64 { + assert(0b0000000000000000000000000000000000000000000000000000000000001110 == 14) + assert(3 == OnesCount64(14)) +} + +func TestRotateLeft8 { + assert(0b00001111 == 15) + assert(0b00111100 == RotateLeft8(15, 2)) + assert(0b11000011 == RotateLeft8(15, -2)) +} + +func TestRotateLeft16 { + assert(0b0000000000001111 == 15) + assert(0b0000000000111100 == RotateLeft16(15, 2)) + assert(0b1100000000000011 == RotateLeft16(15, -2)) +} + +func TestRotateLeft32 { + assert(0b00000000000000000000000000001111 == 15) + assert(0b00000000000000000000000000111100 == RotateLeft32(15, 2)) + assert(0b11000000000000000000000000000011 == RotateLeft32(15, -2)) +} + + +func TestRotateLeft64 { + assert(0b0000000000000000000000000000000000000000000000000000000000001111 == 15) + assert(0b0000000000000000000000000000000000000000000000000000000000111100 == RotateLeft64(15, 2)) + assert(0b1100000000000000000000000000000000000000000000000000000000000011 == RotateLeft64(15, -2)) +} + +func TestReverse8 { + assert(0b00010011 == 19) + assert(0b11001000 == Reverse8(19)) +} + +func TestReverse16 { + assert(0b0000000000010011 == 19) + assert(0b1100100000000000 == Reverse16(19)) +} + +func TestReverse32 { + assert(0b00000000000000000000000000010011 == 19) + assert(0b11001000000000000000000000000000 == Reverse32(19)) +} + +func TestReverse64 { + assert(0b0000000000000000000000000000000000000000000000000000000000010011 == 19) + assert(0b1100100000000000000000000000000000000000000000000000000000000000 == Reverse64(19)) +} + +func TestReverseBytes16 { + assert(0b0000000000001111 == 15) + assert(0b0000111100000000 == ReverseBytes16(15)) +} + +func TestReverseBytes32 { + assert(0b00000000000000000000000000001111 == 15) + assert(0b00001111000000000000000000000000 == ReverseBytes32(15)) +} + +func TestReverseBytes64 { + assert(0b0000000000000000000000000000000000000000000000000000000000001111 == 15) + assert(0b0000111100000000000000000000000000000000000000000000000000000000 == ReverseBytes64(15)) +} + +func TestLen8 { + assert(0b00001000 == 8) + assert(4 == Len8(8)) +} + +func TestLen16 { + assert(0b0000000000001000 == 8) + assert(4 == Len16(8)) +} + +func TestLen32 { + assert(0b00000000000000000000000000001000 == 8) + assert(4 == Len32(8)) +} + +func TestLen64 { + assert(0b0000000000000000000000000000000000000000000000000000000000001000 == 8) + assert(4 == Len64(8)) +} diff --git a/waroot/src/math/bits/make_examples.go b/waroot/src/math/bits/make_examples.go deleted file mode 100644 index ac4004df4149033a96febdbd0358a68f46b1cf3c..0000000000000000000000000000000000000000 --- a/waroot/src/math/bits/make_examples.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build ignore -// +build ignore - -// This program generates example_test.go. - -package main - -import ( - "bytes" - "fmt" - "log" - "math/bits" - "os" -) - -const header = `// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Code generated by go run make_examples.go. DO NOT EDIT. - -package bits_test - -import ( - "fmt" - "math/bits" -) -` - -func main() { - w := bytes.NewBuffer([]byte(header)) - - for _, e := range []struct { - name string - in int - out [4]interface{} - out2 [4]interface{} - }{ - { - name: "LeadingZeros", - in: 1, - out: [4]interface{}{bits.LeadingZeros8(1), bits.LeadingZeros16(1), bits.LeadingZeros32(1), bits.LeadingZeros64(1)}, - }, - { - name: "TrailingZeros", - in: 14, - out: [4]interface{}{bits.TrailingZeros8(14), bits.TrailingZeros16(14), bits.TrailingZeros32(14), bits.TrailingZeros64(14)}, - }, - { - name: "OnesCount", - in: 14, - out: [4]interface{}{bits.OnesCount8(14), bits.OnesCount16(14), bits.OnesCount32(14), bits.OnesCount64(14)}, - }, - { - name: "RotateLeft", - in: 15, - out: [4]interface{}{bits.RotateLeft8(15, 2), bits.RotateLeft16(15, 2), bits.RotateLeft32(15, 2), bits.RotateLeft64(15, 2)}, - out2: [4]interface{}{bits.RotateLeft8(15, -2), bits.RotateLeft16(15, -2), bits.RotateLeft32(15, -2), bits.RotateLeft64(15, -2)}, - }, - { - name: "Reverse", - in: 19, - out: [4]interface{}{bits.Reverse8(19), bits.Reverse16(19), bits.Reverse32(19), bits.Reverse64(19)}, - }, - { - name: "ReverseBytes", - in: 15, - out: [4]interface{}{nil, bits.ReverseBytes16(15), bits.ReverseBytes32(15), bits.ReverseBytes64(15)}, - }, - { - name: "Len", - in: 8, - out: [4]interface{}{bits.Len8(8), bits.Len16(8), bits.Len32(8), bits.Len64(8)}, - }, - } { - for i, size := range []int{8, 16, 32, 64} { - if e.out[i] == nil { - continue // function doesn't exist - } - f := fmt.Sprintf("%s%d", e.name, size) - fmt.Fprintf(w, "\nfunc Example%s() {\n", f) - switch e.name { - case "RotateLeft", "Reverse", "ReverseBytes": - fmt.Fprintf(w, "\tfmt.Printf(\"%%0%db\\n\", %d)\n", size, e.in) - if e.name == "RotateLeft" { - fmt.Fprintf(w, "\tfmt.Printf(\"%%0%db\\n\", bits.%s(%d, 2))\n", size, f, e.in) - fmt.Fprintf(w, "\tfmt.Printf(\"%%0%db\\n\", bits.%s(%d, -2))\n", size, f, e.in) - } else { - fmt.Fprintf(w, "\tfmt.Printf(\"%%0%db\\n\", bits.%s(%d))\n", size, f, e.in) - } - fmt.Fprintf(w, "\t// Output:\n") - fmt.Fprintf(w, "\t// %0*b\n", size, e.in) - fmt.Fprintf(w, "\t// %0*b\n", size, e.out[i]) - if e.name == "RotateLeft" && e.out2[i] != nil { - fmt.Fprintf(w, "\t// %0*b\n", size, e.out2[i]) - } - default: - fmt.Fprintf(w, "\tfmt.Printf(\"%s(%%0%db) = %%d\\n\", %d, bits.%s(%d))\n", f, size, e.in, f, e.in) - fmt.Fprintf(w, "\t// Output:\n") - fmt.Fprintf(w, "\t// %s(%0*b) = %d\n", f, size, e.in, e.out[i]) - } - fmt.Fprintf(w, "}\n") - } - } - - if err := os.WriteFile("example_test.go", w.Bytes(), 0666); err != nil { - log.Fatal(err) - } -} diff --git a/waroot/src/runtime/runtime_arduino.wa b/waroot/src/runtime/runtime_arduino.wa index a464450a9427f812ede372046c410cfbe4848d85..85afe1e43d0252e64513186dc31446ece8060c79 100644 --- a/waroot/src/runtime/runtime_arduino.wa +++ b/waroot/src/runtime/runtime_arduino.wa @@ -2,7 +2,7 @@ import "syscall/arduino" -var WAOS = "arduino" +const WAOS = "arduino" #wa:linkname $runtime.argsSizesGet func argsSizesGet(result_argc: i32, result_argv_len: i32) => (errno: i32) { @@ -70,8 +70,8 @@ func waPrintI64(i: i32) { } #wa:linkname $runtime.waPrintU64 -func waPrintU64(i: i32) { - printU64(u64(i)) +func waPrintU64(i: u64) { + printU64(i) } #wa:linkname $runtime.waPrintF32 diff --git a/waroot/src/runtime/runtime_chrome.wa b/waroot/src/runtime/runtime_chrome.wa index bbe005a90f832fea208b5d00d2722d9990562323..4b563d5ec58c64e85dcd64876c62d63cff45dd66 100644 --- a/waroot/src/runtime/runtime_chrome.wa +++ b/waroot/src/runtime/runtime_chrome.wa @@ -2,7 +2,7 @@ import "syscall/chrome" -var WAOS = "chrome" +const WAOS = "chrome" #wa:linkname $runtime.argsSizesGet func argsSizesGet(result_argc: i32, result_argv_len: i32) => (errno: i32) { @@ -70,8 +70,8 @@ func waPrintI64(i: i32) { } #wa:linkname $runtime.waPrintU64 -func waPrintU64(i: i32) { - printU64(u64(i)) +func waPrintU64(i: u64) { + printU64(i) } #wa:linkname $runtime.waPrintF32 diff --git a/waroot/src/runtime/runtime_mvp.wa b/waroot/src/runtime/runtime_mvp.wa index 3245d51c0254a2ddc51ce5e0ea47b4594e4f95d9..62c122676f3779105bba7bd6902518ea7ac91ce6 100644 --- a/waroot/src/runtime/runtime_mvp.wa +++ b/waroot/src/runtime/runtime_mvp.wa @@ -2,7 +2,7 @@ import "syscall/mvp" -var WAOS = "mvp" +const WAOS = "mvp" #wa:linkname $runtime.argsSizesGet func argsSizesGet(result_argc: i32, result_argv_len: i32) => (errno: i32) { diff --git a/waroot/src/runtime/runtime_wasi.wa b/waroot/src/runtime/runtime_wasi.wa index 1eedcd55eec14bdb3177c98852f72594675f717a..bcadbf0ac164ca647971e1eee106c68f0239624b 100644 --- a/waroot/src/runtime/runtime_wasi.wa +++ b/waroot/src/runtime/runtime_wasi.wa @@ -2,7 +2,7 @@ import "syscall/wasi" -var WAOS = "wasi" +const WAOS = "wasi" #wa:linkname $runtime.argsSizesGet func argsSizesGet(result_argc: i32, result_argv_len: i32) => (errno: i32) {