Skip to content

Commit 834679b

Browse files
authored
Enable more than one handle type in *.witx (#421)
This commit reworks how handle types work at the representation level in `*.witx` file to follow the expected design of resources in the interface types specification. Previously handle types were simply `(handle)`, which meant that there could only be one actual handle type in the world (structurally at least). After this commit, however, there can be multiple handle types. First abstract types must be introduced as a `resource`, for example: (resource $fd) This declares that the module exports a type named `$fd` and it's abstract in that the representation is not known. At the interface layer you can't pass an `$fd` directly because it's representation is not known. To do that, however, you can do: (param $x (handle $fd)) The `handle` type now refers to a particular `resource` that it refers to. Values of type `handle T` can exist and are what's passed at the boundaries. This is all largely just an internal structuring concern at this point. This has no ramifications for WASI which still has an `$fd` type for functions that is represented with an `i32`. This is largely a forward-looking change to allow multiple types of resources defined by different modules and all used by one another. This commit also updates `use` syntax where `use` will pull from either the type or the resource namespace. Furthermore a new `(use ($foo as $bar) ...)` syntax was added to locally renamed something within a module.
1 parent fc3da39 commit 834679b

File tree

13 files changed

+252
-48
lines changed

13 files changed

+252
-48
lines changed

phases/ephemeral/witx/typenames.witx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,9 @@
281281
)
282282
)
283283

284+
(resource $fd)
284285
;;; A file descriptor handle.
285-
(typename $fd (handle))
286+
(typename $fd (handle $fd))
286287

287288
;;; A region of memory for scatter/gather reads.
288289
(typename $iovec

phases/old/snapshot_0/witx/typenames.witx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,9 @@
273273
)
274274
)
275275

276+
(resource $fd)
276277
;;; A file descriptor handle.
277-
(typename $fd (handle))
278+
(typename $fd (handle $fd))
278279

279280
;;; A region of memory for scatter/gather reads.
280281
(typename $iovec

phases/snapshot/witx/typenames.witx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,9 @@
273273
)
274274
)
275275

276+
(resource $fd)
276277
;;; A file descriptor handle.
277-
(typename $fd (handle))
278+
(typename $fd (handle $fd))
278279

