Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/wit-component/src/encoding/wit/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ impl InterfaceEncoder<'_> {
let iface = &self.resolve.interfaces[interface];
let mut type_order = IndexSet::new();
for (_, id) in iface.types.iter() {
let ty = &self.resolve.types[*id];
if let TypeOwner::Interface(iface_id) = ty.owner {
self.interface = Some(iface_id);
}
self.encode_valtype(self.resolve, &Type::Id(*id))?;
type_order.insert(*id);
}
Expand Down
60 changes: 59 additions & 1 deletion crates/wit-component/src/encoding/wit/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ impl InterfaceEncoder<'_> {
let iface = &self.resolve.interfaces[interface];
let mut type_order = IndexSet::new();
for (_, id) in iface.types.iter() {
let ty = &self.resolve.types[*id];
if let TypeOwner::Interface(iface_id) = ty.owner {
self.interface = Some(iface_id);
}
self.encode_valtype(self.resolve, &Type::Id(*id))?;
type_order.insert(*id);
}
Expand Down Expand Up @@ -218,14 +222,68 @@ impl InterfaceEncoder<'_> {
.unwrap()
.export(name, ComponentTypeRef::Func(ty));
}
let instance = self.pop_instance();
let mut instance = self.pop_instance();
self.encode_nested(iface, &mut instance)?;

let idx = self.outer.type_count();
self.outer.ty().instance(&instance);
self.import_map.insert(interface, self.instances);
self.instances += 1;
Ok(idx)
}

fn encode_nested<'a>(
&'a mut self,
iface: &Interface,
instance: &'a mut InstanceType,
) -> Result<&mut InstanceType> {
for (nest_name, nest_item) in &iface.nested {
let package_id = self
.resolve
.package_names
.get(&nest_item.package_name)
.unwrap();
let package = &self.resolve.packages[*package_id];
let nested = package.interfaces.get(&nest_item.iface_name).unwrap();
let nested_iface = &self.resolve.interfaces[*nested];
let mut inst = InterfaceEncoder::new(&self.resolve);
inst.push_instance();
for (_, id) in &nested_iface.types {
let ty = &self.resolve.types[*id];
if let TypeOwner::Interface(iface_id) = ty.owner {
inst.interface = Some(iface_id);
}
inst.encode_valtype(self.resolve, &Type::Id(*id))?;
}
let ty = instance.ty();
let nested_instance = &mut inst.pop_instance();
for (nest_name, deep_nest) in &nested_iface.nested {
let deep_pkg_id = self
.resolve
.package_names
.get(&deep_nest.package_name)
.unwrap();
let deep_package = &self.resolve.packages[*deep_pkg_id];
let deep_iface_id = deep_package.interfaces.get(&deep_nest.iface_name).unwrap();
let deep_nest = &self.resolve.interfaces[*deep_iface_id];
let mut clone = nested_instance.clone();
let deep_instance = self.encode_nested(deep_nest, &mut clone)?;
let deep_ty = nested_instance.ty();
deep_ty.instance(&deep_instance);
nested_instance.export(
nest_name,
ComponentTypeRef::Instance(deep_instance.type_count()),
);
}
ty.instance(&nested_instance);
instance.export(
nest_name,
ComponentTypeRef::Instance(instance.type_count() - 1),
);
}
Ok(instance)
}

