├── .github └── workflows │ └── main.yml ├── .gitignore ├── BINARY.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── README.tpl ├── crates └── text-parser │ ├── Cargo.toml │ ├── build.rs │ └── src │ ├── actions.rs │ ├── error.rs │ ├── grammar.lalrpop │ ├── lexer.rs │ ├── lib.rs │ └── parser.rs ├── src ├── ast.rs ├── binary │ ├── decode.rs │ ├── encode.rs │ └── mod.rs ├── lib.rs ├── quickcheck.rs └── text.rs └── tests ├── readme_up_to_date.rs └── tests.rs /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | test: 6 | name: Test 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@master 10 | - name: Install Rust 11 | run: rustup update stable && rustup default stable 12 | - run: cargo install cargo-readme --vers "^3" 13 | - run: cargo test --all 14 | - run: cargo test --all --all-features 15 | 16 | rustfmt: 17 | name: Rustfmt 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@master 21 | - name: Install Rust 22 | run: rustup update stable && rustup default stable && rustup component add rustfmt 23 | - run: cargo fmt -- --check 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /BINARY.md: -------------------------------------------------------------------------------- 1 | # Straw Proposal Binary Format for Wasm Web IDL Bindings 2 | 3 | This document describes the straw proposal binary format that this crate 4 | currently supports. 5 | 6 | 7 | 8 | 9 | 10 | - [The Web IDL Bindings Custom Section](#the-web-idl-bindings-custom-section) 11 | - [Subsections](#subsections) 12 | - [The Web IDL Type Subsection](#the-web-idl-type-subsection) 13 | - [Web IDL Functions](#web-idl-functions) 14 | - [Web IDL Dictionaries](#web-idl-dictionaries) 15 | - [Web IDL Enumerations](#web-idl-enumerations) 16 | - [Web IDL Unions](#web-idl-unions) 17 | - [References to Web IDL Types](#references-to-web-idl-types) 18 | - [The Function Binding Subsection](#the-function-binding-subsection) 19 | - [Function Bindings](#function-bindings) 20 | - [Outgoing Bindings](#outgoing-bindings) 21 | - [Incoming Bindings](#incoming-bindings) 22 | - [Binds](#binds) 23 | 24 | 25 | 26 | ## The Web IDL Bindings Custom Section 27 | 28 | **Custom section name:** `webidl-bindings`. 29 | 30 | ## Subsections 31 | 32 | The data of a Web IDL Bindings custom section contains a sequence of 33 | subsections. Each subsection consists of: 34 | 35 | * a one-byte *id*, 36 | * a `u32` *size* of its contents, in bytes, 37 | * the subsection's actual *contents*, whose structure is determined by its 38 | subsection *id*. 39 | 40 | ``` 41 | webidl_bindings_sec ::= section[0](webidl_bindings_data) 42 | 43 | webidl_bindings_data ::= n:name (if name = "webidl-bindings") 44 | webidl_type_subsec? 45 | bindings_subsec 46 | 47 | webidl_bindings_subsection[N](B) ::= N:byte size:u32 B (if size = |B|) 48 | ``` 49 | 50 | The following subsection ids are used: 51 | 52 | | Id | Subsection | 53 | |:--:|:------------------------| 54 | | 0 | Web IDL Type Subsection | 55 | | 1 | Bindings Subsection | 56 | 57 | ## The Web IDL Type Subsection 58 | 59 | The Web IDL Type Subsection is a sequence of `webidl_type` definitions: 60 | 61 | ``` 62 | webidl_type_subsec ::= webidl_bindings_subsection[0](vec(webidl_type)) 63 | ``` 64 | 65 | A `webidl_type` is a function, dictionary, enumeration, or union: 66 | 67 | ``` 68 | webidl_type ::= 0x0 webidl_function 69 | ::= 0x1 webidl_dictionary 70 | ::= 0x2 webidl_enumeration 71 | ::= 0x3 webidl_union 72 | ``` 73 | 74 | ### Web IDL Functions 75 | 76 | Functions are encoded as their function kind, which is one of 77 | 78 | * static (0x0) 79 | * method and receiver type (0x1) 80 | * constructor (0x2) 81 | 82 | followed by a sequence of references to their parameter types, and an optional 83 | reference to its result type: 84 | 85 | ``` 86 | webidl_function ::= webidl_function_kind 87 | vec(webidl_function_param) 88 | webidl_function_result 89 | 90 | webidl_function_kind ::= 0x0 # static 91 | ::= 0x1 webidl_type_reference # method 92 | ::= 0x2 # constructor 93 | 94 | webidl_function_param ::= webidl_type_reference 95 | 96 | webidl_function_result ::= 0x0 97 | ::= 0x1 webidl_type_reference 98 | ``` 99 | 100 | ### Web IDL Dictionaries 101 | 102 | Dictionaries are encodes as a `vec` of pairs of the dictionary field's UTF-8 103 | name string and a reference to the field's value: 104 | 105 | ``` 106 | webidl_dictionary ::= vec(webidl_dictionary_field) 107 | 108 | webidl_dictionary_field ::= name webidl_type_reference 109 | ``` 110 | 111 | ### Web IDL Enumerations 112 | 113 | Enumerations are encoded as a `vec` of their values' UTF-8 name strings. 114 | 115 | ``` 116 | webidl_enumeration ::= vec(name) 117 | ``` 118 | 119 | ### Web IDL Unions 120 | 121 | Unions are encoded as a `vec` of references to their member types: 122 | 123 | ``` 124 | webidl_union ::= vec(webidl_type_reference) 125 | ``` 126 | 127 | ## References to Web IDL Types 128 | 129 | References to Web IDL types appear in both the Web IDL Type Subsection and in 130 | the Web IDL Function Binding Subsection. 131 | 132 | References to Web IDL types are encoded as `i32`s and come in two forms: 133 | 134 | 1. References to compound Web IDL types are `>= 0` and are indices referencing 135 | the `i`th compound type defined in the Web IDL Type Subsection. 136 | 2. Scalar Web IDL values are encoded as negative numbers, and each scalar 137 | type has its own discriminant. 138 | 139 | ``` 140 | webidl_type_reference ::= i:i32 (if i >= 0) => index into Web IDL Type Subsection 141 | ::= i:i32 (if i == -1) => any 142 | ::= i:i32 (if i == -2) => boolean 143 | ::= i:i32 (if i == -3) => byte 144 | ::= i:i32 (if i == -4) => octet 145 | ::= i:i32 (if i == -5) => long 146 | ::= i:i32 (if i == -6) => unsigned long 147 | ::= i:i32 (if i == -7) => short 148 | ::= i:i32 (if i == -8) => unsigned short 149 | ::= i:i32 (if i == -9) => long long 150 | ::= i:i32 (if i == -10) => unsigned long long 151 | ::= i:i32 (if i == -11) => float 152 | ::= i:i32 (if i == -12) => unrestricted float 153 | ::= i:i32 (if i == -13) => double 154 | ::= i:i32 (if i == -14) => unrestricted double 155 | ::= i:i32 (if i == -15) => DOMString 156 | ::= i:i32 (if i == -16) => ByteString 157 | ::= i:i32 (if i == -17) => USVString 158 | ::= i:i32 (if i == -18) => object 159 | ::= i:i32 (if i == -19) => symbol 160 | ::= i:i32 (if i == -20) => ArrayBuffer 161 | ::= i:i32 (if i == -21) => DataView 162 | ::= i:i32 (if i == -22) => Int8Array 163 | ::= i:i32 (if i == -23) => Int16Array 164 | ::= i:i32 (if i == -24) => Int32Array 165 | ::= i:i32 (if i == -25) => Uint8Array 166 | ::= i:i32 (if i == -26) => Uint16Array 167 | ::= i:i32 (if i == -27) => Uint32Array 168 | ::= i:i32 (if i == -28) => Uint8clampedArray 169 | ::= i:i32 (if i == -29) => Float32Array 170 | ::= i:i32 (if i == -30) => Float64Array 171 | ``` 172 | 173 | ## The Function Binding Subsection 174 | 175 | The Web IDL Function Binding Subsection is a sequence of `function_binding`s and 176 | `bind`s: 177 | 178 | ``` 179 | bindings_subsec ::= webidl_bindings_subsection[1]( vec(function_binding) vec(bind) ) 180 | ``` 181 | 182 | ### Function Bindings 183 | 184 | Function bindings come in two flavors: 185 | 186 | 1. Import bindings connect imported external Web IDL function to Wasm functions. 187 | 2. Export bindings connect exported Wasm functions to external Web IDL callers. 188 | 189 | ``` 190 | function_binding ::= 0x0 import_binding 191 | ::= 0x1 export_binding 192 | 193 | import_binding ::= typeidx # Wasm function type 194 | webidl_type_reference # Web IDL function type 195 | outgoing_binding_map # Parameters 196 | incoming_binding_map # Result 197 | 198 | export_binding ::= typeidx # Wasm function type 199 | webidl_type_reference # Web IDL function type 200 | incoming_binding_map # Parameters 201 | outgoing_binding_map # Result 202 | ``` 203 | 204 | ### Outgoing Bindings 205 | 206 | An `outgoing_binding_map` is a sequence of `outgoing_binding_expression`s, and 207 | each expression kind is assigned its own discriminant: 208 | 209 | ``` 210 | outgoing_binding_map ::= vec(outgoing_binding_expression) 211 | 212 | outgoing_binding_expression ::= 0x0 webidl_type_reference u32 # as 213 | ::= 0x1 webidl_type_reference u32 u32 # utf8-str 214 | ::= 0x2 webidl_type_reference u32 # utf8-cstr 215 | ::= 0x3 webidl_type_reference u32 # i32-to-enum 216 | ::= 0x4 webidl_type_reference u32 u32 # view 217 | ::= 0x5 webidl_type_reference u32 u32 # copy 218 | ::= 0x6 # dict 219 | webidl_type_reference 220 | vec(outgoing_binding_expression) 221 | ::= 0x7 webidl_type_reference u32 u32 # bind-export 222 | ``` 223 | 224 | ### Incoming Bindings 225 | 226 | An `incoming_binding_map` is a sequence of nested `incoming_binding_expression` 227 | trees, and each expression kind is assigned its own discriminant: 228 | 229 | ``` 230 | incoming_binding_map ::= vec(incoming_binding_expression) 231 | 232 | incoming_binding_expression ::= 0x0 u32 # get 233 | ::= 0x1 valtype incoming_binding_expression # as 234 | ::= 0x2 name incoming_binding_expression # alloc-utf8-str 235 | ::= 0x3 name incoming_binding_expression # alloc-copy 236 | ::= 0x4 # enum-to-i32 237 | webidl_type_reference 238 | incoming_binding_expression 239 | ::= 0x5 u32 incoming_binding_expression # field 240 | ::= 0x6 # bind-import 241 | typeidx 242 | u32 243 | incoming_binding_expression 244 | ``` 245 | 246 | ### Binds 247 | 248 | A `bind` pairs the index of a Wasm function with the index of a 249 | `function_binding`: 250 | 251 | ``` 252 | bind ::= funcidx u32 253 | ``` 254 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasm-webidl-bindings" 3 | version = "0.8.0" 4 | authors = ["Nick Fitzgerald ", "The Rust and WebAssembly Working Group"] 5 | edition = "2018" 6 | description = "Raw WebIDL bindings binary encoder/decoder with an AST. Still in a state of flux!" 7 | repository = "https://github.com/rustwasm/wasm-webidl-bindings" 8 | license = "MIT/Apache-2.0" 9 | readme = "./README.md" 10 | 11 | [dependencies] 12 | anyhow = "1.0.18" 13 | leb128 = "0.2.4" 14 | walrus = "0.15.0" 15 | wasm-webidl-bindings-text-parser = { version = "=0.8.0", path = "crates/text-parser", optional = true } 16 | id-arena = "2.2.1" 17 | quickcheck = { version = "0.8.5", optional = true } 18 | rand = { version = "0.6.5", optional = true } 19 | 20 | [dev-dependencies] 21 | lazy_static = "1.3.0" 22 | 23 | [workspace] 24 | members = [ 25 | "crates/text-parser" 26 | ] 27 | 28 | [features] 29 | text = ['wasm-webidl-bindings-text-parser'] 30 | quickchecking = ['rand', 'quickcheck'] 31 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Alex Crichton 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `wasm-webidl-bindings` 2 | 3 | 4 | **Read, write, and manipulate the Wasm WebIDL bindings custom section.** 5 | 6 | [![](https://docs.rs/wasm-webidl-bindings/badge.svg)](https://docs.rs/wasm-webidl-bindings/) 7 | [![](https://img.shields.io/crates/v/wasm-webidl-bindings.svg)](https://crates.io/crates/wasm-webidl-bindings) 8 | [![](https://img.shields.io/crates/d/wasm-webidl-bindings.svg)](https://crates.io/crates/wasm-webidl-bindings) 9 | 10 | ### What's Inside 11 | 12 | * A parser for the straw proposal text format. See `crates/text-parser/src/grammar.lalrpop`. 13 | 14 | * A set of AST types for representing and manipulating WebIDL bindings. See 15 | `src/ast.rs`. 16 | 17 | * An encoder and decoder for the straw proposal binary format. See the 18 | implementation at `src/binary/encode.rs` and details on the format at 19 | `BINARY.md`. 20 | 21 | ### Example 22 | 23 | #### Parsing the Text Format and Encoding it in the Binary Format 24 | 25 | ```rust 26 | #[cfg(feature = "text")] 27 | use wasm_webidl_bindings::{binary, text}; 28 | 29 | // Get the `walrus::Module` that this webidl-bindings section is for. 30 | // 31 | // The Wasm type and func that are being bound are: 32 | // 33 | // (type $EncodeIntoFuncWasm 34 | // (param anyref anyref i32 i32) 35 | // (result i64 i64)) 36 | // 37 | // (func $encodeInto 38 | // (import "TextEncoder" "encodeInto") 39 | // (type $EncodeIntoFuncWasm)) 40 | let raw_wasm: Vec = get_wasm_buffer_from_somewhere(); 41 | 42 | let mut config = walrus::ModuleConfig::default(); 43 | 44 | // Register a function to run after the module is parsed, but with access to the 45 | // mapping from indices in the original Wasm binary to their newly assigned 46 | // walrus IDs. 47 | // 48 | // This is where we will parse the Web IDL bindings text. 49 | config.on_parse(|module, indices_to_ids| { 50 | let webidl_bindings = text::parse(module, indices_to_ids, r#" 51 | type $TextEncoderEncodeIntoResult 52 | (dict 53 | (field "read" unsigned long long) 54 | (field "written" unsigned long long)) 55 | 56 | type $EncodeIntoFuncWebIDL 57 | (func (method any) 58 | (param USVString Uint8Array) 59 | (result $TextEncoderEncodeIntoResult)) 60 | 61 | func-binding $encodeIntoBinding import $EncodeIntoFuncWasm $EncodeIntoFuncWebIDL 62 | (param 63 | (as any 0) 64 | (as any 1) 65 | (view Int8Array 2 3)) 66 | (result 67 | (as i64 (field 0 (get 0))) 68 | (as i64 (field 1 (get 0)))) 69 | 70 | bind $encodeInto $encodeIntoBinding 71 | "#)?; 72 | 73 | println!("The parsed Web IDL bindings are {:#?}", webidl_bindings); 74 | 75 | // Insert the `webidl_bindings` into the module as a custom section. 76 | module.customs.add(webidl_bindings); 77 | 78 | Ok(()) 79 | }); 80 | 81 | let mut module = config.parse(&raw_wasm)?; 82 | 83 | // Reserialize the Wasm module along with its new Web IDL bindings 84 | // section. 85 | let new_raw_wasm = module.emit_wasm(); 86 | ``` 87 | 88 | -------------------------------------------------------------------------------- /README.tpl: -------------------------------------------------------------------------------- 1 | # `{{crate}}` 2 | 3 | {{readme}} 4 | -------------------------------------------------------------------------------- /crates/text-parser/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasm-webidl-bindings-text-parser" 3 | version = "0.8.0" 4 | description = "Raw WebIDL bindings text encoder/decoder. Still in a state of flux!" 5 | repository = "https://github.com/rustwasm/wasm-webidl-bindings" 6 | license = "MIT/Apache-2.0" 7 | authors = ["The Rust and WebAssembly Working Group"] 8 | edition = "2018" 9 | 10 | [build-dependencies] 11 | lalrpop = "0.17.1" 12 | 13 | [dependencies] 14 | anyhow = "1.0.18" 15 | lalrpop-util = "0.17.1" 16 | leb128 = "0.2.4" 17 | regex = "1.1.7" 18 | walrus = "0.15.0" 19 | -------------------------------------------------------------------------------- /crates/text-parser/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | lalrpop::Configuration::new() 3 | .use_cargo_dir_conventions() 4 | .emit_rerun_directives(true) 5 | .process() 6 | .unwrap(); 7 | } 8 | -------------------------------------------------------------------------------- /crates/text-parser/src/actions.rs: -------------------------------------------------------------------------------- 1 | pub trait Actions { 2 | type WebidlBindingsSection; 3 | fn webidl_bindings_section( 4 | &mut self, 5 | types: Self::WebidlTypeSubsection, 6 | bindings: Self::WebidlFunctionBindingsSubsection, 7 | ) -> Self::WebidlBindingsSection; 8 | 9 | type WebidlTypeSubsection; 10 | fn webidl_type_subsection( 11 | &mut self, 12 | types: Vec, 13 | ) -> Self::WebidlTypeSubsection; 14 | 15 | type WebidlType; 16 | fn webidl_type(&mut self, name: Option<&str>, ty: Self::WebidlCompoundType) 17 | -> Self::WebidlType; 18 | 19 | type WebidlCompoundType: From 20 | + From 21 | + From 22 | + From; 23 | 24 | type WebidlFunction; 25 | fn webidl_function( 26 | &mut self, 27 | kind: Option, 28 | params: Option, 29 | result: Option, 30 | ) -> Self::WebidlFunction; 31 | 32 | type WebidlFunctionKind: From 33 | + From; 34 | 35 | type WebidlFunctionKindMethod; 36 | fn webidl_function_kind_method( 37 | &mut self, 38 | ty: Self::WebidlTypeRef, 39 | ) -> Self::WebidlFunctionKindMethod; 40 | 41 | type WebidlFunctionKindConstructor; 42 | fn webidl_function_kind_constructor_default_new_target( 43 | &mut self, 44 | ) -> Self::WebidlFunctionKindConstructor; 45 | 46 | type WebidlFunctionParams; 47 | fn webidl_function_params( 48 | &mut self, 49 | tys: Vec, 50 | ) -> Self::WebidlFunctionParams; 51 | 52 | type WebidlFunctionResult; 53 | fn webidl_function_result(&mut self, ty: Self::WebidlTypeRef) -> Self::WebidlFunctionResult; 54 | 55 | type WebidlDictionary; 56 | fn webidl_dictionary( 57 | &mut self, 58 | fields: Vec, 59 | ) -> Self::WebidlDictionary; 60 | 61 | type WebidlDictionaryField; 62 | fn webidl_dictionary_field( 63 | &mut self, 64 | name: Self::WebidlDictionaryFieldName, 65 | ty: Self::WebidlTypeRef, 66 | ) -> Self::WebidlDictionaryField; 67 | 68 | type WebidlDictionaryFieldName; 69 | fn webidl_dictionary_field_name(&mut self, name: &str) -> Self::WebidlDictionaryFieldName; 70 | 71 | type WebidlEnumeration; 72 | fn webidl_enumeration( 73 | &mut self, 74 | values: Vec, 75 | ) -> Self::WebidlEnumeration; 76 | 77 | type WebidlEnumerationValue; 78 | fn webidl_enumeration_value(&mut self, value: &str) -> Self::WebidlEnumerationValue; 79 | 80 | type WebidlUnion; 81 | fn webidl_union(&mut self, members: Vec) -> Self::WebidlUnion; 82 | 83 | type WebidlFunctionBindingsSubsection; 84 | fn webidl_function_bindings_subsection( 85 | &mut self, 86 | bindings: Vec, 87 | binds: Vec, 88 | ) -> Self::WebidlFunctionBindingsSubsection; 89 | 90 | type FunctionBinding: From + From; 91 | 92 | type ImportBinding; 93 | fn import_binding( 94 | &mut self, 95 | name: Option<&str>, 96 | wasm_ty: Self::WasmFuncTypeRef, 97 | webidl_ty: Self::WebidlTypeRef, 98 | params: Option, 99 | result: Option, 100 | ) -> Self::ImportBinding; 101 | 102 | type ExportBinding; 103 | fn export_binding( 104 | &mut self, 105 | name: Option<&str>, 106 | wasm_ty: Self::WasmFuncTypeRef, 107 | webidl_ty: Self::WebidlTypeRef, 108 | params: Option, 109 | result: Option, 110 | ) -> Self::ExportBinding; 111 | 112 | type Bind; 113 | fn bind(&mut self, func: Self::WasmFuncRef, binding: Self::BindingRef) -> Self::Bind; 114 | 115 | type OutgoingBindingMap; 116 | fn outgoing_binding_map( 117 | &mut self, 118 | bindings: Vec, 119 | ) -> Self::OutgoingBindingMap; 120 | 121 | type IncomingBindingMap; 122 | fn incoming_binding_map( 123 | &mut self, 124 | bindings: Vec, 125 | ) -> Self::IncomingBindingMap; 126 | 127 | type OutgoingBindingExpression: From 128 | + From 129 | + From 130 | + From 131 | + From 132 | + From 133 | + From 134 | + From; 135 | 136 | type OutgoingBindingExpressionAs; 137 | fn outgoing_binding_expression_as( 138 | &mut self, 139 | ty: Self::WebidlTypeRef, 140 | idx: u32, 141 | ) -> Self::OutgoingBindingExpressionAs; 142 | 143 | type OutgoingBindingExpressionUtf8Str; 144 | fn outgoing_binding_expression_utf8_str( 145 | &mut self, 146 | ty: Self::WebidlTypeRef, 147 | offset: u32, 148 | length: u32, 149 | ) -> Self::OutgoingBindingExpressionUtf8Str; 150 | 151 | type OutgoingBindingExpressionUtf8CStr; 152 | fn outgoing_binding_expression_utf8_c_str( 153 | &mut self, 154 | ty: Self::WebidlTypeRef, 155 | offset: u32, 156 | ) -> Self::OutgoingBindingExpressionUtf8CStr; 157 | 158 | type OutgoingBindingExpressionI32ToEnum; 159 | fn outgoing_binding_expression_i32_to_enum( 160 | &mut self, 161 | ty: Self::WebidlTypeRef, 162 | idx: u32, 163 | ) -> Self::OutgoingBindingExpressionI32ToEnum; 164 | 165 | type OutgoingBindingExpressionView; 166 | fn outgoing_binding_expression_view( 167 | &mut self, 168 | ty: Self::WebidlTypeRef, 169 | offset: u32, 170 | length: u32, 171 | ) -> Self::OutgoingBindingExpressionView; 172 | 173 | type OutgoingBindingExpressionCopy; 174 | fn outgoing_binding_expression_copy( 175 | &mut self, 176 | ty: Self::WebidlTypeRef, 177 | offset: u32, 178 | length: u32, 179 | ) -> Self::OutgoingBindingExpressionCopy; 180 | 181 | type OutgoingBindingExpressionDict; 182 | fn outgoing_binding_expression_dict( 183 | &mut self, 184 | ty: Self::WebidlTypeRef, 185 | fields: Vec, 186 | ) -> Self::OutgoingBindingExpressionDict; 187 | 188 | type OutgoingBindingExpressionBindExport; 189 | fn outgoing_binding_expression_bind_export( 190 | &mut self, 191 | ty: Self::WebidlTypeRef, 192 | binding: Self::BindingRef, 193 | idx: u32, 194 | ) -> Self::OutgoingBindingExpressionBindExport; 195 | 196 | type IncomingBindingExpression: From 197 | + From 198 | + From 199 | + From 200 | + From 201 | + From 202 | + From; 203 | 204 | type IncomingBindingExpressionGet; 205 | fn incoming_binding_expression_get(&mut self, idx: u32) -> Self::IncomingBindingExpressionGet; 206 | 207 | type IncomingBindingExpressionAs; 208 | fn incoming_binding_expression_as( 209 | &mut self, 210 | ty: Self::WasmValType, 211 | expr: Self::IncomingBindingExpression, 212 | ) -> Self::IncomingBindingExpressionAs; 213 | 214 | type IncomingBindingExpressionAllocUtf8Str; 215 | fn incoming_binding_expression_alloc_utf8_str( 216 | &mut self, 217 | alloc_func_name: &str, 218 | expr: Self::IncomingBindingExpression, 219 | ) -> Self::IncomingBindingExpressionAllocUtf8Str; 220 | 221 | type IncomingBindingExpressionAllocCopy; 222 | fn incoming_binding_expression_alloc_copy( 223 | &mut self, 224 | alloc_func_name: &str, 225 | expr: Self::IncomingBindingExpression, 226 | ) -> Self::IncomingBindingExpressionAllocCopy; 227 | 228 | type IncomingBindingExpressionEnumToI32; 229 | fn incoming_binding_expression_enum_to_i32( 230 | &mut self, 231 | ty: Self::WebidlTypeRef, 232 | expr: Self::IncomingBindingExpression, 233 | ) -> Self::IncomingBindingExpressionEnumToI32; 234 | 235 | type IncomingBindingExpressionField; 236 | fn incoming_binding_expression_field( 237 | &mut self, 238 | idx: u32, 239 | expr: Self::IncomingBindingExpression, 240 | ) -> Self::IncomingBindingExpressionField; 241 | 242 | type IncomingBindingExpressionBindImport; 243 | fn incoming_binding_expression_bind_import( 244 | &mut self, 245 | ty: Self::WasmFuncTypeRef, 246 | binding: Self::BindingRef, 247 | expr: Self::IncomingBindingExpression, 248 | ) -> Self::IncomingBindingExpressionBindImport; 249 | 250 | type WebidlTypeRef: From 251 | + From 252 | + From; 253 | 254 | type WebidlTypeRefNamed; 255 | fn webidl_type_ref_named(&mut self, name: &str) -> Option; 256 | 257 | type WebidlTypeRefIndexed; 258 | fn webidl_type_ref_indexed(&mut self, idx: u32) -> Option; 259 | 260 | type WebidlScalarType; 261 | fn webidl_scalar_type_any(&mut self) -> Self::WebidlScalarType; 262 | fn webidl_scalar_type_boolean(&mut self) -> Self::WebidlScalarType; 263 | fn webidl_scalar_type_byte(&mut self) -> Self::WebidlScalarType; 264 | fn webidl_scalar_type_octet(&mut self) -> Self::WebidlScalarType; 265 | fn webidl_scalar_type_long(&mut self) -> Self::WebidlScalarType; 266 | fn webidl_scalar_type_unsigned_long(&mut self) -> Self::WebidlScalarType; 267 | fn webidl_scalar_type_short(&mut self) -> Self::WebidlScalarType; 268 | fn webidl_scalar_type_unsigned_short(&mut self) -> Self::WebidlScalarType; 269 | fn webidl_scalar_type_long_long(&mut self) -> Self::WebidlScalarType; 270 | fn webidl_scalar_type_unsigned_long_long(&mut self) -> Self::WebidlScalarType; 271 | fn webidl_scalar_type_float(&mut self) -> Self::WebidlScalarType; 272 | fn webidl_scalar_type_unrestricted_float(&mut self) -> Self::WebidlScalarType; 273 | fn webidl_scalar_type_double(&mut self) -> Self::WebidlScalarType; 274 | fn webidl_scalar_type_unrestricted_double(&mut self) -> Self::WebidlScalarType; 275 | fn webidl_scalar_type_dom_string(&mut self) -> Self::WebidlScalarType; 276 | fn webidl_scalar_type_byte_string(&mut self) -> Self::WebidlScalarType; 277 | fn webidl_scalar_type_usv_string(&mut self) -> Self::WebidlScalarType; 278 | fn webidl_scalar_type_object(&mut self) -> Self::WebidlScalarType; 279 | fn webidl_scalar_type_symbol(&mut self) -> Self::WebidlScalarType; 280 | fn webidl_scalar_type_array_buffer(&mut self) -> Self::WebidlScalarType; 281 | fn webidl_scalar_type_data_view(&mut self) -> Self::WebidlScalarType; 282 | fn webidl_scalar_type_int8_array(&mut self) -> Self::WebidlScalarType; 283 | fn webidl_scalar_type_int16_array(&mut self) -> Self::WebidlScalarType; 284 | fn webidl_scalar_type_int32_array(&mut self) -> Self::WebidlScalarType; 285 | fn webidl_scalar_type_uint8_array(&mut self) -> Self::WebidlScalarType; 286 | fn webidl_scalar_type_uint16_array(&mut self) -> Self::WebidlScalarType; 287 | fn webidl_scalar_type_uint32_array(&mut self) -> Self::WebidlScalarType; 288 | fn webidl_scalar_type_uint8_clamped_array(&mut self) -> Self::WebidlScalarType; 289 | fn webidl_scalar_type_float32_array(&mut self) -> Self::WebidlScalarType; 290 | fn webidl_scalar_type_float64_array(&mut self) -> Self::WebidlScalarType; 291 | 292 | type WasmValType; 293 | fn wasm_val_type_i32(&mut self) -> Self::WasmValType; 294 | fn wasm_val_type_i64(&mut self) -> Self::WasmValType; 295 | fn wasm_val_type_f32(&mut self) -> Self::WasmValType; 296 | fn wasm_val_type_f64(&mut self) -> Self::WasmValType; 297 | fn wasm_val_type_v128(&mut self) -> Self::WasmValType; 298 | fn wasm_val_type_anyref(&mut self) -> Self::WasmValType; 299 | 300 | type WasmFuncTypeRef: From + From; 301 | 302 | type WasmFuncTypeRefNamed; 303 | fn wasm_func_type_ref_named(&mut self, name: &str) -> Option; 304 | 305 | type WasmFuncTypeRefIndexed; 306 | fn wasm_func_type_ref_indexed(&mut self, idx: u32) -> Option; 307 | 308 | type WasmFuncRef: From + From; 309 | 310 | type WasmFuncRefNamed; 311 | fn wasm_func_ref_named(&mut self, name: &str) -> Option; 312 | 313 | type WasmFuncRefIndexed; 314 | fn wasm_func_ref_indexed(&mut self, idx: u32) -> Option; 315 | 316 | type BindingRef: From + From; 317 | 318 | type BindingRefNamed; 319 | fn binding_ref_named(&mut self, name: &str) -> Option; 320 | 321 | type BindingRefIndexed; 322 | fn binding_ref_indexed(&mut self, idx: u32) -> Option; 323 | } 324 | -------------------------------------------------------------------------------- /crates/text-parser/src/error.rs: -------------------------------------------------------------------------------- 1 | pub(crate) fn error(error: S) -> lalrpop_util::ParseError 2 | where 3 | S: Into, 4 | { 5 | let error = error.into(); 6 | lalrpop_util::ParseError::User { error } 7 | } 8 | -------------------------------------------------------------------------------- /crates/text-parser/src/grammar.lalrpop: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | use crate::error::error; 3 | use crate::lexer::Token; 4 | 5 | grammar<'input, A>(input: &'input str, actions: &mut A) 6 | where A: crate::Actions; 7 | 8 | pub(crate) WebidlBindingsSection: A::WebidlBindingsSection = 9 | => 10 | actions.webidl_bindings_section(types, bindings); 11 | 12 | WebidlTypeSubsection: A::WebidlTypeSubsection = 13 | => actions.webidl_type_subsection(types); 14 | 15 | pub(crate) WebidlType: A::WebidlType = 16 | "type" => 17 | actions.webidl_type(name, ty); 18 | 19 | WebidlCompoundType: A::WebidlCompoundType = { 20 | => a.into(), 21 | => a.into(), 22 | => a.into(), 23 | => a.into(), 24 | }; 25 | 26 | WebidlFunction: A::WebidlFunction = { 27 | "(" 28 | "func" 29 | 30 | 31 | 32 | ")" => actions.webidl_function(kind, params, result), 33 | }; 34 | 35 | WebidlFunctionKind: A::WebidlFunctionKind = { 36 | => a.into(), 37 | => a.into(), 38 | // NB: functions that lack a kind are implicitly static. 39 | }; 40 | 41 | WebidlFunctionKindMethod: A::WebidlFunctionKindMethod = 42 | "(" "method" ")" => 43 | actions.webidl_function_kind_method(ty); 44 | 45 | WebidlFunctionKindConstructor: A::WebidlFunctionKindConstructor = { 46 | "(" "constructor" "default-new-target" ")" => 47 | actions.webidl_function_kind_constructor_default_new_target(), 48 | // TODO: What are the non-default target forms? 49 | }; 50 | 51 | WebidlFunctionParams: A::WebidlFunctionParams = 52 | "(" "param" ")" => 53 | actions.webidl_function_params(tys); 54 | 55 | WebidlFunctionResult: A::WebidlFunctionResult = 56 | "(" "result" ")" => 57 | actions.webidl_function_result(ty); 58 | 59 | WebidlDictionary: A::WebidlDictionary = 60 | "(" "dict" ")" => 61 | actions.webidl_dictionary(fields); 62 | 63 | WebidlDictionaryField: A::WebidlDictionaryField = 64 | "(" "field" ")" => 65 | actions.webidl_dictionary_field(name, ty); 66 | 67 | WebidlDictionaryFieldName: A::WebidlDictionaryFieldName = 68 | => 69 | actions.webidl_dictionary_field_name(&name[1..(name.len() - 1)]); 70 | 71 | WebidlEnumeration: A::WebidlEnumeration = 72 | "(" "enum" ")" => 73 | actions.webidl_enumeration(values); 74 | 75 | WebidlEnumerationValue: A::WebidlEnumerationValue = 76 | => 77 | actions.webidl_enumeration_value(&value[1..(value.len() - 1)]); 78 | 79 | WebidlUnion: A::WebidlUnion = 80 | "(" "union" ")" => 81 | actions.webidl_union(members); 82 | 83 | WebidlFunctionBindingsSubsection: A::WebidlFunctionBindingsSubsection = 84 | 85 | => 86 | actions.webidl_function_bindings_subsection(bindings, binds); 87 | 88 | FunctionBinding: A::FunctionBinding = { 89 | => a.into(), 90 | => a.into(), 91 | }; 92 | 93 | pub(crate) ImportBinding: A::ImportBinding = 94 | "func-binding" 95 | 96 | "import" 97 | 98 | 99 | 100 | => 101 | actions.import_binding( 102 | name, 103 | wasm_ty, 104 | webidl_ty, 105 | webidl_params.map(|params| params.2), 106 | webidl_result.map(|result| result.2), 107 | ); 108 | 109 | pub(crate) ExportBinding: A::ExportBinding = 110 | "func-binding" 111 | 112 | "export" 113 | 114 | 115 | 116 | => 117 | actions.export_binding( 118 | name, 119 | wasm_ty, 120 | webidl_ty, 121 | webidl_params.map(|params| params.2), 122 | webidl_result.map(|result| result.2), 123 | ); 124 | 125 | pub(crate) Bind: A::Bind = 126 | "bind" => 127 | actions.bind(func, binding); 128 | 129 | OutgoingBindingMap: A::OutgoingBindingMap = 130 | => 131 | actions.outgoing_binding_map(bindings); 132 | 133 | IncomingBindingMap: A::IncomingBindingMap = 134 | => 135 | actions.incoming_binding_map(bindings); 136 | 137 | pub(crate) WebidlTypeRef: A::WebidlTypeRef = { 138 | "type="? => a.into(), 139 | "type="? => a.into(), 140 | "type="? => a.into(), 141 | }; 142 | 143 | WebidlTypeRefNamed: A::WebidlTypeRefNamed = 144 | =>? { 145 | actions 146 | .webidl_type_ref_named(s) 147 | .ok_or_else(|| error(format!("unknown Web IDL type name: '{}'", s))) 148 | }; 149 | 150 | WebidlTypeRefIndexed: A::WebidlTypeRefIndexed = 151 | =>? { 152 | actions 153 | .webidl_type_ref_indexed(idx) 154 | .ok_or_else(|| error(format!("unknown Web IDL type index: {}", idx))) 155 | }; 156 | 157 | pub(crate) WebidlIndex: u32 = "idx="? ; 158 | 159 | WebidlScalarType: A::WebidlScalarType = { 160 | "any" => actions.webidl_scalar_type_any(), 161 | "boolean" => actions.webidl_scalar_type_boolean(), 162 | "byte" => actions.webidl_scalar_type_byte(), 163 | "octet" => actions.webidl_scalar_type_octet(), 164 | "long" => actions.webidl_scalar_type_long(), 165 | "unsigned long" => actions.webidl_scalar_type_unsigned_long(), 166 | "short" => actions.webidl_scalar_type_short(), 167 | "unsigned short" => actions.webidl_scalar_type_unsigned_short(), 168 | "long long" => actions.webidl_scalar_type_long_long(), 169 | "unsigned long long" => actions.webidl_scalar_type_unsigned_long_long(), 170 | "float" => actions.webidl_scalar_type_float(), 171 | "unrestricted float" => actions.webidl_scalar_type_unrestricted_float(), 172 | "double" => actions.webidl_scalar_type_double(), 173 | "unrestricted double" => actions.webidl_scalar_type_unrestricted_double(), 174 | "DOMString" => actions.webidl_scalar_type_dom_string(), 175 | "ByteString" => actions.webidl_scalar_type_byte_string(), 176 | "USVString" => actions.webidl_scalar_type_usv_string(), 177 | "object" => actions.webidl_scalar_type_object(), 178 | "symbol" => actions.webidl_scalar_type_symbol(), 179 | 180 | // "Scalar" arrays. 181 | "ArrayBuffer" => actions.webidl_scalar_type_array_buffer(), 182 | "DataView" => actions.webidl_scalar_type_data_view(), 183 | "Int8Array" => actions.webidl_scalar_type_int8_array(), 184 | "Int16Array" => actions.webidl_scalar_type_int16_array(), 185 | "Int32Array" => actions.webidl_scalar_type_int32_array(), 186 | "Uint8Array" => actions.webidl_scalar_type_uint8_array(), 187 | "Uint16Array" => actions.webidl_scalar_type_uint16_array(), 188 | "Uint32Array" => actions.webidl_scalar_type_uint32_array(), 189 | "Uint8ClampedArray" => actions.webidl_scalar_type_uint8_clamped_array(), 190 | "Float32Array" => actions.webidl_scalar_type_float32_array(), 191 | "Float64Array" => actions.webidl_scalar_type_float64_array(), 192 | }; 193 | 194 | pub(crate) WasmValType: A::WasmValType = { 195 | "i32" => actions.wasm_val_type_i32(), 196 | "i64" => actions.wasm_val_type_i64(), 197 | "f32" => actions.wasm_val_type_f32(), 198 | "f64" => actions.wasm_val_type_f64(), 199 | "v128" => actions.wasm_val_type_v128(), 200 | "anyref" => actions.wasm_val_type_anyref(), 201 | }; 202 | 203 | pub(crate) WasmFuncTypeRef: A::WasmFuncTypeRef = { 204 | => a.into(), 205 | => a.into(), 206 | }; 207 | 208 | WasmFuncTypeRefNamed: A::WasmFuncTypeRefNamed = 209 | =>? { 210 | actions 211 | .wasm_func_type_ref_named(s) 212 | .ok_or_else(|| error(format!("unknown Wasm function type name: '{}'", s))) 213 | }; 214 | 215 | WasmFuncTypeRefIndexed: A::WasmFuncTypeRefIndexed = 216 | =>? { 217 | actions 218 | .wasm_func_type_ref_indexed(idx) 219 | .ok_or_else(|| error(format!("unknown Wasm function type index: {}", idx))) 220 | }; 221 | 222 | pub(crate) WasmFuncRef: A::WasmFuncRef = { 223 | => a.into(), 224 | => a.into(), 225 | }; 226 | 227 | WasmFuncRefNamed: A::WasmFuncRefNamed = 228 | =>? { 229 | actions 230 | .wasm_func_ref_named(s) 231 | .ok_or_else(|| error(format!("unknown Wasm function name: '{}'", s))) 232 | }; 233 | 234 | WasmFuncRefIndexed: A::WasmFuncRefIndexed = 235 | =>? { 236 | actions 237 | .wasm_func_ref_indexed(idx) 238 | .ok_or_else(|| error(format!("unknown Wasm function index: {}", idx))) 239 | }; 240 | 241 | pub(crate) BindingRef: A::BindingRef = { 242 | => a.into(), 243 | => a.into(), 244 | }; 245 | 246 | BindingRefNamed: A::BindingRefNamed = 247 | =>? { 248 | actions 249 | .binding_ref_named(s) 250 | .ok_or_else(|| error(format!("unknown function binding name: '{}'", s))) 251 | }; 252 | 253 | BindingRefIndexed: A::BindingRefIndexed = 254 | =>? { 255 | actions 256 | .binding_ref_indexed(idx) 257 | .ok_or_else(|| error(format!("unknown function binding index: {}", idx))) 258 | }; 259 | 260 | pub(crate) OutgoingBindingExpression: A::OutgoingBindingExpression = { 261 | => a.into(), 262 | => a.into(), 263 | => a.into(), 264 | => a.into(), 265 | => a.into(), 266 | => a.into(), 267 | => a.into(), 268 | => a.into(), 269 | }; 270 | 271 | OutgoingBindingExpressionAs: A::OutgoingBindingExpressionAs = 272 | "(" "as" ")" => 273 | actions.outgoing_binding_expression_as(ty, idx); 274 | 275 | OutgoingBindingExpressionUtf8Str: A::OutgoingBindingExpressionUtf8Str = 276 | "(" "utf8-str" ")" => 277 | actions.outgoing_binding_expression_utf8_str(ty, offset, length); 278 | 279 | OutgoingBindingExpressionUtf8CStr: A::OutgoingBindingExpressionUtf8CStr = 280 | "(" "utf8-cstr" ")" => 281 | actions.outgoing_binding_expression_utf8_c_str(ty, offset); 282 | 283 | OutgoingBindingExpressionI32ToEnum: A::OutgoingBindingExpressionI32ToEnum = 284 | "(" "i32-to-enum" ")" => 285 | actions.outgoing_binding_expression_i32_to_enum(ty, idx); 286 | 287 | OutgoingBindingExpressionView: A::OutgoingBindingExpressionView = 288 | "(" "view" ")" => 289 | actions.outgoing_binding_expression_view(ty, offset, length); 290 | 291 | OutgoingBindingExpressionCopy: A::OutgoingBindingExpressionCopy = 292 | "(" "copy" ")" => 293 | actions.outgoing_binding_expression_copy(ty, offset, length); 294 | 295 | OutgoingBindingExpressionDict: A::OutgoingBindingExpressionDict = 296 | "(" "dict" ")" => 297 | actions.outgoing_binding_expression_dict(ty, fields); 298 | 299 | OutgoingBindingExpressionBindExport: A::OutgoingBindingExpressionBindExport = 300 | "(" 301 | "bind-export" 302 | 303 | 304 | 305 | ")" => 306 | actions.outgoing_binding_expression_bind_export(ty, binding, idx); 307 | 308 | pub(crate) IncomingBindingExpression: A::IncomingBindingExpression = { 309 | => a.into(), 310 | => a.into(), 311 | => a.into(), 312 | => a.into(), 313 | => a.into(), 314 | => a.into(), 315 | => a.into(), 316 | }; 317 | 318 | IncomingBindingExpressionGet: A::IncomingBindingExpressionGet = 319 | "(" "get" ")" => 320 | actions.incoming_binding_expression_get(idx); 321 | 322 | IncomingBindingExpressionAs: A::IncomingBindingExpressionAs = 323 | "(" "as" ")" => 324 | actions.incoming_binding_expression_as(ty, expr); 325 | 326 | IncomingBindingExpressionAllocUtf8Str: A::IncomingBindingExpressionAllocUtf8Str = 327 | "(" 328 | "alloc-utf8-str" 329 | 330 | 331 | ")" => 332 | actions.incoming_binding_expression_alloc_utf8_str(alloc_func_name, expr); 333 | 334 | IncomingBindingExpressionAllocCopy: A::IncomingBindingExpressionAllocCopy = 335 | "(" 336 | "alloc-copy" 337 | 338 | 339 | ")" => 340 | actions.incoming_binding_expression_alloc_copy(alloc_func_name, expr); 341 | 342 | IncomingBindingExpressionEnumToI32: A::IncomingBindingExpressionEnumToI32 = 343 | "(" "enum-to-i32" ")" => 344 | actions.incoming_binding_expression_enum_to_i32(ty, expr); 345 | 346 | IncomingBindingExpressionField: A::IncomingBindingExpressionField = 347 | "(" "field" ")" => 348 | actions.incoming_binding_expression_field(idx, expr); 349 | 350 | IncomingBindingExpressionBindImport: A::IncomingBindingExpressionBindImport = 351 | "(" 352 | "bind-import" 353 | 354 | 355 | 356 | ")" => 357 | actions.incoming_binding_expression_bind_import(ty, binding, expr); 358 | 359 | Unsigned: u32 = => u32::from_str(s).unwrap(); 360 | 361 | Identifier: &'input str = ; 362 | 363 | QuotedString: &'input str = ; 364 | 365 | extern { 366 | type Location = usize; 367 | type Error = String; 368 | 369 | enum Token<'input> { 370 | "(" => Token::LeftParenthesis, 371 | ")" => Token::RightParenthesis, 372 | "ArrayBuffer" => Token::ArrayBuffer, 373 | "ByteString" => Token::ByteString, 374 | "DOMString" => Token::DOMString, 375 | "DataView" => Token::DataView, 376 | "Float32Array" => Token::Float32Array, 377 | "Float64Array" => Token::Float64Array, 378 | "Int16Array" => Token::Int16Array, 379 | "Int32Array" => Token::Int32Array, 380 | "Int8Array" => Token::Int8Array, 381 | "USVString" => Token::USVString, 382 | "Uint16Array" => Token::Uint16Array, 383 | "Uint32Array" => Token::Uint32Array, 384 | "Uint8Array" => Token::Uint8Array, 385 | "Uint8ClampedArray" => Token::Uint8ClampedArray, 386 | "alloc-copy" => Token::AllocCopy, 387 | "alloc-utf8-cstr" => Token::AllocUtf8CStr, 388 | "alloc-utf8-str" => Token::AllocUtf8Str, 389 | "any" => Token::Any, 390 | "anyref" => Token::Anyref, 391 | "as" => Token::As, 392 | "bind" => Token::Bind, 393 | "bind-export" => Token::BindExport, 394 | "bind-import" => Token::BindImport, 395 | "boolean" => Token::Boolean, 396 | "byte" => Token::Byte, 397 | "constructor" => Token::Constructor, 398 | "copy" => Token::Copy, 399 | "default-new-target" => Token::DefaultNewTarget, 400 | "dict" => Token::Dict, 401 | "double" => Token::Double, 402 | "enum" => Token::Enum, 403 | "enum-to-i32" => Token::EnumToI32, 404 | "export" => Token::Export, 405 | "f32" => Token::F32, 406 | "f64" => Token::F64, 407 | "field" => Token::Field, 408 | "float" => Token::Float, 409 | "func" => Token::Func, 410 | "func-binding" => Token::FuncBinding, 411 | "get" => Token::Get, 412 | "i32" => Token::I32, 413 | "i32-to-enum" => Token::I32ToEnum, 414 | "i64" => Token::I64, 415 | "idx=" => Token::Index, 416 | "import" => Token::Import, 417 | "long long" => Token::LongLong, 418 | "long" => Token::Long, 419 | "method" => Token::Method, 420 | "object" => Token::Object, 421 | "octet" => Token::Octet, 422 | "param" => Token::Param, 423 | "result" => Token::Result, 424 | "short" => Token::Short, 425 | "symbol" => Token::Symbol, 426 | "type=" => Token::TypeRef, 427 | "type" => Token::Type, 428 | "union" => Token::Union, 429 | "unrestricted double" => Token::UnrestrictedDouble, 430 | "unrestricted float" => Token::UnrestrictedFloat, 431 | "unsigned long long" => Token::UnsignedLongLong, 432 | "unsigned long" => Token::UnsignedLong, 433 | "unsigned short" => Token::UnsignedShort, 434 | "utf8-cstr" => Token::Utf8CStr, 435 | "utf8-str" => Token::Utf8Str, 436 | "v128" => Token::V128, 437 | "view" => Token::View, 438 | r"[0-9]+" => Token::Unsigned(<&'input str>), 439 | r"[a-zA-Z$][a-zA-Z0-9$_]*" => Token::Identifier(<&'input str>), 440 | r#""(([^\\"]|\\.)*)""# => Token::QuotedString(<&'input str>), 441 | } 442 | } 443 | -------------------------------------------------------------------------------- /crates/text-parser/src/lexer.rs: -------------------------------------------------------------------------------- 1 | use regex::{Regex, RegexSet}; 2 | use std::{cmp, fmt}; 3 | 4 | #[derive(Debug, Clone, PartialEq)] 5 | pub enum Token<'input> { 6 | LeftParenthesis, 7 | RightParenthesis, 8 | ArrayBuffer, 9 | ByteString, 10 | DOMString, 11 | DataView, 12 | Float32Array, 13 | Float64Array, 14 | Int16Array, 15 | Int32Array, 16 | Int8Array, 17 | USVString, 18 | Uint16Array, 19 | Uint32Array, 20 | Uint8Array, 21 | Uint8ClampedArray, 22 | AllocCopy, 23 | AllocUtf8CStr, 24 | AllocUtf8Str, 25 | Any, 26 | Anyref, 27 | As, 28 | Bind, 29 | BindExport, 30 | BindImport, 31 | Boolean, 32 | Byte, 33 | Constructor, 34 | Copy, 35 | DefaultNewTarget, 36 | Dict, 37 | Double, 38 | Enum, 39 | EnumToI32, 40 | Export, 41 | F32, 42 | F64, 43 | Field, 44 | Float, 45 | Func, 46 | FuncBinding, 47 | Get, 48 | I32, 49 | I32ToEnum, 50 | I64, 51 | Index, 52 | Import, 53 | LongLong, 54 | Long, 55 | Method, 56 | Object, 57 | Octet, 58 | Param, 59 | Result, 60 | Short, 61 | Symbol, 62 | Type, 63 | TypeRef, 64 | Union, 65 | UnrestrictedDouble, 66 | UnrestrictedFloat, 67 | UnsignedLongLong, 68 | UnsignedLong, 69 | UnsignedShort, 70 | Utf8CStr, 71 | Utf8Str, 72 | V128, 73 | View, 74 | Unsigned(&'input str), 75 | Identifier(&'input str), 76 | QuotedString(&'input str), 77 | } 78 | 79 | impl<'input> fmt::Display for Token<'input> { 80 | fn fmt<'formatter>(&self, f: &mut fmt::Formatter<'formatter>) -> fmt::Result { 81 | write!(f, "{:?}", self) 82 | } 83 | } 84 | 85 | pub struct LexerBuilder { 86 | regex_set: RegexSet, 87 | regex_vec: Vec, 88 | skip_regex: Regex, 89 | } 90 | 91 | impl LexerBuilder { 92 | pub fn new() -> Self { 93 | let lexemes: &[&str] = &[ 94 | "^\\(", 95 | "^\\)", 96 | "^ArrayBuffer", 97 | "^ByteString", 98 | "^DOMString", 99 | "^DataView", 100 | "^Float32Array", 101 | "^Float64Array", 102 | "^Int16Array", 103 | "^Int32Array", 104 | "^Int8Array", 105 | "^USVString", 106 | "^Uint16Array", 107 | "^Uint32Array", 108 | "^Uint8Array", 109 | "^Uint8ClampedArray", 110 | "^alloc\\-copy", 111 | "^alloc\\-utf8\\-cstr", 112 | "^alloc\\-utf8\\-str", 113 | "^any", 114 | "^anyref", 115 | "^as", 116 | "^bind", 117 | "^bind\\-export", 118 | "^bind\\-import", 119 | "^boolean", 120 | "^byte", 121 | "^constructor", 122 | "^copy", 123 | "^default\\-new\\-target", 124 | "^dict", 125 | "^double", 126 | "^enum", 127 | "^enum\\-to\\-i32", 128 | "^export", 129 | "^f32", 130 | "^f64", 131 | "^field", 132 | "^float", 133 | "^func", 134 | "^func\\-binding", 135 | "^get", 136 | "^i32", 137 | "^i32\\-to\\-enum", 138 | "^i64", 139 | "^idx=", 140 | "^import", 141 | "^long long", 142 | "^long", 143 | "^method", 144 | "^object", 145 | "^octet", 146 | "^param", 147 | "^result", 148 | "^short", 149 | "^symbol", 150 | "^type=", 151 | "^type", 152 | "^union", 153 | "^unrestricted double", 154 | "^unrestricted float", 155 | "^unsigned long long", 156 | "^unsigned long", 157 | "^unsigned short", 158 | "^utf8\\-cstr", 159 | "^utf8\\-str", 160 | "^v128", 161 | "^view", 162 | r"^([0-9]+)", 163 | r"^([a-zA-Z$][a-zA-Z0-9$_]*)", 164 | r#"^"(([^\\"]|\\.)*)""#, 165 | ]; 166 | 167 | Self { 168 | regex_set: RegexSet::new(lexemes).unwrap(), 169 | regex_vec: lexemes 170 | .iter() 171 | .map(|lexeme| Regex::new(lexeme).unwrap()) 172 | .collect(), 173 | skip_regex: Regex::new(r#"^(\p{White_Space}+|;[^;]+;|;;[^\n]+)+"#).unwrap(), 174 | } 175 | } 176 | 177 | pub fn lexer<'input, 'builder>(&'builder self, input: &'input str) -> Lexer<'input, 'builder> { 178 | Lexer { 179 | input: input, 180 | consumed: 0, 181 | regex_set: &self.regex_set, 182 | regex_vec: &self.regex_vec, 183 | skip_regex: &self.skip_regex, 184 | } 185 | } 186 | } 187 | 188 | pub struct Lexer<'input, 'builder> { 189 | input: &'input str, 190 | consumed: usize, 191 | regex_set: &'builder RegexSet, 192 | regex_vec: &'builder Vec, 193 | skip_regex: &'builder Regex, 194 | } 195 | 196 | impl<'input, 'builder> Iterator for Lexer<'input, 'builder> { 197 | type Item = Result<(usize, Token<'input>, usize), String>; 198 | 199 | fn next(&mut self) -> Option { 200 | let (input, input_offset) = match self.skip_regex.find(self.input) { 201 | Some(match_) => { 202 | let offset = match_.end(); 203 | 204 | (&self.input[offset..], offset) 205 | } 206 | 207 | None => (self.input, 0), 208 | }; 209 | let start_offset = self.consumed + input_offset; 210 | 211 | if input.is_empty() { 212 | self.input = input; 213 | self.consumed = start_offset; 214 | 215 | None 216 | } else { 217 | let matches = self.regex_set.matches(input); 218 | 219 | if !matches.matched_any() { 220 | Some(Err(format!( 221 | "Invalid token at {}: `{}…`", 222 | start_offset, 223 | &input[..cmp::min(input.len(), 10)] 224 | ))) 225 | } else { 226 | let mut longest_match = 0; 227 | let mut token_by_regex = &self.regex_set.patterns()[0]; 228 | 229 | for i in 0..self.regex_set.len() { 230 | if matches.matched(i) { 231 | let this_match = self.regex_vec[i].find(input).unwrap(); 232 | let length = this_match.end(); 233 | 234 | if length > longest_match { 235 | longest_match = length; 236 | token_by_regex = &self.regex_set.patterns()[i]; 237 | } 238 | } 239 | } 240 | 241 | let result = &input[..longest_match]; 242 | let remaining = &input[longest_match..]; 243 | let end_offset = start_offset + longest_match; 244 | 245 | self.input = remaining; 246 | self.consumed = end_offset; 247 | 248 | Some(Ok(( 249 | start_offset, 250 | match token_by_regex.as_ref() { 251 | "^\\(" => Token::LeftParenthesis, 252 | "^\\)" => Token::RightParenthesis, 253 | "^ArrayBuffer" => Token::ArrayBuffer, 254 | "^ByteString" => Token::ByteString, 255 | "^DOMString" => Token::DOMString, 256 | "^DataView" => Token::DataView, 257 | "^Float32Array" => Token::Float32Array, 258 | "^Float64Array" => Token::Float64Array, 259 | "^Int16Array" => Token::Int16Array, 260 | "^Int32Array" => Token::Int32Array, 261 | "^Int8Array" => Token::Int8Array, 262 | "^USVString" => Token::USVString, 263 | "^Uint16Array" => Token::Uint16Array, 264 | "^Uint32Array" => Token::Uint32Array, 265 | "^Uint8Array" => Token::Uint8Array, 266 | "^Uint8ClampedArray" => Token::Uint8ClampedArray, 267 | "^alloc\\-copy" => Token::AllocCopy, 268 | "^alloc\\-utf8\\-cstr" => Token::AllocUtf8CStr, 269 | "^alloc\\-utf8\\-str" => Token::AllocUtf8Str, 270 | "^any" => Token::Any, 271 | "^anyref" => Token::Anyref, 272 | "^as" => Token::As, 273 | "^bind" => Token::Bind, 274 | "^bind\\-export" => Token::BindExport, 275 | "^bind\\-import" => Token::BindImport, 276 | "^boolean" => Token::Boolean, 277 | "^byte" => Token::Byte, 278 | "^constructor" => Token::Constructor, 279 | "^copy" => Token::Copy, 280 | "^default\\-new\\-target" => Token::DefaultNewTarget, 281 | "^dict" => Token::Dict, 282 | "^double" => Token::Double, 283 | "^enum" => Token::Enum, 284 | "^enum\\-to\\-i32" => Token::EnumToI32, 285 | "^export" => Token::Export, 286 | "^f32" => Token::F32, 287 | "^f64" => Token::F64, 288 | "^field" => Token::Field, 289 | "^float" => Token::Float, 290 | "^func" => Token::Func, 291 | "^func\\-binding" => Token::FuncBinding, 292 | "^get" => Token::Get, 293 | "^i32" => Token::I32, 294 | "^i32\\-to\\-enum" => Token::I32ToEnum, 295 | "^i64" => Token::I64, 296 | "^idx=" => Token::Index, 297 | "^import" => Token::Import, 298 | "^long long" => Token::LongLong, 299 | "^long" => Token::Long, 300 | "^method" => Token::Method, 301 | "^object" => Token::Object, 302 | "^octet" => Token::Octet, 303 | "^param" => Token::Param, 304 | "^result" => Token::Result, 305 | "^short" => Token::Short, 306 | "^symbol" => Token::Symbol, 307 | "^type=" => Token::TypeRef, 308 | "^type" => Token::Type, 309 | "^union" => Token::Union, 310 | "^unrestricted double" => Token::UnrestrictedDouble, 311 | "^unrestricted float" => Token::UnrestrictedFloat, 312 | "^unsigned long long" => Token::UnsignedLongLong, 313 | "^unsigned long" => Token::UnsignedLong, 314 | "^unsigned short" => Token::UnsignedShort, 315 | "^utf8\\-cstr" => Token::Utf8CStr, 316 | "^utf8\\-str" => Token::Utf8Str, 317 | "^v128" => Token::V128, 318 | "^view" => Token::View, 319 | r"^([0-9]+)" => Token::Unsigned(result), 320 | r"^([a-zA-Z$][a-zA-Z0-9$_]*)" => Token::Identifier(result), 321 | r#"^"(([^\\"]|\\.)*)""# => Token::QuotedString(result), 322 | _ => unreachable!(), 323 | }, 324 | end_offset, 325 | ))) 326 | } 327 | } 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /crates/text-parser/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Working with the text format. 2 | 3 | mod actions; 4 | mod error; 5 | mod lexer; 6 | mod parser; 7 | 8 | pub use actions::Actions; 9 | pub use parser::parse_with_actions; 10 | -------------------------------------------------------------------------------- /crates/text-parser/src/parser.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports, dead_code, missing_debug_implementations)] 2 | 3 | use crate::actions::Actions; 4 | use crate::lexer; 5 | 6 | include!(concat!(env!("OUT_DIR"), "/grammar.rs")); 7 | 8 | /// Parse the given straw proposal text format input with custom parse actions. 9 | /// 10 | /// Supply an `Actions` to do something while parsing. If you want to construct 11 | /// the default AST, use `wasm_webidl_bindings::text::parse` which uses the 12 | /// `wasm_webidl_bindings::ast::BuildAstActions` to construct the default AST. 13 | pub fn parse_with_actions( 14 | actions: &mut A, 15 | input: &str, 16 | ) -> anyhow::Result 17 | where 18 | A: Actions, 19 | { 20 | let lexer_builder = lexer::LexerBuilder::new(); 21 | let lexer = lexer_builder.lexer(input); 22 | 23 | let ast = WebidlBindingsSectionParser::new() 24 | .parse(input, actions, lexer) 25 | .map_err(|e| anyhow::anyhow!("{}", e))?; 26 | Ok(ast) 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use super::*; 32 | 33 | macro_rules! t { 34 | ( $( $x:expr )* ) => { 35 | ParseTree::List(vec![ $( $x.into() ),* ]) 36 | }; 37 | } 38 | 39 | #[derive(Clone, Debug, PartialEq, Eq)] 40 | enum ParseTree { 41 | List(Vec), 42 | Atom(String), 43 | } 44 | 45 | impl From<&'_ str> for ParseTree { 46 | fn from(s: &str) -> ParseTree { 47 | s.to_string().into() 48 | } 49 | } 50 | 51 | impl From for ParseTree { 52 | fn from(s: String) -> ParseTree { 53 | ParseTree::Atom(s) 54 | } 55 | } 56 | 57 | impl From for ParseTree { 58 | fn from(x: u32) -> ParseTree { 59 | ParseTree::Atom(x.to_string()) 60 | } 61 | } 62 | 63 | impl From> for ParseTree { 64 | fn from(v: Vec) -> ParseTree { 65 | ParseTree::List(v) 66 | } 67 | } 68 | 69 | impl> From> for ParseTree { 70 | fn from(t: Option) -> ParseTree { 71 | if let Some(t) = t { 72 | t!("Some" t) 73 | } else { 74 | t!("None") 75 | } 76 | } 77 | } 78 | 79 | struct BuildParseTree; 80 | 81 | impl crate::actions::Actions for BuildParseTree { 82 | type WebidlBindingsSection = ParseTree; 83 | fn webidl_bindings_section( 84 | &mut self, 85 | types: Self::WebidlTypeSubsection, 86 | bindings: Self::WebidlFunctionBindingsSubsection, 87 | ) -> Self::WebidlBindingsSection { 88 | t!("WebidlBindingsSection" types bindings) 89 | } 90 | 91 | type WebidlTypeSubsection = ParseTree; 92 | fn webidl_type_subsection( 93 | &mut self, 94 | types: Vec, 95 | ) -> Self::WebidlTypeSubsection { 96 | t!("WebidlTypeSubsection" types) 97 | } 98 | 99 | type WebidlType = ParseTree; 100 | fn webidl_type( 101 | &mut self, 102 | name: Option<&str>, 103 | ty: Self::WebidlCompoundType, 104 | ) -> Self::WebidlType { 105 | t!("WebidlType" name ty) 106 | } 107 | 108 | type WebidlCompoundType = ParseTree; 109 | 110 | type WebidlFunction = ParseTree; 111 | fn webidl_function( 112 | &mut self, 113 | kind: Option, 114 | params: Option, 115 | result: Option, 116 | ) -> Self::WebidlFunction { 117 | t!("WebidlFunction" kind params result) 118 | } 119 | 120 | type WebidlFunctionKind = ParseTree; 121 | 122 | type WebidlFunctionKindMethod = ParseTree; 123 | fn webidl_function_kind_method( 124 | &mut self, 125 | ty: Self::WebidlTypeRef, 126 | ) -> Self::WebidlFunctionKindMethod { 127 | t!("WebidlFunctionKindMethod" ty) 128 | } 129 | 130 | type WebidlFunctionKindConstructor = ParseTree; 131 | fn webidl_function_kind_constructor_default_new_target( 132 | &mut self, 133 | ) -> Self::WebidlFunctionKindConstructor { 134 | t!("WebidlFunctionKindConstructor") 135 | } 136 | 137 | type WebidlFunctionParams = ParseTree; 138 | fn webidl_function_params( 139 | &mut self, 140 | tys: Vec, 141 | ) -> Self::WebidlFunctionParams { 142 | t!("WebidlFunctionParams" tys) 143 | } 144 | 145 | type WebidlFunctionResult = ParseTree; 146 | fn webidl_function_result( 147 | &mut self, 148 | ty: Self::WebidlTypeRef, 149 | ) -> Self::WebidlFunctionResult { 150 | t!("WebidlFunctionResult" ty) 151 | } 152 | 153 | type WebidlDictionary = ParseTree; 154 | fn webidl_dictionary( 155 | &mut self, 156 | fields: Vec, 157 | ) -> Self::WebidlDictionary { 158 | t!("WebidlDictionary" fields) 159 | } 160 | 161 | type WebidlDictionaryField = ParseTree; 162 | fn webidl_dictionary_field( 163 | &mut self, 164 | name: Self::WebidlDictionaryFieldName, 165 | ty: Self::WebidlTypeRef, 166 | ) -> Self::WebidlDictionaryField { 167 | t!("WebidlDictionaryField" name ty) 168 | } 169 | 170 | type WebidlDictionaryFieldName = ParseTree; 171 | fn webidl_dictionary_field_name(&mut self, name: &str) -> Self::WebidlDictionaryFieldName { 172 | t!("WebidlDictionaryFieldName" name) 173 | } 174 | 175 | type WebidlEnumeration = ParseTree; 176 | fn webidl_enumeration( 177 | &mut self, 178 | values: Vec, 179 | ) -> Self::WebidlEnumeration { 180 | t!("WebidlEnumeration" values) 181 | } 182 | 183 | type WebidlEnumerationValue = ParseTree; 184 | fn webidl_enumeration_value(&mut self, value: &str) -> Self::WebidlEnumerationValue { 185 | t!("WebidlEnumerationValue" value) 186 | } 187 | 188 | type WebidlUnion = ParseTree; 189 | fn webidl_union(&mut self, members: Vec) -> Self::WebidlUnion { 190 | t!("WebidlUnion" members) 191 | } 192 | 193 | type WebidlFunctionBindingsSubsection = ParseTree; 194 | fn webidl_function_bindings_subsection( 195 | &mut self, 196 | bindings: Vec, 197 | binds: Vec, 198 | ) -> Self::WebidlFunctionBindingsSubsection { 199 | t!("WebidlFunctionBindingsSubsection" bindings binds) 200 | } 201 | 202 | type FunctionBinding = ParseTree; 203 | 204 | type ImportBinding = ParseTree; 205 | fn import_binding( 206 | &mut self, 207 | name: Option<&str>, 208 | wasm_ty: Self::WasmFuncTypeRef, 209 | webidl_ty: Self::WebidlTypeRef, 210 | params: Option, 211 | result: Option, 212 | ) -> Self::ImportBinding { 213 | t!("ImportBinding" name wasm_ty webidl_ty params result) 214 | } 215 | 216 | type ExportBinding = ParseTree; 217 | fn export_binding( 218 | &mut self, 219 | name: Option<&str>, 220 | wasm_ty: Self::WasmFuncTypeRef, 221 | webidl_ty: Self::WebidlTypeRef, 222 | params: Option, 223 | result: Option, 224 | ) -> Self::ExportBinding { 225 | t!("ExportBinding" name wasm_ty webidl_ty params result) 226 | } 227 | 228 | type Bind = ParseTree; 229 | fn bind(&mut self, func: Self::WasmFuncRef, binding: Self::BindingRef) -> Self::Bind { 230 | t!("Bind" func binding) 231 | } 232 | 233 | type OutgoingBindingMap = ParseTree; 234 | fn outgoing_binding_map( 235 | &mut self, 236 | bindings: Vec, 237 | ) -> Self::OutgoingBindingMap { 238 | t!("OutgoingBindingMap" bindings) 239 | } 240 | 241 | type IncomingBindingMap = ParseTree; 242 | fn incoming_binding_map( 243 | &mut self, 244 | bindings: Vec, 245 | ) -> Self::IncomingBindingMap { 246 | t!("IncomingBindingMap" bindings) 247 | } 248 | 249 | type OutgoingBindingExpression = ParseTree; 250 | 251 | type OutgoingBindingExpressionAs = ParseTree; 252 | fn outgoing_binding_expression_as( 253 | &mut self, 254 | ty: Self::WebidlTypeRef, 255 | idx: u32, 256 | ) -> Self::OutgoingBindingExpressionAs { 257 | t!("OutgoingBindingExpressionAs" ty idx) 258 | } 259 | 260 | type OutgoingBindingExpressionUtf8Str = ParseTree; 261 | fn outgoing_binding_expression_utf8_str( 262 | &mut self, 263 | ty: Self::WebidlTypeRef, 264 | offset: u32, 265 | length: u32, 266 | ) -> Self::OutgoingBindingExpressionUtf8Str { 267 | t!("OutgoingBindingExpressionUtf8Str" ty offset length) 268 | } 269 | 270 | type OutgoingBindingExpressionUtf8CStr = ParseTree; 271 | fn outgoing_binding_expression_utf8_c_str( 272 | &mut self, 273 | ty: Self::WebidlTypeRef, 274 | offset: u32, 275 | ) -> Self::OutgoingBindingExpressionUtf8CStr { 276 | t!("OutgoingBindingExpressionUtf8CStr" ty offset) 277 | } 278 | 279 | type OutgoingBindingExpressionI32ToEnum = ParseTree; 280 | fn outgoing_binding_expression_i32_to_enum( 281 | &mut self, 282 | ty: Self::WebidlTypeRef, 283 | idx: u32, 284 | ) -> Self::OutgoingBindingExpressionI32ToEnum { 285 | t!("OutgoingBindingExpressionI32ToEnum" ty idx) 286 | } 287 | 288 | type OutgoingBindingExpressionView = ParseTree; 289 | fn outgoing_binding_expression_view( 290 | &mut self, 291 | ty: Self::WebidlTypeRef, 292 | offset: u32, 293 | length: u32, 294 | ) -> Self::OutgoingBindingExpressionView { 295 | t!("OutgoingBindingExpressionView" ty offset length) 296 | } 297 | 298 | type OutgoingBindingExpressionCopy = ParseTree; 299 | fn outgoing_binding_expression_copy( 300 | &mut self, 301 | ty: Self::WebidlTypeRef, 302 | offset: u32, 303 | length: u32, 304 | ) -> Self::OutgoingBindingExpressionCopy { 305 | t!("OutgoingBindingExpressionCopy" ty offset length) 306 | } 307 | 308 | type OutgoingBindingExpressionDict = ParseTree; 309 | fn outgoing_binding_expression_dict( 310 | &mut self, 311 | ty: Self::WebidlTypeRef, 312 | fields: Vec, 313 | ) -> Self::OutgoingBindingExpressionDict { 314 | t!("OutgoingBindingExpressionDict" ty fields) 315 | } 316 | 317 | type OutgoingBindingExpressionBindExport = ParseTree; 318 | fn outgoing_binding_expression_bind_export( 319 | &mut self, 320 | ty: Self::WebidlTypeRef, 321 | binding: Self::BindingRef, 322 | idx: u32, 323 | ) -> Self::OutgoingBindingExpressionBindExport { 324 | t!("OutgoingBindingExpressionBindExport" ty binding idx) 325 | } 326 | 327 | type IncomingBindingExpression = ParseTree; 328 | 329 | type IncomingBindingExpressionGet = ParseTree; 330 | fn incoming_binding_expression_get( 331 | &mut self, 332 | idx: u32, 333 | ) -> Self::IncomingBindingExpressionGet { 334 | t!("IncomingBindingExpressionGet" idx) 335 | } 336 | 337 | type IncomingBindingExpressionAs = ParseTree; 338 | fn incoming_binding_expression_as( 339 | &mut self, 340 | ty: Self::WasmValType, 341 | expr: Self::IncomingBindingExpression, 342 | ) -> Self::IncomingBindingExpressionAs { 343 | t!("IncomingBindingExpressionAs" ty expr) 344 | } 345 | 346 | type IncomingBindingExpressionAllocUtf8Str = ParseTree; 347 | fn incoming_binding_expression_alloc_utf8_str( 348 | &mut self, 349 | alloc_func_name: &str, 350 | expr: Self::IncomingBindingExpression, 351 | ) -> Self::IncomingBindingExpressionAllocUtf8Str { 352 | t!("IncomingBindingExpressionAllocUtf8Str" alloc_func_name expr) 353 | } 354 | 355 | type IncomingBindingExpressionAllocCopy = ParseTree; 356 | fn incoming_binding_expression_alloc_copy( 357 | &mut self, 358 | alloc_func_name: &str, 359 | expr: Self::IncomingBindingExpression, 360 | ) -> Self::IncomingBindingExpressionAllocCopy { 361 | t!("IncomingBindingExpressionAllocCopy" alloc_func_name expr) 362 | } 363 | 364 | type IncomingBindingExpressionEnumToI32 = ParseTree; 365 | fn incoming_binding_expression_enum_to_i32( 366 | &mut self, 367 | ty: Self::WebidlTypeRef, 368 | expr: Self::IncomingBindingExpression, 369 | ) -> Self::IncomingBindingExpressionEnumToI32 { 370 | t!("IncomingBindingExpressionEnumToI32" ty expr) 371 | } 372 | 373 | type IncomingBindingExpressionField = ParseTree; 374 | fn incoming_binding_expression_field( 375 | &mut self, 376 | idx: u32, 377 | expr: Self::IncomingBindingExpression, 378 | ) -> Self::IncomingBindingExpressionField { 379 | t!("IncomingBindingExpressionField" idx expr) 380 | } 381 | 382 | type IncomingBindingExpressionBindImport = ParseTree; 383 | fn incoming_binding_expression_bind_import( 384 | &mut self, 385 | ty: Self::WasmFuncTypeRef, 386 | binding: Self::BindingRef, 387 | expr: Self::IncomingBindingExpression, 388 | ) -> Self::IncomingBindingExpressionBindImport { 389 | t!("IncomingBindingExpressionBindImport" ty binding expr) 390 | } 391 | 392 | type WebidlTypeRef = ParseTree; 393 | 394 | type WebidlTypeRefNamed = ParseTree; 395 | fn webidl_type_ref_named(&mut self, name: &str) -> Option { 396 | Some(t!("WebidlTypeRefNamed" name)) 397 | } 398 | 399 | type WebidlTypeRefIndexed = ParseTree; 400 | fn webidl_type_ref_indexed(&mut self, idx: u32) -> Option { 401 | Some(t!("WebidlTypeRefIndexed" idx)) 402 | } 403 | 404 | type WebidlScalarType = ParseTree; 405 | fn webidl_scalar_type_any(&mut self) -> Self::WebidlScalarType { 406 | t!("WebidlScalarType" "any") 407 | } 408 | fn webidl_scalar_type_boolean(&mut self) -> Self::WebidlScalarType { 409 | t!("WebidlScalarType" "boolean") 410 | } 411 | fn webidl_scalar_type_byte(&mut self) -> Self::WebidlScalarType { 412 | t!("WebidlScalarType" "byte") 413 | } 414 | fn webidl_scalar_type_octet(&mut self) -> Self::WebidlScalarType { 415 | t!("WebidlScalarType" "octet") 416 | } 417 | fn webidl_scalar_type_long(&mut self) -> Self::WebidlScalarType { 418 | t!("WebidlScalarType" "long") 419 | } 420 | fn webidl_scalar_type_unsigned_long(&mut self) -> Self::WebidlScalarType { 421 | t!("WebidlScalarType" "unsigned long") 422 | } 423 | fn webidl_scalar_type_short(&mut self) -> Self::WebidlScalarType { 424 | t!("WebidlScalarType" "short") 425 | } 426 | fn webidl_scalar_type_unsigned_short(&mut self) -> Self::WebidlScalarType { 427 | t!("WebidlScalarType" "unsigned short") 428 | } 429 | fn webidl_scalar_type_long_long(&mut self) -> Self::WebidlScalarType { 430 | t!("WebidlScalarType" "long long") 431 | } 432 | fn webidl_scalar_type_unsigned_long_long(&mut self) -> Self::WebidlScalarType { 433 | t!("WebidlScalarType" "unsigned long long") 434 | } 435 | fn webidl_scalar_type_float(&mut self) -> Self::WebidlScalarType { 436 | t!("WebidlScalarType" "float") 437 | } 438 | fn webidl_scalar_type_unrestricted_float(&mut self) -> Self::WebidlScalarType { 439 | t!("WebidlScalarType" "unrestricted float") 440 | } 441 | fn webidl_scalar_type_double(&mut self) -> Self::WebidlScalarType { 442 | t!("WebidlScalarType" "double") 443 | } 444 | fn webidl_scalar_type_unrestricted_double(&mut self) -> Self::WebidlScalarType { 445 | t!("WebidlScalarType" "unrestricted double") 446 | } 447 | fn webidl_scalar_type_dom_string(&mut self) -> Self::WebidlScalarType { 448 | t!("WebidlScalarType" "DOMString") 449 | } 450 | fn webidl_scalar_type_byte_string(&mut self) -> Self::WebidlScalarType { 451 | t!("WebidlScalarType" "ByteString") 452 | } 453 | fn webidl_scalar_type_usv_string(&mut self) -> Self::WebidlScalarType { 454 | t!("WebidlScalarType" "USVString") 455 | } 456 | fn webidl_scalar_type_object(&mut self) -> Self::WebidlScalarType { 457 | t!("WebidlScalarType" "object") 458 | } 459 | fn webidl_scalar_type_symbol(&mut self) -> Self::WebidlScalarType { 460 | t!("WebidlScalarType" "symbol") 461 | } 462 | fn webidl_scalar_type_array_buffer(&mut self) -> Self::WebidlScalarType { 463 | t!("WebidlScalarType" "ArrayBuffer") 464 | } 465 | fn webidl_scalar_type_data_view(&mut self) -> Self::WebidlScalarType { 466 | t!("WebidlScalarType" "DataView") 467 | } 468 | fn webidl_scalar_type_int8_array(&mut self) -> Self::WebidlScalarType { 469 | t!("WebidlScalarType" "Int8Array") 470 | } 471 | fn webidl_scalar_type_int16_array(&mut self) -> Self::WebidlScalarType { 472 | t!("WebidlScalarType" "Int16Array") 473 | } 474 | fn webidl_scalar_type_int32_array(&mut self) -> Self::WebidlScalarType { 475 | t!("WebidlScalarType" "Int32Array") 476 | } 477 | fn webidl_scalar_type_uint8_array(&mut self) -> Self::WebidlScalarType { 478 | t!("WebidlScalarType" "Uint8Array") 479 | } 480 | fn webidl_scalar_type_uint16_array(&mut self) -> Self::WebidlScalarType { 481 | t!("WebidlScalarType" "Uint16Array") 482 | } 483 | fn webidl_scalar_type_uint32_array(&mut self) -> Self::WebidlScalarType { 484 | t!("WebidlScalarType" "Uint32Array") 485 | } 486 | fn webidl_scalar_type_uint8_clamped_array(&mut self) -> Self::WebidlScalarType { 487 | t!("WebidlScalarType" "Uint8ClampedArray") 488 | } 489 | fn webidl_scalar_type_float32_array(&mut self) -> Self::WebidlScalarType { 490 | t!("WebidlScalarType" "Float32Array") 491 | } 492 | fn webidl_scalar_type_float64_array(&mut self) -> Self::WebidlScalarType { 493 | t!("WebidlScalarType" "Float64Array") 494 | } 495 | 496 | type WasmValType = ParseTree; 497 | fn wasm_val_type_i32(&mut self) -> Self::WasmValType { 498 | t!("WasmValType" "i32") 499 | } 500 | fn wasm_val_type_i64(&mut self) -> Self::WasmValType { 501 | t!("WasmValType" "i64") 502 | } 503 | fn wasm_val_type_f32(&mut self) -> Self::WasmValType { 504 | t!("WasmValType" "f32") 505 | } 506 | fn wasm_val_type_f64(&mut self) -> Self::WasmValType { 507 | t!("WasmValType" "f64") 508 | } 509 | fn wasm_val_type_v128(&mut self) -> Self::WasmValType { 510 | t!("WasmValType" "v128") 511 | } 512 | fn wasm_val_type_anyref(&mut self) -> Self::WasmValType { 513 | t!("WasmValType" "anyref") 514 | } 515 | 516 | type WasmFuncTypeRef = ParseTree; 517 | 518 | type WasmFuncTypeRefNamed = ParseTree; 519 | fn wasm_func_type_ref_named(&mut self, name: &str) -> Option { 520 | Some(t!("WasmFuncTypeRefNamed" name)) 521 | } 522 | 523 | type WasmFuncTypeRefIndexed = ParseTree; 524 | fn wasm_func_type_ref_indexed(&mut self, idx: u32) -> Option { 525 | Some(t!("WasmFuncTypeRefIndexed" idx)) 526 | } 527 | 528 | type WasmFuncRef = ParseTree; 529 | 530 | type WasmFuncRefNamed = ParseTree; 531 | fn wasm_func_ref_named(&mut self, name: &str) -> Option { 532 | Some(t!("WasmFuncRefNamed" name)) 533 | } 534 | 535 | type WasmFuncRefIndexed = ParseTree; 536 | fn wasm_func_ref_indexed(&mut self, idx: u32) -> Option { 537 | Some(t!("WasmFuncRefIndexed" idx)) 538 | } 539 | 540 | type BindingRef = ParseTree; 541 | 542 | type BindingRefNamed = ParseTree; 543 | fn binding_ref_named(&mut self, name: &str) -> Option { 544 | Some(t!("BindingRefNamed" name)) 545 | } 546 | 547 | type BindingRefIndexed = ParseTree; 548 | fn binding_ref_indexed(&mut self, idx: u32) -> Option { 549 | Some(t!("BindingRefIndexed" idx)) 550 | } 551 | } 552 | 553 | macro_rules! ok { 554 | ($name: ident, $parser: ident, $input: expr, $output: expr) => { 555 | #[test] 556 | fn $name() { 557 | let actions = &mut BuildParseTree; 558 | let lexer_builder = crate::lexer::LexerBuilder::new(); 559 | let lexer = lexer_builder.lexer($input); 560 | 561 | let actual = $parser::new().parse($input, actions, lexer).unwrap(); 562 | let expected = $output; 563 | println!("actual = {:#?}", actual); 564 | println!("expected = {:#?}", expected); 565 | assert_eq!(actual, expected); 566 | } 567 | }; 568 | } 569 | 570 | macro_rules! err { 571 | ($name: ident, $parser: ident, $input: expr) => { 572 | #[test] 573 | fn $name() { 574 | let actions = &mut BuildParseTree; 575 | let lexer_builder = crate::lexer::LexerBuilder::new(); 576 | let lexer = lexer_builder.lexer($input); 577 | 578 | assert!($parser::new().parse($input, actions, lexer).is_err()); 579 | } 580 | }; 581 | } 582 | 583 | ok!( 584 | explainer_example, 585 | WebidlBindingsSectionParser, 586 | // The Wasm type and func that are being bound are: 587 | // 588 | // (type $EncodeIntoFuncWasm 589 | // (param anyref anyref i32 i32) 590 | // (result i64 i64)) 591 | // 592 | // (func $encodeInto 593 | // (import "TextEncoder" "encodeInto") 594 | // (type $EncodeIntoFuncWasm)) 595 | r#" 596 | ;; Define the signature of `encodeInto`. 597 | type $TextEncoderEncodeIntoResult 598 | (; a dictionary with 2 fields: `read` and `written`. ; dict 599 | (field "read" unsigned long long) 600 | (field "written" unsigned long long)) 601 | 602 | type $EncodeIntoFuncWebIDL 603 | (func (method any) 604 | (param USVString Uint8Array) 605 | (result $TextEncoderEncodeIntoResult)) 606 | 607 | ;; Apply the binding. 608 | func-binding $encodeIntoBinding import $EncodeIntoFuncWasm $EncodeIntoFuncWebIDL 609 | (param 610 | (as any 0) 611 | (as type=any idx=1) 612 | (view Uint8Array 2 3)) 613 | (result 614 | (as i64 (field 0 (get 0))) 615 | (as i64 (field 1 (get idx=0)))) 616 | 617 | bind $encodeInto $encodeIntoBinding 618 | "#, 619 | t!("WebidlBindingsSection" 620 | t!("WebidlTypeSubsection" 621 | t!(t!("WebidlType" 622 | t!("Some" "$TextEncoderEncodeIntoResult") 623 | t!("WebidlDictionary" 624 | t!(t!("WebidlDictionaryField" 625 | t!("WebidlDictionaryFieldName" "read") 626 | t!("WebidlScalarType" "unsigned long long")) 627 | t!("WebidlDictionaryField" 628 | t!("WebidlDictionaryFieldName" "written") 629 | t!("WebidlScalarType" "unsigned long long"))))) 630 | t!("WebidlType" 631 | t!("Some" "$EncodeIntoFuncWebIDL") 632 | t!("WebidlFunction" 633 | t!("Some" t!("WebidlFunctionKindMethod" t!("WebidlScalarType" "any"))) 634 | t!("Some" t!("WebidlFunctionParams" 635 | t!(t!("WebidlScalarType" "USVString") 636 | t!("WebidlScalarType" "Uint8Array")))) 637 | t!("Some" t!("WebidlFunctionResult" 638 | t!("WebidlTypeRefNamed" "$TextEncoderEncodeIntoResult"))))))) 639 | t!("WebidlFunctionBindingsSubsection" 640 | t!(t!("ImportBinding" 641 | t!("Some" "$encodeIntoBinding") 642 | t!("WasmFuncTypeRefNamed" "$EncodeIntoFuncWasm") 643 | t!("WebidlTypeRefNamed" "$EncodeIntoFuncWebIDL") 644 | t!("Some" t!("OutgoingBindingMap" 645 | t!(t!("OutgoingBindingExpressionAs" 646 | t!("WebidlScalarType" "any") 647 | 0) 648 | t!("OutgoingBindingExpressionAs" 649 | t!("WebidlScalarType" "any") 650 | 1) 651 | t!("OutgoingBindingExpressionView" 652 | t!("WebidlScalarType" "Uint8Array") 653 | 2 654 | 3)))) 655 | t!("Some" t!("IncomingBindingMap" 656 | t!(t!("IncomingBindingExpressionAs" 657 | t!("WasmValType" "i64") 658 | t!("IncomingBindingExpressionField" 659 | 0 660 | t!("IncomingBindingExpressionGet" 0))) 661 | t!("IncomingBindingExpressionAs" 662 | t!("WasmValType" "i64") 663 | t!("IncomingBindingExpressionField" 664 | 1 665 | t!("IncomingBindingExpressionGet" 0)))))))) 666 | t!(t!("Bind" 667 | t!("WasmFuncRefNamed" "$encodeInto") 668 | t!("BindingRefNamed" "$encodeIntoBinding"))))) 669 | ); 670 | 671 | ok!( 672 | webidl_type_func_ok_1, 673 | WebidlTypeParser, 674 | "type $AddContactFuncWebIDL (func (method any) (param $Contact DOMString) (result boolean))", 675 | t!("WebidlType" 676 | t!("Some" "$AddContactFuncWebIDL") 677 | t!("WebidlFunction" 678 | t!("Some" t!("WebidlFunctionKindMethod" 679 | t!("WebidlScalarType" "any"))) 680 | t!("Some" t!("WebidlFunctionParams" 681 | t!(t!("WebidlTypeRefNamed" "$Contact") 682 | t!("WebidlScalarType" "DOMString")))) 683 | t!("Some" t!("WebidlFunctionResult" t!("WebidlScalarType" "boolean"))))) 684 | ); 685 | ok!( 686 | webidl_type_func_ok_2, 687 | WebidlTypeParser, 688 | "type $AddContactFuncWebIDL (func (method any) (param $Contact DOMString))", 689 | t!("WebidlType" 690 | t!("Some" "$AddContactFuncWebIDL") 691 | t!("WebidlFunction" 692 | t!("Some" t!("WebidlFunctionKindMethod" 693 | t!("WebidlScalarType" "any"))) 694 | t!("Some" t!("WebidlFunctionParams" 695 | t!(t!("WebidlTypeRefNamed" "$Contact") 696 | t!("WebidlScalarType" "DOMString")))) 697 | t!("None"))) 698 | ); 699 | ok!( 700 | webidl_type_func_ok_3, 701 | WebidlTypeParser, 702 | "type $AddContactFuncWebIDL (func (param DOMString))", 703 | t!("WebidlType" 704 | t!("Some" "$AddContactFuncWebIDL") 705 | t!("WebidlFunction" 706 | t!("None") 707 | t!("Some" t!("WebidlFunctionParams" t!(t!("WebidlScalarType" "DOMString")))) 708 | t!("None"))) 709 | ); 710 | ok!( 711 | webidl_type_func_ok_4, 712 | WebidlTypeParser, 713 | "type $AddContactFuncWebIDL (func (param))", 714 | t!("WebidlType" 715 | t!("Some" "$AddContactFuncWebIDL") 716 | t!("WebidlFunction" 717 | t!("None") 718 | t!("Some" t!("WebidlFunctionParams" t!())) 719 | t!("None"))) 720 | ); 721 | ok!( 722 | webidl_type_func_ok_5, 723 | WebidlTypeParser, 724 | "type $AddContactFuncWebIDL (func)", 725 | t!("WebidlType" 726 | t!("Some" "$AddContactFuncWebIDL") 727 | t!("WebidlFunction" 728 | t!("None") 729 | t!("None") 730 | t!("None"))) 731 | ); 732 | ok!( 733 | webidl_type_func_ok_6, 734 | WebidlTypeParser, 735 | "type (func)", 736 | t!("WebidlType" 737 | t!("None") 738 | t!("WebidlFunction" 739 | t!("None") 740 | t!("None") 741 | t!("None"))) 742 | ); 743 | ok!( 744 | webidl_type_func_ok_7, 745 | WebidlTypeParser, 746 | "type MyCtor (func (constructor default-new-target) (result any))", 747 | t!("WebidlType" 748 | t!("Some" "MyCtor") 749 | t!("WebidlFunction" 750 | t!("Some" t!("WebidlFunctionKindConstructor")) 751 | t!("None") 752 | t!("Some" t!("WebidlFunctionResult" t!("WebidlScalarType" "any"))))) 753 | ); 754 | err!( 755 | webidl_type_func_err_1, 756 | WebidlTypeParser, 757 | "type blahBlahBlah" 758 | ); 759 | err!( 760 | webidl_type_func_err_2, 761 | WebidlTypeParser, 762 | "type blahBlahBlah (func (result any) (result any))" 763 | ); 764 | err!( 765 | webidl_type_func_err_3, 766 | WebidlTypeParser, 767 | "type blahBlahBlah (func (method any) (method any))" 768 | ); 769 | 770 | ok!( 771 | webidl_type_dict_ok_1, 772 | WebidlTypeParser, 773 | r#"type $Contact (dict (field "name" DOMString) (field "age" long))"#, 774 | t!("WebidlType" 775 | t!("Some" "$Contact") 776 | t!("WebidlDictionary" 777 | t!(t!("WebidlDictionaryField" 778 | t!("WebidlDictionaryFieldName" "name") 779 | t!("WebidlScalarType" "DOMString")) 780 | t!("WebidlDictionaryField" 781 | t!("WebidlDictionaryFieldName" "age") 782 | t!("WebidlScalarType" "long"))))) 783 | ); 784 | ok!( 785 | webidl_type_dict_ok_2, 786 | WebidlTypeParser, 787 | r#"type $Contact (dict)"#, 788 | t!("WebidlType" 789 | t!("Some" "$Contact") 790 | t!("WebidlDictionary" t!())) 791 | ); 792 | err!( 793 | webidl_type_dict_err_1, 794 | WebidlTypeParser, 795 | r#"type $Contact (dict (field "name"))"# 796 | ); 797 | err!( 798 | webidl_type_dict_err_2, 799 | WebidlTypeParser, 800 | r#"type $Contact (dict (field DOMString))"# 801 | ); 802 | 803 | ok!( 804 | webidl_type_enum_ok_1, 805 | WebidlTypeParser, 806 | r#"type Blah (enum "uno" "dos" "tres")"#, 807 | t!("WebidlType" 808 | t!("Some" "Blah") 809 | t!("WebidlEnumeration" 810 | t!( 811 | t!("WebidlEnumerationValue" "uno") 812 | t!("WebidlEnumerationValue" "dos") 813 | t!("WebidlEnumerationValue" "tres") 814 | ) 815 | ) 816 | ) 817 | ); 818 | ok!( 819 | webidl_type_enum_ok_2, 820 | WebidlTypeParser, 821 | r#"type (enum)"#, 822 | t!("WebidlType" 823 | t!("None") 824 | t!("WebidlEnumeration" t!()) 825 | ) 826 | ); 827 | err!( 828 | webidl_type_enum_err_1, 829 | WebidlTypeParser, 830 | r#"type (enum 1 2 3)"# 831 | ); 832 | 833 | ok!( 834 | webidl_type_union_ok_1, 835 | WebidlTypeParser, 836 | "type MyUnion (union long boolean)", 837 | t!("WebidlType" 838 | t!("Some" "MyUnion") 839 | t!("WebidlUnion" 840 | t!( 841 | t!("WebidlScalarType" "long") 842 | t!("WebidlScalarType" "boolean") 843 | ) 844 | ) 845 | ) 846 | ); 847 | ok!( 848 | webidl_type_union_ok_2, 849 | WebidlTypeParser, 850 | "type (union)", 851 | t!("WebidlType" 852 | t!("None") 853 | t!("WebidlUnion" t!()) 854 | ) 855 | ); 856 | err!( 857 | webidl_type_union_err_1, 858 | WebidlTypeParser, 859 | r#"type (union "hello")"# 860 | ); 861 | 862 | ok!( 863 | import_binding_ok_1, 864 | ImportBindingParser, 865 | "func-binding Yoyo import MyWasmFunc MyWebidlFunc (param (as any 0)) (result (as i32 (get 0)))", 866 | t!("ImportBinding" 867 | t!("Some" "Yoyo") 868 | t!("WasmFuncTypeRefNamed" "MyWasmFunc") 869 | t!("WebidlTypeRefNamed" "MyWebidlFunc") 870 | t!("Some" t!("OutgoingBindingMap" 871 | t!( 872 | t!("OutgoingBindingExpressionAs" 873 | t!("WebidlScalarType" "any") 874 | 0 875 | ) 876 | ) 877 | )) 878 | t!("Some" t!("IncomingBindingMap" 879 | t!( 880 | t!("IncomingBindingExpressionAs" 881 | t!("WasmValType" "i32") 882 | t!("IncomingBindingExpressionGet" 0) 883 | ) 884 | ) 885 | )) 886 | ) 887 | ); 888 | ok!( 889 | import_binding_ok_2, 890 | ImportBindingParser, 891 | "func-binding import MyWasmFunc MyWebidlFunc (param) (result)", 892 | t!("ImportBinding" 893 | t!("None") 894 | t!("WasmFuncTypeRefNamed" "MyWasmFunc") 895 | t!("WebidlTypeRefNamed" "MyWebidlFunc") 896 | t!("Some" t!("OutgoingBindingMap" t!())) 897 | t!("Some" t!("IncomingBindingMap" t!())) 898 | ) 899 | ); 900 | ok!( 901 | import_binding_ok_3, 902 | ImportBindingParser, 903 | "func-binding import MyWasmFunc MyWebidlFunc (param)", 904 | t!("ImportBinding" 905 | t!("None") 906 | t!("WasmFuncTypeRefNamed" "MyWasmFunc") 907 | t!("WebidlTypeRefNamed" "MyWebidlFunc") 908 | t!("Some" t!("OutgoingBindingMap" t!())) 909 | t!("None") 910 | ) 911 | ); 912 | ok!( 913 | import_binding_ok_4, 914 | ImportBindingParser, 915 | "func-binding import MyWasmFunc MyWebidlFunc (result)", 916 | t!("ImportBinding" 917 | t!("None") 918 | t!("WasmFuncTypeRefNamed" "MyWasmFunc") 919 | t!("WebidlTypeRefNamed" "MyWebidlFunc") 920 | t!("None") 921 | t!("Some" t!("IncomingBindingMap" t!())) 922 | ) 923 | ); 924 | err!( 925 | import_binding_err_3, 926 | ImportBindingParser, 927 | "func-binding import MyWasmFunc (param) (result)" 928 | ); 929 | err!( 930 | import_binding_err_4, 931 | ImportBindingParser, 932 | "func-binding import MyWebidlFunc (param) (result)" 933 | ); 934 | err!( 935 | import_binding_err_5, 936 | ImportBindingParser, 937 | "func-binding MyWasmFunc MyWebidlFunc (param) (result)" 938 | ); 939 | err!( 940 | import_binding_err_6, 941 | ImportBindingParser, 942 | "import MyWasmFunc MyWebidlFunc (param) (result)" 943 | ); 944 | 945 | ok!( 946 | export_binding_ok_1, 947 | ExportBindingParser, 948 | "func-binding $Yoyo export MyWasmFunc MyWebidlFunc (param (as i32 (get 0))) (result (as any 0))", 949 | t!("ExportBinding" 950 | t!("Some" "$Yoyo") 951 | t!("WasmFuncTypeRefNamed" "MyWasmFunc") 952 | t!("WebidlTypeRefNamed" "MyWebidlFunc") 953 | t!("Some" t!("IncomingBindingMap" 954 | t!( 955 | t!("IncomingBindingExpressionAs" 956 | t!("WasmValType" "i32") 957 | t!("IncomingBindingExpressionGet" 0) 958 | ) 959 | ) 960 | )) 961 | t!("Some" t!("OutgoingBindingMap" 962 | t!( 963 | t!("OutgoingBindingExpressionAs" 964 | t!("WebidlScalarType" "any") 965 | 0 966 | ) 967 | ) 968 | )) 969 | ) 970 | ); 971 | ok!( 972 | export_binding_ok_2, 973 | ExportBindingParser, 974 | "func-binding export $MyWasmFunc $MyWebidlFunc (param) (result)", 975 | t!("ExportBinding" 976 | t!("None") 977 | t!("WasmFuncTypeRefNamed" "$MyWasmFunc") 978 | t!("WebidlTypeRefNamed" "$MyWebidlFunc") 979 | t!("Some" t!("IncomingBindingMap" t!())) 980 | t!("Some" t!("OutgoingBindingMap" t!())) 981 | ) 982 | ); 983 | ok!( 984 | export_binding_ok_3, 985 | ExportBindingParser, 986 | "func-binding export $MyWasmFunc $MyWebidlFunc (param)", 987 | t!("ExportBinding" 988 | t!("None") 989 | t!("WasmFuncTypeRefNamed" "$MyWasmFunc") 990 | t!("WebidlTypeRefNamed" "$MyWebidlFunc") 991 | t!("Some" t!("IncomingBindingMap" t!())) 992 | t!("None") 993 | ) 994 | ); 995 | ok!( 996 | export_binding_ok_4, 997 | ExportBindingParser, 998 | "func-binding export $MyWasmFunc $MyWebidlFunc (result)", 999 | t!("ExportBinding" 1000 | t!("None") 1001 | t!("WasmFuncTypeRefNamed" "$MyWasmFunc") 1002 | t!("WebidlTypeRefNamed" "$MyWebidlFunc") 1003 | t!("None") 1004 | t!("Some" t!("OutgoingBindingMap" t!())) 1005 | ) 1006 | ); 1007 | err!( 1008 | export_binding_err_3, 1009 | ExportBindingParser, 1010 | "func-binding export MyWasmFunc (param) (result)" 1011 | ); 1012 | err!( 1013 | export_binding_err_4, 1014 | ExportBindingParser, 1015 | "func-binding export MyWebidlFunc (param) (result)" 1016 | ); 1017 | err!( 1018 | export_binding_err_5, 1019 | ExportBindingParser, 1020 | "func-binding MyWasmFunc MyWebidlFunc (param) (result)" 1021 | ); 1022 | err!( 1023 | export_binding_err_6, 1024 | ExportBindingParser, 1025 | "export MyWasmFunc MyWebidlFunc (param) (result)" 1026 | ); 1027 | 1028 | ok!( 1029 | webidl_type_ref_ok_1, 1030 | WebidlTypeRefParser, 1031 | "$Contact", 1032 | t!("WebidlTypeRefNamed" "$Contact") 1033 | ); 1034 | ok!( 1035 | webidl_type_ref_ok_2, 1036 | WebidlTypeRefParser, 1037 | "type=$Contact", 1038 | t!("WebidlTypeRefNamed" "$Contact") 1039 | ); 1040 | ok!( 1041 | webidl_type_ref_ok_3, 1042 | WebidlTypeRefParser, 1043 | "42", 1044 | t!("WebidlTypeRefIndexed" 42) 1045 | ); 1046 | ok!( 1047 | webidl_type_ref_ok_4, 1048 | WebidlTypeRefParser, 1049 | "type=42", 1050 | t!("WebidlTypeRefIndexed" 42) 1051 | ); 1052 | err!(webidl_type_ref_err, WebidlTypeRefParser, "1abc"); 1053 | 1054 | ok!( 1055 | wasm_type_ref_ok_1, 1056 | WasmValTypeParser, 1057 | "i32", 1058 | t!("WasmValType" "i32") 1059 | ); 1060 | ok!( 1061 | wasm_type_ref_ok_2, 1062 | WasmValTypeParser, 1063 | "i64", 1064 | t!("WasmValType" "i64") 1065 | ); 1066 | ok!( 1067 | wasm_type_ref_ok_3, 1068 | WasmValTypeParser, 1069 | "f32", 1070 | t!("WasmValType" "f32") 1071 | ); 1072 | ok!( 1073 | wasm_type_ref_ok_4, 1074 | WasmValTypeParser, 1075 | "f64", 1076 | t!("WasmValType" "f64") 1077 | ); 1078 | ok!( 1079 | wasm_type_ref_ok_5, 1080 | WasmValTypeParser, 1081 | "v128", 1082 | t!("WasmValType" "v128") 1083 | ); 1084 | ok!( 1085 | wasm_type_ref_ok_6, 1086 | WasmValTypeParser, 1087 | "anyref", 1088 | t!("WasmValType" "anyref") 1089 | ); 1090 | err!(wasm_type_ref_err, WasmValTypeParser, "a32"); 1091 | 1092 | ok!( 1093 | export_binding_ref_ok_1, 1094 | BindingRefParser, 1095 | "$Contact", 1096 | t!("BindingRefNamed" "$Contact") 1097 | ); 1098 | ok!( 1099 | export_binding_ref_ok_2, 1100 | BindingRefParser, 1101 | "42", 1102 | t!("BindingRefIndexed" 42) 1103 | ); 1104 | err!(export_binding_ref_err, BindingRefParser, "1abc"); 1105 | 1106 | ok!( 1107 | wasm_func_ref_ok_1, 1108 | WasmFuncRefParser, 1109 | "$my_func", 1110 | t!("WasmFuncRefNamed" "$my_func") 1111 | ); 1112 | ok!( 1113 | wasm_func_ref_ok_2, 1114 | WasmFuncRefParser, 1115 | "42", 1116 | t!("WasmFuncRefIndexed" 42) 1117 | ); 1118 | err!(wasm_func_ref_err, WasmFuncRefParser, "1abc"); 1119 | 1120 | ok!( 1121 | outgoing_binding_expression_as_ok_1, 1122 | OutgoingBindingExpressionParser, 1123 | "(as long 2)", 1124 | t!("OutgoingBindingExpressionAs" 1125 | t!("WebidlScalarType" "long") 1126 | 2 1127 | ) 1128 | ); 1129 | ok!( 1130 | outgoing_binding_expression_as_ok_2, 1131 | OutgoingBindingExpressionParser, 1132 | "(as 1 2)", 1133 | t!("OutgoingBindingExpressionAs" 1134 | t!("WebidlTypeRefIndexed" 1) 1135 | 2 1136 | ) 1137 | ); 1138 | err!( 1139 | outgoing_binding_expression_as_err_1, 1140 | OutgoingBindingExpressionParser, 1141 | "(as long)" 1142 | ); 1143 | err!( 1144 | outgoing_binding_expression_as_err_2, 1145 | OutgoingBindingExpressionParser, 1146 | "(as 2)" 1147 | ); 1148 | 1149 | ok!( 1150 | outgoing_binding_expression_utf8_str_ok, 1151 | OutgoingBindingExpressionParser, 1152 | "(utf8-str DOMString 123 456)", 1153 | t!("OutgoingBindingExpressionUtf8Str" 1154 | t!("WebidlScalarType" "DOMString") 1155 | 123 1156 | 456 1157 | ) 1158 | ); 1159 | err!( 1160 | outgoing_binding_expression_utf8_str_err_1, 1161 | OutgoingBindingExpressionParser, 1162 | "(utf8-str DOMString 123)" 1163 | ); 1164 | err!( 1165 | outgoing_binding_expression_utf8_str_err_2, 1166 | OutgoingBindingExpressionParser, 1167 | "(utf8-str 123 456)" 1168 | ); 1169 | 1170 | ok!( 1171 | outgoing_binding_expression_utf8_c_str_ok, 1172 | OutgoingBindingExpressionParser, 1173 | "(utf8-cstr DOMString 123)", 1174 | t!("OutgoingBindingExpressionUtf8CStr" 1175 | t!("WebidlScalarType" "DOMString") 1176 | 123 1177 | ) 1178 | ); 1179 | err!( 1180 | outgoing_binding_expression_utf8_c_str_err_1, 1181 | OutgoingBindingExpressionParser, 1182 | "(utf8-cstr DOMString)" 1183 | ); 1184 | err!( 1185 | outgoing_binding_expression_utf8_c_str_err_2, 1186 | OutgoingBindingExpressionParser, 1187 | "(utf8-cstr 123)" 1188 | ); 1189 | 1190 | ok!( 1191 | outgoing_binding_expression_i32_to_enum_ok, 1192 | OutgoingBindingExpressionParser, 1193 | "(i32-to-enum Blah 22)", 1194 | t!("OutgoingBindingExpressionI32ToEnum" 1195 | t!("WebidlTypeRefNamed" "Blah") 1196 | 22 1197 | ) 1198 | ); 1199 | err!( 1200 | outgoing_binding_expression_i32_to_enum_err_1, 1201 | OutgoingBindingExpressionParser, 1202 | "(i32-to-enum Blah)" 1203 | ); 1204 | err!( 1205 | outgoing_binding_expression_i32_to_enum_err_2, 1206 | OutgoingBindingExpressionParser, 1207 | "(i32-to-enum 22)" 1208 | ); 1209 | 1210 | ok!( 1211 | outgoing_binding_expression_view_ok, 1212 | OutgoingBindingExpressionParser, 1213 | "(view Uint8Array 123 456)", 1214 | t!("OutgoingBindingExpressionView" 1215 | t!("WebidlScalarType" "Uint8Array") 1216 | 123 1217 | 456 1218 | ) 1219 | ); 1220 | err!( 1221 | outgoing_binding_expression_view_err_1, 1222 | OutgoingBindingExpressionParser, 1223 | "(view Uint8Array 123)" 1224 | ); 1225 | err!( 1226 | outgoing_binding_expression_view_err_2, 1227 | OutgoingBindingExpressionParser, 1228 | "(view 123 456)" 1229 | ); 1230 | 1231 | ok!( 1232 | outgoing_binding_expression_copy_ok, 1233 | OutgoingBindingExpressionParser, 1234 | "(copy Uint8Array 123 456)", 1235 | t!("OutgoingBindingExpressionCopy" 1236 | t!("WebidlScalarType" "Uint8Array") 1237 | 123 1238 | 456 1239 | ) 1240 | ); 1241 | err!( 1242 | outgoing_binding_expression_copy_err_1, 1243 | OutgoingBindingExpressionParser, 1244 | "(copy Uint8Array 123)" 1245 | ); 1246 | err!( 1247 | outgoing_binding_expression_copy_err_2, 1248 | OutgoingBindingExpressionParser, 1249 | "(copy 123 456)" 1250 | ); 1251 | 1252 | ok!( 1253 | outgoing_binding_expression_dict_ok_1, 1254 | OutgoingBindingExpressionParser, 1255 | "(dict $Contact (utf8-str DOMString 0 1) (as long 2))", 1256 | t!("OutgoingBindingExpressionDict" 1257 | t!("WebidlTypeRefNamed" "$Contact") 1258 | t!( 1259 | t!("OutgoingBindingExpressionUtf8Str" 1260 | t!("WebidlScalarType" "DOMString") 1261 | 0 1262 | 1) 1263 | t!("OutgoingBindingExpressionAs" 1264 | t!("WebidlScalarType" "long") 1265 | 2) 1266 | ) 1267 | ) 1268 | ); 1269 | ok!( 1270 | outgoing_binding_expression_dict_ok_2, 1271 | OutgoingBindingExpressionParser, 1272 | "(dict $Contact)", 1273 | t!("OutgoingBindingExpressionDict" 1274 | t!("WebidlTypeRefNamed" "$Contact") 1275 | t!() 1276 | ) 1277 | ); 1278 | err!( 1279 | outgoing_binding_expression_dict_err_1, 1280 | OutgoingBindingExpressionParser, 1281 | "(dict (as long 1))" 1282 | ); 1283 | 1284 | ok!( 1285 | outgoing_binding_expression_bind_export_ok_1, 1286 | OutgoingBindingExpressionParser, 1287 | "(bind-export $SomeCallback $SomeBinding 2)", 1288 | t!("OutgoingBindingExpressionBindExport" 1289 | t!("WebidlTypeRefNamed" "$SomeCallback") 1290 | t!("BindingRefNamed" "$SomeBinding") 1291 | 2 1292 | ) 1293 | ); 1294 | err!( 1295 | outgoing_binding_expression_bind_export_err_1, 1296 | OutgoingBindingExpressionParser, 1297 | "(bind-export SomeBinding 2)" 1298 | ); 1299 | err!( 1300 | outgoing_binding_expression_bind_export_err_2, 1301 | OutgoingBindingExpressionParser, 1302 | "(bind-export SomeCallback 2)" 1303 | ); 1304 | err!( 1305 | outgoing_binding_expression_bind_export_err_3, 1306 | OutgoingBindingExpressionParser, 1307 | "(bind-export SomeCallback SomeBinding)" 1308 | ); 1309 | 1310 | ok!( 1311 | incoming_binding_expression_get_ok_1, 1312 | IncomingBindingExpressionParser, 1313 | "(get 9)", 1314 | t!("IncomingBindingExpressionGet" 9) 1315 | ); 1316 | err!( 1317 | incoming_binding_expression_get_err_1, 1318 | IncomingBindingExpressionParser, 1319 | "(get)" 1320 | ); 1321 | err!( 1322 | incoming_binding_expression_get_err_2, 1323 | IncomingBindingExpressionParser, 1324 | "(get 1 2)" 1325 | ); 1326 | 1327 | ok!( 1328 | incoming_binding_expression_as_ok_1, 1329 | IncomingBindingExpressionParser, 1330 | "(as i32 (get 0))", 1331 | t!("IncomingBindingExpressionAs" 1332 | t!("WasmValType" "i32") 1333 | t!("IncomingBindingExpressionGet" 0) 1334 | ) 1335 | ); 1336 | err!( 1337 | incoming_binding_expression_as_err_1, 1338 | IncomingBindingExpressionParser, 1339 | "(as i32)" 1340 | ); 1341 | err!( 1342 | incoming_binding_expression_as_err_2, 1343 | IncomingBindingExpressionParser, 1344 | "(as (get 1))" 1345 | ); 1346 | 1347 | ok!( 1348 | incoming_binding_expression_alloc_utf8_str_ok_1, 1349 | IncomingBindingExpressionParser, 1350 | "(alloc-utf8-str malloc (get 0))", 1351 | t!("IncomingBindingExpressionAllocUtf8Str" 1352 | "malloc" 1353 | t!("IncomingBindingExpressionGet" 0) 1354 | ) 1355 | ); 1356 | err!( 1357 | incoming_binding_expression_alloc_utf8_str_err_1, 1358 | IncomingBindingExpressionParser, 1359 | "(alloc-utf8-str (get 0))" 1360 | ); 1361 | err!( 1362 | incoming_binding_expression_alloc_utf8_str_err_2, 1363 | IncomingBindingExpressionParser, 1364 | "(alloc-utf8-str malloc)" 1365 | ); 1366 | 1367 | ok!( 1368 | incoming_binding_expression_alloc_copy_ok_1, 1369 | IncomingBindingExpressionParser, 1370 | "(alloc-copy malloc (get 0))", 1371 | t!("IncomingBindingExpressionAllocCopy" 1372 | "malloc" 1373 | t!("IncomingBindingExpressionGet" 0) 1374 | ) 1375 | ); 1376 | err!( 1377 | incoming_binding_expression_alloc_copy_err_1, 1378 | IncomingBindingExpressionParser, 1379 | "(alloc-copy (get 0))" 1380 | ); 1381 | err!( 1382 | incoming_binding_expression_alloc_copy_err_2, 1383 | IncomingBindingExpressionParser, 1384 | "(alloc-copy malloc)" 1385 | ); 1386 | 1387 | ok!( 1388 | incoming_binding_expression_enum_to_i32_ok_1, 1389 | IncomingBindingExpressionParser, 1390 | "(enum-to-i32 Blah (get 0))", 1391 | t!("IncomingBindingExpressionEnumToI32" 1392 | t!("WebidlTypeRefNamed" "Blah") 1393 | t!("IncomingBindingExpressionGet" 0) 1394 | ) 1395 | ); 1396 | err!( 1397 | incoming_binding_expression_enum_to_i32_err_1, 1398 | IncomingBindingExpressionParser, 1399 | "(enum-to-i32 (get 0))" 1400 | ); 1401 | err!( 1402 | incoming_binding_expression_enum_to_i32_err_2, 1403 | IncomingBindingExpressionParser, 1404 | "(enum-to-i32 Blah)" 1405 | ); 1406 | 1407 | ok!( 1408 | incoming_binding_expression_field_ok_1, 1409 | IncomingBindingExpressionParser, 1410 | "(field 0 (get 1))", 1411 | t!("IncomingBindingExpressionField" 1412 | 0 1413 | t!("IncomingBindingExpressionGet" 1) 1414 | ) 1415 | ); 1416 | err!( 1417 | incoming_binding_expression_field_err_1, 1418 | IncomingBindingExpressionParser, 1419 | "(field (get 1))" 1420 | ); 1421 | err!( 1422 | incoming_binding_expression_field_err_2, 1423 | IncomingBindingExpressionParser, 1424 | "(field 0)" 1425 | ); 1426 | 1427 | ok!( 1428 | incoming_binding_expression_bind_import_ok_1, 1429 | IncomingBindingExpressionParser, 1430 | "(bind-import hi hello (get 1))", 1431 | t!("IncomingBindingExpressionBindImport" 1432 | t!("WasmFuncTypeRefNamed" "hi") 1433 | t!("BindingRefNamed" "hello") 1434 | t!("IncomingBindingExpressionGet" 1) 1435 | ) 1436 | ); 1437 | err!( 1438 | incoming_binding_expression_bind_import_err_1, 1439 | IncomingBindingExpressionParser, 1440 | "(bind-import hi hello)" 1441 | ); 1442 | err!( 1443 | incoming_binding_expression_bind_import_err_2, 1444 | IncomingBindingExpressionParser, 1445 | "(bind-import hi (get 1))" 1446 | ); 1447 | err!( 1448 | incoming_binding_expression_bind_import_err_3, 1449 | IncomingBindingExpressionParser, 1450 | "(bind-import hello (get 1))" 1451 | ); 1452 | 1453 | ok!(webidl_index_ok_1, WebidlIndexParser, "42", 42); 1454 | ok!(webidl_index_ok_2, WebidlIndexParser, "idx=42", 42); 1455 | err!(webidl_index_err_1, WebidlIndexParser, "idx="); 1456 | } 1457 | -------------------------------------------------------------------------------- /src/binary/encode.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::*; 2 | use id_arena::Id; 3 | use std::collections::HashMap; 4 | use std::io; 5 | 6 | pub(crate) struct EncodeContext<'a> { 7 | indices: &'a walrus::IdsToIndices, 8 | webidl_type_id_to_idx: HashMap, u32>, 9 | binding_id_to_idx: HashMap, u32>, 10 | } 11 | 12 | // Factor this out into a trait to make testing easier. 13 | pub(crate) trait Indices { 14 | fn assign_webidl_type_index(&mut self, id: Id); 15 | fn webidl_type_index(&self, id: Id) -> u32; 16 | fn assign_binding_index(&mut self, id: Id); 17 | fn binding_index(&self, id: Id) -> u32; 18 | fn wasm_func_index(&self, id: walrus::FunctionId) -> u32; 19 | fn wasm_func_type_index(&self, id: walrus::TypeId) -> u32; 20 | } 21 | 22 | impl Indices for EncodeContext<'_> { 23 | fn assign_webidl_type_index(&mut self, id: Id) { 24 | let idx = self.webidl_type_id_to_idx.len() as u32; 25 | let old_idx = self.webidl_type_id_to_idx.insert(id, idx); 26 | assert!(old_idx.is_none()); 27 | } 28 | 29 | fn webidl_type_index(&self, id: Id) -> u32 { 30 | self.webidl_type_id_to_idx[&id] 31 | } 32 | 33 | fn assign_binding_index(&mut self, id: Id) { 34 | let idx = self.binding_id_to_idx.len() as u32; 35 | let old_idx = self.binding_id_to_idx.insert(id, idx); 36 | assert!(old_idx.is_none()); 37 | } 38 | 39 | fn binding_index(&self, id: Id) -> u32 { 40 | self.binding_id_to_idx[&id] 41 | } 42 | 43 | fn wasm_func_index(&self, id: walrus::FunctionId) -> u32 { 44 | self.indices.get_func_index(id) 45 | } 46 | 47 | fn wasm_func_type_index(&self, id: walrus::TypeId) -> u32 { 48 | self.indices.get_type_index(id) 49 | } 50 | } 51 | 52 | impl EncodeContext<'_> { 53 | pub fn new(indices: &walrus::IdsToIndices) -> EncodeContext { 54 | EncodeContext { 55 | indices, 56 | webidl_type_id_to_idx: Default::default(), 57 | binding_id_to_idx: Default::default(), 58 | } 59 | } 60 | } 61 | 62 | pub(crate) trait Encode { 63 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 64 | where 65 | Cx: Indices, 66 | W: ?Sized + io::Write; 67 | } 68 | 69 | impl<'a, T> Encode for &'a T 70 | where 71 | T: Encode, 72 | { 73 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 74 | where 75 | Cx: Indices, 76 | W: ?Sized + io::Write, 77 | { 78 | (**self).encode(cx, w) 79 | } 80 | } 81 | 82 | trait WriteExt: io::Write { 83 | fn byte(&mut self, b: u8) -> io::Result<()> { 84 | self.write_all(&[b])?; 85 | Ok(()) 86 | } 87 | 88 | fn uleb(&mut self, val: u32) -> io::Result<()> { 89 | leb128::write::unsigned(self, val as u64)?; 90 | Ok(()) 91 | } 92 | 93 | fn ileb(&mut self, val: i32) -> io::Result<()> { 94 | leb128::write::signed(self, val as i64)?; 95 | Ok(()) 96 | } 97 | 98 | fn vec(&mut self, cx: &mut Cx, items: I) -> io::Result<()> 99 | where 100 | Cx: Indices, 101 | I: IntoIterator, 102 | I::IntoIter: ExactSizeIterator, 103 | E: Encode, 104 | { 105 | let items = items.into_iter(); 106 | self.uleb(items.len() as u32)?; 107 | for x in items { 108 | x.encode(cx, self)?; 109 | } 110 | Ok(()) 111 | } 112 | } 113 | 114 | impl WriteExt for W where W: ?Sized + io::Write {} 115 | 116 | impl Encode for String { 117 | fn encode(&self, _cx: &mut Cx, w: &mut W) -> io::Result<()> 118 | where 119 | Cx: Indices, 120 | W: ?Sized + io::Write, 121 | { 122 | w.uleb(self.len() as u32)?; 123 | w.write_all(self.as_bytes()) 124 | } 125 | } 126 | 127 | impl Encode for WebidlBindings { 128 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 129 | where 130 | Cx: Indices, 131 | W: ?Sized + io::Write, 132 | { 133 | // A temporary version marker while we wait for the official spec to 134 | // stabilize 135 | crate::version().to_string().encode(cx, w)?; 136 | 137 | // Web IDL Type Subsection. 138 | self.types.encode(cx, w)?; 139 | 140 | // Web IDL Function Binding Subsection. 141 | w.byte(1)?; 142 | 143 | // Bindings. 144 | // 145 | // First assign them all indices. 146 | for (id, _) in self.bindings.arena.iter() { 147 | cx.assign_binding_index(id); 148 | } 149 | // Then actually encode them. 150 | w.vec(cx, self.bindings.arena.iter().map(|(_, binding)| binding))?; 151 | 152 | // Binds. 153 | w.vec(cx, self.binds.arena.iter().map(|(_id, b)| b)) 154 | } 155 | } 156 | 157 | impl Encode for WebidlTypes { 158 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 159 | where 160 | Cx: Indices, 161 | W: ?Sized + io::Write, 162 | { 163 | w.byte(0)?; 164 | for (id, _) in self.arena.iter() { 165 | cx.assign_webidl_type_index(id); 166 | } 167 | w.vec(cx, self.arena.iter().map(|(_, ty)| ty)) 168 | } 169 | } 170 | 171 | impl Encode for WebidlType { 172 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 173 | where 174 | Cx: Indices, 175 | W: ?Sized + io::Write, 176 | { 177 | self.ty.encode(cx, w) 178 | } 179 | } 180 | 181 | impl Encode for WebidlCompoundType { 182 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 183 | where 184 | Cx: Indices, 185 | W: ?Sized + io::Write, 186 | { 187 | match self { 188 | WebidlCompoundType::Function(f) => { 189 | w.byte(0)?; 190 | f.encode(cx, w) 191 | } 192 | WebidlCompoundType::Dictionary(d) => { 193 | w.byte(1)?; 194 | d.encode(cx, w) 195 | } 196 | WebidlCompoundType::Enumeration(e) => { 197 | w.byte(2)?; 198 | e.encode(cx, w) 199 | } 200 | WebidlCompoundType::Union(u) => { 201 | w.byte(3)?; 202 | u.encode(cx, w) 203 | } 204 | } 205 | } 206 | } 207 | 208 | impl Encode for WebidlFunction { 209 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 210 | where 211 | Cx: Indices, 212 | W: ?Sized + io::Write, 213 | { 214 | self.kind.encode(cx, w)?; 215 | w.vec(cx, &self.params)?; 216 | if let Some(result) = self.result.as_ref() { 217 | w.byte(1)?; 218 | result.encode(cx, w) 219 | } else { 220 | w.byte(0) 221 | } 222 | } 223 | } 224 | 225 | impl Encode for WebidlFunctionKind { 226 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 227 | where 228 | Cx: Indices, 229 | W: ?Sized + io::Write, 230 | { 231 | match self { 232 | WebidlFunctionKind::Static => w.byte(0), 233 | WebidlFunctionKind::Method(m) => { 234 | w.byte(1)?; 235 | m.ty.encode(cx, w) 236 | } 237 | WebidlFunctionKind::Constructor => w.byte(2), 238 | } 239 | } 240 | } 241 | 242 | impl Encode for WebidlTypeRef { 243 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 244 | where 245 | Cx: Indices, 246 | W: ?Sized + io::Write, 247 | { 248 | match self { 249 | WebidlTypeRef::Id(id) => w.ileb(cx.webidl_type_index(*id) as i32), 250 | WebidlTypeRef::Scalar(s) => s.encode(cx, w), 251 | } 252 | } 253 | } 254 | 255 | impl Encode for WebidlScalarType { 256 | fn encode(&self, _cx: &mut Cx, w: &mut W) -> io::Result<()> 257 | where 258 | Cx: Indices, 259 | W: ?Sized + io::Write, 260 | { 261 | match self { 262 | WebidlScalarType::Any => w.ileb(-1), 263 | WebidlScalarType::Boolean => w.ileb(-2), 264 | WebidlScalarType::Byte => w.ileb(-3), 265 | WebidlScalarType::Octet => w.ileb(-4), 266 | WebidlScalarType::Long => w.ileb(-5), 267 | WebidlScalarType::UnsignedLong => w.ileb(-6), 268 | WebidlScalarType::Short => w.ileb(-7), 269 | WebidlScalarType::UnsignedShort => w.ileb(-8), 270 | WebidlScalarType::LongLong => w.ileb(-9), 271 | WebidlScalarType::UnsignedLongLong => w.ileb(-10), 272 | WebidlScalarType::Float => w.ileb(-11), 273 | WebidlScalarType::UnrestrictedFloat => w.ileb(-12), 274 | WebidlScalarType::Double => w.ileb(-13), 275 | WebidlScalarType::UnrestrictedDouble => w.ileb(-14), 276 | WebidlScalarType::DomString => w.ileb(-15), 277 | WebidlScalarType::ByteString => w.ileb(-16), 278 | WebidlScalarType::UsvString => w.ileb(-17), 279 | WebidlScalarType::Object => w.ileb(-18), 280 | WebidlScalarType::Symbol => w.ileb(-19), 281 | WebidlScalarType::ArrayBuffer => w.ileb(-20), 282 | WebidlScalarType::DataView => w.ileb(-21), 283 | WebidlScalarType::Int8Array => w.ileb(-22), 284 | WebidlScalarType::Int16Array => w.ileb(-23), 285 | WebidlScalarType::Int32Array => w.ileb(-24), 286 | WebidlScalarType::Uint8Array => w.ileb(-25), 287 | WebidlScalarType::Uint16Array => w.ileb(-26), 288 | WebidlScalarType::Uint32Array => w.ileb(-27), 289 | WebidlScalarType::Uint8ClampedArray => w.ileb(-28), 290 | WebidlScalarType::Float32Array => w.ileb(-29), 291 | WebidlScalarType::Float64Array => w.ileb(-30), 292 | } 293 | } 294 | } 295 | 296 | impl Encode for WebidlDictionary { 297 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 298 | where 299 | Cx: Indices, 300 | W: ?Sized + io::Write, 301 | { 302 | w.vec(cx, &self.fields) 303 | } 304 | } 305 | 306 | impl Encode for WebidlDictionaryField { 307 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 308 | where 309 | Cx: Indices, 310 | W: ?Sized + io::Write, 311 | { 312 | self.name.encode(cx, w)?; 313 | self.ty.encode(cx, w) 314 | } 315 | } 316 | 317 | impl Encode for WebidlEnumeration { 318 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 319 | where 320 | Cx: Indices, 321 | W: ?Sized + io::Write, 322 | { 323 | w.vec(cx, &self.values) 324 | } 325 | } 326 | 327 | impl Encode for WebidlUnion { 328 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 329 | where 330 | Cx: Indices, 331 | W: ?Sized + io::Write, 332 | { 333 | w.vec(cx, &self.members) 334 | } 335 | } 336 | 337 | impl Encode for FunctionBinding { 338 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 339 | where 340 | Cx: Indices, 341 | W: ?Sized + io::Write, 342 | { 343 | match self { 344 | FunctionBinding::Import(i) => { 345 | w.byte(0)?; 346 | i.encode(cx, w) 347 | } 348 | FunctionBinding::Export(e) => { 349 | w.byte(1)?; 350 | e.encode(cx, w) 351 | } 352 | } 353 | } 354 | } 355 | 356 | impl Encode for ImportBinding { 357 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 358 | where 359 | Cx: Indices, 360 | W: ?Sized + io::Write, 361 | { 362 | self.wasm_ty.encode(cx, w)?; 363 | self.webidl_ty.encode(cx, w)?; 364 | self.params.encode(cx, w)?; 365 | self.result.encode(cx, w) 366 | } 367 | } 368 | 369 | impl Encode for ExportBinding { 370 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 371 | where 372 | Cx: Indices, 373 | W: ?Sized + io::Write, 374 | { 375 | self.wasm_ty.encode(cx, w)?; 376 | self.webidl_ty.encode(cx, w)?; 377 | self.params.encode(cx, w)?; 378 | self.result.encode(cx, w) 379 | } 380 | } 381 | 382 | impl Encode for walrus::ValType { 383 | fn encode(&self, _cx: &mut Cx, w: &mut W) -> io::Result<()> 384 | where 385 | Cx: Indices, 386 | W: ?Sized + io::Write, 387 | { 388 | match self { 389 | walrus::ValType::I32 => w.byte(0x7f), 390 | walrus::ValType::I64 => w.byte(0x7e), 391 | walrus::ValType::F32 => w.byte(0x7d), 392 | walrus::ValType::F64 => w.byte(0x7c), 393 | walrus::ValType::V128 => w.byte(0x7b), 394 | walrus::ValType::Anyref => w.byte(0x6f), 395 | } 396 | } 397 | } 398 | 399 | impl Encode for walrus::TypeId { 400 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 401 | where 402 | Cx: Indices, 403 | W: ?Sized + io::Write, 404 | { 405 | w.uleb(cx.wasm_func_type_index(*self)) 406 | } 407 | } 408 | 409 | impl Encode for OutgoingBindingMap { 410 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 411 | where 412 | Cx: Indices, 413 | W: ?Sized + io::Write, 414 | { 415 | w.vec(cx, &self.bindings) 416 | } 417 | } 418 | 419 | impl Encode for OutgoingBindingExpression { 420 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 421 | where 422 | Cx: Indices, 423 | W: ?Sized + io::Write, 424 | { 425 | match self { 426 | OutgoingBindingExpression::As(e) => { 427 | w.byte(0)?; 428 | e.ty.encode(cx, w)?; 429 | w.uleb(e.idx) 430 | } 431 | OutgoingBindingExpression::Utf8Str(e) => { 432 | w.byte(1)?; 433 | e.ty.encode(cx, w)?; 434 | w.uleb(e.offset)?; 435 | w.uleb(e.length) 436 | } 437 | OutgoingBindingExpression::Utf8CStr(e) => { 438 | w.byte(2)?; 439 | e.ty.encode(cx, w)?; 440 | w.uleb(e.offset) 441 | } 442 | OutgoingBindingExpression::I32ToEnum(e) => { 443 | w.byte(3)?; 444 | e.ty.encode(cx, w)?; 445 | w.uleb(e.idx) 446 | } 447 | OutgoingBindingExpression::View(e) => { 448 | w.byte(4)?; 449 | e.ty.encode(cx, w)?; 450 | w.uleb(e.offset)?; 451 | w.uleb(e.length) 452 | } 453 | OutgoingBindingExpression::Copy(e) => { 454 | w.byte(5)?; 455 | e.ty.encode(cx, w)?; 456 | w.uleb(e.offset)?; 457 | w.uleb(e.length) 458 | } 459 | OutgoingBindingExpression::Dict(e) => { 460 | w.byte(6)?; 461 | e.ty.encode(cx, w)?; 462 | w.vec(cx, &e.fields) 463 | } 464 | OutgoingBindingExpression::BindExport(e) => { 465 | w.byte(7)?; 466 | e.ty.encode(cx, w)?; 467 | e.binding.encode(cx, w)?; 468 | w.uleb(e.idx) 469 | } 470 | } 471 | } 472 | } 473 | 474 | impl Encode for Id { 475 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 476 | where 477 | Cx: Indices, 478 | W: ?Sized + io::Write, 479 | { 480 | w.uleb(cx.binding_index(*self)) 481 | } 482 | } 483 | 484 | impl Encode for IncomingBindingMap { 485 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 486 | where 487 | Cx: Indices, 488 | W: ?Sized + io::Write, 489 | { 490 | w.vec(cx, &self.bindings) 491 | } 492 | } 493 | 494 | impl Encode for IncomingBindingExpression { 495 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 496 | where 497 | Cx: Indices, 498 | W: ?Sized + io::Write, 499 | { 500 | match self { 501 | IncomingBindingExpression::Get(e) => { 502 | w.byte(0)?; 503 | w.uleb(e.idx) 504 | } 505 | IncomingBindingExpression::As(e) => { 506 | w.byte(1)?; 507 | e.ty.encode(cx, w)?; 508 | e.expr.encode(cx, w) 509 | } 510 | IncomingBindingExpression::AllocUtf8Str(e) => { 511 | w.byte(2)?; 512 | e.alloc_func_name.encode(cx, w)?; 513 | e.expr.encode(cx, w) 514 | } 515 | IncomingBindingExpression::AllocCopy(e) => { 516 | w.byte(3)?; 517 | e.alloc_func_name.encode(cx, w)?; 518 | e.expr.encode(cx, w) 519 | } 520 | IncomingBindingExpression::EnumToI32(e) => { 521 | w.byte(4)?; 522 | e.ty.encode(cx, w)?; 523 | e.expr.encode(cx, w) 524 | } 525 | IncomingBindingExpression::Field(e) => { 526 | w.byte(5)?; 527 | w.uleb(e.idx)?; 528 | e.expr.encode(cx, w) 529 | } 530 | IncomingBindingExpression::BindImport(e) => { 531 | w.byte(6)?; 532 | e.ty.encode(cx, w)?; 533 | e.binding.encode(cx, w)?; 534 | e.expr.encode(cx, w) 535 | } 536 | } 537 | } 538 | } 539 | 540 | impl Encode for Bind { 541 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 542 | where 543 | Cx: Indices, 544 | W: ?Sized + io::Write, 545 | { 546 | self.func.encode(cx, w)?; 547 | self.binding.encode(cx, w) 548 | } 549 | } 550 | 551 | impl Encode for walrus::FunctionId { 552 | fn encode(&self, cx: &mut Cx, w: &mut W) -> io::Result<()> 553 | where 554 | Cx: Indices, 555 | W: ?Sized + io::Write, 556 | { 557 | w.uleb(cx.wasm_func_index(*self)) 558 | } 559 | } 560 | 561 | #[cfg(test)] 562 | mod tests { 563 | use super::*; 564 | 565 | struct TestIndices; 566 | 567 | impl Indices for TestIndices { 568 | fn assign_webidl_type_index(&mut self, _: Id) {} 569 | 570 | fn webidl_type_index(&self, _: Id) -> u32 { 571 | 11 572 | } 573 | 574 | fn assign_binding_index(&mut self, _: Id) {} 575 | 576 | fn binding_index(&self, _: Id) -> u32 { 577 | 22 578 | } 579 | 580 | fn wasm_func_index(&self, _: walrus::FunctionId) -> u32 { 581 | 33 582 | } 583 | 584 | fn wasm_func_type_index(&self, _: walrus::TypeId) -> u32 { 585 | 44 586 | } 587 | } 588 | 589 | // fn get_func_index(&self, id: walrus::FunctionId) -> u32; 590 | // fn get_func_type_index(&self, id: walrus::TypeId) -> u32; 591 | fn do_assert_encoding(ast: E, expected: &[u8]) 592 | where 593 | E: Encode, 594 | { 595 | let mut actual = vec![]; 596 | ast.encode(&mut TestIndices, &mut actual) 597 | .expect("writing to a vec can't fail"); 598 | assert_eq!(expected, &actual[..]); 599 | } 600 | 601 | fn get_webidl_type_ref(b: &mut WebidlBindings) -> WebidlTypeRef { 602 | let id: WebidlUnionId = b.types.insert(WebidlUnion { members: vec![] }); 603 | let id: Id = id.into(); 604 | id.into() 605 | } 606 | 607 | fn get_wasm_func_ref(m: &mut walrus::Module) -> walrus::FunctionId { 608 | for f in m.funcs.iter() { 609 | return f.id().into(); 610 | } 611 | 612 | walrus::FunctionBuilder::new(&mut m.types, &[], &[]) 613 | .finish(vec![], &mut m.funcs) 614 | .into() 615 | } 616 | 617 | fn get_wasm_func_type_ref(m: &mut walrus::Module) -> walrus::TypeId { 618 | m.types.add(&[], &[]) 619 | } 620 | 621 | fn get_binding_ref(b: &mut WebidlBindings, m: &mut walrus::Module) -> Id { 622 | let wasm_ty = get_wasm_func_type_ref(m); 623 | let webidl_ty = get_webidl_type_ref(b); 624 | let id: ImportBindingId = b.bindings.insert(ImportBinding { 625 | wasm_ty, 626 | webidl_ty, 627 | params: OutgoingBindingMap { bindings: vec![] }, 628 | result: IncomingBindingMap { bindings: vec![] }, 629 | }); 630 | let id: Id = id.into(); 631 | id.into() 632 | } 633 | 634 | macro_rules! assert_encoding { 635 | ( 636 | $( 637 | $name:ident( 638 | |$bindings:ident, $module:ident| $ast:expr, 639 | $expected:expr $(,)* 640 | ); 641 | )* 642 | ) => { 643 | $( 644 | #[test] 645 | #[allow(unused_variables)] 646 | fn $name() { 647 | let $bindings = &mut WebidlBindings::default(); 648 | let $module = &mut walrus::Module::default(); 649 | let ast = $ast; 650 | do_assert_encoding(ast, &$expected); 651 | } 652 | )* 653 | } 654 | } 655 | 656 | assert_encoding! { 657 | webidl_bindings_sec( 658 | |b, m| { 659 | let encode_into_result = b.types.insert(WebidlDictionary { 660 | fields: vec![ 661 | WebidlDictionaryField { 662 | name: "read".into(), 663 | ty: WebidlScalarType::UnsignedLongLong.into(), 664 | }, 665 | WebidlDictionaryField { 666 | name: "written".into(), 667 | ty: WebidlScalarType::UnsignedLongLong.into(), 668 | }, 669 | ], 670 | }); 671 | 672 | let encode_into = b.types.insert(WebidlFunction { 673 | kind: WebidlFunctionKind::Method(WebidlFunctionKindMethod { 674 | ty: WebidlScalarType::Any.into(), 675 | }), 676 | params: vec![ 677 | WebidlScalarType::UsvString.into(), 678 | WebidlScalarType::Uint8Array.into(), 679 | ], 680 | result: Some(encode_into_result.into()), 681 | }); 682 | 683 | let binding = b.bindings.insert(ImportBinding { 684 | wasm_ty: get_wasm_func_type_ref(m), 685 | webidl_ty: encode_into.into(), 686 | params: OutgoingBindingMap { 687 | bindings: vec![ 688 | OutgoingBindingExpression::As(OutgoingBindingExpressionAs { 689 | ty: WebidlScalarType::Any.into(), 690 | idx: 0 691 | }), 692 | OutgoingBindingExpression::As(OutgoingBindingExpressionAs { 693 | ty: WebidlScalarType::Any.into(), 694 | idx: 1 695 | }), 696 | OutgoingBindingExpression::View(OutgoingBindingExpressionView { 697 | ty: WebidlScalarType::Uint8Array.into(), 698 | offset: 2, 699 | length: 3 700 | }), 701 | ], 702 | }, 703 | result: IncomingBindingMap { 704 | bindings: vec![ 705 | IncomingBindingExpression::As(IncomingBindingExpressionAs { 706 | ty: walrus::ValType::I64, 707 | expr: Box::new(IncomingBindingExpression::Field( 708 | IncomingBindingExpressionField { 709 | idx: 0, 710 | expr: Box::new(IncomingBindingExpression::Get( 711 | IncomingBindingExpressionGet { idx: 0 }, 712 | )) 713 | } 714 | )) 715 | }), 716 | IncomingBindingExpression::As(IncomingBindingExpressionAs { 717 | ty: walrus::ValType::I64, 718 | expr: Box::new(IncomingBindingExpression::Field( 719 | IncomingBindingExpressionField { 720 | idx: 1, 721 | expr: Box::new(IncomingBindingExpression::Get( 722 | IncomingBindingExpressionGet { idx: 0 }, 723 | )), 724 | } 725 | )) 726 | }), 727 | ], 728 | } 729 | }); 730 | 731 | let func = get_wasm_func_ref(m); 732 | let binding: Id = binding.into(); 733 | b.binds.insert(Bind { 734 | func, 735 | binding, 736 | }); 737 | 738 | &*b 739 | }, 740 | { 741 | let section = vec![ 742 | // types subsection 743 | 0, 744 | // number of types 745 | 2, 746 | // dictionary type 747 | 1, 748 | // number of fields 749 | 2, 750 | // "read" 751 | 4, 114, 101, 97, 100, 752 | 118, 753 | // "written" 754 | 7, 119, 114, 105, 116, 116, 101, 110, 755 | 118, 756 | // function type 757 | 0, 758 | // method 759 | 1, 127, 760 | // params 761 | 2, 111, 103, 762 | // result 763 | 1, 11, 764 | // bindings subsection 765 | 1, 766 | // number of bindings 767 | 1, 768 | // import 769 | 0, 770 | 44, 771 | 11, 772 | // params 773 | 3, 774 | // as 775 | 0, 127, 0, 776 | // as 777 | 0, 127, 1, 778 | // view 779 | 4, 103, 2, 3, 780 | // results 781 | 2, 782 | // as 783 | 1, 126, 784 | // field 785 | 5, 0, 786 | // get 787 | 0, 0, 788 | // as 789 | 1, 126, 790 | // field 791 | 5, 1, 792 | // get 793 | 0, 0, 794 | // number of binds 795 | 1, 796 | // bind 797 | 33, 22, 798 | ]; 799 | let mut bytes = vec![]; 800 | crate::version().to_string().encode(&mut TestIndices, &mut bytes) 801 | .expect("writing to a vec can't fail"); 802 | bytes.extend_from_slice(§ion); 803 | bytes 804 | }, 805 | ); 806 | 807 | webidl_type_function( 808 | |b, m| WebidlType { 809 | name: None, 810 | ty: WebidlCompoundType::Function(WebidlFunction { 811 | kind: WebidlFunctionKind::Static, 812 | params: vec![], 813 | result: None 814 | }), 815 | }, 816 | [ 817 | // Function kind 818 | 0, 819 | // Static kind 820 | 0, 821 | // Number of params 822 | 0, 823 | // Has result? 824 | 0, 825 | ] 826 | ); 827 | webidl_type_dictionary( 828 | |b, m| WebidlType { 829 | name: None, 830 | ty: WebidlCompoundType::Dictionary(WebidlDictionary { 831 | fields: vec![ 832 | WebidlDictionaryField { name: "first".into(), ty: get_webidl_type_ref(b), }, 833 | WebidlDictionaryField { name: "second".into(), ty: get_webidl_type_ref(b), }, 834 | ], 835 | }), 836 | }, 837 | [ 838 | // Dictionary type 839 | 1, 840 | // Number of fields 841 | 2, 842 | // "first" 843 | 5, 102, 105, 114, 115, 116, 844 | 11, 845 | // "second" 846 | 6, 115, 101, 99, 111, 110, 100, 847 | 11, 848 | ], 849 | ); 850 | webidl_type_enumeration( 851 | |b, m| WebidlType { 852 | name: None, 853 | ty: WebidlCompoundType::Enumeration(WebidlEnumeration { 854 | values: vec!["hi".into(), "bye".into()], 855 | }), 856 | }, 857 | [ 858 | // Enumeration type 859 | 2, 860 | // Number of values 861 | 2, 862 | // "hi" 863 | 2, 104, 105, 864 | // "bye" 865 | 3, 98, 121, 101, 866 | ] 867 | ); 868 | webidl_type_union( 869 | |b, m| WebidlType { 870 | name: None, 871 | ty: WebidlCompoundType::Union(WebidlUnion { 872 | members: vec![get_webidl_type_ref(b), get_webidl_type_ref(b)] 873 | }), 874 | }, 875 | [ 876 | // Union type 877 | 3, 878 | // Number of members 879 | 2, 880 | 11, 881 | 11, 882 | ] 883 | ); 884 | 885 | webidl_function_static( 886 | |b, m| WebidlFunction { 887 | kind: WebidlFunctionKind::Static, 888 | params: vec![], 889 | result: None 890 | }, 891 | [ 892 | // Static kind 893 | 0, 894 | // Number of params 895 | 0, 896 | // Has result? 897 | 0, 898 | ] 899 | ); 900 | webidl_function_method( 901 | |b, m| WebidlFunction { 902 | kind: WebidlFunctionKind::Method(WebidlFunctionKindMethod { 903 | ty: get_webidl_type_ref(b), 904 | }), 905 | params: vec![], 906 | result: None 907 | }, 908 | [ 909 | // Method kind 910 | 1, 911 | 11, 912 | // Number of params 913 | 0, 914 | // Has result? 915 | 0, 916 | ] 917 | ); 918 | webidl_function_constructor( 919 | |b, m| WebidlFunction { 920 | kind: WebidlFunctionKind::Constructor, 921 | params: vec![], 922 | result: None 923 | }, 924 | [ 925 | // Constructor kind 926 | 2, 927 | // Number of params 928 | 0, 929 | // Has result? 930 | 0, 931 | ] 932 | ); 933 | webidl_function_params( 934 | |b, m| WebidlFunction { 935 | kind: WebidlFunctionKind::Static, 936 | params: vec![get_webidl_type_ref(b), get_webidl_type_ref(b)], 937 | result: None 938 | }, 939 | [ 940 | // Static kind 941 | 0, 942 | // Number of params 943 | 2, 944 | 11, 945 | 11, 946 | // Has result? 947 | 0, 948 | ] 949 | ); 950 | webidl_function_result( 951 | |b, m| WebidlFunction { 952 | kind: WebidlFunctionKind::Static, 953 | params: vec![], 954 | result: Some(get_webidl_type_ref(b)), 955 | }, 956 | [ 957 | // Static kind 958 | 0, 959 | // Number of params 960 | 0, 961 | // Has result? 962 | 1, 963 | 11, 964 | ] 965 | ); 966 | 967 | webidl_dictionary( 968 | |b, m| WebidlDictionary { 969 | fields: vec![ 970 | WebidlDictionaryField { name: "first".into(), ty: get_webidl_type_ref(b), }, 971 | WebidlDictionaryField { name: "second".into(), ty: get_webidl_type_ref(b), }, 972 | ], 973 | }, 974 | [ 975 | // Number of fields 976 | 2, 977 | // "first" 978 | 5, 102, 105, 114, 115, 116, 979 | 11, 980 | // "second" 981 | 6, 115, 101, 99, 111, 110, 100, 982 | 11, 983 | ], 984 | ); 985 | 986 | webidl_enumeration( 987 | |b, m| WebidlEnumeration { 988 | values: vec!["a".into(), "b".into(), "c".into()], 989 | }, 990 | [ 991 | // Number of values 992 | 3, 993 | // "a" 994 | 1, 97, 995 | // "b" 996 | 1, 98, 997 | // "c" 998 | 1, 99, 999 | ], 1000 | ); 1001 | 1002 | webidl_union( 1003 | |b, m| WebidlUnion { 1004 | members: vec![get_webidl_type_ref(b), get_webidl_type_ref(b)], 1005 | }, 1006 | [ 1007 | // Number of members 1008 | 2, 1009 | 11, 1010 | 11, 1011 | ], 1012 | ); 1013 | 1014 | function_binding_export( 1015 | |b, m| FunctionBinding::Export(ExportBinding { 1016 | wasm_ty: get_wasm_func_type_ref(m), 1017 | webidl_ty: get_webidl_type_ref(b), 1018 | params: IncomingBindingMap { bindings: vec![] }, 1019 | result: OutgoingBindingMap { bindings: vec![] }, 1020 | }), 1021 | [ 1022 | // export binding 1023 | 1, 1024 | // wasm_ty 1025 | 44, 1026 | // webidl_ty 1027 | 11, 1028 | // 0 params 1029 | 0, 1030 | // 0 results 1031 | 0, 1032 | ], 1033 | ); 1034 | 1035 | function_binding_import( 1036 | |b, m| FunctionBinding::Import(ImportBinding { 1037 | wasm_ty: get_wasm_func_type_ref(m), 1038 | webidl_ty: get_webidl_type_ref(b), 1039 | params: OutgoingBindingMap { bindings: vec![] }, 1040 | result: IncomingBindingMap { bindings: vec![] }, 1041 | }), 1042 | [ 1043 | // import binding 1044 | 0, 1045 | // wasm_ty 1046 | 44, 1047 | // webidl_ty 1048 | 11, 1049 | // 0 params 1050 | 0, 1051 | // 0 results 1052 | 0, 1053 | ], 1054 | ); 1055 | 1056 | outgoing_binding_map( 1057 | |b, m| OutgoingBindingMap { 1058 | bindings: vec![ 1059 | OutgoingBindingExpression::As(OutgoingBindingExpressionAs { 1060 | ty: get_webidl_type_ref(b), 1061 | idx: 1, 1062 | }), 1063 | OutgoingBindingExpression::As(OutgoingBindingExpressionAs { 1064 | ty: get_webidl_type_ref(b), 1065 | idx: 2, 1066 | }), 1067 | ] 1068 | }, 1069 | [ 1070 | // Number of expresssions 1071 | 2, 1072 | // as 1073 | 0, 1074 | 11, 1075 | // idx 1076 | 1, 1077 | // as 1078 | 0, 1079 | 11, 1080 | // idx 1081 | 2, 1082 | ], 1083 | ); 1084 | 1085 | outgoing_binding_expression_as( 1086 | |b, m| OutgoingBindingExpression::As(OutgoingBindingExpressionAs { 1087 | ty: get_webidl_type_ref(b), 1088 | idx: 2, 1089 | }), 1090 | [ 1091 | // as 1092 | 0, 1093 | 11, 1094 | // idx 1095 | 2, 1096 | ], 1097 | ); 1098 | outgoing_binding_expression_utf8_str( 1099 | |b, m| OutgoingBindingExpression::Utf8Str(OutgoingBindingExpressionUtf8Str { 1100 | ty: get_webidl_type_ref(b), 1101 | offset: 3, 1102 | length: 4, 1103 | }), 1104 | [ 1105 | // utf8-str 1106 | 1, 1107 | // get_webidl_type_ref(b) 1108 | 11, 1109 | // offset 1110 | 3, 1111 | // length 1112 | 4, 1113 | ], 1114 | ); 1115 | outgoing_binding_expression_utf8_cstr( 1116 | |b, m| OutgoingBindingExpression::Utf8CStr(OutgoingBindingExpressionUtf8CStr { 1117 | ty: get_webidl_type_ref(b), 1118 | offset: 99, 1119 | }), 1120 | [ 1121 | // utf8-cstr 1122 | 2, 1123 | 11, 1124 | // offset 1125 | 99, 1126 | ], 1127 | ); 1128 | outgoing_binding_expression_i32_to_enum( 1129 | |b, m| OutgoingBindingExpression::I32ToEnum(OutgoingBindingExpressionI32ToEnum { 1130 | ty: get_webidl_type_ref(b), 1131 | idx: 4, 1132 | }), 1133 | [ 1134 | // i32-to-enum 1135 | 3, 1136 | 11, 1137 | // idx 1138 | 4, 1139 | ], 1140 | ); 1141 | outgoing_binding_expression_view( 1142 | |b, m| OutgoingBindingExpression::View(OutgoingBindingExpressionView { 1143 | ty: get_webidl_type_ref(b), 1144 | offset: 1, 1145 | length: 2, 1146 | }), 1147 | [ 1148 | // view 1149 | 4, 1150 | 11, 1151 | // offset 1152 | 1, 1153 | // length 1154 | 2, 1155 | ], 1156 | ); 1157 | outgoing_binding_expression_copy( 1158 | |b, m| OutgoingBindingExpression::Copy(OutgoingBindingExpressionCopy { 1159 | ty: get_webidl_type_ref(b), 1160 | offset: 1, 1161 | length: 2, 1162 | }), 1163 | [ 1164 | // copy 1165 | 5, 1166 | 11, 1167 | // offset 1168 | 1, 1169 | // length 1170 | 2, 1171 | ], 1172 | ); 1173 | outgoing_binding_expression_dict( 1174 | |b, m| OutgoingBindingExpression::Dict(OutgoingBindingExpressionDict { 1175 | ty: get_webidl_type_ref(b), 1176 | fields: vec![ 1177 | OutgoingBindingExpression::As(OutgoingBindingExpressionAs { 1178 | ty: get_webidl_type_ref(b), 1179 | idx: 2, 1180 | }), 1181 | ], 1182 | }), 1183 | [ 1184 | // dict 1185 | 6, 1186 | 11, 1187 | // Number of fields 1188 | 1, 1189 | // as 1190 | 0, 1191 | 11, 1192 | 2 1193 | ], 1194 | ); 1195 | outgoing_binding_expression_bind_export( 1196 | |b, m| OutgoingBindingExpression::BindExport(OutgoingBindingExpressionBindExport { 1197 | ty: get_webidl_type_ref(b), 1198 | binding: get_binding_ref(b, m), 1199 | idx: 3, 1200 | }), 1201 | [ 1202 | // bind-export 1203 | 7, 1204 | 11, 1205 | 22, 1206 | 3, 1207 | ], 1208 | ); 1209 | 1210 | incoming_binding_map( 1211 | |b, m| IncomingBindingMap { 1212 | bindings: vec![ 1213 | IncomingBindingExpression::Get(IncomingBindingExpressionGet { idx: 1 }), 1214 | IncomingBindingExpression::Get(IncomingBindingExpressionGet { idx: 2 }), 1215 | IncomingBindingExpression::Get(IncomingBindingExpressionGet { idx: 3 }), 1216 | ], 1217 | }, 1218 | [ 1219 | // Number of expressions 1220 | 3, 1221 | // get 1222 | 0, 1, 1223 | // get 1224 | 0, 2, 1225 | // get 1226 | 0, 3 1227 | ], 1228 | ); 1229 | 1230 | incoming_binding_expression_get( 1231 | |b, m| IncomingBindingExpression::Get(IncomingBindingExpressionGet { idx: 1 }), 1232 | [ 1233 | // get 1234 | 0, 1235 | 1, 1236 | ] 1237 | ); 1238 | incoming_binding_expression_as( 1239 | |b, m| IncomingBindingExpression::As(IncomingBindingExpressionAs { 1240 | ty: walrus::ValType::I32, 1241 | expr: Box::new(IncomingBindingExpression::Get(IncomingBindingExpressionGet { 1242 | idx: 2, 1243 | })), 1244 | }), 1245 | [ 1246 | // as 1247 | 1, 0x7f, 1248 | // get 1249 | 0, 2, 1250 | ], 1251 | ); 1252 | incoming_binding_expression_alloc_utf8_str( 1253 | |b, m| IncomingBindingExpression::AllocUtf8Str(IncomingBindingExpressionAllocUtf8Str { 1254 | alloc_func_name: "malloc".into(), 1255 | expr: Box::new(IncomingBindingExpression::Get(IncomingBindingExpressionGet { 1256 | idx: 1, 1257 | })), 1258 | }), 1259 | [ 1260 | // alloc-utf8-str 1261 | 2, 1262 | // "malloc" 1263 | 6, 109, 97, 108, 108, 111, 99, 1264 | // get 1265 | 0, 1266 | 1 1267 | ], 1268 | ); 1269 | incoming_binding_expression_alloc_copy( 1270 | |b, m| IncomingBindingExpression::AllocCopy(IncomingBindingExpressionAllocCopy { 1271 | alloc_func_name: "malloc".into(), 1272 | expr: Box::new(IncomingBindingExpression::Get(IncomingBindingExpressionGet { 1273 | idx: 1, 1274 | })), 1275 | }), 1276 | [ 1277 | // alloc-copy 1278 | 3, 1279 | // "malloc" 1280 | 6, 109, 97, 108, 108, 111, 99, 1281 | // get 1282 | 0, 1283 | 1 1284 | ], 1285 | ); 1286 | incoming_binding_expression_enum_to_i32( 1287 | |b, m| IncomingBindingExpression::EnumToI32(IncomingBindingExpressionEnumToI32 { 1288 | ty: get_webidl_type_ref(b), 1289 | expr: Box::new(IncomingBindingExpression::Get(IncomingBindingExpressionGet { 1290 | idx: 2, 1291 | })), 1292 | }), 1293 | [ 1294 | // enum-to-i32 1295 | 4, 1296 | 11, 1297 | // get 1298 | 0, 1299 | 2, 1300 | ], 1301 | ); 1302 | incoming_binding_expression_field( 1303 | |b, m| IncomingBindingExpression::Field(IncomingBindingExpressionField { 1304 | idx: 1, 1305 | expr: Box::new(IncomingBindingExpression::Get(IncomingBindingExpressionGet { 1306 | idx: 2, 1307 | })), 1308 | }), 1309 | [ 1310 | // field 1311 | 5, 1312 | 1, 1313 | // get 1314 | 0, 1315 | 2, 1316 | ], 1317 | ); 1318 | incoming_binding_expression_bind_import( 1319 | |b, m| IncomingBindingExpression::BindImport(IncomingBindingExpressionBindImport { 1320 | ty: get_wasm_func_type_ref(m), 1321 | binding: get_binding_ref(b, m), 1322 | expr: Box::new(IncomingBindingExpression::Get(IncomingBindingExpressionGet { 1323 | idx: 3, 1324 | })), 1325 | }), 1326 | [ 1327 | // bind-import 1328 | 6, 1329 | 44, 1330 | 22, 1331 | // get 1332 | 0, 1333 | 3 1334 | ], 1335 | ); 1336 | 1337 | bind( 1338 | |b, m| Bind { 1339 | func: get_wasm_func_ref(m), 1340 | binding: get_binding_ref(b, m), 1341 | }, 1342 | [33, 22], 1343 | ); 1344 | 1345 | webidl_type_ref(|b, m| get_webidl_type_ref(b), [11]); 1346 | } 1347 | } 1348 | -------------------------------------------------------------------------------- /src/binary/mod.rs: -------------------------------------------------------------------------------- 1 | mod decode; 2 | mod encode; 3 | 4 | use self::decode::{Decode, DecodeContext}; 5 | use self::encode::{Encode, EncodeContext}; 6 | use crate::ast::WebidlBindings; 7 | use std::io; 8 | 9 | /// Encode the given Web IDL bindings section into the given write-able. 10 | pub fn encode( 11 | section: &WebidlBindings, 12 | indices: &walrus::IdsToIndices, 13 | into: &mut W, 14 | ) -> io::Result<()> 15 | where 16 | W: io::Write, 17 | { 18 | let cx = &mut EncodeContext::new(indices); 19 | section.encode(cx, into) 20 | } 21 | 22 | /// Decode the Web IDL bindings custom section data from the given input stream. 23 | /// 24 | /// This does *not* parse the custom section discriminant and "webidl-bindings" 25 | /// custom section name, just the inner data. 26 | pub fn decode(ids: &walrus::IndicesToIds, from: &[u8]) -> anyhow::Result { 27 | let mut cx = DecodeContext::new(ids); 28 | let mut from = from; 29 | WebidlBindings::decode(&mut cx, &mut from)?; 30 | Ok(cx.webidl_bindings) 31 | } 32 | 33 | /// Callback for `walrus::ModuleConfig::on_parse` to parse the webidl bindings 34 | /// custom section if one is found. 35 | pub fn on_parse(module: &mut walrus::Module, ids: &walrus::IndicesToIds) -> anyhow::Result<()> { 36 | let section = match module.customs.remove_raw("webidl-bindings") { 37 | Some(s) => s, 38 | None => return Ok(()), 39 | }; 40 | let bindings = decode(ids, §ion.data)?; 41 | module.customs.add(bindings); 42 | Ok(()) 43 | } 44 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | **Read, write, and manipulate the Wasm WebIDL bindings custom section.** 4 | 5 | [![](https://docs.rs/wasm-webidl-bindings/badge.svg)](https://docs.rs/wasm-webidl-bindings/) 6 | [![](https://img.shields.io/crates/v/wasm-webidl-bindings.svg)](https://crates.io/crates/wasm-webidl-bindings) 7 | [![](https://img.shields.io/crates/d/wasm-webidl-bindings.svg)](https://crates.io/crates/wasm-webidl-bindings) 8 | 9 | ## What's Inside 10 | 11 | * A parser for the straw proposal text format. See `crates/text-parser/src/grammar.lalrpop`. 12 | 13 | * A set of AST types for representing and manipulating WebIDL bindings. See 14 | `src/ast.rs`. 15 | 16 | * An encoder and decoder for the straw proposal binary format. See the 17 | implementation at `src/binary/encode.rs` and details on the format at 18 | `BINARY.md`. 19 | 20 | ## Example 21 | 22 | ### Parsing the Text Format and Encoding it in the Binary Format 23 | 24 | ```rust 25 | #[cfg(feature = "text")] 26 | # fn foo() -> anyhow::Result<()> { 27 | use wasm_webidl_bindings::{binary, text}; 28 | 29 | // Get the `walrus::Module` that this webidl-bindings section is for. 30 | // 31 | // The Wasm type and func that are being bound are: 32 | // 33 | // (type $EncodeIntoFuncWasm 34 | // (param anyref anyref i32 i32) 35 | // (result i64 i64)) 36 | // 37 | // (func $encodeInto 38 | // (import "TextEncoder" "encodeInto") 39 | // (type $EncodeIntoFuncWasm)) 40 | # let get_wasm_buffer_from_somewhere = || unimplemented!(); 41 | let raw_wasm: Vec = get_wasm_buffer_from_somewhere(); 42 | 43 | let mut config = walrus::ModuleConfig::default(); 44 | 45 | // Register a function to run after the module is parsed, but with access to the 46 | // mapping from indices in the original Wasm binary to their newly assigned 47 | // walrus IDs. 48 | // 49 | // This is where we will parse the Web IDL bindings text. 50 | config.on_parse(|module, indices_to_ids| { 51 | let webidl_bindings = text::parse(module, indices_to_ids, r#" 52 | type $TextEncoderEncodeIntoResult 53 | (dict 54 | (field "read" unsigned long long) 55 | (field "written" unsigned long long)) 56 | 57 | type $EncodeIntoFuncWebIDL 58 | (func (method any) 59 | (param USVString Uint8Array) 60 | (result $TextEncoderEncodeIntoResult)) 61 | 62 | func-binding $encodeIntoBinding import $EncodeIntoFuncWasm $EncodeIntoFuncWebIDL 63 | (param 64 | (as any 0) 65 | (as any 1) 66 | (view Int8Array 2 3)) 67 | (result 68 | (as i64 (field 0 (get 0))) 69 | (as i64 (field 1 (get 0)))) 70 | 71 | bind $encodeInto $encodeIntoBinding 72 | "#)?; 73 | 74 | println!("The parsed Web IDL bindings are {:#?}", webidl_bindings); 75 | 76 | // Insert the `webidl_bindings` into the module as a custom section. 77 | module.customs.add(webidl_bindings); 78 | 79 | Ok(()) 80 | }); 81 | 82 | let mut module = config.parse(&raw_wasm)?; 83 | 84 | // Reserialize the Wasm module along with its new Web IDL bindings 85 | // section. 86 | let new_raw_wasm = module.emit_wasm(); 87 | # let _ = new_raw_wasm; 88 | # Ok(()) 89 | # } 90 | ``` 91 | 92 | */ 93 | #![deny(missing_debug_implementations)] 94 | 95 | pub mod ast; 96 | pub mod binary; 97 | #[cfg(feature = "text")] 98 | pub mod text; 99 | 100 | #[cfg(feature = "quickcheck")] 101 | mod quickcheck; 102 | 103 | fn version() -> &'static str { 104 | env!("CARGO_PKG_VERSION") 105 | } 106 | -------------------------------------------------------------------------------- /src/quickcheck.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::*; 2 | use quickcheck::{Arbitrary, Gen}; 3 | use rand::{seq::IteratorRandom, Rng}; 4 | 5 | impl Arbitrary for WebidlBindings { 6 | fn arbitrary(g: &mut G) -> Self { 7 | let mut wb = WebidlBindings::default(); 8 | wb.arbitrary_types(g); 9 | wb.arbitrary_function_bindings(g); 10 | wb.arbitrary_binds(g); 11 | wb 12 | } 13 | } 14 | 15 | impl WebidlBindings { 16 | fn arbitrary_types(&mut self, g: &mut impl Gen) { 17 | for _ in 0..g.size() { 18 | match g.gen_range(0, 4) { 19 | 0 => { 20 | // Function. 21 | self.arbitrary_webidl_function(g); 22 | } 23 | 1 => { 24 | // Dictionary. 25 | self.arbitrary_webidl_dictionary(g); 26 | } 27 | 2 => { 28 | // Enumeration. 29 | self.arbitrary_webidl_enumeration(g); 30 | } 31 | 3 => { 32 | // Union. 33 | self.arbitrary_webidl_union(g); 34 | } 35 | _ => unreachable!(), 36 | } 37 | } 38 | } 39 | 40 | fn arbitrary_webidl_function(&mut self, g: &mut impl Gen) { 41 | let kind = match g.gen_range(0, 3) { 42 | 0 => WebidlFunctionKind::Static, 43 | 1 => WebidlFunctionKind::Method(WebidlFunctionKindMethod { 44 | ty: WebidlScalarType::Any.into(), 45 | }), 46 | 2 => WebidlFunctionKind::Constructor, 47 | _ => unreachable!(), 48 | }; 49 | 50 | let params: Vec<_> = (0..g.size()) 51 | .map(|_| self.arbitrary_webidl_type_ref(g)) 52 | .collect(); 53 | 54 | let result = if g.gen() { 55 | Some(self.arbitrary_webidl_type_ref(g)) 56 | } else { 57 | None 58 | }; 59 | 60 | self.types.insert(WebidlFunction { 61 | kind, 62 | params, 63 | result, 64 | }); 65 | } 66 | 67 | fn arbitrary_webidl_type_ref(&mut self, g: &mut impl Gen) -> WebidlTypeRef { 68 | if self.types.arena.len() == 0 || g.gen() { 69 | // Scalar type. 70 | match g.gen_range(0, 30) { 71 | 0 => WebidlScalarType::Any.into(), 72 | 1 => WebidlScalarType::Boolean.into(), 73 | 2 => WebidlScalarType::Byte.into(), 74 | 3 => WebidlScalarType::Octet.into(), 75 | 4 => WebidlScalarType::Long.into(), 76 | 5 => WebidlScalarType::UnsignedLong.into(), 77 | 6 => WebidlScalarType::Short.into(), 78 | 7 => WebidlScalarType::UnsignedShort.into(), 79 | 8 => WebidlScalarType::LongLong.into(), 80 | 9 => WebidlScalarType::UnsignedLongLong.into(), 81 | 10 => WebidlScalarType::Float.into(), 82 | 11 => WebidlScalarType::UnrestrictedFloat.into(), 83 | 12 => WebidlScalarType::Double.into(), 84 | 13 => WebidlScalarType::UnrestrictedDouble.into(), 85 | 14 => WebidlScalarType::DomString.into(), 86 | 15 => WebidlScalarType::ByteString.into(), 87 | 16 => WebidlScalarType::UsvString.into(), 88 | 17 => WebidlScalarType::Object.into(), 89 | 18 => WebidlScalarType::Symbol.into(), 90 | 19 => WebidlScalarType::ArrayBuffer.into(), 91 | 20 => WebidlScalarType::DataView.into(), 92 | 21 => WebidlScalarType::Int8Array.into(), 93 | 22 => WebidlScalarType::Int16Array.into(), 94 | 23 => WebidlScalarType::Int32Array.into(), 95 | 24 => WebidlScalarType::Uint8Array.into(), 96 | 25 => WebidlScalarType::Uint16Array.into(), 97 | 26 => WebidlScalarType::Uint32Array.into(), 98 | 27 => WebidlScalarType::Uint8ClampedArray.into(), 99 | 28 => WebidlScalarType::Float32Array.into(), 100 | 29 => WebidlScalarType::Float64Array.into(), 101 | _ => unreachable!(), 102 | } 103 | } else { 104 | // Reference to an existing compound type. 105 | self.types 106 | .arena 107 | .iter() 108 | .map(|(id, _)| id) 109 | .choose(g) 110 | .unwrap() 111 | .into() 112 | } 113 | } 114 | 115 | fn arbitrary_webidl_dictionary(&mut self, g: &mut impl Gen) { 116 | let fields: Vec<_> = (0..g.size()) 117 | .map(|_| { 118 | let name = String::arbitrary(g); 119 | let ty = self.arbitrary_webidl_type_ref(g); 120 | WebidlDictionaryField { name, ty } 121 | }) 122 | .collect(); 123 | 124 | self.types.insert(WebidlDictionary { fields }); 125 | } 126 | 127 | fn arbitrary_webidl_enumeration(&mut self, g: &mut impl Gen) { 128 | let values: Vec<_> = (0..g.size()).map(|_| String::arbitrary(g)).collect(); 129 | self.types.insert(WebidlEnumeration { values }); 130 | } 131 | 132 | fn arbitrary_webidl_union(&mut self, g: &mut impl Gen) { 133 | let members: Vec<_> = (0..g.size()) 134 | .map(|_| self.arbitrary_webidl_type_ref(g)) 135 | .collect(); 136 | self.types.insert(WebidlUnion { members }); 137 | } 138 | 139 | fn arbitrary_function_bindings(&mut self, _g: &mut impl Gen) { 140 | // TODO: we don't actually generate any of these because we need to get 141 | // `walrus::TypeId`s which means we need access to the `walrus::Module`. 142 | } 143 | 144 | fn arbitrary_binds(&mut self, _g: &mut impl Gen) { 145 | // TODO: same story! We don't actually generate any bind statements here 146 | // because we need access to a wasm module in order to get ahold of ids 147 | // pointing to its functions. 148 | } 149 | } 150 | 151 | #[cfg(test)] 152 | mod tests { 153 | use crate::ast::WebidlBindings; 154 | 155 | quickcheck::quickcheck! { 156 | fn can_encode_and_decode_arbitrary_webidl_bindings(section: WebidlBindings) -> () { 157 | let mut module = walrus::Module::default(); 158 | module.customs.add(section); 159 | let buf = module.emit_wasm(); 160 | 161 | let mut config = walrus::ModuleConfig::default(); 162 | config.on_parse(|module, ids| { 163 | let raw = module.customs.remove_raw("webidl-bindings") 164 | .expect("the webidl-bindings custom section should have been emitted"); 165 | crate::binary::decode(ids, &raw.data) 166 | .expect("should decode webidl-bindings section OK"); 167 | Ok(()) 168 | }); 169 | config.parse(&buf).expect("should parse the wasm OK"); 170 | } 171 | 172 | fn doesnt_panic_on_arbitrary_bytes(data: Vec) -> () { 173 | let mut module = walrus::Module::default(); 174 | module.customs.add(walrus::RawCustomSection { 175 | name: "webidl-bindings".into(), 176 | data, 177 | }); 178 | let wasm_buf = module.emit_wasm(); 179 | 180 | let mut config = walrus::ModuleConfig::default(); 181 | config.on_parse(|module, ids| { 182 | let raw = module.customs.remove_raw("webidl-bindings").unwrap(); 183 | 184 | // This should never panic regardless what is in `data`. 185 | let _ = crate::binary::decode(ids, &raw.data); 186 | 187 | Ok(()) 188 | }); 189 | config.parse(&wasm_buf).unwrap(); 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/text.rs: -------------------------------------------------------------------------------- 1 | //! Working with the text format. 2 | 3 | pub use wasm_webidl_bindings_text_parser::*; 4 | 5 | /// Parse the given straw proposal text format input into an AST. 6 | pub fn parse( 7 | module: &walrus::Module, 8 | indices_to_ids: &walrus::IndicesToIds, 9 | input: &str, 10 | ) -> anyhow::Result { 11 | let mut bindings = crate::ast::WebidlBindings::default(); 12 | let mut actions = crate::ast::BuildAstActions::new(&mut bindings, module, indices_to_ids); 13 | parse_with_actions(&mut actions, input)?; 14 | Ok(bindings) 15 | } 16 | -------------------------------------------------------------------------------- /tests/readme_up_to_date.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::process::Command; 3 | 4 | #[test] 5 | fn cargo_readme_up_to_date() { 6 | println!("Checking that `cargo readme > README.md` is up to date..."); 7 | 8 | let expected = Command::new("cargo") 9 | .arg("readme") 10 | .current_dir(env!("CARGO_MANIFEST_DIR")) 11 | .output() 12 | .expect("should run `cargo readme` OK") 13 | .stdout; 14 | let expected = String::from_utf8_lossy(&expected); 15 | 16 | let actual = fs::read_to_string(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md")) 17 | .expect("should read README.md OK"); 18 | 19 | if actual != expected { 20 | panic!("Run `cargo readme > README.md` to update README.md"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/tests.rs: -------------------------------------------------------------------------------- 1 | 2 | --------------------------------------------------------------------------------