RFC-0086:RFC-0050 更新:FIDL 屬性語法

RFC-0086:RFC-0050 更新:FIDL 屬性語法
狀態已接受
領域
  • FIDL
說明

以 FIDL 語言指定新的屬性語法。

問題
毛皮變化
作者
審查人員
提交日期 (年-月-日)2021-03-09
審查日期 (年-月-日)2021-04-07

摘要

本文件會說明新的 attributes 語法, FIDL 語言。

另請參閱:

提振精神

FIDL 屬性提供將編譯時間中繼資料附加至 FIDL 的明確方法 宣告,讓作者能夠將額外資訊傳遞至 FIDL 編譯器 相關文件 (文件NoDoc) 編譯時間驗證 (ForDeprecatedCBindings)、 程式碼生成 (轉換傳輸),所需的 API 可用性 (可供探索),以此類推。 「官方」屬性,FIDL 作者就可以定義自己的「自訂」 這類屬性不會影響編譯,但仍會附加至 產生 FIDL JSON Intermediate Representation, 使用。

現有屬性語法缺少三個屬性:

  • 多個屬性是以逗號分隔的宣告 如下所示:[Discoverable, NoDoc, Transport = "Channel"]。這項做法缺乏彈性 因為屬性是彼此獨立的。
  • 屬性目前只能接受 0 或一個引數,但
  • 當屬性接受引數時,值一律為字串。例如: MaxBytes 屬性採用字串化數字做為引數,如下所示: [MaxBytes="128"]。這會造成混淆,尤其是在 FIDL 的其他部分 都是可預測的字詞

系統目前將 FIDL 語法進行重大遷移, RFC-0050:語法更新工作。對他們來說 也可以變更屬性的語法

設計

語法

每個屬性都屬於單一宣告,其中包含屬性名稱 前方加上 @ 符號 (以慣例為 lower_snake_cased)。適用對象 宣告包含多個屬性的宣告時,沒有偏好的排序方式 屬性。舉例來說,屬性宣告 [Discoverable, NoDoc, Transport = "Channel"] 現在可以寫成:

@discoverable
@no_doc
@transport("Channel")
protocol P {};

如有必要,屬性名稱可視需要加上一組括號。 ,且包含一或多個引數的逗號分隔清單。引數可以是 任何有效的 FIDL 常數。例如:

const DEFAULT_TRANSPORT string = "Channel";

@transport(DEFAULT_TRANSPORT)
protocol P {};

引數必須以小寫的「關鍵字」表示與類似語法 在 Python 中找到的屬性,但針對 只需要加入一個引數,即可省略關鍵字。引數輸入和存在 只會驗證 fidlc 原生的屬性。適用對象 這類屬性,編譯器可能會預設省略對 預先定義的值請參考下列模擬 @native 的使用範例 屬性,該屬性需要兩個必要引數 (req_areq_b),以及兩個 選擇性參數(opt_aopt_b):

const C bool = true;
@native(req_a="Foo",req_b=3)                  // OK: neither opt arg is set
@native(req_a="Foo",req_b=3,opt_c=C)          // OK: only opt_a is set
@native(req_a="Foo",req_b=3,opt_d=-4)         // OK: only opt_b is set
@native(req_a="Foo",req_b=3,opt_c=C,opt_d=-4) // OK: both opt args are set
@native(req_a="Foo",req_b=3,opt_d=-4,opt_c=C) // OK: arg order is irrelevant
@native(opt_d=-4,req_a="Foo",req_b=3)         // OK: arg order is irrelevant
@native(req_b=3)                              // Error: missing req_a
@native(req_a="Foo")                          // Error: missing req_b
type S = struct {};

作者定義的自訂屬性為無結構,且單純是以 並在 FIDL 檔案中運作編譯器無法驗證數字 及其正確型別 (不過當我們選擇導入「In-FIDL」屬性時,應會因此變更 如下所述 替代方案一節)。因此, 強制執行屬性簽章的文法正確性。範例 以下顯示作者定義屬性 @custom

