1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
use crate::ast::*; use crate::Error; mod expand; mod names; mod tyexpand; pub fn resolve<'a>(module: &mut Module<'a>) -> Result<Names<'a>, Error> { let fields = match &mut module.kind { ModuleKind::Text(fields) => fields, _ => return Ok(Default::default()), }; // First up, let's de-inline import/export annotations since this'll // restructure the module and affect how we count indices in future passes // since function definitions turn into imports. // // The first pass switches all inline imports to explicit `Import` items. // This pass also counts all `Import` items per-type to start building up // the index space so we know the corresponding index for each item. // // In a second pass we then remove all inline `export` annotations, again // counting indices as we go along to ensure we always know the index for // what we're exporting. // // The final step is then taking all of the injected `export` fields and // actually pushing them onto our list of fields. let mut expander = expand::Expander::default(); expander.process(fields, expand::Expander::deinline_import); expander.process(fields, expand::Expander::deinline_export); for i in 1..fields.len() { let span = match &fields[i] { ModuleField::Import(i) => i.span, _ => continue, }; let name = match &fields[i - 1] { ModuleField::Memory(_) => "memory", ModuleField::Func(_) => "function", ModuleField::Table(_) => "table", ModuleField::Global(_) => "global", _ => continue, }; return Err(Error::new(span, format!("import after {}", name))); } // For the second pass we resolve all inline type annotations. This will, in // the order that we see them, append to the list of types. Note that types // are indexed so we're careful to always insert new types just before the // field that we're looking at. // // It's not strictly required that we `move_types_first` here but it gets // our indexing to exactly match wabt's which our test suite is asserting. let mut cur = 0; let mut expander = tyexpand::Expander::default(); move_types_first(fields); while cur < fields.len() { expander.expand(&mut fields[cur]); for new in expander.to_prepend.drain(..) { fields.insert(cur, new); cur += 1; } cur += 1; } // Perform name resolution over all `Index` items to resolve them all to // indices instead of symbolic names. // // For this operation we do need to make sure that imports are sorted first // because otherwise we'll be calculating indices in the wrong order. move_imports_first(fields); let mut resolver = names::Resolver::default(); for field in fields.iter_mut() { resolver.register(field); } for field in fields.iter_mut() { resolver.resolve(field)?; } Ok(Names { resolver }) } fn move_imports_first(fields: &mut [ModuleField<'_>]) { fields.sort_by_key(|f| match f { ModuleField::Import(_) => false, _ => true, }); } fn move_types_first(fields: &mut [ModuleField<'_>]) { fields.sort_by_key(|f| match f { ModuleField::Type(_) => false, _ => true, }); } /// Representation of the results of name resolution for a module. /// /// This structure is returned from the /// [`Module::resolve`](crate::Module::resolve) function and can be used to /// resolve your own name arguments if you have any. #[derive(Default)] pub struct Names<'a> { resolver: names::Resolver<'a>, } impl<'a> Names<'a> { /// Resolves `idx` within the function namespace. /// /// If `idx` is a `Num`, it is ignored, but if it's an `Id` then it will be /// looked up in the function namespace and converted to a `Num`. If the /// `Id` is not defined then an error will be returned. pub fn resolve_func(&self, idx: &mut Index<'a>) -> Result<(), Error> { self.resolver.resolve_idx(idx, names::Ns::Func) } /// Resolves `idx` within the memory namespace. /// /// If `idx` is a `Num`, it is ignored, but if it's an `Id` then it will be /// looked up in the memory namespace and converted to a `Num`. If the /// `Id` is not defined then an error will be returned. pub fn resolve_memory(&self, idx: &mut Index<'a>) -> Result<(), Error> { self.resolver.resolve_idx(idx, names::Ns::Memory) } /// Resolves `idx` within the table namespace. /// /// If `idx` is a `Num`, it is ignored, but if it's an `Id` then it will be /// looked up in the table namespace and converted to a `Num`. If the /// `Id` is not defined then an error will be returned. pub fn resolve_table(&self, idx: &mut Index<'a>) -> Result<(), Error> { self.resolver.resolve_idx(idx, names::Ns::Table) } /// Resolves `idx` within the global namespace. /// /// If `idx` is a `Num`, it is ignored, but if it's an `Id` then it will be /// looked up in the global namespace and converted to a `Num`. If the /// `Id` is not defined then an error will be returned. pub fn resolve_global(&self, idx: &mut Index<'a>) -> Result<(), Error> { self.resolver.resolve_idx(idx, names::Ns::Global) } }