design: Flesh out PDL document
This commit is contained in:
parent
ec965caa27
commit
44b174c161
126
design/pdl.md
126
design/pdl.md
@ -28,7 +28,8 @@ PDL allows defining a protocol using HOPP and TAPE.
|
|||||||
| String | SBA/LBA | * | UTF-8 string
|
| String | SBA/LBA | * | UTF-8 string
|
||||||
| Buffer | SBA/LBA | * | Byte array
|
| Buffer | SBA/LBA | * | Byte array
|
||||||
| []\<TYPE\> | OTA | * | Array of any type[^1]
|
| []\<TYPE\> | OTA | * | Array of any type[^1]
|
||||||
| Table | KTV | * |
|
| Table | KTV | * | Table with undefined schema
|
||||||
|
| {...} | KTV | * | Table with defined schema
|
||||||
|
|
||||||
[^1]: Excluding SI and SBA. I5 and U5 cannot be used in an array, but String and
|
[^1]: Excluding SI and SBA. I5 and U5 cannot be used in an array, but String and
|
||||||
Buffer are simply forced to use their "long" variant.
|
Buffer are simply forced to use their "long" variant.
|
||||||
@ -37,19 +38,25 @@ Buffer are simply forced to use their "long" variant.
|
|||||||
|
|
||||||
## Tokens
|
## Tokens
|
||||||
|
|
||||||
| Name | Syntax |
|
PDL files are divided into tokens, which assemble together into larger language
|
||||||
| -------- | ------------------ |
|
structures. They are separated by whitespace.
|
||||||
| Method | `M[0-9A-Fa-f]{4}` |
|
|
||||||
| Key | `[0-9A-Fa-f]{4}` |
|
| Name | Syntax | Description
|
||||||
| Ident | `[A-Z][A-Za-z0-9]` |
|
| -------- | ------------------ | -----------
|
||||||
| Comma | `,` |
|
| Magic | `PDL/0` | Must appear at the very start of the file.
|
||||||
| LBrace | `{` |
|
| Method | `M[0-9A-Fa-f]{4}` | A 16-bit hexadecimal method code.
|
||||||
| RBrace | `}` |
|
| Key | `[0-9A-Fa-f]{4}` | A 16-bit hexadecimal table key.
|
||||||
| LBracket | `[` |
|
| Ident | `[A-Z][A-Za-z0-9]` | An identifier.
|
||||||
| RBracket | `]` |
|
| Comma | `,` | A comma separator.
|
||||||
|
| LBrace | `{` | A left curly brace.
|
||||||
|
| RBrace | `}` | A right curly brace.
|
||||||
|
| LBracket | `[` | A left square bracket.
|
||||||
|
| RBracket | `]` | A right square bracket.
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
|
All files must begin with a Magic token.
|
||||||
|
|
||||||
Types are expressed with an Ident. A table can be used by either writing the
|
Types are expressed with an Ident. A table can be used by either writing the
|
||||||
name of the type (Table), or by defining a schema with curly braces. Arrays must
|
name of the type (Table), or by defining a schema with curly braces. Arrays must
|
||||||
be expressed using two matching square brackets before their element type.
|
be expressed using two matching square brackets before their element type.
|
||||||
@ -66,6 +73,8 @@ can be anything.
|
|||||||
Here is an example of all that:
|
Here is an example of all that:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
PDL/0
|
||||||
|
|
||||||
M0000 Connect {
|
M0000 Connect {
|
||||||
0000 Name String,
|
0000 Name String,
|
||||||
0001 Password String,
|
0001 Password String,
|
||||||
@ -81,3 +90,98 @@ User {
|
|||||||
0002 Followers U32,
|
0002 Followers U32,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## EBNF Description
|
||||||
|
|
||||||
|
Below is an EBNF description of the language.
|
||||||
|
|
||||||
|
```
|
||||||
|
<file> -> <magic> (<message> | <typedef)*
|
||||||
|
<magic> -> "PDL/0"
|
||||||
|
<method> -> /M[0-9A-Fa-f]{4}/
|
||||||
|
<key> -> /[0-9A-Fa-f]{4}/
|
||||||
|
<ident> -> /[A-Z][A-Za-z0-9]/
|
||||||
|
<field> -> <key> <ident> <type>
|
||||||
|
<type> -> <ident>
|
||||||
|
| "[" "]" <type>
|
||||||
|
| "{" (<field> ",")* <field>? "}"
|
||||||
|
<message> -> <method> <ident> <type>
|
||||||
|
<typedef> -> <ident> <type>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Go Code Generation
|
||||||
|
|
||||||
|
Given one or more PDL files representing a protocol, the compiler shall generate
|
||||||
|
a Go package named "protocol", which shall contain types for message and type
|
||||||
|
definitions, as well as encoding and decoding methods.
|
||||||
|
|
||||||
|
### Static Section
|
||||||
|
|
||||||
|
The compiler shall write a static section alongside the generated code. It
|
||||||
|
shall contain this text:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Table is a KTV table with an undefined schema.
|
||||||
|
type Table map[uint16] any
|
||||||
|
|
||||||
|
// Message is any message that can be sent along this protocol.
|
||||||
|
type Message interface {
|
||||||
|
codec.Encodable
|
||||||
|
codec.Decodable
|
||||||
|
|
||||||
|
// Method returns the method code of the message.
|
||||||
|
Method() uint16
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Preamble
|
||||||
|
|
||||||
|
At the start of each file but after the package name, the compiler shall emit
|
||||||
|
this text:
|
||||||
|
|
||||||
|
```go
|
||||||
|
/* # Do not edit this package by hand!
|
||||||
|
*
|
||||||
|
* This file was automatically generated by the Holanet PDL compiler. The
|
||||||
|
* source file is located at <path>
|
||||||
|
* Please edit that file instead, and re-compile it to this location.
|
||||||
|
*
|
||||||
|
* HOPP, TAPE, METADAPT, PDL/0 (c) 2025 holanet.xyz
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
Where `<path>` is the path of the protocol definition file relative to the
|
||||||
|
generated file.
|
||||||
|
|
||||||
|
### Message Definitions
|
||||||
|
|
||||||
|
For each defined message, the compiler shall generate a Go type named
|
||||||
|
`MessageName`, where `Name` is the name of the message as written in its
|
||||||
|
definition. The message shall be encodable, and shall have `Encode` and `Decode`
|
||||||
|
methods as described below.
|
||||||
|
|
||||||
|
All messages shall satisfy a `Message` interface, which is defined in the
|
||||||
|
static section.
|
||||||
|
|
||||||
|
### Type Definitions
|
||||||
|
|
||||||
|
For each defined type, the compiler shall generate a Go type with the same name
|
||||||
|
as written in its definition. The Go type shall be encodable, and shall have
|
||||||
|
`Encode` and `Decode` methods as described below.
|
||||||
|
|
||||||
|
### Encoding and Decoding Methods
|
||||||
|
|
||||||
|
Each encodable type shall be given an `Encode` method and a `Decode` method,
|
||||||
|
which will take in a `codec.Encoder` and a `codec.Decoder` respectively. Both
|
||||||
|
return an `(int, error)` pair describing the amount of bytes written and an
|
||||||
|
error if the write stopped early. `Encode` will encode the data within the
|
||||||
|
message to the given encoder, and `Decode` will decode data from the given
|
||||||
|
decoder and place it in the type's value. The methods shall not retain or close
|
||||||
|
any encoders or decoders they are given. Both methods shall have pointer
|
||||||
|
receivers. In effect, these methods will satisfy `codec.Encodable` and
|
||||||
|
`codec.Decodable`.
|
||||||
|
|
||||||
|
### Connection
|
||||||
|
|
||||||
|
The compiler shall generate a `Conn` struct which embeds a `hopp.Conn`, which
|
||||||
|
is the real "porcelain" of the generated code. Any
|
||||||
|
Loading…
Reference in New Issue
Block a user