...
 
Commits (45)
    https://gitcode.net/wa-lang/wa/-/commit/c5ce3a5e5475be2262a6182631c57b62b860ba43 标准库增加 buffer 实现, 尚不能使用 2023-08-16T20:57:03+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/88316e15a45891d81730f2f1a15317fd41cf5c74 bytes 包的 Buffer 补充测试 2023-08-16T22:17:00+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/fb6798f38da8b3093799df616d28691ff183169c 修复贪吃蛇发布脚本 2023-08-17T07:38:22+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/61c1638260d4b823cf722344a47d96d69c0707c0 bytes 包添加 Reader 实现 2023-08-18T06:58:17+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/c1b8fc1e62b2232493ae5b183cbaa141b834d938 bytes.Reader 增加测试 2023-08-18T07:20:14+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/1c9855f2c7e4113210b970ce434345f0dde9b9f6 数据段留16字节安全区 2023-08-18T14:51:31+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/740912a32e449c65afb6eea62c64c9080fecc17c 结构体匿名嵌入时忽略包名 2023-08-18T14:52:50+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/7a4d1e6b8a150ad5f5a78aa430c76e36c1221111 修正bytes.TestReaderCopyNothing测试 2023-08-18T14:53:37+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/ac3d716b585e729958d443edca8427d237a35a4a 强制检查:值类型不能赋值给非空接口 2023-08-18T15:09:08+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/baf0f798e2c9804d7106eaa33db9b9c703964f2d fix bytes test 2023-08-18T18:47:47+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/80bc37c983ca0b64e754d153878a446969b8d1b9 增加 bytes.Compare 函数和测试 2023-08-19T20:07:04+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/431facd2d766461dcc4819bef0f52e1545ea8766 bytes 包更多测试 2023-08-20T07:10:53+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/14a0ac062c1861b51acebc37bef978738fa24e9f bytes 包更多函数和测试 2023-08-20T11:24:10+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/7cb70a8d9bcffe02ef37eedfd2e73a4313a8ec1e 修正[low:high:max]语法未处理max的问题 2023-08-20T20:56:45+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/28ba454b25afa25a801af566a65c375b8ac456c5 Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-08-20T20:56:55+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/34dbf326f09b1a0cc25c5b3d589083017d64e3d3 bytes 测试代码微调 2023-08-20T22:26:43+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/69aaa0d61f0a5d6d8196b46340d759ce78a3384f bytes 包补充函数和测试 2023-08-21T06:52:52+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/91ecd0c29700047744ac8fa7938d1e6f5c508279 bytes 包补充测试 2023-08-21T07:26:36+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/6557bef69283e7264793e92fd0aadc75c2c27b4a 补充测试 2023-08-21T19:36:09+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/ee0c4c718d0e2151fd8208773cb9e20bc88adedd bytes 包补充函数和测试 2023-08-22T20:13:59+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/619098ff90bb465d92c5b7977144f4e3c61db954 导出waHeapAlloc、waHeapFree 2023-08-24T20:53:12+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/b4eb99057bfcd6a18e7999bd9cbfe8b8ad3db1ce Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-08-24T20:53:20+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/cd3645e40a75b0b69d6b28ba9294cc227003d0ec 导出runtime.Release 2023-08-24T21:54:10+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/c06198e1c619a7aec86fe539cb47c162cb0a421f bytes 包补充测试 2023-08-25T07:06:31+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/4277b7f28de8f97bba4185ac7a3927e82db1c81a Merge branch 'master' of gitee.com:wa-lang/wa 2023-08-25T07:07:33+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/a27b5d5eaa59dfd13fc334fec6c1ef466660ec12 unicode/utf8 包补充测试 2023-08-25T22:56:35+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/ae1ddc37989fffcab1863899c3b0fdef925250dc 修正有符号数右移时符号位错的问题 2023-08-26T17:36:50+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/f4b37652046ceb0476392971e8e25ff1c28b1f85 Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-08-26T17:37:23+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/fe8be85b56d265e3ed2a96c6c492578424acfd23 unicode/utf8 包补充测试 2023-08-27T07:34:00+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/b257139578b77ac3b2c4193556cb82816cbec1e8 chore: add wa wasm zip 2023-08-28T14:54:44+08:00 xxx humengmingxx@gmail.com https://gitcode.net/wa-lang/wa/-/commit/d4dd9898615e8348ba811f86f7f790d209f34164 wa大整数运算 2023-08-29T19:19:48+08:00 trueabc 547551933@qq.com https://gitcode.net/wa-lang/wa/-/commit/90a05044678fdd846a9a351f38a145275edfa1fe !13 凹语言大整数库 2023-08-29T12:29:48+00:00 丁尔男 476582@qq.com Merge pull request !13 from 啊bc/master https://gitcode.net/wa-lang/wa/-/commit/e556debf78446c1786d828f45b1111be63036710 math/big 标准库生效 2023-08-29T21:55:53+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/ee56900e3e204d371aedeed98e448c7c89c0fb0a 增加字符串按 rune 遍历(for range迭代) 2023-08-29T22:47:37+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/6017de5bec2804cdc8c42f842d50da18069fb2cd Merge branch 'backend_wasm' 2023-08-29T22:47:58+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/1329c4a0f20b1b9725138e59e3c7309636be0177 Merge branch 'master' of https://gitee.com/wa-lang/wa 2023-08-29T22:48:05+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/e3145d88e892833916059d146fc417fb9f1467d6 unicode/utf8 添加 EncodeRuneString 函数 2023-08-29T23:18:51+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/6157ec2a236d49cfcd0ba9bd8b57619466fea180 静态数据段避开栈 2023-08-30T10:01:17+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/37299bc094dd58ebe4b7abdd0e6e4cf139408600 Merge branch 'master' into backend_wasm 2023-08-30T11:06:29+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/7f484df65b1e84ac4332e987549315f3a5b8585b wasi 目标下支持打印 unicode rune 2023-08-30T11:20:24+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/a03e731d98fb1d84b2a353f467166a5d6a9eb842 补完 string 与 []rune 的相互转换 2023-08-30T16:43:05+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/33f6724e76183b120e95b4b97fd827cd804bfc6e wir.Module 增加无类型整数类型(为重构做准备) 2023-08-30T17:03:59+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/deaa7f87c0b082a6687bc7a34e3b8de0734a9ffe unicode/utf8 补充测试 2023-08-30T21:26:06+08:00 chai2010 chaishushan@gmail.com https://gitcode.net/wa-lang/wa/-/commit/53f9d895c824dca646c0cd40a424c64a0f7755dc 修正 runtime 的 utf8 相关常量定义位置错误 2023-08-30T22:05:31+08:00 3dgen 476582@qq.com https://gitcode.net/wa-lang/wa/-/commit/d6c5c21a6810aae75ed6a0e5167faaab09824e98 Merge branch 'backend_wasm' 2023-08-30T22:06:07+08:00 3dgen 476582@qq.com