@custom(a="Bar",b=true) // OK: grammatically correct
@custom("Bar",true)     // Error: bad grammar - multiple args require keywords
@custom("Bar")          // OK: correct grammar (though signature now unclear)
@custom(true)           // OK: correct grammar (signature even more unclear)
@custom()               // Error: bad grammar - cannot have empty arguments list
@custom                 // OK: grammatically correct
type S = struct {};

修改後的新 FIDL 屬性的 BNF 文法 語法為:

attribute = "@", IDENTIFIER , ( "(" , constant | attribute-args, ")" ) ;
attribute-args = attribute-arg | attribute-arg, "," attribute-args;
attribute-arg = IDENTIFIER , "=" , constant;

RFC-0040:ID 唯一性適用於屬性名稱。這個 表示屬性名稱中不同的大小寫和連續底線 在正式名稱解析期間降為單一通用名稱。下列 因此,這樣會導致範圍衝突,在編譯期間產生錯誤:

@foo_bar
@FooBar   // Error: re-used attribute name "foo_bar"
@fooBar   // Error: re-used attribute name "foo_bar"
@Foo_Bar  // Error: re-used attribute name "foo_bar"
@foo__bar // Error: re-used attribute name "foo_bar"
@FOOBar   // Error: re-used attribute name "foo_bar"
type S = struct {};

JSON IR

屬性的 FIDL JSON 中介表示法結構定義 反映新的語法結構定義的屬性 definition 現在提供 location 欄位來追蹤 屬性宣告的檔案內位置。以下為「value」欄位 會替換為 arguments 欄位,該欄位會將每個引數的值儲存為 name/value 配對,而後者採用前者, #/definitions/constant。適用於只接受一個引數的屬性 來源中沒有關鍵字 name,因此唯一的引數名稱會預設為 "value"

此外,compose 個段落和 reserved 資料表/工會成員是 不能攜帶屬性此 RFC 能解決這些疏忽 將新的 #/definitions/compose 定義新增為 #/definitions/interface,並正式在 #/definitions/table-member

