diff --git a/generate/generate.go b/generate/generate.go index 427f638..7919219 100644 --- a/generate/generate.go +++ b/generate/generate.go @@ -555,17 +555,88 @@ func (this *Generator) generateDecodeBranch(hash [16]byte, typ Type) (n int, err n += nn; if err != nil { return n, err } nn, err = this.printf(" decoder *tape.Decoder, tag tape.Tag) (nn int, err error) \n{") n += nn; if err != nil { return n, err } + this.push() - switch typ := typ.(type) { - case TypeArray: - // OTA: * + nn, err = this.iprintf("var nn int\n") + n += nn; if err != nil { return n, err } - case TypeTableDefined: - // KTV: ( )* - // TODO - default: return n, fmt.Errorf("unexpected type: %T", typ) - } - + switch typ := typ.(type) { + case TypeArray: + // OTA: * + // read header + lengthVar := this.newTemporaryVar("length") + nn, err := this.iprintf("var %s uint64\n", lengthVar) + n += nn; if err != nil { return n, err } + nn, err = this.iprintf("%s, nn, err = decoder.ReadUintN(int(tag.CN()))\n", lengthVar) + n += nn; if err != nil { return n, err } + nn, err = this.generateErrorCheck() + n += nn; if err != nil { return n, err } + elementTagVar := this.newTemporaryVar("elementTag") + nn, err = this.iprintf("var %s uint64\n", lengthVar) + n += nn; if err != nil { return n, err } + nn, err = this.iprintf("%s, nn, err = decoder.ReadTag()\n", elementTagVar) + n += nn; if err != nil { return n, err } + nn, err = this.generateErrorCheck() + n += nn; if err != nil { return n, err } + + // abort macro + abort := func() (n int, err error) { + // skim entire array + nn, err = this.iprintf("for _ = range %s {\n", lengthVar) + n += nn; if err != nil { return n, err } + this.push() + nn, err = this.iprintf("nn, err = tape.Skim(decoder, tag)") + n += nn; if err != nil { return n, err } + nn, err = this.generateErrorCheck() + n += nn; if err != nil { return n, err } + this.pop() + nn, err = this.iprintf("}\n") + n += nn; if err != nil { return n, err } + nn, err = this.iprintf("return n, nil") + n += nn; if err != nil { return n, err } + return n, nil + } + + // validate header + // TODO: here, validate that length is less than the + // max, whatever that is configured to be. the reason we + // want to read it here is that we would have to skip + // the tag anyway so why not. + nn, err = this.iprintf("if %s != ", elementTagVar) + n += nn; if err != nil { return n, err } + nn, err = this.generateTag(typ.Element, "(*this)") + n += nn; if err != nil { return n, err } + nn, err = this.printf(" {\n") + n += nn; if err != nil { return n, err } + this.push() + nn, err = abort() + n += nn; if err != nil { return n, err } + this.pop() + nn, err = this.iprintf("}\n") + n += nn; if err != nil { return n, err } + + // decode payloads + nn, err = this.iprintf("*this = make(") + n += nn; if err != nil { return n, err } + nn, err = this.generateType(typ) + n += nn; if err != nil { return n, err } + nn, err = this.printf(", %s)\n", lengthVar) + n += nn; if err != nil { return n, err } + nn, err = this.iprintf("for index := range %s {\n", lengthVar) + n += nn; if err != nil { return n, err } + this.push() + nn, err = this.generateDecodeValue(typ.Element, "(*this)[index]", elementTagVar) + n += nn; if err != nil { return n, err } + this.pop() + nn, err = this.iprintf("}\n") + n += nn; if err != nil { return n, err } + case TypeTableDefined: + // KTV: ( )* + // TODO + default: return n, fmt.Errorf("unexpected type: %T", typ) + } + + this.pop() nn, err = this.iprintf("}") n += nn; if err != nil { return n, err } return n, nil