From 44b174c161adc94c24eb4046a3f0a188db768541 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Wed, 4 Jun 2025 12:46:20 -0400 Subject: [PATCH] design: Flesh out PDL document --- design/pdl.md | 126 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 115 insertions(+), 11 deletions(-) diff --git a/design/pdl.md b/design/pdl.md index 6c5d625..b39da72 100644 --- a/design/pdl.md +++ b/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 | []\ | 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. + +``` + -> ( | -> "PDL/0" + -> /M[0-9A-Fa-f]{4}/ + -> /[0-9A-Fa-f]{4}/ + -> /[A-Z][A-Za-z0-9]/ + -> + -> + | "[" "]" + | "{" ( ",")* ? "}" + -> + -> +``` + +## 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 + * Please edit that file instead, and re-compile it to this location. + * + * HOPP, TAPE, METADAPT, PDL/0 (c) 2025 holanet.xyz + */ +``` + +Where `` 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