總之,這個 RFC 引入了三種新的結構定義定義 (#/definitions/attribute-arg#/definitions/attribute-args#/definitions/compose) 並另外修改了另外三種 (#/definitions/attribute#/definitions/interface#/definitions/table-member)。新屬性 定義看起來會像這樣:

"attribute-arg": {
  {
    "description": "Definition of an attribute argument",
    "type": "object",
    "required": [
        "name",
        "value",
    ],
    "properties": {
      "name": {
        "description": "Name of the attribute argument",
        "type": "string",
      },
      "value": {
        "description": "Value of the attribute argument",
        "$ref": "#/definitions/constant",
      },
      "location": {
        "description": "Source location of the attribute argument",
        "$ref": "#/definitions/location"
      },
    },
  },
},
"attribute-args": {
  {
    "description": "Definition of an attributes argument list",
    "type": "array",
    "items": {
      "description": "List of arguments",
      "$ref": "#/definitions/attribute-arg",
    },
  },
},
"attribute": {
  {
    "description": "Definition of an attribute",
    "type": "object",
    "required": [
        "name",
        "arguments",
        "location",
    ],
    "properties": {
      "name": {
        "description": "Attribute name",
        "type": "string",
      },
      "arguments": {
        "description": "Attribute arguments",
        "$ref": "#/definitions/attribute-args",
      },
      "location": {
        "description": "Source location of the declaration",
        "$ref": "#/definitions/location",
      },
    },
  },
},
"compose": {
  {
    "description": "Compose member of an interface declaration",
    "type": "object",
    "required": [
        "name",
        "location",
    ],
    "properties": {
      "name": {
        "$ref": "#/definitions/compound-identifier",
        "description": "Name of the composed interface"
      },
      "maybe_attributes": {
        "description": "Optional list of attributes of the compose declaration",
        "$ref": "#/definitions/attributes-list",
      },
      "location": {
        "description": "Source location of the compose declaration",
        "$ref": "#/definitions/location",
      },
    },
  },
},

延續上一節的 @native 範例, 針對 type S 的 JSON IR 輸出內容,其 maybe_attributes 欄位會是:

"maybe_attributes": [
  {
    "name": "native",
    "arguments": [
      // Note: the omitted opt_d is not included in the IR
      {
        "name": "req_a",
        "value": {
          "kind": "literal",
          "value": "Foo",
          "expression": "\"Foo\"",
          "value": {
            "kind": "string",
            "value": "Foo",
            "expression": "\"Foo\"",
          },
        },
      },
      {
        "name": "req_b",
        "value": {
          "kind": "literal",
          "value": "3",
          "expression": "3",
          "literal": {
            "kind": "numeric",
            "value": "3",
            "expression": "3",
          },
        },
      },
      {
        "name": "opt_c",
        "value": {
          "kind": "identifier",
          "value": "true",
          "expression": "C",
          "identifier": "example/C",
        },
      },
    ],
    "location": {
        "filename": "/path/to/src/fidl/file/example.fidl",
        "line": 4,
        "column": 0,
        "length": 36,
    },
  },
],

個案研究:FIDL 版本管理

RFC-0083: FIDL 版本管理說明瞭 將版本管理中繼資料附加到 FIDL 宣告及其成員。於 也就是定義了新的屬性 @available,該屬性採用的 platformsinceremoveddeprecatednote 引數。例如:

@available(since=2)
type User = table {
  // Was created with struct at version 2, so no @available attribute is needed.
  1: is_admin bool;
  // Deprecated in favor of, and eventually replaced by, the name field.
  @available(deprecated=3,removed=4,note="use UTF-8 `name` instead")
  2: uid vector<uint8>;
  // The current (unreleased) version constrains this definition.
  // Placing "removed" before "since" is discouraged, but won't fail compilation.
  @available(removed="HEAD",since=3)
  3: name string;
  @available(since="HEAD")
  3: name string:60;
};

值得注意的是,引數會參照編號的平台版本 (例如 sinceremoveddeprecated) 也可以使用特殊字串 "HEAD"。這表示這些引數不會只有一個也很容易 可解析的類型,例如 uint8。這種建構項目是可以接受的,因為 特定的「官方」類型驗證規則@available 之類的屬性 寫死在編譯器本身中其他更細微的規則 限制只有 @available 個屬性附加至 library 宣告 可能會包含 platform 引數,也會以輪輻的方式處理。

實作

此提案將做為更廣泛的 RFC-0050 的一部分進行。 FIDL 語法轉換。所有以「new」記載的 FIDL 檔案語法將 以符合 RFC 的 文法將會隨之更新,反映其他方面的設計 RFC-0050。

此外,結構定義也會更新為 適用本文件指定的 JSON IR 變更。不過, 實際遷移至 語法,以確保 RFC-0050 定義 語法所產生的 IR 就像是驗證 正確性。因此,更新 attributes. 定義必須同時 再進行 RFC-0050 遷移作業,確保 JSON IR 並未變更 在這段期間。

成效

這類語法變更不太可能對效能造成影響。

安全性考量

這些語法變更不太可能會對安全性造成重大影響。確實 讓未來安全驗證屬性產生小衝擊 更容易撰寫及推理

隱私權注意事項

這些語法變更不太可能對隱私權造成重大影響。確實 未來可能在隱私權驗證屬性上導入潛在好處 更容易撰寫及推理

測試

這類語法變更不太可能會對測試造成重大影響。確實 在未來的測試檢測屬性中 增加潛在好處 更容易撰寫及推理

說明文件

所有相關文件和範例都將更新,加入新的 語法做為 RFC-0050 說明文件更新的一部分。於 請參閱官方 FIDL 的參考說明文件 屬性都將更新,以反映此設計所製定的規則。 注意每個屬性的有效引數類型和默示預設值。

缺點、替代方案與不明

In-FIDL 屬性結構定義

可用的語法幾乎是無限的設計空間。本節 不會試圖解決所有問題但有些選項 考慮允許定義註解函式的介面 「透過 FIDL」。這個替代語法及其拒絕原因 。

請參考以下 FIDL 檔案,該檔案含有其自訂屬性的介面 定義於內嵌:

type MyAttrArgs = table {
  1: foo string;
  2: bar int32;
  3: baz bool;
};
@myAttr(MyAttrArgs{foo: "abc", bar: 1, baz: false})
type MyStruct = struct {...};

這個設計的優點在於「自行食用 Dogfood 測試:」FIDL 是介面 所以不必定義內建介面 以及編譯器感知屬性函式嗎?此外,這也意味著 建立自訂的使用者定義屬性。 編譯器會將這類使用者定義的中繼資訊, 產生的繫結程式碼依然是開放式問題

由於嘗試過多,這個設計路徑最終會遭到拒絕。以上皆非 在未來可預見的屬性中,屬性的使用情境必須 定義能力,而且這項功能尚未釐清 有利的未來目標本文件建議的語法為 對其他熱門程式語言 (例如 Rust 和 Python。

目前的設計中未明確排除 In-FIDL 實作項目 因此,這個替代方案仍是可行的 新增至屬性語法

在屬性引數中使用字串常值

針對本文件中指定的設計,其中一種可能的改變是 不必允許使用輸入的引數,也可以保留 所有引數值都屬於字串常值請參考以下範例 說明這類設計:

const MAX_STR string = "123";
const MAX_NUM uint64 = 123;

@max_handles(123)     // Error: cannot use non-string types
@max_handles(MAX_STR) // Error: cannot use const identifiers
@max_handles(MAX_NUM) // Error: cannot use non-string types or const identifiers
@max_handles("123")   // OK: only string literals are allowed
type S = struct {};

這項設計的缺點是易於實作的簡易實作。目的地: 容納型別的屬性引數,後端所需的 複雜的擷取邏輯可適當解讀各種可能的類型 定義每個屬性引數。先前簡單從 傳送至 int 123 的字串 "123" 已足夠,後端現在需要處理 整個 #/definitions/constant 結構定義中的一部分其他 將實作成本乘以支援的後端數量。

允許使用類型屬性的好處是能集中處理這類屬性 轉換邏輯。舉例來說,假設 @my_custom_attr("3.")。如果每個後端都應該自行執行類型轉換 可能判定 "3." 是要轉換為整數的有效值,而另一個 則不一定。很難抓出這塊木頭的所有細節 後端的屬性導入作業 是難免的正在放大一個 使用 fidlc 屬性類型行為的正規知識。 不一致的情況

拒絕的輕微修改

本文件中描述的屬性語法會明確指出 單一宣告所附加的多個屬性之間的排序為 無關緊要。另一種做法是強制執行字母順序 順序。由於作者定義自訂屬性和 未來 fidlc 原生屬性可能會以其他可能的方式參照其他屬性 之所以能受惠於具體的排序方式嗎?請考量下列兩項做法 由作者定義的自訂屬性,但這些屬性的順序會令人混淆 如需要按字母順序排序:

@this_attr("Foo")
@test_for_this_attr(false)
protocol P {};

此外,我們也建議將駝峰式大小寫視為 屬性語法這項建議最終遭到拒絕,因為無 FIDL 樣式指南中的其他大小寫建議 而且在 1X 之後加入新的機器系列 屬性的大小寫樣式。

既有作品和參考資料

此 RFC 是 RFC-0050:語法 中定義的語法演變 修訂 ,進而修改正式的 FIDL 文法

本提案以「歸因類」模型為基礎導入 特別是其他語言:

  • Python 的裝飾器語法關鍵字引數設計有助於激發靈感 本文說明本文件採用的一些設計選項,例如使用 @ 符號,以及參照每個關鍵字的引數。
  • Rust 的屬性規格,而十分重要 某些語法選擇在概念上也類似 提案。
  • Cap'n Proto 的註解結構定義 會視為更有用的替代方案 使用本文件提議的語法