Files
wip-reference/draft/wip-idl.md
T

9.4 KiB

WIP IDL

WIP IDLは、Operationのinput / outputを記述するための小さなinterface definition languageである。

WIP IDLのsourceそのものをschemaのcanonicalな交換形式とする。HostとClientの間でJSON SchemaやIDLを変換したJSON ASTを交換することは前提としない。Clientはsourceをparseして内部表現を構築し、必要に応じてAI Tool schemaやGUI formへ投影する。

この文書では、WIP IDLの初期文法と型を定義する。

設計方針

  • Operation境界の型だけを表現する。
  • 文法を小さく保ち、一般的なschema validation languageにはしない。
  • Operationのinputは名前付きfieldを持つrecordとする。
  • Wire上の値表現はTransport Bindingが定める。
  • JSON SchemaはWIPの交換形式にせず、必要なClientが生成する。
  • Worldspaceのエントリは、そのpathを表すentry型として扱う。

Source

WIP IDL sourceはUTF-8 textとする。ASCII space、tab、LFによる空白は、tokenを分離する場合を除いて意味を持たない。

//から行末まではcommentとし、parserは無視する。

IdentifierはASCIIの英字または_で始まり、以降にASCIIの英数字または_を含められる。

identifier = (ALPHA | "_") { ALPHA | DIGIT | "_" };

Keyword、primitive type名、Worldspace固有型名はidentifierとして使用できない。

Named typeにはUpperCamelCase、Operation、field、enum case、union caseにはsnake_caseを使用する。

Grammar

以下のEBNFは空白とcommentを省略して示す。

document = { declaration } ;

declaration = type-declaration | operation-declaration ;

type-declaration = "type", type-name, "=", type-definition, ";" ;

type-definition = type-expression | enum-type | union-type ;

operation-declaration =
  "operation", identifier, "{",
    "input", ":", type-expression, ";",
    "output", ":", type-expression, ";",
  "}" ;

type-expression =
    primitive-type
  | worldspace-type
  | type-name
  | record-type
  | list-type ;

record-type =
  "{", [ record-field, { ",", record-field }, [ "," ] ], "}" ;

record-field = identifier, [ "?" ], ":", type-expression ;

list-type = "[", type-expression, "]" ;

enum-type =
  "enum", "{", identifier, { ",", identifier }, [ "," ], "}" ;

union-type =
  "union", "{", union-case, { ",", union-case }, [ "," ], "}" ;

union-case = identifier, [ "(", type-expression, ")" ] ;

primitive-type =
    "unit"
  | "boolean"
  | "integer"
  | "number"
  | "string"
  | "bytes"
  | "json" ;

worldspace-type = "entry" ;

type-name = identifier ;

同じdocument内でtype名またはOperation名を重複して宣言してはならない。Named typeは同じdocument内で宣言されたtypeを参照する。

Primitive types

Type 意味 WIP over HTTPSでの表現 制約
unit 値を持たない JSON null Optional fieldの省略とは区別する
boolean 真偽値 JSON boolean
integer 符号付き整数 小数部を持たないJSON number -9007199254740991以上、9007199254740991以下
number IEEE 754 binary64値 JSON number NaN、positive infinity、negative infinityは不可
string Unicode string JSON string
bytes 任意のoctet列 RFC 4648 Section 4のbase64を格納したJSON string paddingを含む
json opaqueな任意のJSON value JSON value Clientは内部構造をschemaとして解釈しない

integerの範囲は、異なる言語のClient間で正確に交換できる範囲に制限している。この範囲を超える整数はintegerとしてencodeしない。i64u64bigint等の追加型とlosslessなwire表現は将来の拡張として扱う。

jsonは外部APIの応答など構造を事前に固定できない値のためのescape hatchであり、通常のOperation interfaceではより具体的な型を優先する。

Composite types

Type 構文 意味 WIP over HTTPSでの表現
Record { field: Type } 名前付きfieldの集合 JSON object
List [Type] 同じ型の順序付き値 JSON array
Named type type Name = Type; 型への名前付け 参照先と同じ表現
Enum enum { first, second } payloadを持たないcaseの集合 case名のJSON string
Union union { case(Type), empty } discriminatorを持つcaseの集合 $caseを持つJSON object

Record

Recordは名前付きfieldの集合である。

type Query = {
  text: string,
  limit?: integer,
};

