use crate::{
Enum, Flags, Ident, Interface, InterfaceItem, Package, PackageName, Params, Record, Resource,
ResourceFunc, Result_, Results, StandaloneFunc, Tuple, Type, TypeDef, TypeDefKind, Variant,
World, WorldItem,
};
use id_arena::Id;
use wit_parser::PackageId;
pub fn packages_from_parsed(resolve: &wit_parser::Resolve) -> Vec<Package> {
let converter = Converter::new(resolve);
converter.convert()
}
struct Converter<'a> {
resolve: &'a wit_parser::Resolve,
}
impl<'a> Converter<'a> {
fn new(resolve: &'a wit_parser::Resolve) -> Self {
Self { resolve }
}
fn convert(&self) -> Vec<Package> {
self.resolve
.packages
.iter()
.map(|(p_id, p)| self.convert_package(p_id, p))
.collect()
}
fn convert_package(&self, package_id: PackageId, package: &wit_parser::Package) -> Package {
let mut output = Package::new(self.convert_package_name(&package.name));
for (_, id) in &package.interfaces {
let interface = self.resolve.interfaces.get(*id).unwrap();
output.interface(self.convert_interface(
package_id,
interface,
None,
wit_parser::TypeOwner::Interface(*id),
));
}
for (_, id) in &package.worlds {
let world = self.resolve.worlds.get(*id).unwrap();
output.world(self.convert_world(package_id, world, wit_parser::TypeOwner::World(*id)));
}
output
}
fn convert_package_name(&self, package: &wit_parser::PackageName) -> PackageName {
PackageName::new(
package.namespace.clone(),
package.name.clone(),
package.version.clone(),
)
}
fn convert_world(
&self,
package_id: PackageId,
world: &wit_parser::World,
owner: wit_parser::TypeOwner,
) -> World {
let mut output = World::new(world.name.clone());
for (key, item) in &world.imports {
match item {
wit_parser::WorldItem::Interface { id, .. } => {
let interface = self.resolve.interfaces.get(*id).unwrap();
let ident = self.interface_ident(package_id, Some(key), interface);
if interface.name.is_some() {
output.item(WorldItem::named_interface_import(ident))
} else {
output.item(WorldItem::inline_interface_import(self.convert_interface(
package_id,
interface,
Some(ident),
owner,
)))
}
}
wit_parser::WorldItem::Function(func) => {
if let Some(func) = self.standalone_func_convert(func) {
output.item(WorldItem::function_import(func));
}
}
wit_parser::WorldItem::Type(type_id) => {
let (target, item, rename) = self.convert_world_item_type(package_id, *type_id);
output.use_type(target, item, rename)
}
}
}
for (key, item) in &world.exports {
match item {
wit_parser::WorldItem::Interface { id, .. } => {
let interface = self.resolve.interfaces.get(*id).unwrap();
let ident = self.interface_ident(package_id, Some(key), interface);
if interface.name.is_some() {
output.item(WorldItem::named_interface_export(ident));
} else {
output.item(WorldItem::inline_interface_export(self.convert_interface(
package_id,
interface,
Some(ident),
owner,
)));
}
}
wit_parser::WorldItem::Function(func) => {
if let Some(func) = self.standalone_func_convert(func) {
output.item(WorldItem::function_export(func));
}
}
wit_parser::WorldItem::Type(type_id) => {
let (target, item, rename) = self.convert_world_item_type(package_id, *type_id);
output.use_type(target, item, rename)
}
}
}
output.uses_mut().sort();
output.items_mut().sort();
output
}
fn convert_world_item_type(
&self,
package_id: PackageId,
type_id: wit_parser::TypeId,
) -> (Ident, Ident, Option<Ident>) {
let type_def = self.resolve.types.get(type_id).unwrap();
let underlying_type_def = self.underlying_type_def(&type_def);
let interface_ident = self
.type_def_owner_interface_ident(package_id, underlying_type_def)
.expect("Type not part of an interface");
let local_type_name = type_def.name.clone().unwrap();
let underlying_local_type_name = underlying_type_def.name.clone().unwrap();
if underlying_local_type_name == local_type_name {
(interface_ident, local_type_name.into(), None)
} else {
(
interface_ident,
underlying_local_type_name.into(),
Some(local_type_name.into()),
)
}
}
fn convert_interface(
&self,
package_id: PackageId,
interface: &wit_parser::Interface,
inlined_name: Option<Ident>,
owner: wit_parser::TypeOwner,
) -> Interface {
let mut output =
Interface::new(interface.name.clone().map(Ident::new).unwrap_or_else(|| {
inlined_name
.clone()
.expect("inlined interface must pass in inlined_name")
}));
for (_, func) in &interface.functions {
if let Some(func) = self.standalone_func_convert(func) {
output.items.push(InterfaceItem::Function(func));
}
}
for (_, type_id) in &interface.types {
let type_def = self.resolve.types.get(*type_id).unwrap();
let underlying_type_def = self.underlying_type_def(&type_def);
if underlying_type_def.owner == owner {
if let Some(type_def) = self.convert_type_def(type_def, *type_id) {
output.item(InterfaceItem::TypeDef(type_def));
}
} else {
let interface_ident = self
.type_def_owner_interface_ident(package_id, underlying_type_def)
.expect("Type not part of an interface");
let local_type_name = type_def.name.clone().unwrap();
let underlying_local_type_name = underlying_type_def.name.clone().unwrap();
if underlying_local_type_name == local_type_name {
output.use_type(interface_ident, local_type_name, None);
} else {
output.use_type(
interface_ident,
underlying_local_type_name,
Some(local_type_name.into()),
);
}
}
}
output.uses_mut().sort();
output.items_mut().sort();
output
}
fn convert_type_def(
&self,
type_def: &wit_parser::TypeDef,
type_def_id: Id<wit_parser::TypeDef>,
) -> Option<TypeDef> {
match &type_def.name {
None => None,
Some(name) => {
let kind = match &type_def.kind {
wit_parser::TypeDefKind::Record(record) => {
let output = self.convert_record(record);
TypeDefKind::Record(output)
}
wit_parser::TypeDefKind::Resource => {
let output = self.convert_resource(type_def_id, name, &type_def.owner);
TypeDefKind::Resource(output)
}
wit_parser::TypeDefKind::Flags(flags) => {
let output = self.convert_flags(flags);
TypeDefKind::Flags(output)
}
wit_parser::TypeDefKind::Variant(variant) => {
let output = self.convert_variant(variant);
TypeDefKind::Variant(output)
}
wit_parser::TypeDefKind::Enum(enum_) => {
let output = self.convert_enum(enum_);
TypeDefKind::Enum(output)
}
wit_parser::TypeDefKind::Future(ty) => {
TypeDefKind::Type(Type::future(self.convert_option_type(ty)))
}
wit_parser::TypeDefKind::Stream(ty) => {
TypeDefKind::Type(Type::stream(self.convert_type(ty)))
}
wit_parser::TypeDefKind::ErrorContext => TypeDefKind::Type(Type::ErrorContext),
wit_parser::TypeDefKind::Option(ty) => {
let output = Type::option(self.convert_type(ty));
TypeDefKind::Type(output)
}
wit_parser::TypeDefKind::List(ty) => {
let output = Type::list(self.convert_type(ty));
TypeDefKind::Type(output)
}
wit_parser::TypeDefKind::Handle(handle) => {
let output = self.handle_to_type(handle);
TypeDefKind::Type(output)
}
wit_parser::TypeDefKind::Result(result) => {
let output = Type::result(self.convert_result(result));
TypeDefKind::Type(output)
}
wit_parser::TypeDefKind::Tuple(tuple) => {
let output = Type::Tuple(self.convert_tuple(tuple));
TypeDefKind::Type(output)
}
wit_parser::TypeDefKind::Type(ty) => {
let output = self.convert_type(ty);
TypeDefKind::Type(output)
}
wit_parser::TypeDefKind::Unknown => unreachable!(),
};
Some(TypeDef::new(name.clone(), kind))
}
}
}
fn convert_option_type(&self, ty: &Option<wit_parser::Type>) -> Option<Type> {
ty.as_ref().map(|ty| self.convert_type(ty))
}
fn convert_type(&self, type_: &wit_parser::Type) -> Type {
match type_ {
wit_parser::Type::Bool => Type::Bool,
wit_parser::Type::U8 => Type::U8,
wit_parser::Type::U16 => Type::U16,
wit_parser::Type::U32 => Type::U32,
wit_parser::Type::U64 => Type::U64,
wit_parser::Type::S8 => Type::S8,
wit_parser::Type::S16 => Type::S16,
wit_parser::Type::S32 => Type::S32,
wit_parser::Type::S64 => Type::S64,
wit_parser::Type::F32 => Type::F32,
wit_parser::Type::F64 => Type::F64,
wit_parser::Type::Char => Type::Char,
wit_parser::Type::String => Type::String,
wit_parser::Type::Id(id) => {
let type_def = self.resolve.types.get(*id).expect("Type not found");
match &type_def.name {
Some(name) => Type::named(name.clone()),
None => match &type_def.kind {
wit_parser::TypeDefKind::Tuple(tuple) => {
Type::Tuple(self.convert_tuple(tuple))
}
wit_parser::TypeDefKind::Option(type_) => {
Type::option(self.convert_type(type_))
}
wit_parser::TypeDefKind::Result(result) => {
Type::result(self.convert_result(result))
}
wit_parser::TypeDefKind::List(type_) => {
Type::list(self.convert_type(type_))
}
wit_parser::TypeDefKind::Handle(handle) => self.handle_to_type(handle),
wit_parser::TypeDefKind::Future(type_) => {
Type::future(self.convert_option_type(type_))
}
wit_parser::TypeDefKind::Stream(type_) => {
Type::stream(self.convert_type(type_))
}
wit_parser::TypeDefKind::ErrorContext => Type::ErrorContext,
wit_parser::TypeDefKind::Record(_)
| wit_parser::TypeDefKind::Resource
| wit_parser::TypeDefKind::Flags(_)
| wit_parser::TypeDefKind::Variant(_)
| wit_parser::TypeDefKind::Enum(_)
| wit_parser::TypeDefKind::Type(_) => {
panic!("type doesn't have a name, and can't be inlined")
}
wit_parser::TypeDefKind::Unknown => unreachable!(),
},
}
}
}
}
fn convert_enum(&self, enum_: &wit_parser::Enum) -> Enum {
let mut output = Enum::empty();
for case in &enum_.cases {
output.case(case.name.clone())
}
output
}
fn convert_record(&self, record: &wit_parser::Record) -> Record {
Record::new(record.fields.iter().map(|field| {
let name = field.name.clone();
let type_ = self.convert_type(&field.ty);
(name, type_)
}))
}
fn convert_variant(&self, variant: &wit_parser::Variant) -> Variant {
let mut output = Variant::empty();
for case in &variant.cases {
match &case.ty {
Some(ty) => {
let ty = self.convert_type(ty);
output.case((case.name.clone(), ty))
}
None => output.case((case.name.clone(),)),
}
}
output
}
fn convert_flags(&self, flags: &wit_parser::Flags) -> Flags {
Flags::new(flags.flags.iter().map(|flag| (flag.name.clone(),)))
}
fn convert_resource(
&self,
resource_id: Id<wit_parser::TypeDef>,
name: &str,
owner: &wit_parser::TypeOwner,
) -> Resource {
let functions = match owner {
wit_parser::TypeOwner::World(_) => {
todo!("Enable once win-encoder supports `include`")
}
wit_parser::TypeOwner::Interface(id) => {
&self.resolve.interfaces.get(*id).unwrap().functions
}
wit_parser::TypeOwner::None => panic!("Resource has to have an owner"),
};
let mut output = Resource::empty();
for (_, func) in functions {
if let Some(method) = self.convert_resource_func(resource_id, name, func) {
output.func(method);
}
}
output
}
fn convert_resource_func(
&self,
resource_id: Id<wit_parser::TypeDef>,
resource_name: &str,
func: &wit_parser::Function,
) -> Option<ResourceFunc> {
let mut skip_first_param = false;
let mut with_returns = true;
let mut method = match func.kind {
wit_parser::FunctionKind::Freestanding => return None,
wit_parser::FunctionKind::Method(id) => {
if id != resource_id {
return None;
}
skip_first_param = true;
let name = clean_func_name(resource_name, &func.name);
ResourceFunc::method(name)
}
wit_parser::FunctionKind::Static(id) => {
if id != resource_id {
return None;
}
let name = clean_func_name(resource_name, &func.name);
ResourceFunc::static_(name)
}
wit_parser::FunctionKind::Constructor(id) => {
if id != resource_id {
return None;
}
with_returns = false;
ResourceFunc::constructor()
}
};
method.set_params(self.convert_params(&func.params));
if skip_first_param {
method.params_mut().items_mut().remove(0);
}
if with_returns {
method.set_results(self.convert_results(&func.results));
}
Some(method)
}
fn standalone_func_convert(&self, func: &wit_parser::Function) -> Option<StandaloneFunc> {
match func.kind {
wit_parser::FunctionKind::Method(_)
| wit_parser::FunctionKind::Static(_)
| wit_parser::FunctionKind::Constructor(_) => None,
wit_parser::FunctionKind::Freestanding => {
let mut output = StandaloneFunc::new(func.name.clone());
output.set_params(self.convert_params(&func.params));
output.set_results(self.convert_results(&func.results));
Some(output)
}
}
}
fn convert_params(&self, params: &wit_parser::Params) -> Params {
let mut output = Params::empty();
for (name, ty) in params.iter() {
let name = name.to_string();
let ty = self.convert_type(ty);
output.push(name, ty);
}
output
}
fn convert_results(&self, results: &wit_parser::Results) -> Results {
match results {
wit_parser::Results::Named(named) => Results::named(named.iter().map(|(name, ty)| {
let ty = self.convert_type(ty);
(name.to_owned(), ty)
})),
wit_parser::Results::Anon(ty) => Results::Anon(self.convert_type(ty)),
}
}
fn handle_to_type(&self, handle: &wit_parser::Handle) -> Type {
let id = match handle {
wit_parser::Handle::Own(id) => id,
wit_parser::Handle::Borrow(id) => id,
};
let type_def = self.resolve.types.get(*id).expect("Type not found");
let name = type_def
.name
.clone()
.expect("Handles should only be for resources, and resources should have names");
match handle {
wit_parser::Handle::Own(_) => Type::named(name),
wit_parser::Handle::Borrow(_) => Type::borrow(name),
}
}
fn convert_result(&self, result: &wit_parser::Result_) -> Result_ {
match (&result.ok, &result.err) {
(None, None) => Result_::empty(),
(Some(ok), None) => Result_::ok(self.convert_type(ok)),
(None, Some(err)) => Result_::err(self.convert_type(err)),
(Some(ok), Some(err)) => Result_::both(self.convert_type(ok), self.convert_type(err)),
}
}
fn convert_tuple(&self, tuple: &wit_parser::Tuple) -> Tuple {
let mut output = Tuple::empty();
for ty in tuple.types.iter() {
output.types_mut().push(self.convert_type(ty));
}
output
}
fn interface_ident(
&self,
package_id: PackageId,
world_key: Option<&wit_parser::WorldKey>,
interface: &wit_parser::Interface,
) -> Ident {
match &interface.name {
Some(name) => {
if interface.package == Some(package_id) {
Ident::new(name.clone())
} else {
let package = interface
.package
.map(|package_id| self.resolve.packages.get(package_id).unwrap());
match package {
Some(package) => Ident::new(format!(
"{}:{}/{}{}",
package.name.namespace,
package.name.name,
name,
package
.name
.version
.as_ref()
.map(|version| format!("@{}", version))
.unwrap_or_else(|| "".to_string())
)),
None => Ident::new(name.clone()),
}
}
}
None => match world_key {
Some(world_key) => match world_key {
wit_parser::WorldKey::Name(name) => Ident::new(name.clone()),
wit_parser::WorldKey::Interface(_) => {
unreachable!("inlined interface must have a world key name")
}
},
None => panic!("inlined interface requires a world key"),
},
}
}
fn underlying_type_def(&'a self, type_def: &'a wit_parser::TypeDef) -> &'a wit_parser::TypeDef {
match &type_def.kind {
wit_parser::TypeDefKind::Type(type_) => match &type_ {
wit_parser::Type::Id(type_id) => {
let type_def = self.resolve.types.get(*type_id).unwrap();
type_def
}
_ => type_def,
},
_ => type_def,
}
}
fn type_def_owner_interface_ident(
&self,
package_id: PackageId,
type_def: &wit_parser::TypeDef,
) -> Option<Ident> {
if let wit_parser::TypeOwner::Interface(id) = type_def.owner {
Some(self.interface_ident(package_id, None, self.resolve.interfaces.get(id).unwrap()))
} else {
None
}
}
}
fn clean_func_name(resource_name: &str, method_name: &str) -> String {
const METHOD_PREFIX: &str = "[method]";
const STATIC_PREFIX: &str = "[static]";
let method_name = method_name
.strip_prefix(METHOD_PREFIX)
.unwrap_or(method_name);
let method_name = method_name
.strip_prefix(STATIC_PREFIX)
.unwrap_or(method_name);
let method_name = method_name.strip_prefix(resource_name).unwrap();
let method_name = method_name.strip_prefix(".").unwrap();
method_name.to_string()
}