diff --git a/internal/backends/compiler_wat/compile.go b/internal/backends/compiler_wat/compile.go index 40fda0f..911572e 100644 --- a/internal/backends/compiler_wat/compile.go +++ b/internal/backends/compiler_wat/compile.go @@ -42,6 +42,13 @@ func (p *Compiler) Compile(prog *loader.Program, mainFunc string) (output string } sort.Strings(pkgnames) + for i, v := range pkgnames { + if v == "runtime" && i != 0 { + pkgnames[i] = pkgnames[0] + pkgnames[0] = "runtime" + } + } + for _, n := range pkgnames { p.ssaPkg = prog.Pkgs[n].SSAPkg p.CompilePkgConst(p.ssaPkg) diff --git a/internal/backends/compiler_wat/compile_func.go b/internal/backends/compiler_wat/compile_func.go index 3f57c22..8de39ca 100644 --- a/internal/backends/compiler_wat/compile_func.go +++ b/internal/backends/compiler_wat/compile_func.go @@ -359,6 +359,10 @@ func (g *functionGenerator) genValue(v ssa.Value) ([]wat.Inst, wir.ValueType) { // logger.Printf("Instruction already exist:%s\n", v) //} + if v, ok := v.(*ssa.Range); ok { + return g.genRange(v) + } + //Todo: 下面的做法过于粗暴 g.tLib.compile(v.Type()) @@ -419,6 +423,9 @@ func (g *functionGenerator) genValue(v ssa.Value) ([]wat.Inst, wir.ValueType) { case *ssa.TypeAssert: return g.genTypeAssert(v) + + case *ssa.Next: + return g.genNext(v) } logger.Fatalf("Todo: %v, type: %T", v, v) @@ -1142,6 +1149,22 @@ func (g *functionGenerator) genTypeAssert(inst *ssa.TypeAssert) (insts []wat.Ins 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 { + ret_type = g.tLib.compile(inst.Type()) + iter := g.getValue(inst.Iter).value + insts = g.module.EmitGenNext_String(iter) + } else { + logger.Fatalf("Todo:%T", inst.Type()) + } + return +} + func (g *functionGenerator) addRegister(typ wir.ValueType) wir.Value { defer func() { g.cur_local_id++ }() name := "$t" + strconv.Itoa(g.cur_local_id) diff --git a/internal/backends/compiler_wat/wir/instruction_emitter.go b/internal/backends/compiler_wat/wir/instruction_emitter.go index 04936d0..1129641 100644 --- a/internal/backends/compiler_wat/wir/instruction_emitter.go +++ b/internal/backends/compiler_wat/wir/instruction_emitter.go @@ -16,8 +16,8 @@ func (m *Module) EmitAssginValue(lh, rh Value) []wat.Inst { insts = append(insts, lh.EmitRelease()...) insts = append(insts, lh.EmitInit()...) } else { - if !lh.Type().Equal(rh.Type()) { - logger.Fatal("x.Type() != y.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:", lh.Type().Name(), ", y.Type():", rh.Type().Name()) } insts = append(insts, rh.EmitPush()...) @@ -893,6 +893,28 @@ 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) { + 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) { iface := i.(*aInterface) insts = append(insts, iface.Extract("d").EmitPush()...) diff --git a/waroot/src/runtime/runtime.wa b/waroot/src/runtime/runtime.wa index d8998bb..a3bbb64 100644 --- a/waroot/src/runtime/runtime.wa +++ b/waroot/src/runtime/runtime.wa @@ -163,3 +163,43 @@ func refToPtr_byteSlice(t: []byte) => i32 { func refToPtr_string(s: string) => i32 { return U8_string_to_ptr(s) } + +type stringIter struct { + ptr: uint + len: int + pos: int +} + +#wa:runtime_getter +func get_u8(p: u32) => u8 + +#wa:runtime_setter +func set_u8(p: u32, v: u8) + +func next_rune(iter: stringIter) => (ok: bool, k: int, v: rune, pos: int) { + if iter.pos >= iter.len { + return false, iter.pos, 0, iter.pos + } + + p0 := i32(get_u8(u32(iter.ptr) + u32(iter.pos))) + if p0 & 0b10000000 == 0 { + return true, iter.pos, rune(p0), iter.pos + 1 + } else if p0 & 0b11100000 == 0b11000000 { + p0 = (p0 & 0b11111) << 6 + p1 := i32(get_u8(u32(iter.ptr) + u32(iter.pos) + 1)) & 0b00111111 + return true, iter.pos, rune(p0 | p1), iter.pos + 2 + } else if p0 & 0b11110000 == 0b11100000 { + p0 = (p0 & 0b1111) << 12 + p1 := (i32(get_u8(u32(iter.ptr) + u32(iter.pos) + 1)) & 0b00111111) << 6 + p2 := (i32(get_u8(u32(iter.ptr) + u32(iter.pos) + 2)) & 0b00111111) + return true, iter.pos, rune(p0 | p1 | p2), iter.pos + 3 + } else if p0 & 0b11111000 == 0b11110000 { + p0 = (p0 & 0b111) << 18 + p1 := (i32(get_u8(u32(iter.ptr) + u32(iter.pos) + 1)) & 0b00111111) << 12 + p2 := (i32(get_u8(u32(iter.ptr) + u32(iter.pos) + 2)) & 0b00111111) << 6 + p3 := (i32(get_u8(u32(iter.ptr) + u32(iter.pos) + 3)) & 0b00111111) + return true, iter.pos, rune(p0 | p1 | p2 | p3), iter.pos + 4 + } + + return +}