Compare commits

...

5 Commits

5 changed files with 78 additions and 29 deletions

View File

@ -6,7 +6,7 @@ PDL allows defining a protocol using HOPP and TAPE.
| Syntax | TN | CN | Description
| ---------- | ------- | -: | -----------
| I5 | SI | |
| I5 | SI | |
| I8 | LSI | 0 |
| I16 | LSI | 1 |
| I32 | LSI | 3 |
@ -25,6 +25,7 @@ PDL allows defining a protocol using HOPP and TAPE.
| F64 | FP | 7 |
| F128[^2] | FP | 15 |
| F256[^2] | FP | 31 |
| Bool | SI | |
| String | SBA/LBA | * | UTF-8 string
| Buffer | SBA/LBA | * | Byte array
| []\<TYPE\> | OTA | * | Array of any type[^1]

View File

@ -116,12 +116,16 @@ func (this *Generator) generateTypedef(name string, typedef Typedef) (n int, err
typ := typedef.Type
// type definition
// TODO doc
nn, err := this.iprintf(
"\n// %s represents the protocol data type %s.\n",
name, name)
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("type %s ", name)
if typedef.Doc == "" {
nn, err := this.iprintf(
"\n// %s represents the protocol data type %s.\n",
name, name)
n += nn; if err != nil { return n, err }
} else {
nn, err := this.iprintf("\n%s\n", this.formatComment(typedef.Doc))
n += nn; if err != nil { return n, err }
}
nn, err := this.iprintf("type %s ", name)
n += nn; if err != nil { return n, err }
nn, err = this.generateType(typ)
n += nn; if err != nil { return n, err }
@ -211,11 +215,16 @@ func (this *Generator) generateTypedef(name string, typedef Typedef) (n int, err
// generateMessage generates the structure, as well as encoding decoding
// functions for the given message.
func (this *Generator) generateMessage(method uint16, message Message) (n int, err error) {
// TODO doc
nn, err := this.iprintf(
"\n// %s represents the protocol message M%04X %s.\n",
message.Name, method, message.Name)
nn, err = this.iprintf("type %s ", this.resolveMessageName(message.Name))
if message.Doc == "" {
nn, err := this.iprintf(
"\n// %s represents the protocol message M%04X %s.\n",
message.Name, method, message.Name)
n += nn; if err != nil { return n, err }
} else {
nn, err := this.iprintf("\n%s\n", this.formatComment(message.Doc))
n += nn; if err != nil { return n, err }
}
nn, err := this.iprintf("type %s ", this.resolveMessageName(message.Name))
n += nn; if err != nil { return n, err }
nn, err = this.generateType(message.Type)
n += nn; if err != nil { return n, err }
@ -1094,8 +1103,9 @@ func (this *Generator) generateTypeTableDefined(typ TypeTableDefined) (n int, er
for _, key := range slices.Sorted(maps.Keys(typ.Fields)) {
field := typ.Fields[key]
// TODO doc
nn, err := this.iprintf("%s ", field.Name)
nn, err := this.iprintf("%s\n", this.formatComment(field.Doc))
n += nn; if err != nil { return n, err }
nn, err = this.iprintf("%s ", field.Name)
n += nn; if err != nil { return n, err }
nn, err = this.generateType(field.Type)
n += nn; if err != nil { return n, err }
@ -1180,6 +1190,10 @@ func (this *Generator) iprintf(format string, args ...any) (n int, err error) {
return fmt.Fprintf(this.Output, this.indent() + format, args...)
}
func (this *Generator) formatComment(comment string) string {
return "// " + strings.ReplaceAll(comment, "\n", "\n" + this.indent() + "// ")
}
func (this *Generator) resolveMessageName(message string) string {
return "Message" + message
}

View File

@ -1,6 +1,7 @@
package generate
import "io"
import "strings"
import "strconv"
import "git.tebibyte.media/sashakoshka/goparse"
@ -47,18 +48,28 @@ func (this *parser) parse() error {
}
func (this *parser) parseTopLevel() error {
err := this.ExpectDesc("message or typedef", TokenMethod, TokenIdent)
if err != nil { return err }
if this.EOF() { return nil }
doc := ""
for {
err := this.ExpectDesc("message or typedef", TokenMethod, TokenIdent, TokenComment)
if err != nil { return err }
if this.EOF() { return nil }
if this.Kind() == TokenComment {
if doc != "" { doc += "\n" }
doc += this.parseComment(this.Value())
this.Next()
} else {
break
}
}
switch this.Kind() {
case TokenMethod: return this.parseMessage()
case TokenIdent: return this.parseTypedef()
case TokenMethod: return this.parseMessage(doc)
case TokenIdent: return this.parseTypedef(doc)
}
panic("bug")
}
func (this *parser) parseMessage() error {
func (this *parser) parseMessage(doc string) error {
err := this.Expect(TokenMethod)
if err != nil { return err }
method, err := this.parseHexNumber(this.Value(), 0xFFFF)
@ -72,13 +83,13 @@ func (this *parser) parseMessage() error {
if err != nil { return err }
this.protocol.Messages[uint16(method)] = Message {
Name: name,
// TODO: doc
Doc: doc,
Type: typ,
}
return nil
}
func (this *parser) parseTypedef() error {
func (this *parser) parseTypedef(doc string) error {
err := this.Expect(TokenIdent)
if err != nil { return err }
name := this.Value()
@ -87,7 +98,7 @@ func (this *parser) parseTypedef() error {
typ, err := this.parseType()
if err != nil { return err }
this.protocol.Types[name] = Typedef {
// TODO: doc
Doc: doc,
Type: typ,
}
return nil
@ -121,6 +132,7 @@ func (this *parser) parseType() (Type, error) {
case "Buffer": return TypeBuffer { }, this.Next()
case "Table": return TypeTable { }, this.Next()
case "Any": return TypeAny { }, this.Next()
case "Bool": return TypeBool { }, this.Next()
}
return this.parseTypeNamed()
case TokenLBracket:
@ -161,12 +173,22 @@ func (this *parser) parseTypeTable() (TypeTableDefined, error) {
Fields: make(map[uint16] Field),
}
for {
err := this.ExpectDesc("table field", TokenKey, TokenRBrace)
if err != nil { return TypeTableDefined { }, err }
doc := ""
for {
err := this.ExpectDesc("table field", TokenKey, TokenRBrace, TokenComment)
if err != nil { return TypeTableDefined { }, err }
if this.Kind() == TokenComment {
if doc != "" { doc += "\n" }
doc += this.parseComment(this.Value())
this.Next()
} else {
break
}
}
if this.Is(TokenRBrace) {
break
}
key, field, err := this.parseField()
key, field, err := this.parseField(doc)
if err != nil { return TypeTableDefined { }, err }
typ.Fields[key] = field
err = this.Expect(TokenComma, TokenRBrace)
@ -182,7 +204,7 @@ func (this *parser) parseTypeTable() (TypeTableDefined, error) {
return typ, nil
}
func (this *parser) parseField() (uint16, Field, error) {
func (this *parser) parseField(doc string) (uint16, Field, error) {
err := this.Expect(TokenKey)
if err != nil { return 0, Field { }, err }
key, err := this.parseHexNumber(this.Value(), 0xFFFF)
@ -196,7 +218,7 @@ func (this *parser) parseField() (uint16, Field, error) {
if err != nil { return 0, Field { }, err }
return uint16(key), Field {
Name: name,
// TODO: doc
Doc: doc,
Type: typ,
}, nil
}
@ -211,3 +233,7 @@ func (this *parser) parseHexNumber(input string, maxValue int64) (int64, error)
}
return number, nil
}
func (this *parser) parseComment(input string) string {
return strings.TrimPrefix(strings.TrimPrefix(input, "//"), " ")
}

View File

@ -9,7 +9,7 @@ func TestParse(test *testing.T) {
correct := defaultProtocol()
correct.Messages[0x0000] = Message {
Name: "Connect",
Doc: "Connect is sent from the client to the server as the first message of an\n authenticated transaction.",
Doc: "Connect is sent from the client to the server as the first message of an\nauthenticated transaction.",
Type: TypeTableDefined {
Fields: map[uint16] Field {
0x0000: Field { Name: "Name", Type: TypeString { } },
@ -33,6 +33,7 @@ func TestParse(test *testing.T) {
0x0000: Field { Name: "Name", Type: TypeString { } },
0x0001: Field { Name: "Bio", Type: TypeString { } },
0x0002: Field { Name: "Followers", Type: TypeInt { Bits: 32 } },
0x0003: Field { Name: "Bouncy", Type: TypeBool { } },
},
},
}
@ -61,6 +62,7 @@ func TestParse(test *testing.T) {
0000 Name String,
0001 Bio String,
0002 Followers U32,
0003 Bouncy Bool,
}
Anything Any

View File

@ -49,6 +49,12 @@ func (typ TypeFloat) String() string {
return fmt.Sprintf("F%d", typ.Bits)
}
type TypeBool struct { }
func (TypeBool) String() string {
return "Bool"
}
type TypeString struct { }
func (TypeString) String() string {