fn push_instance(&mut self) {
assert!(self.ty.is_none());
assert!(self.saved_types.is_none());
Expand Down
10 changes: 9 additions & 1 deletion crates/wit-component/src/printing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl WitPrinter {
}

if has_multiple_packages {
self.output.push_str("{");
self.output.push_str("{\n");
self.output.indent += 1
} else {
self.print_semicolon();
Expand All @@ -82,6 +82,14 @@ impl WitPrinter {
self.output.push_str("interface ");
self.print_name(name);
self.output.push_str(" {\n");
let nested = &resolve.interfaces[*id].nested;
for item in nested {
self.print_stability(&item.1.stability);
self.print_docs(&item.1.docs);
self.output.push_str("nest ");
self.print_name(item.0);
self.output.push_str(";\n")
}
self.print_interface(resolve, *id)?;
writeln!(&mut self.output, "}}\n")?;
}
Expand Down
2 changes: 1 addition & 1 deletion crates/wit-component/tests/interfaces/doc-comments.wat
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
)
)
(export (;5;) "coverage-world" (type 4))
(@custom "package-docs" "\00{\22docs\22:\22package docs;\22,\22worlds\22:{\22coverage-world\22:{\22docs\22:\22world docs\22,\22interfaces\22:{\22i\22:{\22docs\22:\22world inline interface docs\22,\22funcs\22:{\22f\22:\22inline interface func docs\22},\22types\22:{\22t\22:{\22docs\22:\22inline interface typedef docs\22}}}},\22types\22:{\22t\22:{\22docs\22:\22world typedef docs\22}},\22funcs\22:{\22imp\22:\22world func import docs\22,\22exp\22:\22world func export docs\22}}},\22interfaces\22:{\22coverage-iface\22:{\22docs\22:\22interface docs\22,\22funcs\22:{\22[constructor]res\22:\22constructor docs\22,\22[method]res.m\22:\22method docs\22,\22[static]res.s\22:\22static func docs\22,\22f\22:\22interface func docs\22},\22types\22:{\22t\22:{\22docs\22:\22basic typedef docs\22},\22r\22:{\22docs\22:\22record typedef docs\22,\22items\22:{\22f1\22:\22record field docs\22}},\22fl\22:{\22items\22:{\22f1\22:\22flag docs\22}},\22v\22:{\22items\22:{\22c1\22:\22variant case docs\22}},\22e\22:{\22items\22:{\22c1\22:\22enum case docs\22}}}},\22other-comment-forms\22:{\22docs\22:\22other comment forms\5cn multi-line block\22,\22funcs\22:{\22multiple-lines-split\22:\22one doc line\5cnnon-doc in the middle\5cnanother doc line\22,\22mixed-forms\22:\22mixed forms; line doc\5cnplus block doc\5cn multi-line\22}}}}")
(@custom "package-docs" "\00{\22docs\22:\22package docs;\22,\22worlds\22:{\22coverage-world\22:{\22docs\22:\22world docs\22,\22interfaces\22:{\22i\22:{\22docs\22:\22world inline interface docs\22,\22funcs\22:{\22f\22:\22inline interface func docs\22},\22types\22:{\22t\22:{\22docs\22:\22inline interface typedef docs\22}},\22nested\22:{}}},\22types\22:{\22t\22:{\22docs\22:\22world typedef docs\22}},\22funcs\22:{\22imp\22:\22world func import docs\22,\22exp\22:\22world func export docs\22}}},\22interfaces\22:{\22coverage-iface\22:{\22docs\22:\22interface docs\22,\22funcs\22:{\22[constructor]res\22:\22constructor docs\22,\22[method]res.m\22:\22method docs\22,\22[static]res.s\22:\22static func docs\22,\22f\22:\22interface func docs\22},\22types\22:{\22t\22:{\22docs\22:\22basic typedef docs\22},\22r\22:{\22docs\22:\22record typedef docs\22,\22items\22:{\22f1\22:\22record field docs\22}},\22fl\22:{\22items\22:{\22f1\22:\22flag docs\22}},\22v\22:{\22items\22:{\22c1\22:\22variant case docs\22}},\22e\22:{\22items\22:{\22c1\22:\22enum case docs\22}}},\22nested\22:{}},\22other-comment-forms\22:{\22docs\22:\22other comment forms\5cn multi-line block\22,\22funcs\22:{\22multiple-lines-split\22:\22one doc line\5cnnon-doc in the middle\5cnanother doc line\22,\22mixed-forms\22:\22mixed forms; line doc\5cnplus block doc\5cn multi-line\22},\22nested\22:{}}}}")
(@producers
(processed-by "wit-component" "$CARGO_PKG_VERSION")
)
Expand Down
40 changes: 40 additions & 0 deletions crates/wit-component/tests/interfaces/nested.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
(component
(type (;0;)
(component
(type (;0;)
(instance
(type (;0;) (record (field "foo" string)))
(export (;1;) "my-record" (type (eq 0)))
(type (;2;) (func (result string)))
(export (;0;) "hello" (func (type 2)))
(type (;3;)
(instance
(type (;0;) (record (field "foo" string)))
(export (;1;) "nest-record" (type (eq 0)))
(type (;2;)
(instance
(type (;0;) (record (field "foo" string)))
(export (;1;) "nest-record" (type (eq 0)))
)
)
(export (;0;) "foo:nestnest/deep" (instance (type 2)))
)
)
(export (;0;) "foo:nestee/[email protected]" (instance (type 3)))
(type (;4;)
(instance
(export (;0;) "foo" (type (sub resource)))
)
)
(export (;1;) "foo:nestee/[email protected]" (instance (type 4)))
)
)
(export (;0;) "foo:thing/something" (instance (type 0)))
)
)
(export (;1;) "something" (type 0))
(@custom "package-docs" "\01{\22interfaces\22:{\22something\22:{\22types\22:{\22my-record\22:{\22stability\22:{\22stable\22:{\22since\22:\221.0.0\22}}}},\22nested\22:{\22foo:nestee/[email protected]\22:{\22docs\22:{\22contents\22:\22nesting can be documented\22},\22stability\22:\22unknown\22},\22foo:nestee/[email protected]\22:{\22docs\22:{\22contents\22:null},\22stability\22:{\22stable\22:{\22since\22:\221.0.0\22}}}}}}}")
(@producers
(processed-by "wit-component" "$CARGO_PKG_VERSION")
)
)
17 changes: 17 additions & 0 deletions crates/wit-component/tests/interfaces/nested/deps/nestee.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package foo:[email protected];

