Compare commits
11 Commits
2cbf58d558
...
c18e251b4a
| Author | SHA1 | Date | |
|---|---|---|---|
| c18e251b4a | |||
| 170f79c914 | |||
| 77c6b67d65 | |||
| 195d0f9725 | |||
| fa4f591126 | |||
| 12142706e1 | |||
| 30e9ead1ab | |||
| 1118b11bcd | |||
| 7343cf5853 | |||
| a9f583d2e7 | |||
| c4dd129fc5 |
@ -34,6 +34,19 @@ type Message interface {
|
|||||||
// Method returns the method code of the message.
|
// Method returns the method code of the message.
|
||||||
Method() uint16
|
Method() uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// canAssign determines if data from the given source tag can be assigned to
|
||||||
|
// a Go type represented by destination. It is designed to receive destination
|
||||||
|
// values from [generate.Generator.generateCanAssign]. The eventual Go type and
|
||||||
|
// the destination tag must come from the same (or hash-equivalent) PDL type.
|
||||||
|
func canAssign(destination, source tape.Tag) bool {
|
||||||
|
if destination.Is(source) { return true }
|
||||||
|
if (destination == tape.SBA || destination == tape.LBA) &&
|
||||||
|
(source == tape.SBA || source == tape.LBA) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
// Generator converts protocols into Go code.
|
// Generator converts protocols into Go code.
|
||||||
@ -162,6 +175,24 @@ func (this *Generator) generateTypedef(name string, typ Type) (n int, err error)
|
|||||||
this.push()
|
this.push()
|
||||||
nn, err = this.iprintf("var nn int\n")
|
nn, err = this.iprintf("var nn int\n")
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
|
|
||||||
|
nn, err = this.iprintf("if !(")
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
nn, err = this.generateCanAssign(typ, "tag")
|
||||||
|
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 = this.iprintf("nn, err = tape.Skim(decoder, tag)\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("return n, nil\n")
|
||||||
|
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.generateDecodeValue(typ, "this", "tag")
|
nn, err = this.generateDecodeValue(typ, "this", "tag")
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.iprintf("return n, nil\n")
|
nn, err = this.iprintf("return n, nil\n")
|
||||||
@ -233,15 +264,24 @@ func (this *Generator) generateMessage(method uint16, message Message) (n int, e
|
|||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.generateErrorCheck()
|
nn, err = this.generateErrorCheck()
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.iprintf("if !tag.Is(")
|
|
||||||
|
nn, err = this.iprintf("if !(")
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.generateTN(message.Type)
|
nn, err = this.generateCanAssign(message.Type, "tag")
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.printf(") {\n")
|
nn, err = this.printf(") {\n")
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
// TODO skip value using the correct TAPE function and return
|
this.push()
|
||||||
|
nn, err = this.iprintf("nn, err = tape.Skim(decoder, tag)\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("return n, nil\n")
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
this.pop()
|
||||||
nn, err = this.iprintf("}\n")
|
nn, err = this.iprintf("}\n")
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
|
|
||||||
nn, err = this.generateDecodeValue(message.Type, "this", "tag")
|
nn, err = this.generateDecodeValue(message.Type, "this", "tag")
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.iprintf("return n, nil\n")
|
nn, err = this.iprintf("return n, nil\n")
|
||||||
@ -538,7 +578,7 @@ func (this *Generator) generateDecodeValue(typ Type, valueSource, tagSource stri
|
|||||||
// - nn int
|
// - nn int
|
||||||
func (this *Generator) generateDecodeBranchCall(typ Type, valueSource, tagSource string) (n int, err error) {
|
func (this *Generator) generateDecodeBranchCall(typ Type, valueSource, tagSource string) (n int, err error) {
|
||||||
hash := HashType(typ)
|
hash := HashType(typ)
|
||||||
nn, err := this.iprintf("nn, err = %s(%s, %s)\n", this.decodeBranchName(hash), valueSource, tagSource)
|
nn, err := this.iprintf("nn, err = %s(%s, decoder, %s)\n", this.decodeBranchName(hash), valueSource, tagSource)
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.generateErrorCheck()
|
nn, err = this.generateErrorCheck()
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
@ -549,11 +589,11 @@ func (this *Generator) generateDecodeBranchCall(typ Type, valueSource, tagSource
|
|||||||
// generateDecodeBranch generates an aggregate decoder function definition for a
|
// generateDecodeBranch generates an aggregate decoder function definition for a
|
||||||
// specified type. It assumes that hash == HashType(typ).
|
// specified type. It assumes that hash == HashType(typ).
|
||||||
func (this *Generator) generateDecodeBranch(hash [16]byte, typ Type) (n int, err error) {
|
func (this *Generator) generateDecodeBranch(hash [16]byte, typ Type) (n int, err error) {
|
||||||
nn, err := this.iprintf("func %s(this *", this.decodeBranchName(hash))
|
nn, err := this.iprintf("\nfunc %s[T ~", this.decodeBranchName(hash))
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.generateType(typ)
|
nn, err = this.generateType(typ)
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.printf(" decoder *tape.Decoder, tag tape.Tag) (nn int, err error) \n{")
|
nn, err = this.printf("](this *T, decoder *tape.Decoder, tag tape.Tag) (n int, err error) {\n")
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
this.push()
|
this.push()
|
||||||
|
|
||||||
@ -585,14 +625,14 @@ func (this *Generator) generateDecodeBranch(hash [16]byte, typ Type) (n int, err
|
|||||||
nn, err = this.iprintf("for _ = range %s {\n", lengthVar)
|
nn, err = this.iprintf("for _ = range %s {\n", lengthVar)
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
this.push()
|
this.push()
|
||||||
nn, err = this.iprintf("nn, err = tape.Skim(decoder, tag)")
|
nn, err = this.iprintf("nn, err = tape.Skim(decoder, %s)\n", elementTagVar)
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.generateErrorCheck()
|
nn, err = this.generateErrorCheck()
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
this.pop()
|
this.pop()
|
||||||
nn, err = this.iprintf("}\n")
|
nn, err = this.iprintf("}\n")
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.iprintf("return n, nil")
|
nn, err = this.iprintf("return n, nil\n")
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
@ -602,11 +642,11 @@ func (this *Generator) generateDecodeBranch(hash [16]byte, typ Type) (n int, err
|
|||||||
// max, whatever that is configured to be. the reason we
|
// max, whatever that is configured to be. the reason we
|
||||||
// want to read it here is that we would have to skip
|
// want to read it here is that we would have to skip
|
||||||
// the tag anyway so why not.
|
// the tag anyway so why not.
|
||||||
nn, err = this.iprintf("if %s != ", elementTagVar)
|
nn, err = this.iprintf("if !(")
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.generateTag(typ.Element, "(*this)")
|
nn, err = this.generateCanAssign(typ.Element, elementTagVar)
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.printf(" {\n")
|
nn, err = this.printf(") {\n")
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
this.push()
|
this.push()
|
||||||
nn, err = abort()
|
nn, err = abort()
|
||||||
@ -622,7 +662,7 @@ func (this *Generator) generateDecodeBranch(hash [16]byte, typ Type) (n int, err
|
|||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.printf(", %s)\n", lengthVar)
|
nn, err = this.printf(", %s)\n", lengthVar)
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
nn, err = this.iprintf("for index := range %s {\n", lengthVar)
|
nn, err = this.iprintf("for index := range int(%s) {\n", lengthVar)
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
this.push()
|
this.push()
|
||||||
nn, err = this.generateDecodeValue(typ.Element, "(*this)[index]", elementTagVar)
|
nn, err = this.generateDecodeValue(typ.Element, "(*this)[index]", elementTagVar)
|
||||||
@ -632,12 +672,106 @@ func (this *Generator) generateDecodeBranch(hash [16]byte, typ Type) (n int, err
|
|||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
case TypeTableDefined:
|
case TypeTableDefined:
|
||||||
// KTV: <length: UN> (<key: U16> <tag: Tag> <value>)*
|
// KTV: <length: UN> (<key: U16> <tag: Tag> <value>)*
|
||||||
// TODO
|
// 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 }
|
||||||
|
indexVar := this.newTemporaryVar("index")
|
||||||
|
nn, err = this.iprintf("%s := 0\n", indexVar)
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
|
||||||
|
// validate header
|
||||||
|
// TODO: here, validate that length is less than the
|
||||||
|
// max, whatever that is configured to be. if not, stop
|
||||||
|
// ALL decoding. skimming huge big ass data could cause
|
||||||
|
// problems
|
||||||
|
|
||||||
|
// read fields
|
||||||
|
nn, err = this.iprintf("for %s = range int(%s) {\n", indexVar, lengthVar)
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
this.push()
|
||||||
|
// read field header
|
||||||
|
fieldKeyVar := this.newTemporaryVar("fieldKey")
|
||||||
|
nn, err = this.iprintf("var %s uint16\n", fieldKeyVar)
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
nn, err = this.iprintf("%s, nn, err = decoder.ReadUint16()\n", fieldKeyVar)
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
nn, err = this.generateErrorCheck()
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
fieldTagVar := this.newTemporaryVar("fieldTag")
|
||||||
|
nn, err = this.iprintf("var %s tape.Tag\n", fieldTagVar)
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
nn, err = this.iprintf("%s, nn, err = decoder.ReadTag()\n", fieldTagVar)
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
nn, err = this.generateErrorCheck()
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
|
||||||
|
// abort field macro
|
||||||
|
abortField := func() (n int, err error) {
|
||||||
|
nn, err = this.iprintf("tape.Skim(decoder, %s)\n", fieldTagVar)
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
nn, err = this.iprintf("continue\n")
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch on tag
|
||||||
|
nn, err = this.iprintf("switch %s {\n", fieldKeyVar)
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
for _, key := range slices.Sorted(maps.Keys(typ.Fields)) {
|
||||||
|
field := typ.Fields[key]
|
||||||
|
nn, err = this.iprintf("case 0x%04X:\n", key)
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
this.push()
|
||||||
|
|
||||||
|
// validate field header
|
||||||
|
nn, err = this.iprintf("if !(")
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
nn, err = this.generateCanAssign(field.Type, fieldTagVar)
|
||||||
|
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 = abortField()
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
this.pop()
|
||||||
|
nn, err = this.iprintf("}\n")
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
|
||||||
|
// decode payload
|
||||||
|
nn, err = this.generateDecodeValue(field.Type, fmt.Sprintf("&(this.%s)", field.Name), fieldTagVar)
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
this.pop()
|
||||||
|
}
|
||||||
|
nn, err = this.iprintf("default:\n")
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
this.push()
|
||||||
|
abortField()
|
||||||
|
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 }
|
||||||
|
|
||||||
|
// TODO once options are implemented, have a set of
|
||||||
|
// bools for each non-optional field, and check here
|
||||||
|
// that they are all true. a counter will not work
|
||||||
|
// because if someone specifies a non-optional field
|
||||||
|
// twice, they can neglect to specify another
|
||||||
|
// non-optional field and we won't even know because the
|
||||||
|
// count will still be even. we shouldn't use a map
|
||||||
|
// either because its an allocation and its way more
|
||||||
|
// memory than just, like 5 bools (on the stack no less)
|
||||||
default: return n, fmt.Errorf("unexpected type: %T", typ)
|
default: return n, fmt.Errorf("unexpected type: %T", typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.pop()
|
this.pop()
|
||||||
nn, err = this.iprintf("}")
|
nn, err = this.iprintf("}\n")
|
||||||
n += nn; if err != nil { return n, err }
|
n += nn; if err != nil { return n, err }
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
@ -831,6 +965,19 @@ func (this *Generator) generateTypeTableDefined(typ TypeTableDefined) (n int, er
|
|||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generateCanAssign generates an expression which checks if the tag specified
|
||||||
|
// by tagSource can be assigned to a Go destination generated from typ. The
|
||||||
|
// generated code is INLINE.
|
||||||
|
func (this *Generator) generateCanAssign(typ Type, tagSource string) (n int, err error) {
|
||||||
|
nn, err := this.printf("canAssign(")
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
nn, err = this.generateTN(typ)
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
nn, err = this.printf(", %s)", tagSource)
|
||||||
|
n += nn; if err != nil { return n, err }
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (this *Generator) validateIntBitSize(size int) error {
|
func (this *Generator) validateIntBitSize(size int) error {
|
||||||
switch size {
|
switch size {
|
||||||
case 5, 8, 16, 32, 64: return nil
|
case 5, 8, 16, 32, 64: return nil
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user