use sigil_stitch::lang::ocaml::OCaml;
use sigil_stitch::prelude::*;
fn main() {
println!("=== Builder API ===\n");
let builder_output = builder_approach();
println!("{builder_output}");
println!("=== sigil_quote! Macro ===\n");
let macro_output = macro_approach();
println!("{macro_output}");
}
fn build_shared_types() -> (TypeSpec, TypeSpec) {
let person = TypeSpec::builder("person", TypeKind::Struct)
.doc("A person record.")
.add_field(
FieldSpec::builder("name", TypeName::primitive("string"))
.build()
.unwrap(),
)
.add_field(
FieldSpec::builder("age", TypeName::primitive("int"))
.build()
.unwrap(),
)
.add_field(
FieldSpec::builder("email", TypeName::optional(TypeName::primitive("string")))
.build()
.unwrap(),
)
.build()
.unwrap();
let string_list = TypeSpec::builder("string_list", TypeKind::TypeAlias)
.extends(TypeName::generic(
TypeName::primitive("list"),
vec![TypeName::primitive("string")],
))
.build()
.unwrap();
(person, string_list)
}
fn builder_approach() -> String {
let (person, string_list) = build_shared_types();
let mut greet_body = CodeBlock::builder();
greet_body.add("\"Hello, \" ^ p.name ^ \"!\"", ());
let greet_fn = FunSpec::builder("greet")
.add_param(ParameterSpec::new("p", TypeName::primitive("person")).unwrap())
.returns(TypeName::primitive("string"))
.body(greet_body.build().unwrap())
.build()
.unwrap();
let list_map = TypeName::importable("List", "map");
let mut map_pair_body = CodeBlock::builder();
map_pair_body.add("%T f [x; x]", (list_map,));
let map_pair_fn = FunSpec::builder("map_pair")
.add_type_param(TypeParamSpec::new("'a"))
.add_type_param(TypeParamSpec::new("'b"))
.add_param(
ParameterSpec::new(
"f",
TypeName::function(vec![TypeName::primitive("'a")], TypeName::primitive("'b")),
)
.unwrap(),
)
.add_param(ParameterSpec::new("x", TypeName::primitive("'a")).unwrap())
.returns(TypeName::generic(
TypeName::primitive("list"),
vec![TypeName::primitive("'b")],
))
.body(map_pair_body.build().unwrap())
.build()
.unwrap();
let mut module_body = CodeBlock::builder();
module_body.add("let capitalize s = String.capitalize_ascii s", ());
module_body.add_line();
let module_code = OCaml::module_block("StringUtils", module_body.build().unwrap()).unwrap();
let mut sig_body = CodeBlock::builder();
sig_body.add("val capitalize : string -> string", ());
sig_body.add_line();
let sig_code = OCaml::module_sig_block("STRING_UTILS", sig_body.build().unwrap()).unwrap();
FileSpec::builder_with("person.ml", OCaml::new())
.add_type(person)
.add_type(string_list)
.add_function(greet_fn)
.add_function(map_pair_fn)
.add_code(module_code)
.add_code(sig_code)
.build()
.unwrap()
.render(80)
.unwrap()
}
fn macro_approach() -> String {
let (person, string_list) = build_shared_types();
let greet_body = sigil_quote!(OCaml {
"Hello, " ^ p.name ^ "!"
})
.unwrap();
let greet_fn = FunSpec::builder("greet")
.add_param(ParameterSpec::new("p", TypeName::primitive("person")).unwrap())
.returns(TypeName::primitive("string"))
.body(greet_body)
.build()
.unwrap();
let list_map = TypeName::importable("List", "map");
let map_pair_body = sigil_quote!(OCaml {
$T(list_map) f [x; x]
})
.unwrap();
let map_pair_fn = FunSpec::builder("map_pair")
.add_type_param(TypeParamSpec::new("'a"))
.add_type_param(TypeParamSpec::new("'b"))
.add_param(
ParameterSpec::new(
"f",
TypeName::function(vec![TypeName::primitive("'a")], TypeName::primitive("'b")),
)
.unwrap(),
)
.add_param(ParameterSpec::new("x", TypeName::primitive("'a")).unwrap())
.returns(TypeName::generic(
TypeName::primitive("list"),
vec![TypeName::primitive("'b")],
))
.body(map_pair_body)
.build()
.unwrap();
let mut module_body = CodeBlock::builder();
module_body.add("let capitalize s = String.capitalize_ascii s", ());
module_body.add_line();
let module_code = OCaml::module_block("StringUtils", module_body.build().unwrap()).unwrap();
let mut sig_body = CodeBlock::builder();
sig_body.add("val capitalize : string -> string", ());
sig_body.add_line();
let sig_code = OCaml::module_sig_block("STRING_UTILS", sig_body.build().unwrap()).unwrap();
FileSpec::builder_with("person.ml", OCaml::new())
.add_type(person)
.add_type(string_list)
.add_function(greet_fn)
.add_function(map_pair_fn)
.add_code(module_code)
.add_code(sig_code)
.build()
.unwrap()
.render(80)
.unwrap()
}