Skip to content

Commit b67b465

Browse files
committed
refactor: refactor import and factory generation
This commit refactors the import and factory generation code to a more modular approach. There are now two steps: 1. The import analysis step, which analyzes the imports in the world and generates a list of interfaces and standalone types in an intermediate representation. 2. The import code generation step, which takes the intermediate representation plus the WIT functions, and generates the Go code for the imports. The goal is to make the code more modular and easier to maintain and test. In doing so, some of the generated code is ever so slightly different from the original, but I've tried to keep the changes to an absolute minimum. Pretty much all that's changed is the order in which the `Close` method is generated, I hope.
1 parent 60b1af3 commit b67b465

15 files changed

Lines changed: 2813 additions & 1606 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/gravity/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ test = false
2727
[dependencies]
2828
clap = "=4.5.48"
2929
genco = "=0.18.1"
30+
indexmap = "2.11.4"
3031
wit-bindgen-core = "=0.46.0"
3132
wit-component = "=0.239.0"
3233

Lines changed: 52 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,49 @@
1+
use std::collections::BTreeMap;
2+
13
use genco::{prelude::*, tokens::Tokens};
2-
use wit_bindgen_core::wit_parser::{Record, Resolve, Type, TypeDef, TypeDefKind};
4+
use wit_bindgen_core::wit_parser::{Resolve, SizeAlign, World};
35

46
use crate::{
5-
codegen::wasm::{Wasm, WasmData},
6-
go::*,
7-
resolve_type,
7+
codegen::{
8+
FactoryGenerator,
9+
factory::FactoryConfig,
10+
imports::{ImportAnalyzer, ImportCodeGenerator},
11+
ir::AnalyzedImports,
12+
wasm::{Wasm, WasmData},
13+
},
14+
go::{GoIdentifier, GoImports},
815
};
916

1017
/// The WIT bindings for a world.
11-
pub struct Bindings {
18+
pub struct Bindings<'a> {
19+
resolve: &'a Resolve,
20+
world: &'a World,
1221
/// The cumulative output tokens containing the Go bindings.
1322
// TODO(#16): Don't use the internal bindings.out field
1423
pub out: Tokens<Go>,
1524

1625
/// The identifier of the Go variable containing the WebAssembly bytes.
1726
raw_wasm_var: GoIdentifier,
27+
28+
/// The Go imports for the bindings.
29+
go_imports: GoImports,
30+
31+
/// The sizes of the architecture.
32+
sizes: &'a SizeAlign,
1833
}
1934

