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
 | 
			
		||||
| Buffer     | SBA/LBA |  * | Byte array
 | 
			
		||||
| []\<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
 | 
			
		||||
Buffer are simply forced to use their "long" variant.
 | 
			
		||||
@ -37,19 +38,25 @@ Buffer are simply forced to use their "long" variant.
 | 
			
		||||
 | 
			
		||||
## Tokens
 | 
			
		||||
 | 
			
		||||
| Name     | Syntax             |
 | 
			
		||||
| -------- | ------------------ |
 | 
			
		||||
| Method   | `M[0-9A-Fa-f]{4}`  |
 | 
			
		||||
| Key      | `[0-9A-Fa-f]{4}`   |
 | 
			
		||||
| Ident    | `[A-Z][A-Za-z0-9]` |
 | 
			
		||||
| Comma    | `,`                |
 | 
			
		||||
| LBrace   | `{`                |
 | 
			
		||||
| RBrace   | `}`                |
 | 
			
		||||
| LBracket | `[`                |
 | 
			
		||||
| RBracket | `]`                |
 | 
			
		||||
PDL files are divided into tokens, which assemble together into larger language
 | 
			
		||||
structures. They are separated by whitespace.
 | 
			
		||||
 | 
			
		||||
| Name     | Syntax             | Description
 | 
			
		||||
| -------- | ------------------ | -----------
 | 
			
		||||
| Magic    | `PDL/0`            | Must appear at the very start of the file.
 | 
			
		||||
| Method   | `M[0-9A-Fa-f]{4}`  | A 16-bit hexadecimal method code.
 | 
			
		||||
| Key      | `[0-9A-Fa-f]{4}`   | A 16-bit hexadecimal table key.
 | 
			
		||||
| Ident    | `[A-Z][A-Za-z0-9]` | An identifier.
 | 
			
		||||
| 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
 | 
			
		||||
 | 
			
		||||
All files must begin with a Magic token.
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
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:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
PDL/0
 | 
			
		||||
 | 
			
		||||
M0000 Connect {
 | 
			
		||||
	0000 Name String,
 | 
			
		||||
	0001 Password String,
 | 
			
		||||
@ -81,3 +90,98 @@ User {
 | 
			
		||||
	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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user