...@@ -123,7 +123,7 @@ func runTest(cfg *config.Config, pkgpath, runPattern string, appArgs ...string) ...@@ -123,7 +123,7 @@ func runTest(cfg *config.Config, pkgpath, runPattern string, appArgs ...string)
tFuncName = strings.ReplaceAll(tFuncName, "/", "$") tFuncName = strings.ReplaceAll(tFuncName, "/", "$")
_, stdout, stderr, err := m.RunFunc(tFuncName) _, stdout, stderr, err := m.RunFunc(tFuncName)
if t.OutputPanic { if t.OutputPanic {
stdout = bytes.TrimSpace(stdout) stdout = fmtGotOutput(stdout)
expect, got := t.Output, string(stdout) expect, got := t.Output, string(stdout)
if exitCode, _ := wazero.AsExitError(err); exitCode == 0 { if exitCode, _ := wazero.AsExitError(err); exitCode == 0 {
...@@ -178,7 +178,7 @@ func runTest(cfg *config.Config, pkgpath, runPattern string, appArgs ...string) ...@@ -178,7 +178,7 @@ func runTest(cfg *config.Config, pkgpath, runPattern string, appArgs ...string)
os.Exit(1) os.Exit(1)
} }
stdout = bytes.TrimSpace(stdout) stdout = fmtGotOutput(stdout)
if t.Output != "" && t.Output == string(stdout) { if t.Output != "" && t.Output == string(stdout) {
continue continue
} }
...@@ -229,7 +229,7 @@ func runTest(cfg *config.Config, pkgpath, runPattern string, appArgs ...string) ...@@ -229,7 +229,7 @@ func runTest(cfg *config.Config, pkgpath, runPattern string, appArgs ...string)
tFuncName = strings.ReplaceAll(tFuncName, "/", "$") tFuncName = strings.ReplaceAll(tFuncName, "/", "$")
_, stdout, stderr, err := m.RunFunc(tFuncName) _, stdout, stderr, err := m.RunFunc(tFuncName)
if t.OutputPanic { if t.OutputPanic {
stdout = bytes.TrimSpace(stdout) stdout = fmtGotOutput(stdout)
expect, got := t.Output, string(stdout) expect, got := t.Output, string(stdout)
if exitCode, _ := wazero.AsExitError(err); exitCode == 0 { if exitCode, _ := wazero.AsExitError(err); exitCode == 0 {
...@@ -280,7 +280,7 @@ func runTest(cfg *config.Config, pkgpath, runPattern string, appArgs ...string) ...@@ -280,7 +280,7 @@ func runTest(cfg *config.Config, pkgpath, runPattern string, appArgs ...string)
os.Exit(1) os.Exit(1)
} }
stdout = bytes.TrimSpace(stdout) stdout = fmtGotOutput(stdout)
if t.Output != "" && t.Output == string(stdout) { if t.Output != "" && t.Output == string(stdout) {
continue continue
} }
...@@ -329,3 +329,12 @@ func sWithPrefix(s, prefix string) string { ...@@ -329,3 +329,12 @@ func sWithPrefix(s, prefix string) string {
} }
return strings.Join(lines, "\n") return strings.Join(lines, "\n")
} }
func fmtGotOutput(stdout []byte) []byte {
stdout = bytes.TrimSpace(stdout)
lines := bytes.Split(stdout, []byte("\n"))
for i, s := range lines {
lines[i] = bytes.TrimSpace(s)
}
return bytes.Join(lines, []byte("\n"))
}
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
default: default:
GOOS=js GOARCH=wasm go build -o wa.wasm GOOS=js GOARCH=wasm go build -o wa.wasm
mv wa.wasm ../../../docs mv wa.wasm ../../../docs
cd ../../../docs && zip wa.wasm.zip wa.wasm
dev-chai: dev-chai:
-rm wa.wasm -rm wa.wasm
......
...@@ -42,6 +42,13 @@ func (p *Compiler) Compile(prog *loader.Program, mainFunc string) (output string ...@@ -42,6 +42,13 @@ func (p *Compiler) Compile(prog *loader.Program, mainFunc string) (output string
} }
sort.Strings(pkgnames) sort.Strings(pkgnames)
for i, v := range pkgnames {
if v == "runtime" && i != 0 {
pkgnames[i] = pkgnames[0]
pkgnames[0] = "runtime"
}
}
for _, n := range pkgnames { for _, n := range pkgnames {
p.ssaPkg = prog.Pkgs[n].SSAPkg p.ssaPkg = prog.Pkgs[n].SSAPkg
p.CompilePkgConst(p.ssaPkg) p.CompilePkgConst(p.ssaPkg)
......
...@@ -359,6 +359,14 @@ func (g *functionGenerator) genValue(v ssa.Value) ([]wat.Inst, wir.ValueType) { ...@@ -359,6 +359,14 @@ func (g *functionGenerator) genValue(v ssa.Value) ([]wat.Inst, wir.ValueType) {
// logger.Printf("Instruction already exist:%s\n", v) // logger.Printf("Instruction already exist:%s\n", v)
//} //}
switch v := v.(type) {
case *ssa.Range:
return g.genRange(v)
case *ssa.Next:
return g.genNext(v)
}
//Todo: 下面的做法过于粗暴 //Todo: 下面的做法过于粗暴
g.tLib.compile(v.Type()) g.tLib.compile(v.Type())
...@@ -859,10 +867,10 @@ func (g *functionGenerator) genFiled(inst *ssa.Field) ([]wat.Inst, wir.ValueType ...@@ -859,10 +867,10 @@ func (g *functionGenerator) genFiled(inst *ssa.Field) ([]wat.Inst, wir.ValueType
field := inst.X.Type().Underlying().(*types.Struct).Field(inst.Field) field := inst.X.Type().Underlying().(*types.Struct).Field(inst.Field)
fieldname := wir.GenSymbolName(field.Name()) fieldname := wir.GenSymbolName(field.Name())
if field.Embedded() { if field.Embedded() {
if _, ok := field.Type().(*types.Named); ok { //if _, ok := field.Type().(*types.Named); ok {
pkgname, _ := wir.GetPkgMangleName(field.Pkg().Path()) // pkgname, _ := wir.GetPkgMangleName(field.Pkg().Path())
fieldname = pkgname + "." + fieldname // fieldname = pkgname + "." + fieldname
} //}
fieldname = "$" + fieldname fieldname = "$" + fieldname
} }
...@@ -873,10 +881,10 @@ func (g *functionGenerator) genFieldAddr(inst *ssa.FieldAddr) ([]wat.Inst, wir.V ...@@ -873,10 +881,10 @@ func (g *functionGenerator) genFieldAddr(inst *ssa.FieldAddr) ([]wat.Inst, wir.V
field := inst.X.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Struct).Field(inst.Field) field := inst.X.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Struct).Field(inst.Field)
fieldname := wir.GenSymbolName(field.Name()) fieldname := wir.GenSymbolName(field.Name())
if field.Embedded() { if field.Embedded() {
if _, ok := field.Type().(*types.Named); ok { //if _, ok := field.Type().(*types.Named); ok {
pkgname, _ := wir.GetPkgMangleName(field.Pkg().Path()) // pkgname, _ := wir.GetPkgMangleName(field.Pkg().Path())
fieldname = pkgname + "." + fieldname // fieldname = pkgname + "." + fieldname
} //}
fieldname = "$" + fieldname fieldname = "$" + fieldname
} }
...@@ -916,15 +924,18 @@ func (g *functionGenerator) genSlice(inst *ssa.Slice) ([]wat.Inst, wir.ValueType ...@@ -916,15 +924,18 @@ func (g *functionGenerator) genSlice(inst *ssa.Slice) ([]wat.Inst, wir.ValueType
} }
x := g.getValue(inst.X) x := g.getValue(inst.X)
var low, high wir.Value var low, high, max wir.Value
if inst.Low != nil { if inst.Low != nil {
low = g.getValue(inst.Low).value low = g.getValue(inst.Low).value
} }
if inst.High != nil { if inst.High != nil {
high = g.getValue(inst.High).value high = g.getValue(inst.High).value
} }
if inst.Max != nil {
max = g.getValue(inst.Max).value
}
return g.module.EmitGenSlice(x.value, low, high) return g.module.EmitGenSlice(x.value, low, high, max)
} }
func (g *functionGenerator) genMakeSlice(inst *ssa.MakeSlice) ([]wat.Inst, wir.ValueType) { func (g *functionGenerator) genMakeSlice(inst *ssa.MakeSlice) ([]wat.Inst, wir.ValueType) {
...@@ -1139,6 +1150,21 @@ func (g *functionGenerator) genTypeAssert(inst *ssa.TypeAssert) (insts []wat.Ins ...@@ -1139,6 +1150,21 @@ func (g *functionGenerator) genTypeAssert(inst *ssa.TypeAssert) (insts []wat.Ins
return return
} }
func (g *functionGenerator) genRange(inst *ssa.Range) (insts []wat.Inst, ret_type wir.ValueType) {
x := g.getValue(inst.X)
return g.module.EmitGenRange(x.value)
}
func (g *functionGenerator) genNext(inst *ssa.Next) (insts []wat.Inst, ret_type wir.ValueType) {
if inst.IsString {
iter := g.getValue(inst.Iter).value
return g.module.EmitGenNext_String(iter)
} else {
logger.Fatalf("Todo:%T", inst.Type())
}
return
}
func (g *functionGenerator) addRegister(typ wir.ValueType) wir.Value { func (g *functionGenerator) addRegister(typ wir.ValueType) wir.Value {
defer func() { g.cur_local_id++ }() defer func() { g.cur_local_id++ }()
name := "$t" + strconv.Itoa(g.cur_local_id) name := "$t" + strconv.Itoa(g.cur_local_id)
......
...@@ -129,7 +129,8 @@ func (tLib *typeLib) compile(from types.Type) wir.ValueType { ...@@ -129,7 +129,8 @@ func (tLib *typeLib) compile(from types.Type) wir.ValueType {
sf := ut.Field(i) sf := ut.Field(i)
dtyp := tLib.compile(sf.Type()) dtyp := tLib.compile(sf.Type())
if sf.Embedded() { if sf.Embedded() {
df := tLib.module.NewStructField("$"+dtyp.Name(), dtyp) //df := tLib.module.NewStructField("$"+dtyp.Name(), dtyp)
df := tLib.module.NewStructField("$"+wir.GenSymbolName(sf.Name()), dtyp)
tStruct.AppendField(df) tStruct.AppendField(df)
} else { } else {
df := tLib.module.NewStructField(wir.GenSymbolName(sf.Name()), dtyp) df := tLib.module.NewStructField(wir.GenSymbolName(sf.Name()), dtyp)
...@@ -225,7 +226,8 @@ func (tLib *typeLib) compile(from types.Type) wir.ValueType { ...@@ -225,7 +226,8 @@ func (tLib *typeLib) compile(from types.Type) wir.ValueType {
dtyp := tLib.compile(sf.Type()) dtyp := tLib.compile(sf.Type())
var fname string var fname string
if sf.Embedded() { if sf.Embedded() {
fname = "$" + dtyp.Name() //fname = "$" + dtyp.Name()
fname = "$" + sf.Name()
} else { } else {
fname = sf.Name() fname = sf.Name()
} }
......
...@@ -16,8 +16,8 @@ func (m *Module) EmitAssginValue(lh, rh Value) []wat.Inst { ...@@ -16,8 +16,8 @@ func (m *Module) EmitAssginValue(lh, rh Value) []wat.Inst {
insts = append(insts, lh.EmitRelease()...) insts = append(insts, lh.EmitRelease()...)
insts = append(insts, lh.EmitInit()...) insts = append(insts, lh.EmitInit()...)
} else { } else {
if !lh.Type().Equal(rh.Type()) { if !lh.Type().Equal(rh.Type()) && !(lh.Type().Equal(m.I32) && rh.Type().Equal(m.RUNE) || lh.Type().Equal(m.RUNE) && rh.Type().Equal(m.I32)) {
logger.Fatal("x.Type() != y.Type()") logger.Fatal("x.Type:", lh.Type().Name(), ", y.Type():", rh.Type().Name())
} }
insts = append(insts, rh.EmitPush()...) insts = append(insts, rh.EmitPush()...)
...@@ -27,10 +27,6 @@ func (m *Module) EmitAssginValue(lh, rh Value) []wat.Inst { ...@@ -27,10 +27,6 @@ func (m *Module) EmitAssginValue(lh, rh Value) []wat.Inst {
return insts return insts
} }
func (m *Module) EmitConvertValueType(from, to ValueType) {
logger.Fatal("Todo")
}
func (m *Module) EmitUnOp(x Value, op wat.OpCode) (insts []wat.Inst, ret_type ValueType) { func (m *Module) EmitUnOp(x Value, op wat.OpCode) (insts []wat.Inst, ret_type ValueType) {
if !IsNumber(x) { if !IsNumber(x) {
logger.Fatal("Todo") logger.Fatal("Todo")
...@@ -208,10 +204,9 @@ func (m *Module) EmitBinOp(x, y Value, op wat.OpCode) (insts []wat.Inst, ret_typ ...@@ -208,10 +204,9 @@ func (m *Module) EmitBinOp(x, y Value, op wat.OpCode) (insts []wat.Inst, ret_typ
if x.Type().Size() <= 4 && y.Type().Size() == 8 { if x.Type().Size() <= 4 && y.Type().Size() == 8 {
insts = append(insts, x.EmitPush()...) insts = append(insts, x.EmitPush()...)
insts = append(insts, wat.NewInstConvert_i64_extend_i32_u())
insts = append(insts, y.EmitPush()...) insts = append(insts, y.EmitPush()...)
insts = append(insts, wat.NewInstShl(toWatType(y.Type())))
insts = append(insts, wat.NewInstConvert_i32_wrap_i64()) insts = append(insts, wat.NewInstConvert_i32_wrap_i64())
insts = append(insts, wat.NewInstShl(toWatType(ret_type)))
} else if x.Type().Size() == 8 && y.Type().Size() <= 4 { } else if x.Type().Size() == 8 && y.Type().Size() <= 4 {
insts = append(insts, x.EmitPush()...) insts = append(insts, x.EmitPush()...)
insts = append(insts, y.EmitPush()...) insts = append(insts, y.EmitPush()...)
...@@ -238,10 +233,9 @@ func (m *Module) EmitBinOp(x, y Value, op wat.OpCode) (insts []wat.Inst, ret_typ ...@@ -238,10 +233,9 @@ func (m *Module) EmitBinOp(x, y Value, op wat.OpCode) (insts []wat.Inst, ret_typ
if x.Type().Size() <= 4 && y.Type().Size() == 8 { if x.Type().Size() <= 4 && y.Type().Size() == 8 {
insts = append(insts, x.EmitPush()...) insts = append(insts, x.EmitPush()...)
insts = append(insts, wat.NewInstConvert_i64_extend_i32_u())
insts = append(insts, y.EmitPush()...) insts = append(insts, y.EmitPush()...)
insts = append(insts, wat.NewInstShr(toWatType(y.Type())))
insts = append(insts, wat.NewInstConvert_i32_wrap_i64()) insts = append(insts, wat.NewInstConvert_i32_wrap_i64())
insts = append(insts, wat.NewInstShr(toWatType(ret_type)))
} else if x.Type().Size() == 8 && y.Type().Size() <= 4 { } else if x.Type().Size() == 8 && y.Type().Size() <= 4 {
insts = append(insts, x.EmitPush()...) insts = append(insts, x.EmitPush()...)
insts = append(insts, y.EmitPush()...) insts = append(insts, y.EmitPush()...)
...@@ -469,10 +463,10 @@ func (m *Module) EmitGenIndex(x, id Value) (insts []wat.Inst, ret_type ValueType ...@@ -469,10 +463,10 @@ func (m *Module) EmitGenIndex(x, id Value) (insts []wat.Inst, ret_type ValueType
return return
} }
func (m *Module) EmitGenSlice(x, low, high Value) (insts []wat.Inst, ret_type ValueType) { func (m *Module) EmitGenSlice(x, low, high, max Value) (insts []wat.Inst, ret_type ValueType) {
switch x := x.(type) { switch x := x.(type) {
case *aSlice: case *aSlice:
insts = x.emitSub(low, high) insts = x.emitSub(low, high, max)
ret_type = x.Type() ret_type = x.Type()
case *aString: case *aString:
...@@ -483,12 +477,12 @@ func (m *Module) EmitGenSlice(x, low, high Value) (insts []wat.Inst, ret_type Va ...@@ -483,12 +477,12 @@ func (m *Module) EmitGenSlice(x, low, high Value) (insts []wat.Inst, ret_type Va
switch btype := x.Type().(*Ref).Base.(type) { switch btype := x.Type().(*Ref).Base.(type) {
case *Slice: case *Slice:
slt := m.GenValueType_Slice(btype.Base) slt := m.GenValueType_Slice(btype.Base)
insts = slt.emitGenFromRefOfSlice(x, low, high) insts = slt.emitGenFromRefOfSlice(x, low, high, max)
ret_type = slt ret_type = slt
case *Array: case *Array:
slt := m.GenValueType_Slice(btype.Base) slt := m.GenValueType_Slice(btype.Base)
insts = slt.emitGenFromRefOfArray(x, low, high) insts = slt.emitGenFromRefOfArray(x, low, high, max)
ret_type = slt ret_type = slt
default: default:
...@@ -731,8 +725,13 @@ func (m *Module) EmitGenConvert(x Value, typ ValueType) (insts []wat.Inst) { ...@@ -731,8 +725,13 @@ func (m *Module) EmitGenConvert(x Value, typ ValueType) (insts []wat.Inst) {
insts = append(insts, x.Extract("d").EmitPush()...) insts = append(insts, x.Extract("d").EmitPush()...)
insts = append(insts, x.Extract("l").EmitPush()...) insts = append(insts, x.Extract("l").EmitPush()...)
insts = append(insts, wat.NewInstCall(m.STRING.(*String).genFunc_Append())) insts = append(insts, wat.NewInstCall(m.STRING.(*String).genFunc_Append()))
return
case xt.Equal(m.GenValueType_Slice(m.RUNE)):
insts = append(insts, x.EmitPush()...)
insts = append(insts, wat.NewInstCall("runtime.stringFromRuneSlice"))
return
} }
return
case typ.Equal(m.BYTES): case typ.Equal(m.BYTES):
switch { switch {
...@@ -744,11 +743,19 @@ func (m *Module) EmitGenConvert(x Value, typ ValueType) (insts []wat.Inst) { ...@@ -744,11 +743,19 @@ func (m *Module) EmitGenConvert(x Value, typ ValueType) (insts []wat.Inst) {
insts = append(insts, x.Extract("l").EmitPush()...) insts = append(insts, x.Extract("l").EmitPush()...)
insts = append(insts, x.Extract("l").EmitPush()...) insts = append(insts, x.Extract("l").EmitPush()...)
insts = append(insts, wat.NewInstCall(m.BYTES.(*Slice).genAppendFunc())) insts = append(insts, wat.NewInstCall(m.BYTES.(*Slice).genAppendFunc()))
return
}
case typ.Equal(m.GenValueType_Slice(m.RUNE)):
switch {
case xt.Equal(m.STRING):
insts = append(insts, x.EmitPush()...)
insts = append(insts, wat.NewInstCall("runtime.runeSliceFromString"))
return
} }
return
} }
logger.Fatalf("Todo: %+v %+v", x, typ) logger.Fatalf("Todo: x.type: %s, dest_type: %s", x.Type().Name(), typ.Name())
return return
} }
...@@ -895,6 +902,31 @@ func (m *Module) EmitGenTypeAssert(x Value, destType ValueType, commaOk bool) (i ...@@ -895,6 +902,31 @@ func (m *Module) EmitGenTypeAssert(x Value, destType ValueType, commaOk bool) (i
} }
} }
func (m *Module) EmitGenRange(x Value) (insts []wat.Inst, ret_type ValueType) {
switch x := x.(type) {
case *aString:
ret_type, _ = m.findValueType("runtime.stringIter")
insts = append(insts, x.Extract("d").EmitPush()...)
insts = append(insts, x.Extract("l").EmitPush()...)
insts = append(insts, wat.NewInstConst(wat.I32{}, "0"))
default:
logger.Fatalf("Todo:%T", x)
}
return
}
func (m *Module) EmitGenNext_String(iter Value) (insts []wat.Inst, ret_type ValueType) {
fields := []ValueType{m.BOOL, m.INT, m.RUNE}
ret_type = m.GenValueType_Tuple(fields)
insts = append(insts, iter.EmitPush()...)
insts = append(insts, wat.NewInstCall("runtime.next_rune"))
insts = append(insts, iter.(*aStruct).Extract("pos").EmitPop()...)
return
}
func (m *Module) EmitInvoke(i Value, params []Value, mid int, typeName string) (insts []wat.Inst) { func (m *Module) EmitInvoke(i Value, params []Value, mid int, typeName string) (insts []wat.Inst) {
iface := i.(*aInterface) iface := i.(*aInterface)
insts = append(insts, iface.Extract("d").EmitPush()...) insts = append(insts, iface.Extract("d").EmitPush()...)
......
...@@ -18,7 +18,7 @@ type fnSigWrap struct { ...@@ -18,7 +18,7 @@ type fnSigWrap struct {
Module: Module:
**************************************/ **************************************/
type Module struct { type Module struct {
VOID, BOOL, RUNE, U8, U16, I32, U32, UPTR, I64, U64, F32, F64, STRING, BYTES ValueType VOID, BOOL, RUNE, U8, U16, I32, U32, UPTR, I64, U64, INT, UINT, F32, F64, STRING, BYTES ValueType
types_map map[string]ValueType types_map map[string]ValueType
usedConcreteTypes []ValueType usedConcreteTypes []ValueType
...@@ -44,7 +44,7 @@ type Module struct { ...@@ -44,7 +44,7 @@ type Module struct {
constGlobals []wat.Global constGlobals []wat.Global
DataSeg *DataSeg DataSeg *wat.DataSeg
BaseWat string BaseWat string
} }
...@@ -60,6 +60,8 @@ func NewModule() *Module { ...@@ -60,6 +60,8 @@ func NewModule() *Module {
//m.I16 = &tI16{} //m.I16 = &tI16{}
m.U16 = &tU16{} m.U16 = &tU16{}
m.I32 = &tI32{} m.I32 = &tI32{}
m.INT = m.I32
m.UINT = m.U32
m.U32 = &tU32{} m.U32 = &tU32{}
m.UPTR = m.U32 m.UPTR = m.U32
m.I64 = &tI64{} m.I64 = &tI64{}
...@@ -94,7 +96,7 @@ func NewModule() *Module { ...@@ -94,7 +96,7 @@ func NewModule() *Module {
m.table_map = make(map[string]int) m.table_map = make(map[string]int)
//data_seg中先插入标志,防止产生0值 //data_seg中先插入标志,防止产生0值
m.DataSeg = newDataSeg(0) m.DataSeg = wat.NewDataSeg(2048)
m.DataSeg.Append([]byte("$$wads$$"), 8) m.DataSeg.Append([]byte("$$wads$$"), 8)
m.globalsMapByValue = make(map[ssa.Value]int) m.globalsMapByValue = make(map[ssa.Value]int)
...@@ -297,11 +299,11 @@ func (m *Module) ToWatModule() *wat.Module { ...@@ -297,11 +299,11 @@ func (m *Module) ToWatModule() *wat.Module {
var heap_base wat.Global var heap_base wat.Global
heap_base.V = wat.NewVar("__heap_base", wat.I32{}) heap_base.V = wat.NewVar("__heap_base", wat.I32{})
heap_base.IsMut = false heap_base.IsMut = false
heap_base.InitValue = strconv.Itoa(makeAlign(m.DataSeg.Size(), 16)) heap_base.InitValue = strconv.Itoa(makeAlign(m.DataSeg.Size()+16, 16))
wat_module.Globals = append(wat_module.Globals, heap_base) wat_module.Globals = append(wat_module.Globals, heap_base)
} }
wat_module.DataSeg = m.DataSeg.data wat_module.DataSeg = m.DataSeg
return &wat_module return &wat_module
} }
......
...@@ -63,7 +63,7 @@ func (t *Slice) EmitLoadFromAddr(addr Value, offset int) []wat.Inst { ...@@ -63,7 +63,7 @@ func (t *Slice) EmitLoadFromAddr(addr Value, offset int) []wat.Inst {
} }
/*这个函数极其不优雅*/ /*这个函数极其不优雅*/
func (t *Slice) emitGenFromRefOfSlice(x *aRef, low, high Value) (insts []wat.Inst) { func (t *Slice) emitGenFromRefOfSlice(x *aRef, low, high, max Value) (insts []wat.Inst) {
//block //block
insts = append(insts, x.Extract("d").EmitPush()...) insts = append(insts, x.Extract("d").EmitPush()...)
insts = append(insts, wat.NewInstLoad(wat.U32{}, 0, 1)) insts = append(insts, wat.NewInstLoad(wat.U32{}, 0, 1))
...@@ -93,15 +93,19 @@ func (t *Slice) emitGenFromRefOfSlice(x *aRef, low, high Value) (insts []wat.Ins ...@@ -93,15 +93,19 @@ func (t *Slice) emitGenFromRefOfSlice(x *aRef, low, high Value) (insts []wat.Ins
insts = append(insts, wat.NewInstSub(wat.U32{})) insts = append(insts, wat.NewInstSub(wat.U32{}))
//cap: //cap:
insts = append(insts, x.Extract("d").EmitPush()...) if max == nil {
insts = append(insts, wat.NewInstLoad(wat.U32{}, 12, 1)) insts = append(insts, x.Extract("d").EmitPush()...)
insts = append(insts, wat.NewInstLoad(wat.U32{}, 12, 1))
} else {
insts = append(insts, max.EmitPush()...)
}
insts = append(insts, low.EmitPush()...) insts = append(insts, low.EmitPush()...)
insts = append(insts, wat.NewInstSub(wat.U32{})) insts = append(insts, wat.NewInstSub(wat.U32{}))
return return
} }
func (t *Slice) emitGenFromRefOfArray(x *aRef, low, high Value) (insts []wat.Inst) { func (t *Slice) emitGenFromRefOfArray(x *aRef, low, high, max Value) (insts []wat.Inst) {
//block //block
insts = append(insts, x.Extract("b").EmitPush()...) insts = append(insts, x.Extract("b").EmitPush()...)
...@@ -127,7 +131,11 @@ func (t *Slice) emitGenFromRefOfArray(x *aRef, low, high Value) (insts []wat.Ins ...@@ -127,7 +131,11 @@ func (t *Slice) emitGenFromRefOfArray(x *aRef, low, high Value) (insts []wat.Ins
insts = append(insts, wat.NewInstSub(wat.U32{})) insts = append(insts, wat.NewInstSub(wat.U32{}))
//cap: //cap:
insts = append(insts, array_len.EmitPush()...) if max == nil {
insts = append(insts, array_len.EmitPush()...)
} else {
insts = append(insts, max.EmitPush()...)
}
insts = append(insts, low.EmitPush()...) insts = append(insts, low.EmitPush()...)
insts = append(insts, wat.NewInstSub(wat.U32{})) insts = append(insts, wat.NewInstSub(wat.U32{}))
...@@ -517,7 +525,7 @@ func (v *aSlice) emitStoreToAddr(addr Value, offset int) []wat.Inst { ...@@ -517,7 +525,7 @@ func (v *aSlice) emitStoreToAddr(addr Value, offset int) []wat.Inst {
return v.aStruct.emitStoreToAddr(addr, offset) return v.aStruct.emitStoreToAddr(addr, offset)
} }
func (v *aSlice) emitSub(low, high Value) (insts []wat.Inst) { func (v *aSlice) emitSub(low, high, max Value) (insts []wat.Inst) {
//block //block
insts = append(insts, v.Extract("b").EmitPush()...) insts = append(insts, v.Extract("b").EmitPush()...)
...@@ -540,7 +548,11 @@ func (v *aSlice) emitSub(low, high Value) (insts []wat.Inst) { ...@@ -540,7 +548,11 @@ func (v *aSlice) emitSub(low, high Value) (insts []wat.Inst) {
insts = append(insts, wat.NewInstSub(wat.U32{})) insts = append(insts, wat.NewInstSub(wat.U32{}))
//cap: //cap:
insts = append(insts, v.Extract("c").EmitPush()...) if max == nil {
insts = append(insts, v.Extract("c").EmitPush()...)
} else {
insts = append(insts, max.EmitPush()...)
}
insts = append(insts, low.EmitPush()...) insts = append(insts, low.EmitPush()...)
insts = append(insts, wat.NewInstSub(wat.U32{})) insts = append(insts, wat.NewInstSub(wat.U32{}))
......
package wir package wat
import "bytes" import "bytes"
func makeAlign(i, align int) int {
if align == 1 || align == 0 {
return i
}
return (i + align - 1) / align * align
}
/************************************** /**************************************
DataSeg: DataSeg:
**************************************/ **************************************/
...@@ -10,7 +17,7 @@ type DataSeg struct { ...@@ -10,7 +17,7 @@ type DataSeg struct {
data []byte data []byte
} }
func newDataSeg(start int) *DataSeg { func NewDataSeg(start int) *DataSeg {
return &DataSeg{start: start} return &DataSeg{start: start}
} }
......
...@@ -15,7 +15,7 @@ type Module struct { ...@@ -15,7 +15,7 @@ type Module struct {
FuncTypes []FuncType FuncTypes []FuncType
Globals []Global Globals []Global
Funcs []*Function Funcs []*Function
DataSeg []byte DataSeg *DataSeg
BaseWat string BaseWat string
} }
...@@ -29,9 +29,9 @@ func (m *Module) String() string { ...@@ -29,9 +29,9 @@ func (m *Module) String() string {
s += m.BaseWat s += m.BaseWat
if len(m.DataSeg) > 0 { if len(m.DataSeg.data) > 0 {
s += "(data (i32.const 0) \"" s += "(data (i32.const " + strconv.Itoa(m.DataSeg.start) + ") \""
for _, d := range m.DataSeg { for _, d := range m.DataSeg.data {
s += "\\" s += "\\"
i := strconv.FormatInt(int64(d), 16) i := strconv.FormatInt(int64(d), 16)
if len(i) < 2 { if len(i) < 2 {
......
...@@ -266,6 +266,12 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method * ...@@ -266,6 +266,12 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method *
return return
} }
if len(T.allMethods) != 0 {
if _, ok := V.(*Pointer); !ok {
return T.allMethods[0], false
}
}
// TODO(gri) Consider using method sets here. Might be more efficient. // TODO(gri) Consider using method sets here. Might be more efficient.
if ityp, _ := V.Underlying().(*Interface); ityp != nil { if ityp, _ := V.Underlying().(*Interface); ityp != nil {
......
...@@ -14,5 +14,6 @@ publish: ...@@ -14,5 +14,6 @@ publish:
-rm -rf ../../../docs/snake/ -rm -rf ../../../docs/snake/
mkdir -p ../../../docs/snake mkdir -p ../../../docs/snake
cp ./web/* ../../../docs/snake/ cp ./web/* ../../../docs/snake/
cp ./output/snake.wasm ../../../docs/snake/snake.wasm
clean: clean:
// 版权 @2023 凹语言 作者。保留所有权利。
type Buffer struct {}
func Buffer.Write(p: []byte) => (n: int, err: error) {
return
}
func Buffer.WriteString(s: string) => (n: int, err: error) {
return
}
func Buffer.Bytes => []byte {
return nil
}
\ No newline at end of file
// 版权 @2023 凹语言 作者。保留所有权利。
// Copyright 2009 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.
// Simple byte buffer for marshaling data.
import (
"errors"
"io"
"unicode/utf8"
)
// smallBufferSize is an initial allocation minimal capacity.
const smallBufferSize = 64
// The readOp constants describe the last action performed on
// the buffer, so that UnreadRune and UnreadByte can check for
// invalid usage. opReadRuneX constants are chosen such that
// converted to int they correspond to the rune size that was read.
type readOp: byte
// Don't use iota for these, as the values need to correspond with the
// names and comments, which is easier to see when being explicit.
const (
opRead: readOp = 255 // Any other read operation.
opInvalid: readOp = 0 // Non-read operation.
opReadRune1: readOp = 1 // Read rune of size 1.
opReadRune2: readOp = 2 // Read rune of size 2.
opReadRune3: readOp = 3 // Read rune of size 3.
opReadRune4: readOp = 4 // Read rune of size 4.
)
// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
// The zero value for Buffer is an empty buffer ready to use.
type Buffer struct {
buf: []byte // contents are the bytes buf[off : len(buf)]
off: int // read at &buf[off], write at &buf[len(buf)]
lastRead: readOp // last read operation, so that Unread* can work correctly.
}
// ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.
global ErrTooLarge = "bytes.Buffer: too large"
global errNegativeRead = "bytes.Buffer: reader returned negative count from Read"
const maxInt = int(^uint(0) >> 1)
// Bytes returns a slice of length b.Len() holding the unread portion of the buffer.
// The slice is valid for use only until the next buffer modification (that is,
// only until the next call to a method like Read, Write, Reset, or Truncate).
// The slice aliases the buffer content at least until the next buffer modification,
// so immediate changes to the slice will affect the result of future reads.
func Buffer.Bytes => []byte {
b := this
return b.buf[b.off:]
}
// String returns the contents of the unread portion of the buffer
// as a string. If the Buffer is a nil pointer, it returns "<nil>".
//
// To build strings more efficiently, see the strings.Builder type.
func Buffer.String => string {
b := this
if b == nil {
// Special case, useful in debugging.
return "<nil>"
}
return string(b.buf[b.off:])
}
// empty reports whether the unread portion of the buffer is empty.
func Buffer.empty => bool {
b := this
return len(b.buf) <= b.off
}
// Len returns the number of bytes of the unread portion of the buffer;
// b.Len() == len(b.Bytes()).
func Buffer.Len => int {
b := this
return len(b.buf) - b.off
}
// Cap returns the capacity of the buffer's underlying byte slice, that is, the
// total space allocated for the buffer's data.
func Buffer.Cap => int {
b := this
return cap(b.buf)
}
// Truncate discards all but the first n unread bytes from the buffer
// but continues to use the same allocated storage.
// It panics if n is negative or greater than the length of the buffer.
func Buffer.Truncate(n: int) {
b := this
if n == 0 {
b.Reset()
return
}
b.lastRead = opInvalid
if n < 0 || n > b.Len() {
panic("bytes.Buffer: truncation out of range")
}
b.buf = b.buf[:b.off+n]
}
// Reset resets the buffer to be empty,
// but it retains the underlying storage for use by future writes.
// Reset is the same as Truncate(0).
func Buffer.Reset {
b := this
b.buf = b.buf[:0]
b.off = 0
b.lastRead = opInvalid
}
// tryGrowByReslice is a inlineable version of grow for the fast-case where the
// internal buffer only needs to be resliced.
// It returns the index where bytes should be written and whether it succeeded.
func Buffer.tryGrowByReslice(n: int) => (int, bool) {
b := this
if l := len(b.buf); n <= cap(b.buf)-l {
b.buf = b.buf[:l+n]
return l, true
}
return 0, false
}
// grow grows the buffer to guarantee space for n more bytes.
// It returns the index where bytes should be written.
// If the buffer can't grow it will panic with ErrTooLarge.
func Buffer.grow(n: int) => int {
b := this
m := b.Len()
// If buffer is empty, reset to recover space.
if m == 0 && b.off != 0 {
b.Reset()
}
// Try to grow by means of a reslice.
if i, ok := b.tryGrowByReslice(n); ok {
return i
}
if b.buf == nil && n <= smallBufferSize {
b.buf = make([]byte, n, smallBufferSize)
return 0
}
c := cap(b.buf)
if n <= c/2-m {
// We can slide things down instead of allocating a new
// slice. We only need m+n <= c to slide, but
// we instead let capacity get twice as large so we
// don't spend all our time copying.
copy(b.buf, b.buf[b.off:])
} else if c > maxInt-c-n {
panic(ErrTooLarge)
} else {
// Not enough space anywhere, we need to allocate.
buf := makeSlice(2*c + n)
copy(buf, b.buf[b.off:])
b.buf = buf
}
// Restore b.off and len(b.buf).
b.off = 0
b.buf = b.buf[:m+n]
return m
}
// Grow grows the buffer's capacity, if necessary, to guarantee space for
// another n bytes. After Grow(n), at least n bytes can be written to the
// buffer without another allocation.
// If n is negative, Grow will panic.
// If the buffer can't grow it will panic with ErrTooLarge.
func Buffer.Grow(n: int) {
b := this
if n < 0 {
panic("bytes.Buffer.Grow: negative count")
}
m := b.grow(n)
b.buf = b.buf[:m]
}
// Write appends the contents of p to the buffer, growing the buffer as
// needed. The return value n is the length of p; err is always nil. If the
// buffer becomes too large, Write will panic with ErrTooLarge.
func Buffer.Write(p: []byte) => (n: int, err: error) {
b := this
b.lastRead = opInvalid
m, ok := b.tryGrowByReslice(len(p))
if !ok {
m = b.grow(len(p))
}
return copy(b.buf[m:], p), nil
}
// WriteString appends the contents of s to the buffer, growing the buffer as
// needed. The return value n is the length of s; err is always nil. If the
// buffer becomes too large, WriteString will panic with ErrTooLarge.
func Buffer.WriteString(s: string) => (n: int, err: error) {
b := this
b.lastRead = opInvalid
m, ok := b.tryGrowByReslice(len(s))
if !ok {
m = b.grow(len(s))
}
return copy(b.buf[m:], s), nil
}
// MinRead is the minimum slice size passed to a Read call by
// Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond
// what is required to hold the contents of r, ReadFrom will not grow the
// underlying buffer.
const MinRead = 512
// ReadFrom reads data from r until EOF and appends it to the buffer, growing
// the buffer as needed. The return value n is the number of bytes read. Any
// error except io.EOF encountered during the read is also returned. If the
// buffer becomes too large, ReadFrom will panic with ErrTooLarge.
func Buffer.ReadFrom(r: io.Reader) => (n: int64, err: error) {
b := this
b.lastRead = opInvalid
for {
i := b.grow(MinRead)
b.buf = b.buf[:i]
m, e := r.Read(b.buf[i:cap(b.buf)])
if m < 0 {
panic(errNegativeRead)
}
b.buf = b.buf[:i+m]
n += int64(m)
if e == io.EOF {
return n, nil // e is EOF, so return nil explicitly
}
if e != nil {
return n, e
}
}
}
// makeSlice allocates a slice of size n. If the allocation fails, it panics
// with ErrTooLarge.
func makeSlice(n: int) => []byte {
// If the make fails, give a known error.
// defer func() {
// if recover() != nil {
// panic(ErrTooLarge)
// }
// }()
return make([]byte, n)
}
// WriteTo writes data to w until the buffer is drained or an error occurs.
// The return value n is the number of bytes written; it always fits into an
// int, but it is int64 to match the io.WriterTo interface. Any error
// encountered during the write is also returned.
func Buffer.WriteTo(w: io.Writer) => (n: int64, err: error) {
b := this
b.lastRead = opInvalid
if nBytes := b.Len(); nBytes > 0 {
m, e := w.Write(b.buf[b.off:])
if m > nBytes {
panic("bytes.Buffer.WriteTo: invalid Write count")
}
b.off += m
n = int64(m)
if e != nil {
return n, e
}
// all bytes should have been written, by definition of
// Write method in io.Writer
if m != nBytes {
return n, io.ErrShortWrite
}
}
// Buffer is now empty; reset.
b.Reset()
return n, nil
}
// WriteByte appends the byte c to the buffer, growing the buffer as needed.
// The returned error is always nil, but is included to match bufio.Writer's
// WriteByte. If the buffer becomes too large, WriteByte will panic with
// ErrTooLarge.
func Buffer.WriteByte(c: byte) => error {
b := this
b.lastRead = opInvalid
m, ok := b.tryGrowByReslice(1)
if !ok {
m = b.grow(1)
}
b.buf[m] = c
return nil
}
// WriteRune appends the UTF-8 encoding of Unicode code point r to the
// buffer, returning its length and an error, which is always nil but is
// included to match bufio.Writer's WriteRune. The buffer is grown as needed;
// if it becomes too large, WriteRune will panic with ErrTooLarge.
func Buffer.WriteRune(r: rune) => (n: int, err: error) {
b := this
// Compare as uint32 to correctly handle negative runes.
if uint32(r) < utf8.RuneSelf {
b.WriteByte(byte(r))
return 1, nil
}
b.lastRead = opInvalid
m, ok := b.tryGrowByReslice(utf8.UTFMax)
if !ok {
m = b.grow(utf8.UTFMax)
}
n = utf8.EncodeRune(b.buf[m:m+utf8.UTFMax], r)
b.buf = b.buf[:m+n]
return n, nil
}
// Read reads the next len(p) bytes from the buffer or until the buffer
// is drained. The return value n is the number of bytes read. If the
// buffer has no data to return, err is io.EOF (unless len(p) is zero);
// otherwise it is nil.
func Buffer.Read(p: []byte) => (n: int, err: error) {
b := this
b.lastRead = opInvalid
if b.empty() {
// Buffer is empty, reset to recover space.
b.Reset()
if len(p) == 0 {
return 0, nil
}
return 0, io.EOF
}
n = copy(p, b.buf[b.off:])
b.off += n
if n > 0 {
b.lastRead = opRead
}
return n, nil
}
// Next returns a slice containing the next n bytes from the buffer,
// advancing the buffer as if the bytes had been returned by Read.
// If there are fewer than n bytes in the buffer, Next returns the entire buffer.
// The slice is only valid until the next call to a read or write method.
func Buffer.Next(n: int) => []byte {
b := this
b.lastRead = opInvalid
m := b.Len()
if n > m {
n = m
}
data := b.buf[b.off : b.off+n]
b.off += n
if n > 0 {
b.lastRead = opRead
}
return data
}
// ReadByte reads and returns the next byte from the buffer.
// If no byte is available, it returns error io.EOF.
func Buffer.ReadByte => (byte, error) {
b := this
if b.empty() {
// Buffer is empty, reset to recover space.
b.Reset()
return 0, io.EOF
}
c := b.buf[b.off]
b.off++
b.lastRead = opRead
return c, nil
}
// ReadRune reads and returns the next UTF-8-encoded
// Unicode code point from the buffer.
// If no bytes are available, the error returned is io.EOF.
// If the bytes are an erroneous UTF-8 encoding, it
// consumes one byte and returns U+FFFD, 1.
func Buffer.ReadRune => (r: rune, size: int, err: error) {
b := this
if b.empty() {
// Buffer is empty, reset to recover space.
b.Reset()
return 0, 0, io.EOF
}
c := b.buf[b.off]
if c < utf8.RuneSelf {
b.off++
b.lastRead = opReadRune1
return rune(c), 1, nil
}
r, n := utf8.DecodeRune(b.buf[b.off:])
b.off += n
b.lastRead = readOp(n)
return r, n, nil
}
// UnreadRune unreads the last rune returned by ReadRune.
// If the most recent read or write operation on the buffer was
// not a successful ReadRune, UnreadRune returns an error. (In this regard
// it is stricter than UnreadByte, which will unread the last byte
// from any read operation.)
func Buffer.UnreadRune => error {
b := this
if b.lastRead <= opInvalid {
return errors.New("bytes.Buffer: UnreadRune: previous operation was not a successful ReadRune")
}
if b.off >= int(b.lastRead) {
b.off -= int(b.lastRead)
}
b.lastRead = opInvalid
return nil
}
global errUnreadByte = errors.New("bytes.Buffer: UnreadByte: previous operation was not a successful read")
// UnreadByte unreads the last byte returned by the most recent successful
// read operation that read at least one byte. If a write has happened since
// the last read, if the last read returned an error, or if the read read zero
// bytes, UnreadByte returns an error.
func Buffer.UnreadByte => error {
b := this
if b.lastRead == opInvalid {
return errUnreadByte
}
b.lastRead = opInvalid
if b.off > 0 {
b.off--
}
return nil
}
// ReadBytes reads until the first occurrence of delim in the input,
// returning a slice containing the data up to and including the delimiter.
// If ReadBytes encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadBytes returns err != nil if and only if the returned data does not end in
// delim.
func Buffer.ReadBytes(delim: byte) => (line: []byte, err: error) {
b := this
slice, err := b.readSlice(delim)
// return a copy of slice. The buffer's backing array may
// be overwritten by later calls.
line = append(line, slice...)
return line, err
}
// readSlice is like ReadBytes but returns a reference to internal buffer data.
func Buffer.readSlice(delim: byte) => (line: []byte, err: error) {
b := this
i := IndexByte(b.buf[b.off:], delim)
end := b.off + i + 1
if i < 0 {
end = len(b.buf)
err = io.EOF
}
line = b.buf[b.off:end]
b.off = end
b.lastRead = opRead
return line, err
}
// ReadString reads until the first occurrence of delim in the input,
// returning a string containing the data up to and including the delimiter.
// If ReadString encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadString returns err != nil if and only if the returned data does not end
// in delim.
func Buffer.ReadString(delim: byte) => (line: string, err: error) {
b := this
slice, err := b.readSlice(delim)
return string(slice), err
}
// NewBuffer creates and initializes a new Buffer using buf as its
// initial contents. The new Buffer takes ownership of buf, and the
// caller should not use buf after this call. NewBuffer is intended to
// prepare a Buffer to read existing data. It can also be used to set
// the initial size of the internal buffer for writing. To do that,
// buf should have the desired capacity but a length of zero.
//
// In most cases, new(Buffer) (or just declaring a Buffer variable) is
// sufficient to initialize a Buffer.
func NewBuffer(buf: []byte) => *Buffer { return &Buffer{buf: buf} }
// NewBufferString creates and initializes a new Buffer using string s as its
// initial contents. It is intended to prepare a buffer to read an existing
// string.
//
// In most cases, new(Buffer) (or just declaring a Buffer variable) is
// sufficient to initialize a Buffer.
func NewBufferString(s: string) => *Buffer {
return &Buffer{buf: []byte(s)}
}
// 版权 @2023 凹语言 作者。保留所有权利。
// Copyright 2009 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.
import (
"io"
"unicode/utf8"
)
const N = 10000 // make this bigger for a larger (and slower) test
global testString: string // test data for write tests
global testBytes: []byte // test data; same as testString but as a slice.
type negativeReader: struct{}
func negativeReader.Read(_: []byte) => (int, error) { return -1, nil }
func init {
testBytes = make([]byte, N)
for i := 0; i < N; i++ {
testBytes[i] = 'a' + byte(i%26)
}
testString = string(testBytes)
}
// Verify that contents of buf match the string s.
func check(testname: string, buf: *Buffer, s: string) {
bytes := buf.Bytes()
str := buf.String()
if buf.Len() != len(bytes) {
assert(false)
//t.Errorf("%s: buf.Len() == %d, len(buf.Bytes()) == %d", testname, buf.Len(), len(bytes))
}
if buf.Len() != len(str) {
assert(false)
//t.Errorf("%s: buf.Len() == %d, len(buf.String()) == %d", testname, buf.Len(), len(str))
}
if buf.Len() != len(s) {
assert(false)
//t.Errorf("%s: buf.Len() == %d, len(s) == %d", testname, buf.Len(), len(s))
}
if string(bytes) != s {
assert(false)
//t.Errorf("%s: string(buf.Bytes()) == %q, s == %q", testname, string(bytes), s)
}
}
// Fill buf through n writes of string fus.
// The initial contents of buf corresponds to the string s;
// the result is the final contents of buf returned as a string.
func fillString(testname: string, buf: *Buffer, s: string, n: int, fus: string) => string {
check(testname+" (fill 1)", buf, s)
for ; n > 0; n-- {
m, err := buf.WriteString(fus)
if m != len(fus) {
assert(false)
//t.Errorf(testname+" (fill 2): m == %d, expected %d", m, len(fus))
}
if err != nil {
assert(false)
//t.Errorf(testname+" (fill 3): err should always be nil, found err == %s", err)
}
s += fus
check(testname+" (fill 4)", buf, s)
}
return s
}
// Fill buf through n writes of byte slice fub.
// The initial contents of buf corresponds to the string s;
// the result is the final contents of buf returned as a string.
func fillBytes(testname: string, buf: *Buffer, s: string, n: int, fub: []byte) => string {
check(testname+" (fill 1)", buf, s)
for ; n > 0; n-- {
m, err := buf.Write(fub)
if m != len(fub) {
assert(false)
//t.Errorf(testname+" (fill 2): m == %d, expected %d", m, len(fub))
}
if err != nil {
assert(false)
//t.Errorf(testname+" (fill 3): err should always be nil, found err == %s", err)
}
s += string(fub)
check(testname+" (fill 4)", buf, s)
}
return s
}
func TestNewBuffer {
buf := NewBuffer(testBytes)
check("NewBuffer", buf, testString)
}
func TestNewBufferString {
buf := NewBufferString(testString)
check("NewBufferString", buf, testString)
}
// Empty buf through repeated reads into fub.
// The initial contents of buf corresponds to the string s.
func empty(testname: string, buf: *Buffer, s: string, fub: []byte) {
check(testname+" (empty 1)", buf, s)
for {
n, err := buf.Read(fub)
if n == 0 {
break
}
if err != nil {
assert(false)
//t.Errorf(testname+" (empty 2): err should always be nil, found err == %s", err)
}
s = s[n:]
check(testname+" (empty 3)", buf, s)
}
check(testname+" (empty 4)", buf, "")
}
func TestBasicOperations {
buf: Buffer
for i := 0; i < 5; i++ {
check("TestBasicOperations (1)", &buf, "")
buf.Reset()
check("TestBasicOperations (2)", &buf, "")
buf.Truncate(0)
check("TestBasicOperations (3)", &buf, "")
n, err := buf.Write(testBytes[0:1])
if want := 1; err != nil || n != want {
assert(false)
//t.Errorf("Write: got (%d, %v), want (%d, %v)", n, err, want, nil)
}
check("TestBasicOperations (4)", &buf, "a")
buf.WriteByte(testString[1])
check("TestBasicOperations (5)", &buf, "ab")
n, err = buf.Write(testBytes[2:26])
if want := 24; err != nil || n != want {
assert(false)
//t.Errorf("Write: got (%d, %v), want (%d, %v)", n, err, want, nil)
}
check("TestBasicOperations (6)", &buf, testString[0:26])
buf.Truncate(26)
check("TestBasicOperations (7)", &buf, testString[0:26])
buf.Truncate(20)
check("TestBasicOperations (8)", &buf, testString[0:20])
empty("TestBasicOperations (9)", &buf, testString[0:20], make([]byte, 5))
empty("TestBasicOperations (10)", &buf, "", make([]byte, 100))
buf.WriteByte(testString[1])
c, err := buf.ReadByte()
if want := testString[1]; err != nil || c != want {
assert(false)
//t.Errorf("ReadByte: got (%q, %v), want (%q, %v)", c, err, want, nil)
}
c, err = buf.ReadByte()
if err != io.EOF {
assert(false)
//t.Errorf("ReadByte: got (%q, %v), want (%q, %v)", c, err, byte(0), io.EOF)
}
}
}
func TestLargeStringWrites {
buf: Buffer
limit := 30
// if testing.Short() {
{
limit = 9
}
for i := 3; i < limit; i += 3 {
s := fillString("TestLargeWrites (1)", &buf, "", 5, testString)
empty("TestLargeStringWrites (2)", &buf, s, make([]byte, len(testString)/i))
}
check("TestLargeStringWrites (3)", &buf, "")
}
func TestLargeByteWrites {
buf: Buffer
limit := 30
//if testing.Short() {
{
limit = 9
}
for i := 3; i < limit; i += 3 {
s := fillBytes("TestLargeWrites (1)", &buf, "", 5, testBytes)
empty("TestLargeByteWrites (2)", &buf, s, make([]byte, len(testString)/i))
}
check("TestLargeByteWrites (3)", &buf, "")
}
func TestLargeStringReads {
buf: Buffer
for i := 3; i < 30; i += 3 {
s := fillString("TestLargeReads (1)", &buf, "", 5, testString[0:len(testString)/i])
empty("TestLargeReads (2)", &buf, s, make([]byte, len(testString)))
}
check("TestLargeStringReads (3)", &buf, "")
}
func TestLargeByteReads{
buf: Buffer
for i := 3; i < 30; i += 3 {
s := fillBytes("TestLargeReads (1)", &buf, "", 5, testBytes[0:len(testBytes)/i])
empty("TestLargeReads (2)", &buf, s, make([]byte, len(testString)))
}
check("TestLargeByteReads (3)", &buf, "")
}
/*
func TestMixedReadsAndWrites {
buf: Buffer
s := ""
for i := 0; i < 50; i++ {
wlen := rand.Intn(len(testString))
if i%2 == 0 {
s = fillString(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, testString[0:wlen])
} else {
s = fillBytes(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, testBytes[0:wlen])
}
rlen := rand.Intn(len(testString))
fub := make([]byte, rlen)
n, _ := buf.Read(fub)
s = s[n:]
}
empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len()))
}
*/
func TestCapWithPreallocatedSlice {
buf := NewBuffer(make([]byte, 10))
n := buf.Cap()
if n != 10 {
assert(false)
// t.Errorf("expected 10, got %d", n)
}
}
func TestCapWithSliceAndWrittenData {
buf := NewBuffer(make([]byte, 0, 10))
buf.Write([]byte("test"))
n := buf.Cap()
if n != 10 {
assert(false)
//t.Errorf("expected 10, got %d", n)
}
}
func TestNil {
b: *Buffer
if b.String() != "<nil>" {
assert(false)
//t.Errorf("expected <nil>; got %q", b.String())
}
}
func TestReadFrom {
buf: Buffer
for i := 3; i < 30; i += 3 {
s := fillBytes("TestReadFrom (1)", &buf, "", 5, testBytes[0:len(testBytes)/i])
b: Buffer
b.ReadFrom(&buf)
empty("TestReadFrom (2)", &b, s, make([]byte, len(testString)))
}
}
func TestWriteTo {
buf: Buffer
for i := 3; i < 30; i += 3 {
s := fillBytes("TestWriteTo (1)", &buf, "", 5, testBytes[0:len(testBytes)/i])
b: Buffer
buf.WriteTo(&b)
empty("TestWriteTo (2)", &b, s, make([]byte, len(testString)))
}
}
func TestRuneIO {
const NRune = 1000
// Built a test slice while we write the data
b := make([]byte, utf8.UTFMax*NRune)
buf: Buffer
n := 0
for r := rune(0); r < NRune; r++ {
size := utf8.EncodeRune(b[n:], r)
nbytes, err := buf.WriteRune(r)
if err != nil {
assert(false)
//t.Fatalf("WriteRune(%U) error: %s", r, err)
}
if nbytes != size {
assert(false)
//t.Fatalf("WriteRune(%U) expected %d, got %d", r, size, nbytes)
}
n += size
}
b = b[0:n]
// Check the resulting bytes
if !Equal(buf.Bytes(), b) {
assert(false)
//t.Fatalf("incorrect result from WriteRune: %q not %q", buf.Bytes(), b)
}
p := make([]byte, utf8.UTFMax)
// Read it back with ReadRune
for r := rune(0); r < NRune; r++ {
size := utf8.EncodeRune(p, r)
nr, nbytes, err := buf.ReadRune()
if nr != r || nbytes != size || err != nil {
assert(false)
//t.Fatalf("ReadRune(%U) got %U,%d not %U,%d (err=%s)", r, nr, nbytes, r, size, err)
}
}
// Check that UnreadRune works
buf.Reset()
// check at EOF
if err := buf.UnreadRune(); err == nil {
assert(false)
//t.Fatal("UnreadRune at EOF: got no error")
}
if _, _, err := buf.ReadRune(); err == nil {
assert(false)
//t.Fatal("ReadRune at EOF: got no error")
}
if err := buf.UnreadRune(); err == nil {
assert(false)
//t.Fatal("UnreadRune after ReadRune at EOF: got no error")
}
// check not at EOF
buf.Write(b)
for r := rune(0); r < NRune; r++ {
r1, size, _ := buf.ReadRune()
if err := buf.UnreadRune(); err != nil {
assert(false)
//t.Fatalf("UnreadRune(%U) got error %q", r, err)
}
r2, nbytes, err := buf.ReadRune()
if r1 != r2 || r1 != r || nbytes != size || err != nil {
assert(false)
//t.Fatalf("ReadRune(%U) after UnreadRune got %U,%d not %U,%d (err=%s)", r, r2, nbytes, r, size, err)
}
}
}
func TestWriteInvalidRune {
// Invalid runes, including negative ones, should be written as
// utf8.RuneError.
for _, r := range []rune{-1, utf8.MaxRune + 1} {
buf: Buffer
buf.WriteRune(r)
check("TestWriteInvalidRune", &buf, "\uFFFD")
}
}
func TestNext {
b := []byte{0, 1, 2, 3, 4}
tmp := make([]byte, 5)
for i := 0; i <= 5; i++ {
for j := i; j <= 5; j++ {
for k := 0; k <= 6; k++ {
// 0 <= i <= j <= 5; 0 <= k <= 6
// Check that if we start with a buffer
// of length j at offset i and ask for
// Next(k), we get the right bytes.
buf := NewBuffer(b[0:j])
n, _ := buf.Read(tmp[0:i])
if n != i {
assert(false)
//t.Fatalf("Read %d returned %d", i, n)
}
bb := buf.Next(k)
want := k
if want > j-i {
want = j - i
}
if len(bb) != want {
assert(false)
//t.Fatalf("in %d,%d: len(Next(%d)) == %d", i, j, k, len(bb))
}
for l, v := range bb {
if v != byte(l+i) {
assert(false)
//t.Fatalf("in %d,%d: Next(%d)[%d] = %d, want %d", i, j, k, l, v, l+i)
}
}
}
}
}
}
global readBytesTests = []struct {
buffer: string
delim: byte
expected: []string
err: error
}{
{"", 0, []string{""}, io.EOF},
{"a\x00", 0, []string{"a\x00"}, nil},
{"abbbaaaba", 'b', []string{"ab", "b", "b", "aaab"}, nil},
{"hello\x01world", 1, []string{"hello\x01"}, nil},
{"foo\nbar", 0, []string{"foo\nbar"}, io.EOF},
{"alpha\nbeta\ngamma\n", '\n', []string{"alpha\n", "beta\n", "gamma\n"}, nil},
{"alpha\nbeta\ngamma", '\n', []string{"alpha\n", "beta\n", "gamma"}, io.EOF},
}
func TestReadBytes {
for _, test := range readBytesTests {
buf := NewBufferString(test.buffer)
err: error
for _, expected := range test.expected {
bytes: []byte
bytes, err = buf.ReadBytes(test.delim)
if string(bytes) != expected {
assert(false)
//t.Errorf("expected %q, got %q", expected, bytes)
}
if err != nil {
break
}
}
if err != test.err {
assert(false)
//t.Errorf("expected error %v, got %v", test.err, err)
}
}
}
func TestReadString {
for _, test := range readBytesTests {
buf := NewBufferString(test.buffer)
err: error
for _, expected := range test.expected {
s: string
s, err = buf.ReadString(test.delim)
if s != expected {
assert(false)
//t.Errorf("expected %q, got %q", expected, s)
}
if err != nil {
break
}
}
if err != test.err {
assert(false)
//t.Errorf("expected error %v, got %v", test.err, err)
}
}
}
func TestGrow {
// TODO
}
// Was a bug: used to give EOF reading empty slice at EOF.
func TestReadEmptyAtEOF {
b := new(Buffer)
slice := make([]byte, 0)
n, err := b.Read(slice)
if err != nil {
assert(false)
//t.Errorf("read error: %v", err)
}
if n != 0 {
assert(false)
//t.Errorf("wrong count; got %d want 0", n)
}
}
func TestUnreadByte {
b := new(Buffer)
// check at EOF
if err := b.UnreadByte(); err == nil {
assert(false)
//t.Fatal("UnreadByte at EOF: got no error")
}
if _, err := b.ReadByte(); err == nil {
assert(false)
//t.Fatal("ReadByte at EOF: got no error")
}
if err := b.UnreadByte(); err == nil {
assert(false)
//t.Fatal("UnreadByte after ReadByte at EOF: got no error")
}
// check not at EOF
b.WriteString("abcdefghijklmnopqrstuvwxyz")
// after unsuccessful read
if n, err := b.Read(nil); n != 0 || err != nil {
assert(false)
//t.Fatalf("Read(nil) = %d,%v; want 0,nil", n, err)
}
if err := b.UnreadByte(); err == nil {
assert(false)
//t.Fatal("UnreadByte after Read(nil): got no error")
}
// after successful read
if _, err := b.ReadBytes('m'); err != nil {
assert(false)
//t.Fatalf("ReadBytes: %v", err)
}
if err := b.UnreadByte(); err != nil {
assert(false)
//t.Fatalf("UnreadByte: %v", err)
}
c, err := b.ReadByte()
if err != nil {
assert(false)
//t.Fatalf("ReadByte: %v", err)
}
if c != 'm' {
assert(false)
//t.Errorf("ReadByte = %q; want %q", c, 'm')
}
}
// 版权 @2023 凹语言 作者。保留所有权利。
// MaxLen is the maximum length of the string to be searched for (argument b) in Index.
// If MaxLen is not 0, make sure MaxLen >= 4.
global bytealg_MaxLen: int
// FIXME: the logic of HashStrBytes, HashStrRevBytes, IndexRabinKarpBytes and HashStr, HashStrRev,
// IndexRabinKarp are exactly the same, except that the types are different. Can we eliminate
// three of them without causing allocation?
// PrimeRK is the prime base used in Rabin-Karp algorithm.
const bytealg_PrimeRK = 16777619
const bytealg_MaxBruteForce = 0
// Index returns the index of the first instance of b in a, or -1 if b is not present in a.
// Requires 2 <= len(b) <= MaxLen.
func bytealg_Index(a, b: []byte) => int {
panic("unimplemented")
}
// IndexString returns the index of the first instance of b in a, or -1 if b is not present in a.
// Requires 2 <= len(b) <= MaxLen.
func bytealg_IndexString(a, b: string) => int {
panic("unimplemented")
}
// Cutover reports the number of failures of IndexByte we should tolerate
// before switching over to Index.
// n is the number of bytes processed so far.
// See the bytes.Index implementation for details.
func bytealg_Cutover(n: int) => int {
panic("unimplemented")
}
func bytealg_Count(b: []byte, c: byte) => int {
n := 0
for _, x := range b {
if x == c {
n++
}
}
return n
}
func bytealg_CountString(s: string, c: byte) => int {
n := 0
for i := 0; i < len(s); i++ {
if s[i] == c {
n++
}
}
return n
}
此差异已折叠。
此差异已折叠。
// 版权 @2023 凹语言 作者。保留所有权利。
global compareTests = []struct {
a, b: []byte
i: int
}{
{[]byte(""), []byte(""), 0},
{[]byte("a"), []byte(""), 1},
{[]byte(""), []byte("a"), -1},
{[]byte("abc"), []byte("abc"), 0},
{[]byte("abd"), []byte("abc"), 1},
{[]byte("abc"), []byte("abd"), -1},
{[]byte("ab"), []byte("abc"), -1},
{[]byte("abc"), []byte("ab"), 1},
{[]byte("x"), []byte("ab"), 1},
{[]byte("ab"), []byte("x"), -1},
{[]byte("x"), []byte("a"), 1},
{[]byte("b"), []byte("x"), -1},
// test runtime·memeq's chunked implementation
{[]byte("abcdefgh"), []byte("abcdefgh"), 0},
{[]byte("abcdefghi"), []byte("abcdefghi"), 0},
{[]byte("abcdefghi"), []byte("abcdefghj"), -1},
{[]byte("abcdefghj"), []byte("abcdefghi"), 1},
// nil tests
{nil, nil, 0},
{[]byte(""), nil, 0},
{nil, []byte(""), 0},
{[]byte("a"), nil, 1},
{nil, []byte("a"), -1},
}
func TestCompare {
for _, tt := range compareTests {
numShifts := 16
buffer := make([]byte, len(tt.b)+numShifts)
// vary the input alignment of tt.b
for offset := 0; offset <= numShifts; offset++ {
shiftedB := buffer[offset : len(tt.b)+offset]
copy(shiftedB, tt.b)
cmp := Compare(tt.a, shiftedB)
if cmp != tt.i {
assert(false)
// t.Errorf(`Compare(%q, %q), offset %d = %v; want %v`, tt.a, tt.b, offset, cmp, tt.i)
}
}
}
}
func TestCompareIdenticalSlice {
b := []byte("Hello Gophers!")
if Compare(b, b) != 0 {
assert(false)
//t.Error("b != b")
}
if Compare(b, b[:1]) != 1 {
assert(false)
//t.Error("b > b[:1] failed")
}
}
func TestCompareBytes {
lengths := make([]int, 0) // lengths to test in ascending order
for i := 0; i <= 128; i++ {
lengths = append(lengths, i)
}
lengths = append(lengths, 256, 512, 1024, 1333, 4095, 4096, 4097)
//if !testing.Short() || testenv.Builder() != "" {
// lengths = append(lengths, 65535, 65536, 65537, 99999)
//}
n := lengths[len(lengths)-1]
a := make([]byte, n+1)
b := make([]byte, n+1)
for _, len := range lengths {
// randomish but deterministic data. No 0 or 255.
for i := 0; i < len; i++ {
a[i] = byte(1 + 31*i%254)
b[i] = byte(1 + 31*i%254)
}
// data past the end is different
for i := len; i <= n; i++ {
a[i] = 8
b[i] = 9
}
cmp := Compare(a[:len], b[:len])
if cmp != 0 {
assert(false)
//t.Errorf(`CompareIdentical(%d) = %d`, len, cmp)
}
if len > 0 {
cmp = Compare(a[:len-1], b[:len])
if cmp != -1 {
assert(false)
//t.Errorf(`CompareAshorter(%d) = %d`, len, cmp)
}
cmp = Compare(a[:len], b[:len-1])
if cmp != 1 {
assert(false)
//t.Errorf(`CompareBshorter(%d) = %d`, len, cmp)
}
}
for k := 0; k < len; k++ {
b[k] = a[k] - 1
cmp = Compare(a[:len], b[:len])
if cmp != 1 {
assert(false)
//t.Errorf(`CompareAbigger(%d,%d) = %d`, len, k, cmp)
}
b[k] = a[k] + 1
cmp = Compare(a[:len], b[:len])
if cmp != -1 {
assert(false)
//t.Errorf(`CompareBbigger(%d,%d) = %d`, len, k, cmp)
}
b[k] = a[k]
}
}
}
func TestEndianBaseCompare {
// This test compares byte slices that are almost identical, except one
// difference that for some j, a[j]>b[j] and a[j+1]<b[j+1]. If the implementation
// compares large chunks with wrong endianness, it gets wrong result.
// no vector register is larger than 512 bytes for now
const maxLength = 512
a := make([]byte, maxLength)
b := make([]byte, maxLength)
// randomish but deterministic data. No 0 or 255.
for i := 0; i < maxLength; i++ {
a[i] = byte(1 + 31*i%254)
b[i] = byte(1 + 31*i%254)
}
for i := 2; i <= maxLength; i <<= 1 {
for j := 0; j < i-1; j++ {
a[j] = b[j] - 1
a[j+1] = b[j+1] + 1
cmp := Compare(a[:i], b[:i])
if cmp != -1 {
assert(false)
//t.Errorf(`CompareBbigger(%d,%d) = %d`, i, j, cmp)
}
a[j] = b[j] + 1
a[j+1] = b[j+1] - 1
cmp = Compare(a[:i], b[:i])
if cmp != 1 {
assert(false)
//t.Errorf(`CompareAbigger(%d,%d) = %d`, i, j, cmp)
}
a[j] = b[j]
a[j+1] = b[j+1]
}
}
}
// 版权 @2023 凹语言 作者。保留所有权利。
// Copyright 2012 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.
import (
"errors"
"io"
"unicode/utf8"
)
// A Reader implements the io.Reader, io.ReaderAt, io.WriterTo, io.Seeker,
// io.ByteScanner, and io.RuneScanner interfaces by reading from
// a byte slice.
// Unlike a Buffer, a Reader is read-only and supports seeking.
// The zero value for Reader operates like a Reader of an empty slice.
type Reader struct {
s: []byte
i: i64 // current reading index
prevRune: int // index of previous rune; or < 0
}
// Len returns the number of bytes of the unread portion of the
// slice.
func Reader.Len => int {
r := this
if r.i >= i64(len(r.s)) {
return 0
}
return int(i64(len(r.s)) - r.i)
}
// Size returns the original length of the underlying byte slice.
// Size is the number of bytes available for reading via ReadAt.
// The returned value is always the same and is not affected by calls
// to any other method.
func Reader.Size => i64 {
r := this
return i64(len(r.s))
}
// Read implements the io.Reader interface.
func Reader.Read(b: []byte) => (n: int, err: error) {
r := this
if r.i >= i64(len(r.s)) {
return 0, io.EOF
}
r.prevRune = -1
n = copy(b, r.s[int(r.i):])
r.i += i64(n)
return
}
// ReadAt implements the io.ReaderAt interface.
func Reader.ReadAt(b: []byte, off: i64) => (n: int, err: error) {
r := this
// cannot modify state - see io.ReaderAt
if off < 0 {
return 0, errors.New("bytes.Reader.ReadAt: negative offset")
}
if off >= i64(len(r.s)) {
return 0, io.EOF
}
n = copy(b, r.s[int(off):])
if n < len(b) {
err = io.EOF
}
return
}
// ReadByte implements the io.ByteReader interface.
func Reader.ReadByte => (byte, error) {
r := this
r.prevRune = -1
if r.i >= i64(len(r.s)) {
return 0, io.EOF
}
b := r.s[int(r.i)]
r.i++
return b, nil
}
// UnreadByte complements ReadByte in implementing the io.ByteScanner interface.
func Reader.UnreadByte => error {
r := this
if r.i <= 0 {
return errors.New("bytes.Reader.UnreadByte: at beginning of slice")
}
r.prevRune = -1
r.i--
return nil
}
// ReadRune implements the io.RuneReader interface.
func Reader.ReadRune => (ch: rune, size: int, err: error) {
r := this
if r.i >= i64(len(r.s)) {
r.prevRune = -1
return 0, 0, io.EOF
}
r.prevRune = int(r.i)
if c := r.s[r.i]; c < utf8.RuneSelf {
r.i++
return rune(c), 1, nil
}
ch, size = utf8.DecodeRune(r.s[int(r.i):])
r.i += i64(size)
return
}
// UnreadRune complements ReadRune in implementing the io.RuneScanner interface.
func Reader.UnreadRune => error {
r := this
if r.i <= 0 {
return errors.New("bytes.Reader.UnreadRune: at beginning of slice")
}
if r.prevRune < 0 {
return errors.New("bytes.Reader.UnreadRune: previous operation was not ReadRune")
}
r.i = i64(r.prevRune)
r.prevRune = -1
return nil
}
// Seek implements the io.Seeker interface.
func Reader.Seek(offset: i64, whence: int) => (i64, error) {
r := this
r.prevRune = -1
abs: i64
switch whence {
case io.SeekStart:
abs = offset
case io.SeekCurrent:
abs = r.i + offset
case io.SeekEnd:
abs = i64(len(r.s)) + offset
default:
return 0, errors.New("bytes.Reader.Seek: invalid whence")
}
if abs < 0 {
return 0, errors.New("bytes.Reader.Seek: negative position")
}
r.i = abs
return abs, nil
}
// WriteTo implements the io.WriterTo interface.
func Reader.WriteTo(w: io.Writer) => (n: i64, err: error) {
r := this
r.prevRune = -1
if r.i >= i64(len(r.s)) {
return 0, nil
}
b := r.s[int(r.i):]
m, err := w.Write(b)
if m > len(b) {
panic("bytes.Reader.WriteTo: invalid Write count")
}
r.i += i64(m)
n = i64(m)
if m != len(b) && err == nil {
err = io.ErrShortWrite
}
return
}
// Reset resets the Reader to be reading from b.
func Reader.Reset(b: []byte) {
r := this
*r = Reader{b, 0, -1}
}
// NewReader returns a new Reader reading from b.
func NewReader(b: []byte) => *Reader {
return &Reader{b, 0, -1}
}
// 版权 @2023 凹语言 作者。保留所有权利。
// Copyright 2012 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.
import (
"errors"
"io"
)
func TestReader {
r := NewReader([]byte("0123456789"))
tests := []struct {
off: i64
seek: int
n: int
want: string
wantpos: i64
readerr: error
seekerr: string
}{
{seek: io.SeekStart, off: 0, n: 20, want: "0123456789"},
{seek: io.SeekStart, off: 1, n: 1, want: "1"},
{seek: io.SeekCurrent, off: 1, wantpos: 3, n: 2, want: "34"},
{seek: io.SeekStart, off: -1, seekerr: "bytes.Reader.Seek: negative position"},
{seek: io.SeekStart, off: 1 << 33, wantpos: 1 << 33, readerr: io.EOF},
{seek: io.SeekCurrent, off: 1, wantpos: 1<<33 + 1, readerr: io.EOF},
{seek: io.SeekStart, n: 5, want: "01234"},
{seek: io.SeekCurrent, n: 5, want: "56789"},
{seek: io.SeekEnd, off: -1, n: 1, wantpos: 9, want: "9"},
}
for _, tt := range tests {
pos, err := r.Seek(tt.off, tt.seek)
if err == nil && tt.seekerr != "" {
assert(false)
//t.Errorf("%d. want seek error %q", i, tt.seekerr)
//continue
}
if err != nil && err.Error() != tt.seekerr {
assert(false)
//t.Errorf("%d. seek error = %q; want %q", i, err.Error(), tt.seekerr)
//continue
}
if tt.wantpos != 0 && tt.wantpos != pos {
assert(false)
//t.Errorf("%d. pos = %d, want %d", i, pos, tt.wantpos)
}
buf := make([]byte, tt.n)
n, err := r.Read(buf)
if err != tt.readerr {
assert(false)
//t.Errorf("%d. read = %v; want %v", i, err, tt.readerr)
//continue
}
got := string(buf[:n])
if got != tt.want {
assert(false)
//t.Errorf("%d. got %q; want %q", i, got, tt.want)
}
}
}
func TestReadAfterBigSeek {
r := NewReader([]byte("0123456789"))
if _, err := r.Seek(1<<31+5, io.SeekStart); err != nil {
assert(false)
//t.Fatal(err)
}
if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
assert(false)
//t.Errorf("Read = %d, %v; want 0, EOF", n, err)
}
}
func TestReaderAt {
r := NewReader([]byte("0123456789"))
tests := []struct {
off: i64
n: int
want: string
wanterr: error
}{
{0, 10, "0123456789", nil},
{1, 10, "123456789", io.EOF},
{1, 9, "123456789", nil},
{11, 10, "", io.EOF},
{0, 0, "", nil},
{-1, 0, "", errors.New("bytes.Reader.ReadAt: negative offset")},
}
for _, tt := range tests {
b := make([]byte, tt.n)
rn, err := r.ReadAt(b, tt.off)
got := string(b[:rn])
if got != tt.want {
assert(false)
//t.Errorf("%d. got %q; want %q", i, got, tt.want)
}
if (err == nil && tt.wanterr != nil) || (err != nil && tt.wanterr == nil) {
assert(false)
}
if err != nil && tt.wanterr != nil {
if err.Error() != tt.wanterr.Error() {
assert(false)
}
}
//if fmt.Sprintf("%v", err) != fmt.Sprintf("%v", ) {
//t.Errorf("%d. got error = %v; want %v", i, err, tt.wanterr)
//}
}
}
func TestReaderWriteTo {
for i := 0; i < 30; i += 3 {
l: int
if i > 0 {
l = len(testString) / i
}
s := testString[:l]
r := NewReader(testBytes[:l])
b: Buffer
n, err := r.WriteTo(&b)
if expect := i64(len(s)); n != expect {
assert(false)
//t.Errorf("got %v; want %v", n, expect)
}
if err != nil {
assert(false)
//t.Errorf("for length %d: got error = %v; want nil", l, err)
}
if b.String() != s {
assert(false)
//t.Errorf("got string %q; want %q", b.String(), s)
}
if r.Len() != 0 {
assert(false)
//t.Errorf("reader contains %v bytes; want 0", r.Len())
}
}
}
func TestReaderLen {
const data = "hello world"
r := NewReader([]byte(data))
if got, want := r.Len(), 11; got != want {
assert(false)
//t.Errorf("r.Len(): got %d, want %d", got, want)
}
if n, err := r.Read(make([]byte, 10)); err != nil || n != 10 {
assert(false)
//t.Errorf("Read failed: read %d %v", n, err)
}
if got, want := r.Len(), 1; got != want {
assert(false)
//t.Errorf("r.Len(): got %d, want %d", got, want)
}
if n, err := r.Read(make([]byte, 1)); err != nil || n != 1 {
assert(false)
//t.Errorf("Read failed: read %d %v; want 1, nil", n, err)
}
if got, want := r.Len(), 0; got != want {
assert(false)
//t.Errorf("r.Len(): got %d, want %d", got, want)
}
}
global UnreadRuneErrorTests = []struct {
name: string
f: func(*Reader)
}{
{"Read", func(r: *Reader) { r.Read([]byte{0}) }},
{"ReadByte", func(r: *Reader) { r.ReadByte() }},
{"UnreadRune", func(r: *Reader) { r.UnreadRune() }},
{"Seek", func(r: *Reader) { r.Seek(0, io.SeekCurrent) }},
{"WriteTo", func(r: *Reader) { r.WriteTo(&Buffer{}) }},
}
func TestUnreadRuneError {
for _, tt := range UnreadRuneErrorTests {
reader := NewReader([]byte("0123456789"))
if _, _, err := reader.ReadRune(); err != nil {
assert(false)
// should not happen
//t.Fatal(err)
}
tt.f(reader)
err := reader.UnreadRune()
if err == nil {
assert(false)
//t.Errorf("Unreading after %s: expected error", tt.name)
}
}
}
func TestReaderDoubleUnreadRune {
buf := NewBuffer([]byte("groucho"))
if _, _, err := buf.ReadRune(); err != nil {
assert(false)
// should not happen
//t.Fatal(err)
}
if err := buf.UnreadByte(); err != nil {
assert(false)
// should not happen
//t.Fatal(err)
}
if err := buf.UnreadByte(); err == nil {
assert(false)
//t.Fatal("UnreadByte: expected error, got nil")
}
}
// verify that copying from an empty reader always has the same results,
// regardless of the presence of a WriteTo method.
func TestReaderCopyNothing {
type nErr struct {
n: i64
err: error
}
type justReader struct {
io.Reader
}
type justWriter struct {
io.Writer
}
discard := &justWriter{io.Discard} // hide ReadFrom
with, withOut: nErr
with.n, with.err = io.Copy(discard, NewReader(nil))
withOut.n, withOut.err = io.Copy(discard, &justReader{NewReader(nil)})
if with != withOut {
assert(false)
//t.Errorf("behavior differs: with = %#v; without: %#v", with, withOut)
}
}
// tests that Len is affected by reads, but Size is not.
func TestReaderLenSize {
r := NewReader([]byte("abc"))
io.CopyN(io.Discard, r, 1)
if r.Len() != 2 {
assert(false)
//t.Errorf("Len = %d; want 2", r.Len())
}
if r.Size() != 3 {
assert(false)
//t.Errorf("Size = %d; want 3", r.Size())
}
}
func TestReaderReset {
r := NewReader([]byte("世界"))
if _, _, err := r.ReadRune(); err != nil {
assert(false)
//t.Errorf("ReadRune: unexpected error: %v", err)
}
const want = "abcdef"
r.Reset([]byte(want))
if err := r.UnreadRune(); err == nil {
assert(false)
//t.Errorf("UnreadRune: expected error, got nil")
}
buf, err := io.ReadAll(r)
if err != nil {
assert(false)
//t.Errorf("ReadAll: unexpected error: %v", err)
}
if got := string(buf); got != want {
assert(false)
//t.Errorf("ReadAll: got %q, want %q", got, want)
}
}
func TestReaderZero {
if l := (&Reader{}).Len(); l != 0 {
assert(false)
//t.Errorf("Len: got %d, want 0", l)
}
if n, err := (&Reader{}).Read(nil); n != 0 || err != io.EOF {
assert(false)
//t.Errorf("Read: got %d, %v; want 0, io.EOF", n, err)
}
if n, err := (&Reader{}).ReadAt(nil, 11); n != 0 || err != io.EOF {
assert(false)
//t.Errorf("ReadAt: got %d, %v; want 0, io.EOF", n, err)
}
if b, err := (&Reader{}).ReadByte(); b != 0 || err != io.EOF {
assert(false)
//t.Errorf("ReadByte: got %d, %v; want 0, io.EOF", b, err)
}
if ch, size, err := (&Reader{}).ReadRune(); ch != 0 || size != 0 || err != io.EOF {
assert(false)
//t.Errorf("ReadRune: got %d, %d, %v; want 0, 0, io.EOF", ch, size, err)
}
if offset, err := (&Reader{}).Seek(11, io.SeekStart); offset != 11 || err != nil {
assert(false)
//t.Errorf("Seek: got %d, %v; want 11, nil", offset, err)
}
if s := (&Reader{}).Size(); s != 0 {
assert(false)
//t.Errorf("Size: got %d, want 0", s)
}
if (&Reader{}).UnreadByte() == nil {
assert(false)
//t.Errorf("UnreadByte: got nil, want error")
}
if (&Reader{}).UnreadRune() == nil {
assert(false)
//t.Errorf("UnreadRune: got nil, want error")
}
if n, err := (&Reader{}).WriteTo(io.Discard); n != 0 || err != nil {
assert(false)
//t.Errorf("WriteTo: got %d, %v; want 0, nil", n, err)
}
}
...@@ -167,7 +167,7 @@ type ReadWriteSeeker interface { ...@@ -167,7 +167,7 @@ type ReadWriteSeeker interface {
// //
// The Copy function uses ReaderFrom if available. // The Copy function uses ReaderFrom if available.
type ReaderFrom interface { type ReaderFrom interface {
ReadFrom(r: Reader) => (n: int64, err: error) ReadFrom(r: Reader) => (n: i64, err: error)
} }
// WriterTo is the interface that wraps the WriteTo method. // WriterTo is the interface that wraps the WriteTo method.
...@@ -395,7 +395,7 @@ func copyBuffer(dst: Writer, src: Reader, buf: []byte) => (written: i64, err: er ...@@ -395,7 +395,7 @@ func copyBuffer(dst: Writer, src: Reader, buf: []byte) => (written: i64, err: er
} }
if buf == nil { if buf == nil {
size := 32 * 1024 size := 32 * 1024
if l, ok := src.(*LimitedReader); ok && int64(size) > l.N { if l, ok := src.(*LimitedReader); ok && i64(size) > l.N {
if l.N < 1 { if l.N < 1 {
size = 1 size = 1
} else { } else {
...@@ -414,7 +414,7 @@ func copyBuffer(dst: Writer, src: Reader, buf: []byte) => (written: i64, err: er ...@@ -414,7 +414,7 @@ func copyBuffer(dst: Writer, src: Reader, buf: []byte) => (written: i64, err: er
ew = errInvalidWrite ew = errInvalidWrite
} }
} }
written += int64(nw) written += i64(nw)
if ew != nil { if ew != nil {
err = ew err = ew
break break
...@@ -452,11 +452,11 @@ func LimitedReader.Read(p: []byte) => (n: int, err: error) { ...@@ -452,11 +452,11 @@ func LimitedReader.Read(p: []byte) => (n: int, err: error) {
if this.N <= 0 { if this.N <= 0 {
return 0, EOF return 0, EOF
} }
if int64(len(p)) > this.N { if i64(len(p)) > this.N {
p = p[0:this.N] p = p[0:int(this.N)]
} }
n, err = this.R.Read(p) n, err = this.R.Read(p)
this.N -= int64(n) this.N -= i64(n)
return return
} }
...@@ -479,11 +479,11 @@ func SectionReader.Read(p: []byte) => (n: int, err: error) { ...@@ -479,11 +479,11 @@ func SectionReader.Read(p: []byte) => (n: int, err: error) {
if this.off >= this.limit { if this.off >= this.limit {
return 0, EOF return 0, EOF
} }
if max := this.limit - this.off; int64(len(p)) > max { if max := this.limit - this.off; i64(len(p)) > max {
p = p[0:max] p = p[0:int(max)]
} }
n, err = this.r.ReadAt(p, this.off) n, err = this.r.ReadAt(p, this.off)
this.off += int64(n) this.off += i64(n)
return return
} }
...@@ -513,8 +513,8 @@ func SectionReader.ReadAt(p: []byte, off: i64) => (n: int, err: error) { ...@@ -513,8 +513,8 @@ func SectionReader.ReadAt(p: []byte, off: i64) => (n: int, err: error) {
return 0, EOF return 0, EOF
} }
off += this.base off += this.base
if max := this.limit - off; int64(len(p)) > max { if max := this.limit - off; i64(len(p)) > max {
p = p[0:max] p = p[0:int(max)]
n, err = this.r.ReadAt(p, off) n, err = this.r.ReadAt(p, off)
if err == nil { if err == nil {
err = EOF err = EOF
...@@ -570,7 +570,18 @@ func discard.WriteString(s: string) => (int, error) { ...@@ -570,7 +570,18 @@ func discard.WriteString(s: string) => (int, error) {
} }
func discard.ReadFrom(r: Reader) => (n: i64, err: error) { func discard.ReadFrom(r: Reader) => (n: i64, err: error) {
panic("TODO") buf := make([]byte, 64)
readSize := 0
for {
readSize, err = r.Read(buf)
n += i64(readSize)
if err != nil {
if err == EOF {
return n, nil
}
return
}
}
} }
......
// 版权 @2023 凹语言 作者。保留所有权利。
func TestTODO {
// TODO(chai2010)
}
// Author: TrueAbc
// Note:
// The implementation refers to the go language "math/big" lib.
import "math/bits"
func AAA {
println(bits.UintSize)
}
const (
_S = _W / 8 // 字宽(以字节为单位)
_W = bits.UintSize // 字宽(以位为单位)
_B = 1 << _W // 基数
_M = _B - 1 // 基数掩码
)
// z1<<_W + z0 = x*y
func mulWW(x, y: uint) => (z1, z0: uint) {
return bits.Mul(x, y)
}
// z1<<_W + z0 = x*y + c
func mulAddWWW(x, y, c: uint) => (z1, z0: uint) {
hi, lo := bits.Mul(x, y)
cc: uint
lo, cc = bits.Add(lo, c, 0)
return hi + cc, lo
}
// nlz returns the number of leading zeros in x.
// Wraps bits.LeadingZeros call for convenience.
func nlz(x: uint) => uint {
return uint(bits.LeadingZeros(x))
}
// The resulting carry c is either 0 or 1.
func addVV(z, x, y: []uint) => (c: uint) {
for i := 0; i < len(z) && i < len(x) && i < len(y); i++ {
zi, cc := bits.Add(x[i], y[i], c)
z[i] = zi
c = cc
}
return
}
// The resulting carry c is either 0 or 1.
func subVV(z, x, y: []uint) => (c: uint) {
for i := 0; i < len(z) && i < len(x) && i < len(y); i++ {
zi, cc := bits.Sub(x[i], y[i], c)
z[i] = zi
c = cc
}
return
}
// The resulting carry c is either 0 or 1.
func addVW(z, x: []uint, y: uint) => (c: uint) {
c = y
for i := 0; i < len(z) && i < len(x); i++ {
zi, cc := bits.Add(x[i], c, 0)
z[i] = zi
c = cc
}
return
}
func subVW(z, x: []uint, y: uint) => (c: uint) {
c = y
for i := 0; i < len(z) && i < len(x); i++ {
zi, cc := bits.Sub(x[i], c, 0)
z[i] = zi
c = cc
}
return
}
func shlVU(z, x: []uint, s: uint) => (c: uint) {
if s == 0 {
copy(z, x)
return
}
if len(z) == 0 {
return
}
s &= _W - 1 // hint to the compiler that shifts by s don't need guard code
ŝ := _W - s
ŝ &= _W - 1 // ditto
c = x[len(z)-1] >> ŝ
for i := len(z) - 1; i > 0; i-- {
z[i] = x[i]<<s | x[i-1]>>ŝ
}
z[0] = x[0] << s
return
}
func shrVU(z, x: []uint, s: uint) => (c: uint) {
if s == 0 {
copy(z, x)
return
}
if len(z) == 0 {
return
}
if len(x) != len(z) {
// This is an invariant guaranteed by the caller.
panic("len(x) != len(z)")
}
s &= _W - 1 // hint to the compiler that shifts by s don't need guard code
ŝ := _W - s
ŝ &= _W - 1 // ditto
c = x[0] << ŝ
for i := 1; i < len(z); i++ {
z[i-1] = x[i-1]>>s | x[i]<<ŝ
}
z[len(z)-1] = x[len(z)-1] >> s
return
}
func mulAddVWW(z, x: []uint, y, r: uint) => (c: uint) {
c = r
for i := 0; i < len(z) && i < len(x); i++ {
c, z[i] = mulAddWWW(x[i], y, c)
}
return
}
func addMulVVW(z, x: []uint, y: uint) => (c: uint) {
for i := 0; i < len(z) && i < len(x); i++ {
z1, z0 := mulAddWWW(x[i], y, z[i])
lo, cc := bits.Add(z0, c, 0)
c, z[i] = cc, lo
c += z1
}
return
}
// q = ( x1 << _W + x0 - r)/y. m = floor(( _B^2 - 1 ) / d - _B). Requiring x1<y.
// An approximate reciprocal with a reference to "Improved Division by Invariant Integers
// (IEEE Transactions on Computers, 11 Jun. 2010)"
func divWW(x1, x0, y, m: uint) => (q, r: uint) {
s := nlz(y)
if s != 0 {
x1 = x1<<s | x0>>(_W-s)
x0 <<= s
y <<= s
}
d := y
// We know that
// m = ⎣(B^2-1)/d⎦-B
// ⎣(B^2-1)/d⎦ = m+B
// (B^2-1)/d = m+B+delta1 0 <= delta1 <= (d-1)/d
// B^2/d = m+B+delta2 0 <= delta2 <= 1
// The quotient we're trying to compute is
// quotient = ⎣(x1*B+x0)/d⎦
// = ⎣(x1*B*(B^2/d)+x0*(B^2/d))/B^2⎦
// = ⎣(x1*B*(m+B+delta2)+x0*(m+B+delta2))/B^2⎦
// = ⎣(x1*m+x1*B+x0)/B + x0*m/B^2 + delta2*(x1*B+x0)/B^2⎦
// The latter two terms of this three-term sum are between 0 and 1.
// So we can compute just the first term, and we will be low by at most 2.
t1, t0 := bits.Mul(m, x1)
_, c := bits.Add(t0, x0, 0)
t1, _ = bits.Add(t1, x1, c)
// The quotient is either t1, t1+1, or t1+2.
// We'll try t1 and adjust if needed.
qq := t1
// compute remainder r=x-d*q.
dq1, dq0 := bits.Mul(d, qq)
r0, b := bits.Sub(x0, dq0, 0)
r1, _ := bits.Sub(x1, dq1, b)
// The remainder we just computed is bounded above by B+d:
// r = x1*B + x0 - d*q.
// = x1*B + x0 - d*⎣(x1*m+x1*B+x0)/B⎦
// = x1*B + x0 - d*((x1*m+x1*B+x0)/B-alpha) 0 <= alpha < 1
// = x1*B + x0 - x1*d/B*m - x1*d - x0*d/B + d*alpha
// = x1*B + x0 - x1*d/B*⎣(B^2-1)/d-B⎦ - x1*d - x0*d/B + d*alpha
// = x1*B + x0 - x1*d/B*⎣(B^2-1)/d-B⎦ - x1*d - x0*d/B + d*alpha
// = x1*B + x0 - x1*d/B*((B^2-1)/d-B-beta) - x1*d - x0*d/B + d*alpha 0 <= beta < 1
// = x1*B + x0 - x1*B + x1/B + x1*d + x1*d/B*beta - x1*d - x0*d/B + d*alpha
// = x0 + x1/B + x1*d/B*beta - x0*d/B + d*alpha
// = x0*(1-d/B) + x1*(1+d*beta)/B + d*alpha
// < B*(1-d/B) + d*B/B + d because x0<B (and 1-d/B>0), x1<d, 1+d*beta<=B, alpha<1
// = B - d + d + d
// = B+d
// So r1 can only be 0 or 1. If r1 is 1, then we know q was too small.
// Add 1 to q and subtract d from r. That guarantees that r is <B, so
// we no longer need to keep track of r1.
if r1 != 0 {
qq++
r0 -= d
}
// If the remainder is still too large, increment q one more time.
if r0 >= d {
qq++
r0 -= d
}
return qq, r0 >> s
}
// reciprocalWord return the reciprocal of the divisor. rec = floor(( _B^2 - 1 ) / u - _B). u = d1 << nlz(d1).
func reciprocalWord(d1: uint) => uint {
u := uint(d1 << nlz(d1))
x1 := ^u
x0 := uint(_M)
rec, _ := bits.Div(x1, x0, u) // (_B^2-1)/U-_B = (_B*(_M-C)+_M)/U
return uint(rec)
}
// Author: TrueAbc
// Note:
// The implementation refers to the go language "math/big" lib.
// 暂时把go的大端转换代码copy过来
func Buf2Uint64(b: []byte) => uint64 {
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
}
func Buf2Uint32(b: []byte) => uint32 {
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
}
此差异已折叠。
// Author: TrueAbc
// Note:
// The implementation refers to the go language "math/big" lib.
type funZZ func(z, x, y: *Int) => *Int
type argZZ struct {
z, x, y: *Int
}
var sumZZ = []argZZ{
{NewInt("0"), NewInt("0"), NewInt("0")},
{NewInt("1"), NewInt("1"), NewInt("0")},
{NewInt("1111111110"), NewInt("123456789"), NewInt("987654321")},
{NewInt("-1"), NewInt("-1"), NewInt("0")},
{NewInt("864197532"), NewInt("-123456789"), NewInt("987654321")},
{NewInt("-1111111110"), NewInt("-123456789"), NewInt("-987654321")},
}
func Test_Int_Set() {
println("start test set")
for _, a := range sumZZ {
z: Int
z.Set(a.z)
if (&z).Cmp(a.z) != 0 {
println("error for Int Set")
}
}
}
func testFunZZ(msg: string, f: funZZ, a: argZZ) {
z: Int
f(&z, a.x, a.y)
t := (&z).Cmp(a.z)
if t != 0 {
println(msg, " compute error ", t, ".")
}
}
func Test_Int_Sum() {
println("start test int add and sub")
AddZZ := func(z, x, y: *Int) => *Int { return z.Add(x, y) }
SubZZ := func(z, x, y: *Int) => *Int { return z.Sub(x, y) }
for _, a := range sumZZ {
arg := a
testFunZZ("AddZZ", AddZZ, arg)
arg = argZZ{a.z, a.y, a.x}
testFunZZ("AddZZ symmetric", AddZZ, arg)
arg = argZZ{a.x, a.z, a.y}
testFunZZ("SubZZ", SubZZ, arg)
arg = argZZ{a.y, a.z, a.x}
testFunZZ("SubZZ symmetric", SubZZ, arg)
}
}
var quoTests = []struct {
x, y: string
q, r: string
}{
{
"476217953993950760840509444250624797097991362735329973741718102894495832294430498335824897858659711275234906400899559094370964723884706254265559534144986498357",
"9353930466774385905609975137998169297361893554149986716853295022578535724979483772383667534691121982974895531435241089241440253066816724367338287092081996",
"50911",
"1",
},
{
"11510768301994997771168",
"1328165573307167369775",
"8",
"885443715537658812968",
},
}
func Test_Quo() {
println("start test int quo")
for _, test := range quoTests {
x := NewInt(test.x)
y := NewInt(test.y)
expectedQ := NewInt(test.q)
expectedR := NewInt(test.r)
r := NewInt("0")
q, r := NewInt("0").QuoRem(x, y, r)
if q.Cmp(expectedQ) != 0 || r.Cmp(expectedR) != 0 {
println("error for Int quo")
}
}
}
此差异已折叠。
// Author: TrueAbc
// Note:
// The implementation refers to the go language "math/big" lib.
// test好像并不执行该文件夹, 改为导出方法放在外层执行
func Test_Norm {
t := nat{Data: []uint{1, 0, 0, 0}}
t = t.norm()
if len(t.Data) == 1 && t.Data[0] == 1 {
println("NORM TEST PASS!")
} else {
println("NORM TEST FAILED!")
}
}
func Test_setWord {
t := nat{Data: []uint{1, 2, 3, 4}}
z := t.setWord(0)
println("set zero:", len(z.Data))
z = t.setWord(10)
println("set to 10:", z.Data[0], " ", t.Data[0])
}
func Test_set {
t := nat{Data: []uint{1, 2, 3, 4}}
z := t.set(t)
println(len(z.Data) == len(t.Data))
for i := 0; i < len(z.Data); i++ {
println("item:", z.Data[i], "===", t.Data[i])
}
}
// 参考go单元测试的内容
type funNN func(z: nat, x: nat, y: nat) => nat
type argNN struct {
z: nat
x: nat
y: nat
}
var sumNN = []argNN{
{},
{z: nat{[]uint{1}}, x: nat{nil}, y: nat{[]uint{1}}},
{z: nat{[]uint{1111111110}}, x: nat{[]uint{123456789}}, y: nat{[]uint{987654321}}},
{z: nat{[]uint{0, 0, 0, 1}}, x: nat{nil}, y: nat{[]uint{0, 0, 0, 1}}},
{z: nat{[]uint{0, 0, 0, 1111111110}}, x: nat{[]uint{0, 0, 0, 123456789}}, y: nat{Data: []uint{0, 0, 0, 987654321}}},
{z: nat{[]uint{0, 0, 0, 1}}, x: nat{[]uint{0, 0, _M}}, y: nat{[]uint{0, 0, 1}}},
}
var prodNN = []argNN{
{},
{z: nat{nil}, x: nat{nil}, y: nat{nil}},
{z: nat{nil}, x: nat{[]uint{991}}, y: nat{nil}},
{z: nat{[]uint{991}}, x: nat{[]uint{991}}, y: nat{[]uint{1}}},
{z: nat{[]uint{991 * 991}}, x: nat{[]uint{991}}, y: nat{[]uint{991}}},
{z: nat{[]uint{0, 0, 991 * 991}}, x: nat{[]uint{0, 991}}, y: nat{[]uint{0, 991}}},
{z: nat{[]uint{1 * 991, 2 * 991, 3 * 991, 4 * 991}}, x: nat{[]uint{1, 2, 3, 4}}, y: nat{[]uint{991}}},
{z: nat{[]uint{4, 11, 20, 30, 20, 11, 4}}, x: nat{[]uint{1, 2, 3, 4}}, y: nat{[]uint{4, 3, 2, 1}}},
{
z: natFromString("11790184577738583171520872861412518665678211592275841109096961"),
x: natFromString("515377520732011331036461129765621272702107522001"),
y: natFromString("22876792454961"),
},
}
func testAdd(a: argNN) {
temp := &nat{Data: nil}
z := temp.add(a.x, a.y)
if z.cmp(a.z) != 0 {
println("Error for add result")
}
}
func testSub(a: argNN) {
temp := &nat{Data: nil}
z := temp.sub(a.x, a.y)
if z.cmp(a.z) != 0 {
println("Error for sub result")
}
}
func testMul(a: argNN) {
temp := &nat{Data: nil}
z := temp.mul(a.x, a.y)
if z.cmp(a.z) != 0 {
println("Error for mul result")
}
}
func Test_add {
println("start test add")
for _, a := range sumNN {
testAdd(a)
}
}
func Test_sub {
println("start test sub")
for _, a := range sumNN {
arg := argNN{a.x, a.z, a.y}
testSub(arg)
}
}
func Test_mul {
println("start test mul")
for _, a := range prodNN {
arg := a
testMul(arg)
arg = argNN{a.z, a.y, a.x}
testMul(arg)
}
}
func Test_div {
u := natFromString("11790184577738583171520872861412518665678211592275841109096961")
v := natFromString("515377520732011331036461129765621272702107522001")
w := natFromString("22876792454961") // 商
r := natFromString("0") // 余数
q := &nat{nil}
q2, r2 := q.div(nat{nil}, u, v)
if q2.cmp(w) != 0 {
println("wrong div result")
} else {
println("ok div result")
}
if r2.cmp(r) != 0 {
println("wrong div remainder result")
} else {
println("ok div remainder result")
}
}
func Test_setString {
n := natFromString("22876792454961")
for _, i := range n.Data {
println(i)
}
}
此差异已折叠。
...@@ -384,7 +384,7 @@ func testReverse(x64, want64: u64) { ...@@ -384,7 +384,7 @@ func testReverse(x64, want64: u64) {
func TestReverseBytes { func TestReverseBytes {
for _, test := range []struct { for _, test := range []struct {
x, r uint64 x, r: uint64
}{ }{
{0, 0}, {0, 0},
{0x01, 0x01 << 56}, {0x01, 0x01 << 56},
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
// 版权 @2023 凹语言 作者。保留所有权利。
const (
MaxRune = '\U0010FFFF' // Maximum valid Unicode code point.
ReplacementChar = '\uFFFD' // Represents invalid code points.
MaxASCII = '\u007F' // maximum ASCII value.
MaxLatin1 = '\u00FF' // maximum Latin-1 value.
)
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。