use std::collections::HashMap;
use std::fmt::Write;
use std::{collections::BTreeSet, mem};
use heck::{ToKebabCase, ToSnakeCase, ToUpperCamelCase};
use wit_bindgen_c::{
flags_repr, get_nonempty_type, int_repr, is_arg_by_pointer, is_empty_type, owns_anything,
};
use wit_bindgen_core::wit_parser::{InterfaceId, Resolve, TypeOwner, WorldId};
use wit_bindgen_core::{
uwriteln,
wit_parser::{Field, Function, SizeAlign, Type, TypeDefKind, TypeId, WorldKey},
Files, InterfaceGenerator as _, Source, WorldGenerator,
};
const GOKEYWORDS: [&str; 25] = [
"break",
"default",
"func",
"interface",
"select",
"case",
"defer",
"go",
"map",
"struct",
"chan",
"else",
"goto",
"package",
"switch",
"const",
"fallthrough",
"if",
"range",
"type",
"continue",
"for",
"import",
"return",
"var",
];
fn avoid_keyword(s: &str) -> String {
if GOKEYWORDS.contains(&s) {
format!("{s}_")
} else {
s.into()
}
}
#[derive(Default, Debug, Clone)]
#[cfg_attr(feature = "clap", derive(clap::Args))]
pub struct Opts {}
impl Opts {
pub fn build(&self) -> Box<dyn WorldGenerator> {
Box::new(TinyGo {
_opts: self.clone(),
..TinyGo::default()
})
}
}
#[derive(Default)]
pub struct TinyGo {
_opts: Opts,
src: Source,
export_funcs: Vec<(String, String)>,
world: String,
needs_result_option: bool,
needs_import_unsafe: bool,
needs_fmt_import: bool,
sizes: SizeAlign,
interface_names: HashMap<InterfaceId, String>,
}
impl TinyGo {
fn interface<'a>(&'a mut self, resolve: &'a Resolve, name: &'a str) -> InterfaceGenerator<'a> {
InterfaceGenerator {
src: Source::default(),
gen: self,
resolve,
interface: None,
name,
public_anonymous_types: BTreeSet::new(),
}
}
fn clean_up_export_funcs(&mut self) {
self.export_funcs = vec![];
}
}
impl WorldGenerator for TinyGo {
fn preprocess(&mut self, resolve: &Resolve, world: WorldId) {
let name = &resolve.worlds[world].name;
self.world = name.to_string();
self.sizes.fill(resolve);
}
fn import_interface(
&mut self,
resolve: &Resolve,
name: &WorldKey,
id: InterfaceId,
_files: &mut Files,
) {
let name = &resolve.name_world_key(name);
self.interface_names.insert(id, name.to_string());
self.src.push_str(&format!("// {name}\n"));
let mut gen = self.interface(resolve, name);
gen.interface = Some(id);
gen.types(id);
for (_name, func) in resolve.interfaces[id].functions.iter() {
gen.import(resolve, func);
}
gen.finish();
let src = mem::take(&mut gen.src);
self.src.push_str(&src);
}
fn import_funcs(
&mut self,
resolve: &Resolve,
world: WorldId,
funcs: &[(&str, &Function)],
_files: &mut Files,
) {
let name = &resolve.worlds[world].name;
self.src.push_str(&format!("// {name}\n"));
let mut gen = self.interface(resolve, name);
for (_name, func) in funcs.iter() {
gen.import(resolve, func);
}
gen.finish();
let src = mem::take(&mut gen.src);
self.src.push_str(&src);
}
fn export_interface(
&mut self,
resolve: &Resolve,
name: &WorldKey,
id: InterfaceId,
_files: &mut Files,
) {
let name = &resolve.name_world_key(name);
self.interface_names.insert(id, name.to_string());
self.src.push_str(&format!("// {name}\n"));
self.clean_up_export_funcs();
let mut gen = self.interface(resolve, name);
gen.interface = Some(id);
gen.types(id);
for (_name, func) in resolve.interfaces[id].functions.iter() {
gen.export(resolve, func);
}
gen.finish();
let src = mem::take(&mut gen.src);
self.src.push_str(&src);
if !self.export_funcs.is_empty() {
let interface_var_name = &name.to_snake_case();
let interface_name = &name.to_upper_camel_case();
self.src
.push_str(format!("var {interface_var_name} {interface_name} = nil\n").as_str());
self.src.push_str(
format!(
"func Set{interface_name}(i {interface_name}) {{\n {interface_var_name} = i\n}}\n"
)
.as_str(),
);
self.src
.push_str(format!("type {interface_name} interface {{\n").as_str());
for (interface_func_declaration, _) in &self.export_funcs {
self.src
.push_str(format!("{interface_func_declaration}\n").as_str());
}
self.src.push_str("}\n");
for (_, export_func) in &self.export_funcs {
self.src.push_str(export_func);
}
}
}
fn export_funcs(
&mut self,
resolve: &Resolve,
world: WorldId,
funcs: &[(&str, &Function)],
_files: &mut Files,
) {
let name = &resolve.worlds[world].name;
self.src.push_str(&format!("// {name}\n"));
self.clean_up_export_funcs();
let mut gen = self.interface(resolve, name);
for (_name, func) in funcs.iter() {
gen.export(resolve, func);
}
gen.finish();
let src = mem::take(&mut gen.src);
self.src.push_str(&src);
if !self.export_funcs.is_empty() {
let interface_var_name = &name.to_snake_case();
let interface_name = &name.to_upper_camel_case();
self.src
.push_str(format!("var {interface_var_name} {interface_name} = nil\n").as_str());
self.src.push_str(
format!(
"func Set{interface_name}(i {interface_name}) {{\n {interface_var_name} = i\n}}\n"
)
.as_str(),
);
self.src
.push_str(format!("type {interface_name} interface {{\n").as_str());
for (interface_func_declaration, _) in &self.export_funcs {
self.src
.push_str(format!("{interface_func_declaration}\n").as_str());
}
self.src.push_str("}\n");
for (_, export_func) in &self.export_funcs {
self.src.push_str(export_func);
}
}
}
fn export_types(
&mut self,
resolve: &Resolve,
world: WorldId,
types: &[(&str, TypeId)],
_files: &mut Files,
) {
let name = &resolve.worlds[world].name;
let mut gen = self.interface(resolve, name);
for (name, id) in types {
gen.define_type(name, *id);
}
gen.finish();
let src = mem::take(&mut gen.src);
self.src.push_str(&src);
}
fn finish(&mut self, resolve: &Resolve, id: WorldId, files: &mut Files) {
let world = &resolve.worlds[id];
let mut header = Source::default();
let snake = self.world.to_snake_case();
header.push_str("package ");
header.push_str(&snake);
header.push_str("\n\n");
header.push_str("// #include \"");
header.push_str(self.world.to_snake_case().as_str());
header.push_str(".h\"\n");
header.push_str("import \"C\"\n\n");
if self.needs_import_unsafe {
header.push_str("import \"unsafe\"\n\n");
}
if self.needs_fmt_import {
header.push_str("import \"fmt\"\n\n");
}
let header = mem::take(&mut header);
let src = mem::take(&mut self.src);
files.push(
&format!("{}.go", world.name.to_kebab_case()),
header.as_bytes(),
);
files.push(
&format!("{}.go", world.name.to_kebab_case()),
src.as_bytes(),
);
if self.needs_result_option {
let mut result_option_src = Source::default();
uwriteln!(
result_option_src,
"package {snake}
// inspired from https://github.com/moznion/go-optional
type optionKind int
const (
none optionKind = iota
some
)
type Option[T any] struct {{
kind optionKind
val T
}}
// IsNone returns true if the option is None.
func (o Option[T]) IsNone() bool {{
return o.kind == none
}}
// IsSome returns true if the option is Some.
func (o Option[T]) IsSome() bool {{
return o.kind == some
}}
// Unwrap returns the value if the option is Some.
func (o Option[T]) Unwrap() T {{
if o.kind != some {{
panic(\"Option is None\")
}}
return o.val
}}
// Set sets the value and returns it.
func (o *Option[T]) Set(val T) T {{
o.kind = some
o.val = val
return val
}}
// Unset sets the value to None.
func (o *Option[T]) Unset() {{
o.kind = none
}}
// Some is a constructor for Option[T] which represents Some.
func Some[T any](v T) Option[T] {{
return Option[T]{{
kind: some,
val: v,
}}
}}
// None is a constructor for Option[T] which represents None.
func None[T any]() Option[T] {{
return Option[T]{{
kind: none,
}}
}}
type ResultKind int
const (
Ok ResultKind = iota
Err
)
type Result[T any, E any] struct {{
Kind ResultKind
Val T
Err E
}}
func (r Result[T, E]) IsOk() bool {{
return r.Kind == Ok
}}
func (r Result[T, E]) IsErr() bool {{
return r.Kind == Err
}}
func (r Result[T, E]) Unwrap() T {{
if r.Kind != Ok {{
panic(\"Result is Err\")
}}
return r.Val
}}
func (r Result[T, E]) UnwrapErr() E {{
if r.Kind != Err {{
panic(\"Result is Ok\")
}}
return r.Err
}}
func (r *Result[T, E]) Set(val T) T {{
r.Kind = Ok
r.Val = val
return val
}}
func (r *Result[T, E]) SetErr(err E) E {{
r.Kind = Err
r.Err = err
return err
}}
"
);
files.push(
&format!("{}_types.go", world.name.to_kebab_case()),
result_option_src.as_bytes(),
);
}
let mut opts = wit_bindgen_c::Opts::default();
opts.no_sig_flattening = true;
opts.build().generate(resolve, id, files)
}
}
struct InterfaceGenerator<'a> {
src: Source,
gen: &'a mut TinyGo,
resolve: &'a Resolve,
interface: Option<InterfaceId>,
name: &'a str,
public_anonymous_types: BTreeSet<TypeId>,
}
impl InterfaceGenerator<'_> {
fn get_typedef_target(&self, name: &str) -> String {
format!(
"{}{}",
self.name.to_upper_camel_case(),
name.to_upper_camel_case()
)
}
fn get_c_typedef_target(&self, name: &str) -> String {
format!("{}_{}", self.name.to_snake_case(), name.to_snake_case())
}
fn get_ty(&mut self, ty: &Type) -> String {
match ty {
Type::Bool => "bool".into(),
Type::U8 => "uint8".into(),
Type::U16 => "uint16".into(),
Type::U32 => "uint32".into(),
Type::U64 => "uint64".into(),
Type::S8 => "int8".into(),
Type::S16 => "int16".into(),
Type::S32 => "int32".into(),
Type::S64 => "int64".into(),
Type::Float32 => "float32".into(),
Type::Float64 => "float64".into(),
Type::Char => "rune".into(),
Type::String => "string".into(),
Type::Id(id) => {
let ty = &self.resolve().types[*id];
match &ty.kind {
wit_bindgen_core::wit_parser::TypeDefKind::Type(ty) => self.get_ty(ty),
wit_bindgen_core::wit_parser::TypeDefKind::List(ty) => {
format!("[]{}", self.get_ty(ty))
}
wit_bindgen_core::wit_parser::TypeDefKind::Option(o) => {
self.gen.needs_result_option = true;
format!("Option[{}]", self.get_ty(o))
}
wit_bindgen_core::wit_parser::TypeDefKind::Result(r) => {
self.gen.needs_result_option = true;
format!(
"Result[{}, {}]",
self.get_optional_ty(r.ok.as_ref()),
self.get_optional_ty(r.err.as_ref())
)
}
_ => {
if let Some(name) = &ty.name {
let iface = if let TypeOwner::Interface(owner) = ty.owner {
self.gen.interface_names[&owner].to_upper_camel_case()
} else {
self.name.to_upper_camel_case()
};
format!("{iface}{name}", name = name.to_upper_camel_case())
} else {
self.public_anonymous_types.insert(*id);
format!(
"{namespace}{name}",
namespace = self.name.to_upper_camel_case(),
name = self.get_ty_name(&Type::Id(*id)),
)
}
}
}
}
}
}
fn get_c_ty_without_package(&self, ty: &Type) -> String {
match ty {
Type::Bool => "bool".into(),
Type::U8 => "uint8_t".into(),
Type::U16 => "uint16_t".into(),
Type::U32 => "uint32_t".into(),
Type::U64 => "uint64_t".into(),
Type::S8 => "int8_t".into(),
Type::S16 => "int16_t".into(),
Type::S32 => "int32_t".into(),
Type::S64 => "int64_t".into(),
Type::Float32 => "float".into(),
Type::Float64 => "double".into(),
Type::Char => "uint32_t".into(),
Type::String => {
format!(
"{namespace}_string_t",
namespace = self.gen.world.to_snake_case()
)
}
Type::Id(id) => {
let ty = &self.resolve.types[*id];
match &ty.name {
Some(name) => match ty.owner {
TypeOwner::Interface(owner) => {
format!(
"{namespace}_{name}_t",
namespace = self.resolve.interfaces[owner]
.name
.as_ref()
.map(|s| s.to_snake_case())
.unwrap_or_else(
|| self.gen.interface_names[&owner].to_snake_case()
),
name = name.to_snake_case(),
)
}
TypeOwner::World(owner) => {
format!(
"{namespace}_{name}_t",
namespace = self.resolve.worlds[owner].name.to_snake_case(),
name = name.to_snake_case(),
)
}
TypeOwner::None => {
format!("{name}_t", name = self.gen.world.to_snake_case(),)
}
},
None => match &ty.kind {
TypeDefKind::Type(t) => self.get_c_ty_without_package(t),
_ => format!(
"{namespace}_{name}_t",
namespace = self.gen.world.to_snake_case(),
name = self.get_c_ty_name(&Type::Id(*id)),
),
},
}
}
}
}
fn get_c_ty(&self, ty: &Type) -> String {
let res = self.get_c_ty_without_package(ty);
if res != *"bool" {
format!("C.{res}")
} else {
res
}
}
fn get_ty_name(&self, ty: &Type) -> String {
match ty {
Type::Bool => "Bool".into(),
Type::U8 => "U8".into(),
Type::U16 => "U16".into(),
Type::U32 => "U32".into(),
Type::U64 => "U64".into(),
Type::S8 => "S8".into(),
Type::S16 => "S16".into(),
Type::S32 => "S32".into(),
Type::S64 => "S64".into(),
Type::Float32 => "F32".into(),
Type::Float64 => "F64".into(),
Type::Char => "Byte".into(),
Type::String => "String".into(),
Type::Id(id) => {
let ty = &self.resolve.types[*id];
if let Some(name) = &ty.name {
let prefix = match ty.owner {
TypeOwner::World(owner) => {
self.resolve.worlds[owner].name.to_upper_camel_case()
}
TypeOwner::Interface(owner) => {
self.gen.interface_names[&owner].to_upper_camel_case()
}
TypeOwner::None => "".into(),
};
return format!(
"{prefix}{name}",
prefix = prefix,
name = name.to_upper_camel_case()
);
}
match &ty.kind {
TypeDefKind::Type(t) => self.get_ty_name(t),
TypeDefKind::Record(_)
| TypeDefKind::Flags(_)
| TypeDefKind::Enum(_)
| TypeDefKind::Variant(_)
| TypeDefKind::Union(_) => {
unimplemented!()
}
TypeDefKind::Tuple(t) => {
let mut src = String::new();
src.push_str("Tuple");
src.push_str(&t.types.len().to_string());
for ty in t.types.iter() {
src.push_str(&self.get_ty_name(ty));
}
src.push('T');
src
}
TypeDefKind::Option(t) => {
let mut src = String::new();
src.push_str("Option");
src.push_str(&self.get_ty_name(t));
src.push('T');
src
}
TypeDefKind::Result(r) => {
let mut src = String::new();
src.push_str("Result");
src.push_str(&self.get_optional_ty_name(r.ok.as_ref()));
src.push_str(&self.get_optional_ty_name(r.ok.as_ref()));
src.push('T');
src
}
TypeDefKind::List(t) => {
let mut src = String::new();
src.push_str("List");
src.push_str(&self.get_ty_name(t));
src.push('T');
src
}
TypeDefKind::Future(t) => {
let mut src = String::new();
src.push_str("Future");
src.push_str(&self.get_optional_ty_name(t.as_ref()));
src.push('T');
src
}
TypeDefKind::Stream(t) => {
let mut src = String::new();
src.push_str("Stream");
src.push_str(&self.get_optional_ty_name(t.element.as_ref()));
src.push_str(&self.get_optional_ty_name(t.end.as_ref()));
src.push('T');
src
}
TypeDefKind::Unknown => unreachable!(),
}
}
}
}
fn get_optional_ty_name(&self, ty: Option<&Type>) -> String {
match ty {
Some(ty) => self.get_ty_name(ty),
None => "Empty".into(),
}
}
fn get_c_ty_name(&self, ty: &Type) -> String {
match ty {
Type::Bool => "bool".into(),
Type::Char => "char32".into(),
Type::U8 => "u8".into(),
Type::S8 => "s8".into(),
Type::U16 => "u16".into(),
Type::S16 => "s16".into(),
Type::U32 => "u32".into(),
Type::S32 => "s32".into(),
Type::U64 => "u64".into(),
Type::S64 => "s64".into(),
Type::Float32 => "float32".into(),
Type::Float64 => "float64".into(),
Type::String => "string".into(),
Type::Id(id) => {
let ty = &self.resolve.types[*id];
if let Some(name) = &ty.name {
return name.to_snake_case();
}
match &ty.kind {
TypeDefKind::Type(t) => self.get_c_ty_name(t),
TypeDefKind::Record(_)
| TypeDefKind::Flags(_)
| TypeDefKind::Enum(_)
| TypeDefKind::Variant(_)
| TypeDefKind::Union(_) => {
unimplemented!()
}
TypeDefKind::Tuple(t) => {
let mut src = String::new();
src.push_str("tuple");
src.push_str(&t.types.len().to_string());
for ty in t.types.iter() {
src.push('_');
src.push_str(&self.get_c_ty_name(ty));
}
src
}
TypeDefKind::Option(ty) => {
format!("option_{}", self.get_c_ty_name(ty))
}
TypeDefKind::Result(r) => {
format!(
"result_{}_{}",
self.get_c_optional_type_name(r.ok.as_ref()),
self.get_c_optional_type_name(r.err.as_ref())
)
}
TypeDefKind::List(t) => {
format!("list_{}", self.get_c_ty_name(t))
}
TypeDefKind::Future(t) => {
format!("future_{}", self.get_c_optional_type_name(t.as_ref()),)
}
TypeDefKind::Stream(s) => {
format!(
"stream_{}_{}",
self.get_c_optional_type_name(s.element.as_ref()),
self.get_c_optional_type_name(s.end.as_ref()),
)
}
TypeDefKind::Unknown => unreachable!(),
}
}
}
}
fn get_c_optional_type_name(&self, ty: Option<&Type>) -> String {
match ty {
Some(ty) => self.get_c_ty_name(ty),
None => "void".into(),
}
}
fn get_func_params(&mut self, _resolve: &Resolve, func: &Function) -> String {
let mut params = String::new();
for (i, (name, param)) in func.params.iter().enumerate() {
if i > 0 {
params.push_str(", ");
}
params.push_str(&avoid_keyword(&name.to_snake_case()));
params.push(' ');
params.push_str(&self.get_ty(param));
}
params
}
fn get_func_results(&mut self, _resolve: &Resolve, func: &Function) -> String {
let mut results = String::new();
results.push(' ');
match func.results.len() {
0 => {}
1 => {
results.push_str(&self.get_ty(func.results.iter_types().next().unwrap()));
results.push(' ');
}
_ => {
results.push('(');
for (i, ty) in func.results.iter_types().enumerate() {
if i > 0 {
results.push_str(", ");
}
results.push_str(&self.get_ty(ty));
}
results.push_str(") ");
}
}
results
}
fn print_c_result(&mut self, src: &mut Source, name: &str, param: &Type, in_import: bool) {
self.print_c_param(src, name, param, in_import);
}
fn print_c_param(&mut self, src: &mut Source, name: &str, param: &Type, in_import: bool) {
let pointer_prefix = if in_import { "&" } else { "*" };
let mut prefix = String::new();
let mut param_name = String::new();
let mut postfix = String::new();
if in_import {
if is_arg_by_pointer(self.resolve, param) {
prefix.push_str(pointer_prefix);
}
if name != "err" && name != "ret" {
param_name = format!("lower_{name}");
} else {
param_name.push_str(name);
}
} else {
postfix.push(' ');
param_name.push_str(name);
if is_arg_by_pointer(self.resolve, param) {
postfix.push_str(pointer_prefix);
}
postfix.push_str(&self.get_c_ty(param));
}
src.push_str(&format!("{prefix}{param_name}{postfix}"));
}
fn print_c_func_params(
&mut self,
params: &mut Source,
_resolve: &Resolve,
func: &Function,
in_import: bool,
) {
for (i, (name, param)) in func.params.iter().enumerate() {
if i > 0 {
params.push_str(", ");
}
self.print_c_param(
params,
&avoid_keyword(&name.to_snake_case()),
param,
in_import,
);
}
}
fn print_c_func_results(
&mut self,
src: &mut Source,
_resolve: &Resolve,
func: &Function,
in_import: bool,
) {
let add_param_seperator = |src: &mut Source| {
if !func.params.is_empty() {
src.push_str(", ");
}
};
match func.results.len() {
0 => {
src.push_str(")");
}
1 => {
let return_ty = func.results.iter_types().next().unwrap();
if is_arg_by_pointer(self.resolve, return_ty) {
add_param_seperator(src);
self.print_c_result(src, "ret", return_ty, in_import);
src.push_str(")");
} else {
src.push_str(")");
if !in_import {
src.push_str(&format!(" {ty}", ty = self.get_c_ty(return_ty)));
}
}
}
_n => {
add_param_seperator(src);
for (i, ty) in func.results.iter_types().enumerate() {
if i > 0 {
src.push_str(", ");
}
if in_import {
src.push_str(&format!("&ret{i}"));
} else {
src.push_str(&format!("ret{i} *{ty}", i = i, ty = self.get_c_ty(ty)));
}
}
src.push_str(")");
}
}
}
fn get_c_func_signature(
&mut self,
resolve: &Resolve,
func: &Function,
in_import: bool,
) -> String {
let mut src = Source::default();
let name = if in_import {
self.get_c_typedef_target(&func.name)
} else {
self.get_typedef_target(&func.name)
};
if !in_import {
src.push_str("func ");
} else {
src.push_str("C.");
}
src.push_str(&name);
src.push_str("(");
self.print_c_func_params(&mut src, resolve, func, in_import);
self.print_c_func_results(&mut src, resolve, func, in_import);
src.to_string()
}
fn get_free_c_arg(&mut self, ty: &Type, arg: &str) -> String {
let mut ty_name = self.get_c_ty(ty);
let it: Vec<&str> = ty_name.split('_').collect();
ty_name = it[..it.len() - 1].join("_");
format!("defer {ty_name}_free({arg})\n")
}
fn get_func_signature_no_interface(&mut self, resolve: &Resolve, func: &Function) -> String {
format!(
"{}({}){}",
func.name.to_upper_camel_case(),
self.get_func_params(resolve, func),
self.get_func_results(resolve, func)
)
}
fn print_func_signature(&mut self, resolve: &Resolve, func: &Function) {
self.src.push_str("func ");
let func_name = self.name.to_upper_camel_case();
self.src.push_str(&func_name);
let func_sig = self.get_func_signature_no_interface(resolve, func);
self.src.push_str(&func_sig);
self.src.push_str("{\n");
}
fn get_field_name(&mut self, field: &Field) -> String {
field.name.to_upper_camel_case()
}
fn extract_result_ty(&self, ty: &Type) -> (Option<Type>, Option<Type>) {
match ty {
Type::Id(id) => match &self.resolve.types[*id].kind {
TypeDefKind::Result(r) => (r.ok, r.err),
TypeDefKind::Future(_) => todo!("is_arg_by_pointer for future"),
TypeDefKind::Stream(_) => todo!("is_arg_by_pointer for stream"),
_ => (None, None),
},
_ => (None, None),
}
}
fn extract_list_ty(&self, ty: &Type) -> Option<&Type> {
match ty {
Type::Id(id) => match &self.resolve.types[*id].kind {
TypeDefKind::List(l) => Some(l),
TypeDefKind::Future(_) => todo!("is_arg_by_pointer for future"),
TypeDefKind::Stream(_) => todo!("is_arg_by_pointer for stream"),
_ => None,
},
_ => None,
}
}
fn get_optional_ty(&mut self, ty: Option<&Type>) -> String {
match ty {
Some(ty) => self.get_ty(ty),
None => "struct{}".into(),
}
}
fn print_anonymous_type(&mut self, ty: TypeId) {
let kind = &self.resolve.types[ty].kind;
match kind {
TypeDefKind::Type(_)
| TypeDefKind::Flags(_)
| TypeDefKind::Record(_)
| TypeDefKind::Enum(_)
| TypeDefKind::Variant(_)
| TypeDefKind::Union(_) => {
unreachable!()
}
TypeDefKind::Tuple(t) => {
let name = format!(
"{}{}",
self.name.to_upper_camel_case(),
self.get_ty_name(&Type::Id(ty))
);
self.src.push_str(&format!("type {name} struct {{\n",));
for (i, ty) in t.types.iter().enumerate() {
let ty = self.get_ty(ty);
self.src.push_str(&format!(" F{i} {ty}\n",));
}
self.src.push_str("}\n\n");
}
TypeDefKind::Option(_t) => {}
TypeDefKind::Result(_r) => {}
TypeDefKind::List(_l) => {}
TypeDefKind::Future(_) => todo!("print_anonymous_type for future"),
TypeDefKind::Stream(_) => todo!("print_anonymous_type for stream"),
TypeDefKind::Unknown => unreachable!(),
}
}
fn print_constructor_method_without_value(&mut self, name: &str, case_name: &str) {
uwriteln!(
self.src,
"func {name}{case_name}() {name} {{
return {name}{{kind: {name}Kind{case_name}}}
}}
",
);
}
fn print_accessor_methods(&mut self, name: &str, case_name: &str, ty: &Type) {
self.gen.needs_fmt_import = true;
let ty = self.get_ty(ty);
uwriteln!(
self.src,
"func {name}{case_name}(v {ty}) {name} {{
return {name}{{kind: {name}Kind{case_name}, val: v}}
}}
",
);
uwriteln!(
self.src,
"func (n {name}) Get{case_name}() {ty} {{
if g, w := n.Kind(), {name}Kind{case_name}; g != w {{
panic(fmt.Sprintf(\"Attr kind is %v, not %v\", g, w))
}}
return n.val.({ty})
}}
",
);
uwriteln!(
self.src,
"func (n *{name}) Set{case_name}(v {ty}) {{
n.val = v
n.kind = {name}Kind{case_name}
}}
",
);
}
fn print_kind_method(&mut self, name: &str) {
uwriteln!(
self.src,
"func (n {name}) Kind() {name}Kind {{
return n.kind
}}
"
);
}
fn print_variant_field(&mut self, name: &str, case_name: &str, i: usize) {
if i == 0 {
self.src
.push_str(&format!(" {name}Kind{case_name} {name}Kind = iota\n",));
} else {
self.src.push_str(&format!(" {name}Kind{case_name}\n",));
}
}
fn import(&mut self, resolve: &Resolve, func: &Function) {
let mut func_bindgen = FunctionBindgen::new(self, func);
func.params.iter().for_each(|(name, ty)| {
func_bindgen.lower(&avoid_keyword(&name.to_snake_case()), ty, false);
});
match func.results.len() {
0 => {}
1 => {
let ty = func.results.iter_types().next().unwrap();
func_bindgen.lift("ret", ty);
}
_ => {
for (i, ty) in func.results.iter_types().enumerate() {
func_bindgen.lift(&format!("ret{i}"), ty);
}
}
};
let c_args = func_bindgen.c_args;
let ret = func_bindgen.args;
let lower_src = func_bindgen.lower_src.to_string();
let lift_src = func_bindgen.lift_src.to_string();
self.print_func_signature(resolve, func);
self.src.push_str(lower_src.as_str());
self.import_invoke(resolve, func, c_args, &lift_src, ret);
self.src.push_str("}\n\n");
}
fn import_invoke(
&mut self,
resolve: &Resolve,
func: &Function,
_c_args: Vec<String>,
lift_src: &str,
ret: Vec<String>,
) {
let invoke = self.get_c_func_signature(resolve, func, true);
match func.results.len() {
0 => {
self.src.push_str(&invoke);
self.src.push_str("\n");
}
1 => {
let return_ty = func.results.iter_types().next().unwrap();
if is_arg_by_pointer(self.resolve, return_ty) {
let c_ret_type = self.get_c_ty(return_ty);
self.src.push_str(&format!("var ret {c_ret_type}\n"));
self.src.push_str(&invoke);
self.src.push_str("\n");
} else {
self.src.push_str(&format!("ret := {invoke}\n"));
}
self.src.push_str(lift_src);
self.src.push_str(&format!("return {ret}\n", ret = ret[0]));
}
_n => {
for (i, ty) in func.results.iter_types().enumerate() {
let ty_name = self.get_c_ty(ty);
let var_name = format!("ret{i}");
self.src.push_str(&format!("var {var_name} {ty_name}\n"));
}
self.src.push_str(&invoke);
self.src.push_str("\n");
self.src.push_str(lift_src);
self.src.push_str("return ");
for (i, _) in func.results.iter_types().enumerate() {
if i > 0 {
self.src.push_str(", ");
}
self.src.push_str(&format!("lift_ret{i}"));
}
self.src.push_str("\n");
}
}
}
fn export(&mut self, resolve: &Resolve, func: &Function) {
let mut func_bindgen = FunctionBindgen::new(self, func);
match func.results.len() {
0 => {
func.params.iter().for_each(|(name, ty)| {
func_bindgen.lift(&avoid_keyword(&name.to_snake_case()), ty);
});
}
1 => {
func.params.iter().for_each(|(name, ty)| {
func_bindgen.lift(&avoid_keyword(&name.to_snake_case()), ty);
});
let ty = func.results.iter_types().next().unwrap();
func_bindgen.lower("result", ty, true);
}
_ => {
func.params.iter().for_each(|(name, ty)| {
func_bindgen.lift(&avoid_keyword(&name.to_snake_case()), ty);
});
for (i, ty) in func.results.iter_types().enumerate() {
func_bindgen.lower(&format!("result{i}"), ty, true);
}
}
};
let args = func_bindgen.args;
let ret = func_bindgen.c_args;
let lift_src = func_bindgen.lift_src.to_string();
let lower_src = func_bindgen.lower_src.to_string();
let interface_method_decl = self.get_func_signature_no_interface(resolve, func);
let export_func = {
let mut src = String::new();
src.push_str("//export ");
let name = self.get_c_typedef_target(&func.name);
src.push_str(&name);
src.push('\n');
src.push_str(&self.get_c_func_signature(resolve, func, false));
src.push_str(" {\n");
for (name, ty) in func.params.iter() {
if owns_anything(resolve, &ty) {
let free = self.get_free_c_arg(&ty, &avoid_keyword(&name.to_snake_case()));
src.push_str(&free);
}
}
src.push_str(&lift_src);
let invoke = format!(
"{}.{}({})",
&self.name.to_snake_case(),
&func.name.to_upper_camel_case(),
args.iter()
.enumerate()
.map(|(i, name)| format!(
"{}{}",
name,
if i < func.params.len() - 1 { ", " } else { "" }
))
.collect::<String>()
);
match func.results.len() {
0 => {
src.push_str(&format!("{invoke}\n"));
}
1 => {
let return_ty = func.results.iter_types().next().unwrap();
if is_empty_type(self.resolve, return_ty) {
src.push_str(&format!("{invoke}\n"));
} else {
src.push_str(&format!("result := {invoke}\n"));
}
src.push_str(&lower_src);
let lower_result = &ret[0];
if is_arg_by_pointer(self.resolve, return_ty) {
src.push_str(&format!("*ret = {lower_result}\n"));
} else {
src.push_str(&format!("return {ret}\n", ret = &ret[0]));
}
}
_ => {
for i in 0..func.results.len() {
if i > 0 {
src.push_str(", ")
}
src.push_str(&format!("result{i}"));
}
src.push_str(&format!(" := {invoke}\n"));
src.push_str(&lower_src);
for (i, lower_result) in ret.iter().enumerate() {
src.push_str(&format!("*ret{i} = {lower_result}\n"));
}
}
};
src.push_str("\n}\n");
src
};
self.gen
.export_funcs
.push((interface_method_decl, export_func));
}
fn finish(&mut self) {
while let Some(ty) = self.public_anonymous_types.pop_last() {
self.print_anonymous_type(ty);
}
}
}
impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
fn resolve(&self) -> &'a Resolve {
self.resolve
}
fn type_record(
&mut self,
_id: wit_bindgen_core::wit_parser::TypeId,
name: &str,
record: &wit_bindgen_core::wit_parser::Record,
_docs: &wit_bindgen_core::wit_parser::Docs,
) {
let name = self.get_typedef_target(name);
self.src.push_str(&format!("type {name} struct {{\n",));
for field in record.fields.iter() {
let ty = self.get_ty(&field.ty);
let name = self.get_field_name(field);
self.src.push_str(&format!(" {name} {ty}\n",));
}
self.src.push_str("}\n\n");
}
fn type_flags(
&mut self,
_id: wit_bindgen_core::wit_parser::TypeId,
name: &str,
flags: &wit_bindgen_core::wit_parser::Flags,
_docs: &wit_bindgen_core::wit_parser::Docs,
) {
let name = self.get_typedef_target(name);
self.src.push_str(&format!("type {name} uint64\n"));
self.src.push_str("const (\n");
for (i, flag) in flags.flags.iter().enumerate() {
if i == 0 {
self.src.push_str(&format!(
" {name}_{flag} {name} = 1 << iota\n",
name = name,
flag = flag.name.to_uppercase(),
));
} else {
self.src.push_str(&format!(
" {name}_{flag}\n",
name = name,
flag = flag.name.to_uppercase(),
));
}
}
self.src.push_str(")\n\n");
}
fn type_tuple(
&mut self,
_id: wit_bindgen_core::wit_parser::TypeId,
name: &str,
tuple: &wit_bindgen_core::wit_parser::Tuple,
_docs: &wit_bindgen_core::wit_parser::Docs,
) {
let name = self.get_typedef_target(name);
self.src.push_str(&format!("type {name} struct {{\n",));
for (i, case) in tuple.types.iter().enumerate() {
let ty = self.get_ty(case);
self.src.push_str(&format!("F{i} {ty}\n",));
}
self.src.push_str("}\n\n");
}
fn type_variant(
&mut self,
_id: wit_bindgen_core::wit_parser::TypeId,
name: &str,
variant: &wit_bindgen_core::wit_parser::Variant,
_docs: &wit_bindgen_core::wit_parser::Docs,
) {
let name = self.get_typedef_target(name);
self.src.push_str(&format!("type {name}Kind int\n\n"));
self.src.push_str("const (\n");
for (i, case) in variant.cases.iter().enumerate() {
let case_name = case.name.to_upper_camel_case();
self.print_variant_field(&name, &case_name, i);
}
self.src.push_str(")\n\n");
self.src.push_str(&format!("type {name} struct {{\n"));
self.src.push_str(&format!("kind {name}Kind\n"));
self.src.push_str("val any\n");
self.src.push_str("}\n\n");
self.print_kind_method(&name);
for case in variant.cases.iter() {
let case_name = case.name.to_upper_camel_case();
if let Some(ty) = get_nonempty_type(self.resolve, case.ty.as_ref()) {
self.gen.needs_fmt_import = true;
self.print_accessor_methods(&name, &case_name, ty);
} else {
self.print_constructor_method_without_value(&name, &case_name);
}
}
}
fn type_option(
&mut self,
id: wit_bindgen_core::wit_parser::TypeId,
_name: &str,
_payload: &wit_bindgen_core::wit_parser::Type,
_docs: &wit_bindgen_core::wit_parser::Docs,
) {
self.get_ty(&Type::Id(id));
}
fn type_result(
&mut self,
id: wit_bindgen_core::wit_parser::TypeId,
_name: &str,
_result: &wit_bindgen_core::wit_parser::Result_,
_docs: &wit_bindgen_core::wit_parser::Docs,
) {
self.get_ty(&Type::Id(id));
}
fn type_union(
&mut self,
_id: wit_bindgen_core::wit_parser::TypeId,
name: &str,
union: &wit_bindgen_core::wit_parser::Union,
_docs: &wit_bindgen_core::wit_parser::Docs,
) {
let name = self.get_typedef_target(name);
self.src.push_str(&format!("type {name}Kind int\n\n"));
self.src.push_str("const (\n");
for (i, _case) in union.cases.iter().enumerate() {
let case_name = format!("F{i}");
self.print_variant_field(&name, &case_name, i);
}
self.src.push_str(")\n\n");
self.src.push_str(&format!("type {name} struct {{\n"));
self.src.push_str(&format!("kind {name}Kind\n"));
self.src.push_str("val any\n");
self.src.push_str("}\n\n");
self.print_kind_method(&name);
for (i, case) in union.cases.iter().enumerate() {
self.gen.needs_fmt_import = true;
let case_name = format!("F{i}");
self.print_accessor_methods(&name, &case_name, &case.ty);
}
}
fn type_enum(
&mut self,
_id: wit_bindgen_core::wit_parser::TypeId,
name: &str,
enum_: &wit_bindgen_core::wit_parser::Enum,
_docs: &wit_bindgen_core::wit_parser::Docs,
) {
let name = self.get_typedef_target(name);
self.src.push_str(&format!("type {name}Kind int\n\n"));
self.src.push_str("const (\n");
for (i, case) in enum_.cases.iter().enumerate() {
let case_name = case.name.to_upper_camel_case();
self.print_variant_field(&name, &case_name, i);
}
self.src.push_str(")\n\n");
self.src.push_str(&format!("type {name} struct {{\n"));
self.src.push_str(&format!("kind {name}Kind\n"));
self.src.push_str("}\n\n");
self.print_kind_method(&name);
for case in enum_.cases.iter() {
let case_name = case.name.to_upper_camel_case();
self.print_constructor_method_without_value(&name, &case_name);
}
}
fn type_alias(
&mut self,
_id: wit_bindgen_core::wit_parser::TypeId,
name: &str,
ty: &wit_bindgen_core::wit_parser::Type,
_docs: &wit_bindgen_core::wit_parser::Docs,
) {
let name = self.get_typedef_target(name);
let ty = self.get_ty(ty);
self.src.push_str(&format!("type {name} = {ty}\n"));
}
fn type_list(
&mut self,
_id: wit_bindgen_core::wit_parser::TypeId,
name: &str,
ty: &wit_bindgen_core::wit_parser::Type,
_docs: &wit_bindgen_core::wit_parser::Docs,
) {
let name = self.get_typedef_target(name);
let ty = self.get_ty(ty);
self.src.push_str(&format!("type {name} = {ty}\n"));
}
fn type_builtin(
&mut self,
_id: wit_bindgen_core::wit_parser::TypeId,
_name: &str,
_ty: &wit_bindgen_core::wit_parser::Type,
_docs: &wit_bindgen_core::wit_parser::Docs,
) {
todo!("type_builtin")
}
}
struct FunctionBindgen<'a, 'b> {
interface: &'a mut InterfaceGenerator<'b>,
_func: &'a Function,
c_args: Vec<String>,
args: Vec<String>,
lower_src: Source,
lift_src: Source,
}
impl<'a, 'b> FunctionBindgen<'a, 'b> {
fn new(interface: &'a mut InterfaceGenerator<'b>, func: &'a Function) -> Self {
Self {
interface,
_func: func,
c_args: Vec::new(),
args: Vec::new(),
lower_src: Source::default(),
lift_src: Source::default(),
}
}
fn lower(&mut self, name: &str, ty: &Type, in_export: bool) {
let lower_name = format!("lower_{name}");
self.lower_value(name, ty, lower_name.as_ref());
if !in_export && owns_anything(self.interface.resolve, ty) {
self.lower_src
.push_str(&self.interface.get_free_c_arg(ty, &format!("&{lower_name}")));
}
self.c_args.push(lower_name);
}
fn lower_list_value(&mut self, param: &str, l: &Type, lower_name: &str) {
let list_ty = self.interface.get_c_ty(l);
uwriteln!(
self.lower_src,
"if len({param}) == 0 {{
{lower_name}.ptr = nil
{lower_name}.len = 0
}} else {{
var empty_{lower_name} {list_ty}
{lower_name}.ptr = (*{list_ty})(C.malloc(C.size_t(len({param})) * C.size_t(unsafe.Sizeof(empty_{lower_name}))))
{lower_name}.len = C.size_t(len({param}))"
);
uwriteln!(self.lower_src, "for {lower_name}_i := range {param} {{");
uwriteln!(self.lower_src,
"{lower_name}_ptr := (*{list_ty})(unsafe.Pointer(uintptr(unsafe.Pointer({lower_name}.ptr)) +
uintptr({lower_name}_i)*unsafe.Sizeof(empty_{lower_name})))"
);
let param = &format!("{param}[{lower_name}_i]");
let lower_name = &format!("{lower_name}_ptr");
if let Some(inner) = self.interface.extract_list_ty(l) {
self.lower_list_value(param, &inner.clone(), lower_name);
} else {
self.lower_value(param, l, &format!("{lower_name}_value"));
uwriteln!(self.lower_src, "*{lower_name} = {lower_name}_value");
}
uwriteln!(self.lower_src, "}}");
uwriteln!(self.lower_src, "}}");
}
fn lower_result_value(
&mut self,
param: &str,
ty: &Type,
lower_name: &str,
lower_inner_name1: &str,
lower_inner_name2: &str,
) {
let (ok, err) = self.interface.extract_result_ty(ty);
uwriteln!(self.lower_src, "if {param}.IsOk() {{");
if let Some(ok_inner) = ok {
if !is_empty_type(self.interface.resolve, &ok_inner) {
self.interface.gen.needs_import_unsafe = true;
let c_target_name = self.interface.get_c_ty(&ok_inner);
uwriteln!(
self.lower_src,
"{lower_name}_ptr := (*{c_target_name})(unsafe.Pointer({lower_inner_name1}))"
);
self.lower_value(
&format!("{param}.Unwrap()"),
&ok_inner,
&format!("{lower_name}_val"),
);
uwriteln!(self.lower_src, "*{lower_name}_ptr = {lower_name}_val");
}
}
self.lower_src.push_str("} else {\n");
if let Some(err_inner) = err {
if !is_empty_type(self.interface.resolve, &err_inner) {
self.interface.gen.needs_import_unsafe = true;
let c_target_name = self.interface.get_c_ty(&err_inner);
uwriteln!(
self.lower_src,
"{lower_name}_ptr := (*{c_target_name})(unsafe.Pointer({lower_inner_name2}))"
);
self.lower_value(
&format!("{param}.UnwrapErr()"),
&err_inner,
&format!("{lower_name}_val"),
);
uwriteln!(self.lower_src, "*{lower_name}_ptr = {lower_name}_val");
}
}
self.lower_src.push_str("}\n");
}
fn lower_value(&mut self, param: &str, ty: &Type, lower_name: &str) {
match ty {
Type::Bool => {
uwriteln!(self.lower_src, "{lower_name} := {param}",);
}
Type::String => {
uwriteln!(
self.lower_src,
"var {lower_name} {value}",
value = self.interface.get_c_ty(ty),
);
uwriteln!(
self.lower_src,
"
{lower_name}.ptr = C.CString({param})
{lower_name}.len = C.size_t(len({param}))"
);
}
Type::Id(id) => {
let ty = &self.interface.resolve.types[*id]; match &ty.kind {
TypeDefKind::Record(r) => {
let c_typedef_target = self.interface.get_c_ty(&Type::Id(*id)); uwriteln!(self.lower_src, "var {lower_name} {c_typedef_target}");
for field in r.fields.iter() {
let c_field_name = &self.get_c_field_name(field);
let field_name = &self.interface.get_field_name(field);
self.lower_value(
&format!("{param}.{field_name}"),
&field.ty,
&format!("{lower_name}_{c_field_name}"),
);
uwriteln!(
self.lower_src,
"{lower_name}.{c_field_name} = {lower_name}_{c_field_name}"
)
}
}
TypeDefKind::Flags(f) => {
let int_repr = int_repr(flags_repr(f));
uwriteln!(self.lower_src, "{lower_name} := C.{int_repr}({param})");
}
TypeDefKind::Tuple(t) => {
let c_typedef_target = self.interface.get_c_ty(&Type::Id(*id)); uwriteln!(self.lower_src, "var {lower_name} {c_typedef_target}");
for (i, ty) in t.types.iter().enumerate() {
self.lower_value(
&format!("{param}.F{i}"),
ty,
&format!("{lower_name}_f{i}"),
);
uwriteln!(self.lower_src, "{lower_name}.f{i} = {lower_name}_f{i}");
}
}
TypeDefKind::Option(o) => {
let c_typedef_target = self.interface.get_c_ty(&Type::Id(*id));
uwriteln!(self.lower_src, "var {lower_name} {c_typedef_target}");
uwriteln!(self.lower_src, "if {param}.IsSome() {{");
if !is_empty_type(self.interface.resolve, o) {
self.lower_value(
&format!("{param}.Unwrap()"),
o,
&format!("{lower_name}_val"),
);
uwriteln!(self.lower_src, "{lower_name}.val = {lower_name}_val");
uwriteln!(self.lower_src, "{lower_name}.is_some = true");
}
self.lower_src.push_str("}\n");
}
TypeDefKind::Result(_) => {
let c_typedef_target = self.interface.get_c_ty(&Type::Id(*id));
uwriteln!(self.lower_src, "var {lower_name} {c_typedef_target}");
uwriteln!(self.lower_src, "{lower_name}.is_err = {param}.IsErr()");
let inner_name = format!("&{lower_name}.val");
self.lower_result_value(
param,
&Type::Id(*id),
lower_name,
&inner_name,
&inner_name,
);
}
TypeDefKind::List(l) => {
self.interface.gen.needs_import_unsafe = true;
let c_typedef_target = self.interface.get_c_ty(&Type::Id(*id));
uwriteln!(self.lower_src, "var {lower_name} {c_typedef_target}");
self.lower_list_value(param, l, lower_name);
}
TypeDefKind::Type(t) => {
uwriteln!(
self.lower_src,
"var {lower_name} {value}",
value = self.interface.get_c_ty(t),
);
self.lower_value(param, t, &format!("{lower_name}_val"));
uwriteln!(self.lower_src, "{lower_name} = {lower_name}_val");
}
TypeDefKind::Variant(v) => {
self.interface.gen.needs_import_unsafe = true;
let c_typedef_target = self.interface.get_c_ty(&Type::Id(*id));
let ty = self.interface.get_ty(&Type::Id(*id));
uwriteln!(self.lower_src, "var {lower_name} {c_typedef_target}");
for (i, case) in v.cases.iter().enumerate() {
let case_name = case.name.to_upper_camel_case();
uwriteln!(
self.lower_src,
"if {param}.Kind() == {ty}Kind{case_name} {{"
);
if let Some(ty) =
get_nonempty_type(self.interface.resolve, case.ty.as_ref())
{
let name = self.interface.get_c_ty(ty);
uwriteln!(
self.lower_src,
"
{lower_name}.tag = {i}
{lower_name}_ptr := (*{name})(unsafe.Pointer(&{lower_name}.val))"
);
self.lower_value(
&format!("{param}.Get{case_name}()"),
ty,
&format!("{lower_name}_val"),
);
uwriteln!(self.lower_src, "*{lower_name}_ptr = {lower_name}_val");
} else {
uwriteln!(self.lower_src, "{lower_name}.tag = {i}");
}
self.lower_src.push_str("}\n");
}
}
TypeDefKind::Enum(e) => {
let c_typedef_target = self.interface.get_c_ty(&Type::Id(*id));
let ty = self.interface.get_ty(&Type::Id(*id));
uwriteln!(self.lower_src, "var {lower_name} {c_typedef_target}");
for (i, case) in e.cases.iter().enumerate() {
let case_name = case.name.to_upper_camel_case();
uwriteln!(
self.lower_src,
"if {param}.Kind() == {ty}Kind{case_name} {{"
);
uwriteln!(self.lower_src, "{lower_name} = {i}");
self.lower_src.push_str("}\n");
}
}
TypeDefKind::Union(u) => {
self.interface.gen.needs_import_unsafe = true;
let c_typedef_target = self.interface.get_c_ty(&Type::Id(*id));
let ty = self.interface.get_ty(&Type::Id(*id));
uwriteln!(self.lower_src, "var {lower_name} {c_typedef_target}");
for (i, case) in u.cases.iter().enumerate() {
let case_name = format!("F{i}");
uwriteln!(
self.lower_src,
"if {param}.Kind() == {ty}Kind{case_name} {{"
);
let name = self.interface.get_c_ty(&case.ty);
uwriteln!(
self.lower_src,
"
{lower_name}.tag = {i}
{lower_name}_ptr := (*{name})(unsafe.Pointer(&{lower_name}.val))"
);
self.lower_value(
&format!("{param}.Get{case_name}()"),
&case.ty,
&format!("{lower_name}_val"),
);
uwriteln!(self.lower_src, "*{lower_name}_ptr = {lower_name}_val");
self.lower_src.push_str("}\n");
}
}
TypeDefKind::Future(_) => todo!("impl future"),
TypeDefKind::Stream(_) => todo!("impl future"),
TypeDefKind::Unknown => unreachable!(),
}
}
a => {
uwriteln!(
self.lower_src,
"{lower_name} := {c_type_name}({param_name})",
c_type_name = self.interface.get_c_ty(a),
param_name = param,
);
}
}
}
fn lift(&mut self, name: &str, ty: &Type) {
let lift_name = format!("lift_{name}");
self.lift_value(name, ty, lift_name.as_str());
self.args.push(lift_name);
}
fn lift_value(&mut self, param: &str, ty: &Type, lift_name: &str) {
match ty {
Type::Bool => {
uwriteln!(self.lift_src, "{lift_name} := {param}");
}
Type::String => {
uwriteln!(
self.lift_src,
"var {name} {value}
{lift_name} = C.GoStringN({param}.ptr, C.int({param}.len))",
name = lift_name,
value = self.interface.get_ty(ty),
);
}
Type::Id(id) => {
let ty = &self.interface.resolve.types[*id]; match &ty.kind {
TypeDefKind::Record(r) => {
uwriteln!(
self.lift_src,
"var {name} {value}",
name = lift_name,
value = self.interface.get_ty(&Type::Id(*id)),
);
for field in r.fields.iter() {
let field_name = &self.interface.get_field_name(field);
let c_field_name = &self.get_c_field_name(field);
self.lift_value(
&format!("{param}.{c_field_name}"),
&field.ty,
&format!("{lift_name}_{field_name}"),
);
uwriteln!(
self.lift_src,
"{lift_name}.{field_name} = {lift_name}_{field_name}"
);
}
}
TypeDefKind::Flags(_f) => {
let field = self.interface.get_ty(&Type::Id(*id));
uwriteln!(
self.lift_src,
"var {name} {value}
{lift_name} = {field}({param})",
name = lift_name,
value = self.interface.get_ty(&Type::Id(*id)),
);
}
TypeDefKind::Tuple(t) => {
uwriteln!(
self.lift_src,
"var {name} {value}",
name = lift_name,
value = self.interface.get_ty(&Type::Id(*id)),
);
for (i, t) in t.types.iter().enumerate() {
self.lift_value(
&format!("{param}.f{i}"),
t,
&format!("{lift_name}_F{i}"),
);
uwriteln!(self.lift_src, "{lift_name}.F{i} = {lift_name}_F{i}");
}
}
TypeDefKind::Option(o) => {
let lift_type = self.interface.get_ty(&Type::Id(*id));
uwriteln!(self.lift_src, "var {lift_name} {lift_type}");
uwriteln!(self.lift_src, "if {param}.is_some {{");
self.lift_value(&format!("{param}.val"), o, &format!("{lift_name}_val"));
uwriteln!(self.lift_src, "{lift_name}.Set({lift_name}_val)");
self.lift_src.push_str("} else {\n");
uwriteln!(self.lift_src, "{lift_name}.Unset()");
self.lift_src.push_str("}\n");
}
TypeDefKind::Result(_) => {
self.interface.gen.needs_result_option = true;
let ty = self.interface.get_ty(&Type::Id(*id));
uwriteln!(self.lift_src, "var {lift_name} {ty}");
let (ok, err) = self.interface.extract_result_ty(&Type::Id(*id));
uwriteln!(self.lift_src, "if {param}.is_err {{");
if let Some(err_inner) = err {
let err_inner_name = self.interface.get_c_ty(&err_inner);
if !is_empty_type(self.interface.resolve, &err_inner) {
self.interface.gen.needs_import_unsafe = true;
uwriteln!(self.lift_src, "{lift_name}_ptr := *(*{err_inner_name})(unsafe.Pointer(&{param}.val))");
}
self.lift_value(
&format!("{lift_name}_ptr"),
&err_inner,
&format!("{lift_name}_val"),
);
uwriteln!(self.lift_src, "{lift_name}.SetErr({lift_name}_val)")
} else {
uwriteln!(self.lift_src, "{lift_name}.SetErr(struct{{}}{{}})")
}
uwriteln!(self.lift_src, "}} else {{");
if let Some(ok_inner) = ok {
let ok_inner_name = self.interface.get_c_ty(&ok_inner);
if !is_empty_type(self.interface.resolve, &ok_inner) {
self.interface.gen.needs_import_unsafe = true;
uwriteln!(self.lift_src, "{lift_name}_ptr := *(*{ok_inner_name})(unsafe.Pointer(&{param}.val))");
}
self.lift_value(
&format!("{lift_name}_ptr"),
&ok_inner,
&format!("{lift_name}_val"),
);
uwriteln!(self.lift_src, "{lift_name}.Set({lift_name}_val)")
}
uwriteln!(self.lift_src, "}}");
}
TypeDefKind::List(l) => {
self.interface.gen.needs_import_unsafe = true;
let list_ty = self.interface.get_ty(&Type::Id(*id));
let c_ty_name = self.interface.get_c_ty(l);
uwriteln!(self.lift_src, "var {lift_name} {list_ty}",);
uwriteln!(self.lift_src, "{lift_name} = make({list_ty}, {param}.len)");
uwriteln!(self.lift_src, "if {param}.len > 0 {{");
uwriteln!(self.lift_src, "for {lift_name}_i := 0; {lift_name}_i < int({param}.len); {lift_name}_i++ {{");
uwriteln!(self.lift_src, "var empty_{lift_name} {c_ty_name}");
uwriteln!(
self.lift_src,
"{lift_name}_ptr := *(*{c_ty_name})(unsafe.Pointer(uintptr(unsafe.Pointer({param}.ptr)) +
uintptr({lift_name}_i)*unsafe.Sizeof(empty_{lift_name})))"
);
self.lift_value(
&format!("{lift_name}_ptr"),
l,
&format!("list_{lift_name}"),
);
uwriteln!(
self.lift_src,
"{lift_name}[{lift_name}_i] = list_{lift_name}"
);
self.lift_src.push_str("}\n");
self.lift_src.push_str("}\n");
}
TypeDefKind::Type(t) => {
uwriteln!(
self.lift_src,
"var {lift_name} {value}",
value = self.interface.get_ty(&Type::Id(*id)),
);
self.lift_value(param, t, &format!("{lift_name}_val"));
uwriteln!(self.lift_src, "{lift_name} = {lift_name}_val");
}
TypeDefKind::Variant(v) => {
self.interface.gen.needs_import_unsafe = true;
let name = self.interface.get_ty(&Type::Id(*id));
uwriteln!(self.lift_src, "var {lift_name} {name}");
for (i, case) in v.cases.iter().enumerate() {
let case_name = case.name.to_upper_camel_case();
self.lift_src
.push_str(&format!("if {param}.tag == {i} {{\n"));
if let Some(ty) =
get_nonempty_type(self.interface.resolve, case.ty.as_ref())
{
let ty_name = self.interface.get_c_ty(ty);
uwriteln!(
self.lift_src,
"{lift_name}_ptr := *(*{ty_name})(unsafe.Pointer(&{param}.val))"
);
self.lift_value(
&format!("{lift_name}_ptr"),
ty,
&format!("{lift_name}_val"),
);
uwriteln!(
self.lift_src,
"{lift_name} = {name}{case_name}({lift_name}_val)"
)
} else {
uwriteln!(self.lift_src, "{lift_name} = {name}{case_name}()");
}
self.lift_src.push_str("}\n");
}
}
TypeDefKind::Enum(e) => {
let name = self.interface.get_ty(&Type::Id(*id));
uwriteln!(self.lift_src, "var {lift_name} {name}");
for (i, case) in e.cases.iter().enumerate() {
let case_name = case.name.to_upper_camel_case();
uwriteln!(self.lift_src, "if {param} == {i} {{");
uwriteln!(self.lift_src, "{lift_name} = {name}{case_name}()");
self.lift_src.push_str("}\n");
}
}
TypeDefKind::Union(u) => {
self.interface.gen.needs_import_unsafe = true;
let name = self.interface.get_ty(&Type::Id(*id));
uwriteln!(self.lift_src, "var {lift_name} {name}");
for (i, case) in u.cases.iter().enumerate() {
self.lift_src
.push_str(&format!("if {param}.tag == {i} {{\n"));
let ty = self.interface.get_c_ty(&case.ty);
let case_name = format!("F{i}");
uwriteln!(
self.lift_src,
"
{lift_name}_ptr := *(*{ty})(unsafe.Pointer(&{param}.val))"
);
self.lift_value(
&format!("{lift_name}_ptr"),
&case.ty,
&format!("{lift_name}_val"),
);
uwriteln!(
self.lift_src,
"{lift_name} = {name}{case_name}({lift_name}_val)"
);
self.lift_src.push_str("}\n");
}
}
TypeDefKind::Future(_) => todo!("impl future"),
TypeDefKind::Stream(_) => todo!("impl stream"),
TypeDefKind::Unknown => unreachable!(),
}
}
a => {
let target_name = self.interface.get_ty(a);
uwriteln!(self.lift_src, "var {lift_name} {target_name}",);
uwriteln!(self.lift_src, "{lift_name} = {target_name}({param})",);
}
}
}
fn get_c_field_name(&mut self, field: &Field) -> String {
field.name.to_snake_case()
}
}