interface things {
//nesting can be documented
@since(version = 1.0.0)
nest foo:nestnest/deep;
record nest-record {
foo: string
}
hello: func() -> string;
}

interface more {
resource foo {
bar: func() -> option<string>;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package foo:nestnest;

interface deep {
record deep-record {
foo: string
}
}
14 changes: 14 additions & 0 deletions crates/wit-component/tests/interfaces/nested/nested.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package foo:thing;

interface something {
//nesting can be documented
nest foo:nestee/[email protected];
@since(version = 1.0.0)
nest foo:nestee/[email protected];
@since(version = 1.0.0)
record my-record {
foo: string
}

hello: func() -> string;
}
15 changes: 15 additions & 0 deletions crates/wit-component/tests/interfaces/nested/thing.wit.print
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package foo:thing;

interface something {
/// nesting can be documented
nest foo:nestee/[email protected];
@since(version = 1.0.0)
nest foo:nestee/[email protected];
@since(version = 1.0.0)
record my-record {
foo: string,
}

hello: func() -> string;
}

2 changes: 1 addition & 1 deletion crates/wit-component/tests/interfaces/resources.wat
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@
)
)
(export (;11;) "implicit-own-handles3" (type 10))
(@custom "package-docs" "\00{\22worlds\22:{\22implicit-own-handles3\22:{\22types\22:{\22a\22:{\22docs\22:\22there should only be one `list` type despite there looking like two\5cnlist types here\22}}}},\22interfaces\22:{\22implicit-own-handles2\22:{\22types\22:{\22a\22:{\22docs\22:\22the `own` return and list param should be the same `own`\22},\22b\22:{\22docs\22:\22same as above, even when the `list<b>` implicitly-defined `own` comes\5cnbefore an explicitly defined `own`\22},\22c\22:{\22docs\22:\22same as the above, the `own` argument should have the same type as the\5cnreturn value\22}}}}}")
(@custom "package-docs" "\00{\22worlds\22:{\22implicit-own-handles3\22:{\22types\22:{\22a\22:{\22docs\22:\22there should only be one `list` type despite there looking like two\5cnlist types here\22}}}},\22interfaces\22:{\22implicit-own-handles2\22:{\22types\22:{\22a\22:{\22docs\22:\22the `own` return and list param should be the same `own`\22},\22b\22:{\22docs\22:\22same as above, even when the `list<b>` implicitly-defined `own` comes\5cnbefore an explicitly defined `own`\22},\22c\22:{\22docs\22:\22same as the above, the `own` argument should have the same type as the\5cnreturn value\22}},\22nested\22:{}}}}")
(@producers
(processed-by "wit-component" "$CARGO_PKG_VERSION")
)
Expand Down
2 changes: 1 addition & 1 deletion crates/wit-component/tests/interfaces/wasi-http.wat