20-
impl Bindings {
35+
impl<'a> Bindings<'a> {
2136
/// Creates a new bindings generator for the selected world.
22-
pub fn new(world: &str) -> Self {
23-
let wasm_var = GoIdentifier::private(format!("wasm-file-{world}"));
37+
pub fn new(resolve: &'a Resolve, world: &'a World, sizes: &'a SizeAlign) -> Self {
38+
let world_name = &world.name;
39+
let wasm_var = GoIdentifier::private(format!("wasm-file-{world_name}"));
2440
Self {
25-
// world,
41+
resolve,
42+
world,
2643
out: Tokens::new(),
2744
raw_wasm_var: wasm_var,
45+
go_imports: GoImports::new(),
46+
sizes,
2847
}
2948
}
3049

@@ -33,96 +52,31 @@ impl Bindings {
3352
Wasm::new(&self.raw_wasm_var, wasm).format_into(&mut self.out)
3453
}
3554

36-
pub fn define_type(&mut self, typ_def: &TypeDef, resolve: &Resolve) {
37-
let TypeDef { name, kind, .. } = typ_def;
38-
match kind {
39-
TypeDefKind::Record(Record { fields }) => {
40-
let name = GoIdentifier::public(name.as_deref().expect("record to have a name"));
41-
let fields = fields.iter().map(|field| {
42-
(
43-
GoIdentifier::public(&field.name),
44-
resolve_type(&field.ty, resolve),
45-
)
46-
});
47-
48-
quote_in! { self.out =>
49-
$['\n']
50-
type $name struct {
51-
$(for (name, typ) in fields join ($['\r']) => $name $typ)
52-
}
53-
}
54-
}
55-
TypeDefKind::Resource => todo!("TODO(#5): implement resources"),
56-
TypeDefKind::Handle(_) => todo!("TODO(#5): implement resources"),
57-
TypeDefKind::Flags(_) => todo!("TODO(#4):generate flags type definition"),
58-
TypeDefKind::Tuple(_) => todo!("TODO(#4):generate tuple type definition"),
59-
TypeDefKind::Variant(_) => {
60-
// TODO(#4): Generate aliases if the variant name doesn't match the struct name
61-
}
62-
TypeDefKind::Enum(inner) => {
63-
let name = name.clone().expect("enum to have a name");
64-
let enum_type = &GoIdentifier::private(&name);
65-
66-
let enum_interface = GoIdentifier::public(&name);
67-
68-
let enum_function = &GoIdentifier::private(format!("is-{}", &name));
55+
/// Generates the imports for the bindings.
56+
pub fn generate_imports(&mut self) -> (AnalyzedImports, BTreeMap<String, Tokens<Go>>) {
57+
let analyzer = ImportAnalyzer::new(self.resolve, self.world);
58+
let analyzed = analyzer.analyze();
6959

70-
let variants = inner
71-
.cases
72-
.iter()
73-
.map(|variant| GoIdentifier::public(&variant.name));
74-
75-
quote_in! { self.out =>
76-
$['\n']
77-
type $enum_interface interface {
78-
$enum_function()
79-
}
80-
81-
type $enum_type int
82-
83-
func ($enum_type) $enum_function() {}
60+
let generator =
61+
ImportCodeGenerator::new(self.resolve, &self.go_imports, &analyzed, self.sizes);
62+
let import_chains = generator.import_chains();
63+
generator.format_into(&mut self.out);
64+
(analyzed, import_chains)
65+
}
8466

85-
const (
86-
$(for name in variants join ($['\r']) => $name $enum_type = iota)
87-
)
88-
}
89-
}
90-
TypeDefKind::Option(_) => todo!("TODO(#4): generate option type definition"),
91-
TypeDefKind::Result(_) => todo!("TODO(#4): generate result type definition"),
92-
TypeDefKind::List(_) => todo!("TODO(#4): generate list type definition"),
93-
TypeDefKind::Future(_) => todo!("TODO(#4): generate future type definition"),
94-
TypeDefKind::Stream(_) => todo!("TODO(#4): generate stream type definition"),
95-
TypeDefKind::Type(Type::Id(_)) => {
96-
// TODO(#4): Only skip this if we have already generated the type
97-
}
98-
TypeDefKind::Type(Type::Bool) => todo!("TODO(#4): generate bool type alias"),
99-
TypeDefKind::Type(Type::U8) => todo!("TODO(#4): generate u8 type alias"),
100-
TypeDefKind::Type(Type::U16) => todo!("TODO(#4): generate u16 type alias"),
101-
TypeDefKind::Type(Type::U32) => todo!("TODO(#4): generate u32 type alias"),
102-
TypeDefKind::Type(Type::U64) => todo!("TODO(#4): generate u64 type alias"),
103-
TypeDefKind::Type(Type::S8) => todo!("TODO(#4): generate s8 type alias"),
104-
TypeDefKind::Type(Type::S16) => todo!("TODO(#4): generate s16 type alias"),
105-
TypeDefKind::Type(Type::S32) => todo!("TODO(#4): generate s32 type alias"),
106-
TypeDefKind::Type(Type::S64) => todo!("TODO(#4): generate s64 type alias"),
107-
TypeDefKind::Type(Type::F32) => todo!("TODO(#4): generate f32 type alias"),
108-
TypeDefKind::Type(Type::F64) => todo!("TODO(#4): generate f64 type alias"),
109-
TypeDefKind::Type(Type::Char) => todo!("TODO(#4): generate char type alias"),
110-
TypeDefKind::Type(Type::String) => {
111-
let name =
112-
GoIdentifier::public(name.as_deref().expect("string alias to have a name"));
113-
// TODO(#4): We might want a Type Definition (newtype) instead of Type Alias here
114-
quote_in! { self.out =>
115-
$['\n']
116-
type $name = string
117-
}
118-
}
119-
TypeDefKind::Type(Type::ErrorContext) => {
120-
todo!("TODO(#4): generate error context definition")
121-
}
122-
TypeDefKind::FixedSizeList(_, _) => {
123-
todo!("TODO(#4): generate fixed size list definition")
124-
}
125-
TypeDefKind::Unknown => panic!("cannot generate Unknown type"),
126-
}
67+
/// Generates the factory and instantiate functions, including any
68+
/// required interfaces.
69+
pub fn generate_factory(
70+
&mut self,
71+
analyzed_imports: &AnalyzedImports,
72+
import_chains: BTreeMap<String, Tokens<Go>>,
73+
) {
74+
let config = FactoryConfig {
75+
analyzed_imports,
76+
go_imports: &self.go_imports,
77+
import_chains,
78+
wasm_var_name: &self.raw_wasm_var,
79+
};
80+
FactoryGenerator::new(config).format_into(&mut self.out)
12781
}
12882
}

0 commit comments

Comments
 (0)