?を持たないfieldはrequired、?を持つfieldはoptionalである。Optionalはrecord fieldにのみ適用し、一般化しない。

WIP over HTTPSではrecordをJSON objectとしてencodeする。Optional fieldに値がない場合はfield自体を省略する。FieldをJSON nullにすることは省略と同じ意味ではなく、そのfieldの型がunitまたはjsonとしてnullを許す場合に限る。

宣言されていないfieldをrecordに含めてはならない。

List

Listは同じ型の0個以上の順序付き値を表す。

[entry]

WIP over HTTPSではJSON arrayとしてencodeする。

Named type

type宣言によって型へ名前を付けられる。

type IssueList = [entry];

Aliasを参照する値のwire表現は、参照先の型と同じである。

Enum

Enumはpayloadを持たないcaseの集合である。

type Relation = enum {
  parent,
  sibling,
  related,
};

WIP over HTTPSではcase名をJSON stringとしてencodeする。

"sibling"

Union

Unionはdiscriminatorを持つcaseの集合である。Caseは0個または1個のpayloadを持つ。

type LookupResult = union {
  found(entry),
  not_found,
  ambiguous([entry]),
};

WIP over HTTPSでは$case discriminatorを持つJSON objectとしてencodeする。Payloadを持つcaseはvalue fieldに値を格納する。

{
  "$case": "found",
  "value": "/items/123"
}

Payloadを持たないcaseにはvalueを含めない。

{
  "$case": "not_found"
}

Worldspace type

Type 意味 WIP over HTTPSでの表現
entry 同じWorldspace内のエントリを指すcanonical absolute path JSON string
"/items/123"

Wire上では通常のstringと同じ表現だが、WIP IDL上でentryと宣言された位置にある値だけをClientがエントリとして認識する。通常のstringやopaqueなjsonに含まれるpathらしい文字列を、Clientがエントリとして推測してはならない。

Operation Resultからentryを発見したClientは、そのpathを一時的に利用し、必要に応じてfetchまたはfetch_treeする。複数のpathを効率的に取得するためのbatchingや、取得結果をinvoke responseへ同梱する最適化は、entry型のwire表現とは分離する。

Operationが返したpathは、Operationの実行対象の子に限定されない。親、兄弟、関連Objectなど、Worldspace内の任意のエントリを指してよい。Operationの実行対象と返されたpathの間に、暗黙のTree edgeや意味的関係を推論してはならない。

fetchが返すエントリ公開情報と、fetch_treeが返すindexableなtreeはCore Protocolのresponseであり、WIP IDLの値型としては定義しない。

Operation declarations

Operationはinputとoutputをそれぞれ一つ宣言する。

type Relation = enum {
  parent,
  sibling,
  related,
};

operation get_related_item {
  input: {
    relation: Relation,
    limit?: integer,
  };

  output: {
    items: [entry],
    next_cursor?: string,
  };
}

Operationのinputは、直接またはNamed typeを介してrecordへ解決されなければならない。位置引数は定義しない。

引数を持たないOperationは空のrecordをinputにする。

operation refresh {
  input: {};
  output: unit;
}

Outputには任意のtype expressionまたはNamed typeを使用できる。ただし、将来fieldを追加する可能性があるOperationではrecord outputを推奨する。

Operationのnameやdescriptionなど、input / output型以外のinterface metadataとの対応付けはOperation schemaで定義する。

Schema exchange

HostはOperation interfaceとともに、次のschema情報をClientへ提供する。

項目 内容
Language identifier 初期versionはwip-idl/1
Source WIP IDL source、またはsourceを取得するための参照
Digest Cacheと同一性確認に利用するdigest

交換されるschemaの正本はWIP IDL sourceである。HostはJSON SchemaやIDL ASTを併記する必要はない。

ClientはIDLを内部ASTへparseし、必要に応じてAI provider用JSON Schema、GUI form、言語固有の型などを生成できる。

Sourceのcanonicalization規則、digest algorithm、参照方法の詳細はTransport Bindingで定義する。

未解決事項

  • Sourceにdescriptionやdocumentation commentを含めるか。
  • String length、numeric range、pattern等のconstraintを導入するか。
  • Recursive named typeを許可するか。
  • i64u64bigintdecimal等を追加するか。
  • Sourceのcanonicalizationとdigestの厳密な計算方法。
  • entryが参照するpathのcanonicalization規則。