279280
;;; A region of memory for scatter/gather reads.
280281
(typename $iovec

tools/witx/src/ast.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ pub struct Module {
4545
types: Vec<Rc<NamedType>>,
4646
type_map: HashMap<Id, Rc<NamedType>>,
4747

48+
resources: Vec<Rc<Resource>>,
49+
resource_map: HashMap<Id, Rc<Resource>>,
50+
4851
funcs: Vec<Rc<Function>>,
4952
func_map: HashMap<Id, Rc<Function>>,
5053

@@ -61,6 +64,8 @@ impl Module {
6164
module_id,
6265
types: Default::default(),
6366
type_map: Default::default(),
67+
resources: Default::default(),
68+
resource_map: Default::default(),
6469
funcs: Default::default(),
6570
func_map: Default::default(),
6671
constants: Default::default(),
@@ -80,6 +85,14 @@ impl Module {
8085
self.types.push(ty);
8186
}
8287

88+
pub(crate) fn push_resource(&mut self, r: Rc<Resource>) {
89+
assert!(self
90+
.resource_map
91+
.insert(r.name.clone(), r.clone())
92+
.is_none());
93+
self.resources.push(r);
94+
}
95+
8396
pub(crate) fn push_func(&mut self, func: Rc<Function>) {
8497
assert!(self
8598
.func_map
@@ -100,6 +113,14 @@ impl Module {
100113
self.types.iter()
101114
}
102115

116+
pub fn resource(&self, name: &Id) -> Option<Rc<Resource>> {
117+
self.resource_map.get(name).cloned()
118+
}
119+
120+
pub fn resources<'a>(&'a self) -> impl Iterator<Item = &'a Rc<Resource>> + 'a {
121+
self.resources.iter()
122+
}
123+
103124
/// All of the (unique) types used as "err" variant of results returned from
104125
/// functions.
105126
pub fn error_types<'a>(&'a self) -> impl Iterator<Item = TypeRef> + 'a {
@@ -499,11 +520,37 @@ impl Case {
499520
}
500521

501522
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
502-
pub struct HandleDatatype {}
523+
pub struct Resource {
524+
/// The local name within the module this resource is defined within. This
525+
/// may differ from the id of the resource itself.
526+
pub name: Id,
527+
/// The unique id assigned to this resource.
528+
pub resource_id: ResourceId,
529+
/// Documentation in the defining module, if any.
530+
pub docs: String,
531+
}
532+
533+
/// A unique id used to determine whether two handles are nominally referring
534+
/// to the same resource.
535+
///
536+
/// An id is composed of the definition location (a module id) and the original
537+
/// name within that module.
538+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
539+
pub struct ResourceId {
540+
pub name: Id,
541+
pub module_id: ModuleId,
542+
}
543+
544+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
545+
pub struct HandleDatatype {
546+
/// The resource that this handle references, used for determining if two
547+
/// handle types are nominally equal to one another.
548+
pub resource_id: ResourceId,
549+
}
503550

504551
impl HandleDatatype {
505-
pub fn type_equal(&self, _other: &HandleDatatype) -> bool {
506-
true
552+
pub fn type_equal(&self, other: &HandleDatatype) -> bool {
553+
self.resource_id == other.resource_id
507554
}
508555
}
509556

tools/witx/src/parser.rs

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@ mod kw {
3434
wast::custom_keyword!(noreturn);
3535
wast::custom_keyword!(pointer);
3636
wast::custom_keyword!(record);
37+
wast::custom_keyword!(r#as = "as");
3738
wast::custom_keyword!(r#const = "const");
3839
wast::custom_keyword!(r#enum = "enum");
3940
wast::custom_keyword!(r#union = "union");
4041
wast::custom_keyword!(r#use = "use");
4142
wast::custom_keyword!(repr);
43+
wast::custom_keyword!(resource);
4244
wast::custom_keyword!(s16);
4345
wast::custom_keyword!(s32);
4446
wast::custom_keyword!(s64);
@@ -227,6 +229,7 @@ impl<'a> Parse<'a> for TopLevelModule<'a> {
227229
if parser.peek2::<kw::r#use>()
228230
|| parser.peek2::<annotation::witx>()
229231
|| parser.peek2::<kw::typename>()
232+
|| parser.peek2::<kw::resource>()
230233
{
231234
decls.push(Documented {
232235
comments,
@@ -279,6 +282,7 @@ impl<'a> Parse<'a> for TopLevelSyntax<'a> {
279282
#[derive(Debug, Clone)]
280283
pub enum DeclSyntax<'a> {
281284
Typename(TypenameSyntax<'a>),
285+
Resource(ResourceSyntax<'a>),
282286
Const(Documented<'a, ConstSyntax<'a>>),
283287
}
284288

@@ -289,6 +293,8 @@ impl<'a> Parse<'a> for DeclSyntax<'a> {
289293
Ok(DeclSyntax::Typename(parser.parse()?))
290294
} else if l.peek::<annotation::witx>() {
291295
Ok(DeclSyntax::Const(parser.parse()?))
296+
} else if l.peek::<kw::resource>() {
297+
Ok(DeclSyntax::Resource(parser.parse()?))
292298
} else {
293299
Err(l.error())
294300
}
@@ -313,7 +319,7 @@ impl<'a> Parse<'a> for UseSyntax<'a> {
313319

314320
#[derive(Debug, Clone, PartialEq, Eq)]
315321
pub enum UsedNames<'a> {
316-
List(Vec<wast::Id<'a>>),
322+
List(Vec<UseName<'a>>),
317323
All(wast::Span),
318324
}
319325

@@ -333,6 +339,32 @@ impl<'a> Parse<'a> for UsedNames<'a> {
333339
}
334340
}
335341

342+
#[derive(Debug, Clone, PartialEq, Eq)]
343+
pub struct UseName<'a> {
344+
pub other_name: wast::Id<'a>,
345+
pub our_name: wast::Id<'a>,
346+
}
347+
348+
impl<'a> Parse<'a> for UseName<'a> {
349+
fn parse(parser: Parser<'a>) -> Result<Self> {
350+
let (other_name, our_name) = if parser.peek::<wast::Id>() {
351+
let name = parser.parse()?;
352+
(name, name)
353+
} else {
354+
parser.parens(|p| {
355+
let other_name = p.parse()?;
356+
p.parse::<kw::r#as>()?;
357+
let our_name = p.parse()?;
358+
Ok((other_name, our_name))
359+
})?
360+
};
361+
Ok(UseName {
362+
other_name,
363+
our_name,
364+
})
365+
}
366+
}
367+
336368
#[derive(Debug, Clone, PartialEq, Eq)]
337369
pub struct TypenameSyntax<'a> {
338370
pub ident: wast::Id<'a>,
@@ -357,7 +389,7 @@ pub enum TypedefSyntax<'a> {
357389
Record(RecordSyntax<'a>),
358390
Union(UnionSyntax<'a>),
359391
Variant(VariantSyntax<'a>),
360-
Handle(HandleSyntax),
392+
Handle(HandleSyntax<'a>),
361393
List(Box<TypedefSyntax<'a>>),
362394
Pointer(Box<TypedefSyntax<'a>>),
363395
ConstPointer(Box<TypedefSyntax<'a>>),
@@ -521,6 +553,19 @@ impl<'a> Parse<'a> for ConstSyntax<'a> {
521553
}
522554
}
523555

556+
#[derive(Debug, Clone, PartialEq, Eq)]
557+
pub struct ResourceSyntax<'a> {
558+
pub ident: wast::Id<'a>,
559+
}
560+
561+
impl<'a> Parse<'a> for ResourceSyntax<'a> {
562+
fn parse(parser: Parser<'a>) -> Result<Self> {
563+
parser.parse::<kw::resource>()?;
564+
let ident = parser.parse()?;
565+
Ok(ResourceSyntax { ident })
566+
}
567+
}
568+
524569
#[derive(Debug, Clone, PartialEq, Eq)]
525570
pub struct FlagsSyntax<'a> {
526571
pub repr: Option<BuiltinType>,
@@ -656,12 +701,15 @@ impl<'a> Parse<'a> for CaseSyntax<'a> {
656701
}
657702

658703
#[derive(Debug, Clone, PartialEq, Eq)]
659-
pub struct HandleSyntax {}
704+
pub struct HandleSyntax<'a> {
705+
pub resource: wast::Id<'a>,
706+
}
660707

661-
impl<'a> Parse<'a> for HandleSyntax {
708+
impl<'a> Parse<'a> for HandleSyntax<'a> {
662709
fn parse(parser: Parser<'a>) -> Result<Self> {
663710
parser.parse::<kw::handle>()?;
664-
Ok(HandleSyntax {})
711+
let resource = parser.parse()?;
712+
Ok(HandleSyntax { resource })
665713
}
666714
}
667715

tools/witx/src/toplevel.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -165,19 +165,4 @@ mod test {
165165
e => panic!("wrong error: {:?}", e),
166166
}
167167
}
168-
169-
#[test]
170-
fn use_invalid() {
171-
match parse_witx_with("/a", &MockFs::new(&[("/a", "(use bbbbbbb)")]))
172-
.err()
173-
.unwrap()
174-
{
175-
WitxError::Parse(e) => {
176-
let err = e.to_string();
177-
assert!(err.contains("expected an identifier"), "bad error: {}", err);
178-
assert!(err.contains("/a:1:6"));
179-
}
180-
e => panic!("wrong error: {:?}", e),
181-
}
182-
}
183168
}

0 commit comments

Comments
 (0)