Large diffs are not rendered by default.

58 changes: 58 additions & 0 deletions crates/wit-parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,19 @@ impl<'a> DeclList<'a> {
}
Ok(())
}

fn for_each_nest<'b>(&'b self, mut f: impl FnMut(&'b Nest<'a>) -> Result<()>) -> Result<()> {
for item in self.items.iter() {
if let AstItem::Interface(i) = item {
for item in i.items.iter() {
if let InterfaceItem::Nest(n) = item {
f(n)?;
}
}
}
}
Ok(())
}
}

enum AstItem<'a> {
Expand Down Expand Up @@ -545,6 +558,48 @@ enum InterfaceItem<'a> {
TypeDef(TypeDef<'a>),
Func(NamedFunc<'a>),
Use(Use<'a>),
Nest(Nest<'a>),
}

struct Nest<'a> {
docs: Docs<'a>,
id: PackageName<'a>,
name: Id<'a>,
attributes: Vec<Attribute<'a>>,
}

impl<'a> Nest<'a> {
fn parse(
tokens: &mut Tokenizer<'a>,
docs: Docs<'a>,
attributes: Vec<Attribute<'a>>,
) -> Result<Self> {
tokens.eat(Token::Nest)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you'll want to expect here instead of eat (as eat has a boolean return)

let id = parse_id(tokens)?;
tokens.expect(Token::Colon)?;
// `foo:bar/[email protected]`
let namespace = id;
let pkg_name = parse_id(tokens)?;
tokens.expect(Token::Slash)?;
let name = parse_id(tokens)?;
let version = parse_opt_version(tokens)?;
tokens.expect_semicolon()?;
Ok(Self {
id: PackageName {
docs: Default::default(),
span: Span {
start: namespace.span.start,
end: pkg_name.span.end,
},
namespace,
name: pkg_name,
version,
},
docs,
name,
attributes,
})
}
}

struct Use<'a> {
Expand Down Expand Up @@ -983,6 +1038,9 @@ impl<'a> InterfaceItem<'a> {
NamedFunc::parse(tokens, docs, attributes).map(InterfaceItem::Func)
}
Some((_span, Token::Use)) => Use::parse(tokens, attributes).map(InterfaceItem::Use),
Some((_span, Token::Nest)) => {
Nest::parse(tokens, docs, attributes).map(InterfaceItem::Nest)
}
other => Err(err_expected(tokens, "`type`, `resource` or `func`", other).into()),
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/wit-parser/src/ast/lex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ pub enum Token {
As,
From_,
Static,
Nest,
Interface,
Tuple,
Import,
Expand Down Expand Up @@ -315,6 +316,7 @@ impl<'a> Tokenizer<'a> {
"as" => As,
"from" => From_,
"static" => Static,
"nest" => Nest,
"interface" => Interface,
"tuple" => Tuple,
"world" => World,
Expand Down Expand Up @@ -576,6 +578,7 @@ impl Token {
As => "keyword `as`",
From_ => "keyword `from`",
Static => "keyword `static`",
Nest => "keyword `nest`",
Interface => "keyword `interface`",
Tuple => "keyword `tuple`",
Import => "keyword `import`",
Expand Down
Loading