generate: Implement decoding (untested)

This commit is contained in:
Sasha Koshka 2025-07-16 22:57:12 -04:00
parent d3d7b07a74
commit b73f9fa7ce

View File

@ -190,7 +190,7 @@ func (this *Generator) generateMessage(method uint16, message Message) (n int, e
n += nn; if err != nil { return n, err }
nn, err = this.println()
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("nn, err := encoder.WriteUint8(uint8(tag))\n")
nn, err = this.iprintf("nn, err := encoder.WriteTag(tag)\n")
n += nn; if err != nil { return n, err }
nn, err = this.generateErrorCheck()
n += nn; if err != nil { return n, err }
@ -210,7 +210,12 @@ func (this *Generator) generateMessage(method uint16, message Message) (n int, e
this.resolveMessageName(message.Name))
n += nn; if err != nil { return n, err }
this.push()
// TODO this is a stub
nn, err = this.iprintf("tag, nn, err := decoder.ReadTag()\n")
n += nn; if err != nil { return n, err }
nn, err = this.generateErrorCheck()
n += nn; if err != nil { return n, err }
nn, err = this.generateDecodeValue(message.Type, "this", "tag")
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("return n, nil\n")
n += nn; if err != nil { return n, err }
this.pop()
@ -377,8 +382,10 @@ func (this *Generator) generateEncodeValue(typ Type, valueSource, tagSource stri
n += nn; if err != nil { return n, err }
nn, err = this.generateErrorCheck()
n += nn; if err != nil { return n, err }
default:
panic(fmt.Errorf("unknown type: %T", typ))
}
return n, nil
}
@ -393,10 +400,180 @@ func (this *Generator) generateEncodeValue(typ Type, valueSource, tagSource stri
// - err error
// - nn int
func (this *Generator) generateDecodeValue(typ Type, valueSource, tagSource string) (n int, err error) {
// TODO generate stub so the code runs and we can test encoding at least+
switch typ := typ.(type) {
case TypeInt:
// SI: (none)
// LI: <value: IntN>
if typ.Bits <= 5 {
// SI stores the value in the tag, so we write nothing here
break
}
prefix := "ReadUint"
if typ.Signed {
prefix = "ReadInt"
}
nn, err := this.iprintf("*%s, nn, err = encoder.%s%d()\n", valueSource, prefix, typ.Bits)
n += nn; if err != nil { return n, err }
nn, err = this.generateErrorCheck()
n += nn; if err != nil { return n, err }
case TypeFloat:
// FP: <value: FloatN>
nn, err := this.iprintf("%s, nn, err = encoder.ReadFloat%d(%s)\n", valueSource, typ.Bits)
n += nn; if err != nil { return n, err }
nn, err = this.generateErrorCheck()
n += nn; if err != nil { return n, err }
case TypeString, TypeBuffer:
// SBA: <data: U8>*
// LBA: <length: UN> <data: U8>*
nn, err := this.iprintf("{\n")
this.push()
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("var length uint64\n")
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("if %s.Is(tape.LBA) {\n", tagSource)
n += nn; if err != nil { return n, err }
this.push()
nn, err = this.iprintf(
"length, nn, err = encoder.ReadUintN(uint64(%s.CN()))\n",
tagSource)
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("} else {\n")
n += nn; if err != nil { return n, err }
this.push()
nn, err = this.iprintf("length = uint64(%s.CN())\n", tagSource)
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("buffer := make([]byte, int(length))\n")
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("nn, err = encoder.Read(buffer)\n")
n += nn; if err != nil { return n, err }
nn, err = this.generateErrorCheck()
n += nn; if err != nil { return n, err }
if _, ok := typ.(TypeString); ok {
nn, err = this.iprintf("*%s = string(buffer)\n", valueSource)
n += nn; if err != nil { return n, err }
} else {
nn, err = this.iprintf("*%s = buffer\n", valueSource)
n += nn; if err != nil { return n, err }
}
this.pop()
nn, err = this.iprintf("}\n")
n += nn; if err != nil { return n, err }
case TypeArray:
// OTA: <length: UN> <elementTag: tape.Tag> <values>*
nn, err := this.iprintf("{\n")
this.push()
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("var length uint64\n")
n += nn; if err != nil { return n, err }
nn, err = this.iprintf(
"length, nn, err = encoder.ReadUintN(uint64(%s.CN()))\n",
tagSource)
n += nn; if err != nil { return n, err }
nn, err = this.generateErrorCheck()
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("*%s = make(", valueSource)
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(", int(length))\n")
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("var itemTag tape.Tag\n")
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("itemTag, nn, err = encoder.ReadTag()\n")
n += nn; if err != nil { return n, err }
nn, err = this.generateErrorCheck()
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("for index := range length {\n")
n += nn; if err != nil { return n, err }
this.push()
nn, err = this.generateDecodeValue(
typ.Element,
fmt.Sprintf("(&(*%s)[index])", valueSource),
"itemTag")
n += nn; if err != nil { return n, err }
this.pop()
nn, err = this.iprintf("}\n")
n += nn; if err != nil { return n, err }
this.pop()
nn, err = this.iprintf("}\n")
n += nn; if err != nil { return n, err }
case TypeTable:
// KTV: <length: UN> (<key: U16> <tag: Tag> <value>)*
nn, err := this.iprintf(
"nn, err = tape.DecodeAny(decoder, %s, %s)\n",
valueSource, tagSource)
n += nn; if err != nil { return n, err }
nn, err = this.generateErrorCheck()
n += nn; if err != nil { return n, err }
case TypeTableDefined:
// KTV: <length: UN> (<key: U16> <tag: Tag> <value>)*
nn, err := this.iprintf("{\n")
n += nn; if err != nil { return n, err }
this.push()
nn, err = this.iprintf("var length uint64\n")
n += nn; if err != nil { return n, err }
nn, err = this.iprintf(
"length, nn, err = encoder.ReadUintN(uint64(%s.CN()))\n",
tagSource)
n += nn; if err != nil { return n, err }
nn, err = this.generateErrorCheck()
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("for _ = range length {\n")
n += nn; if err != nil { return n, err }
this.push()
nn, err = this.iprintf("var key uint16\n")
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("key, nn, err = decoder.ReadUint16()\n")
n += nn; if err != nil { return n, err }
nn, err = this.generateErrorCheck()
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("var itemTag tape.Tag\n")
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("itemTag, nn, err = decoder.ReadTag()\n")
n += nn; if err != nil { return n, err }
nn, err = this.generateErrorCheck()
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("switch key {\n")
n += nn; if err != nil { return n, err }
keys := slices.Collect(maps.Keys(typ.Fields))
slices.Sort(keys)
for _, key := range keys {
field := typ.Fields[key]
nn, err = this.iprintf("case 0x%04X:\n", key)
n += nn; if err != nil { return n, err }
this.push()
nn, err = this.generateDecodeValue(
field.Type,
fmt.Sprintf("(&%s.%s)", valueSource, field.Name),
"itemTag")
n += nn; if err != nil { return n, err }
this.pop()
}
nn, err = this.iprintf("}\n")
n += nn; if err != nil { return n, err }
this.pop()
nn, err = this.iprintf("}\n")
n += nn; if err != nil { return n, err }
this.pop()
nn, err = this.iprintf("}\n")
n += nn; if err != nil { return n, err }
case TypeNamed:
// WHATEVER: [WHATEVER]
nn, err := this.iprintf("nn, err = %s.DecodeValue(encoder, %s)\n", valueSource, tagSource)
n += nn; if err != nil { return n, err }
nn, err = this.generateErrorCheck()
n += nn; if err != nil { return n, err }
default:
panic(fmt.Errorf("unknown type: %T", typ))
}
return 0, nil
return n, nil
}
func (this *Generator) generateErrorCheck() (n int, err error) {
@ -438,6 +615,8 @@ func (this *Generator) generateTag(typ Type, source string) (n int, err error) {
if err != nil { return n, err }
nn, err := this.generateTag(resolved, source)
n += nn; if err != nil { return n, err }
default:
panic(fmt.Errorf("unknown type: %T", typ))
}
return n, nil