feat: add a histrical wit-bindgen

This commit is contained in:
2023-01-01 00:25:48 +08:00
parent 01e8f5a959
commit aa50d63aec
419 changed files with 45283 additions and 1 deletions

View File

@@ -0,0 +1,466 @@
use heck::*;
use pulldown_cmark::{html, Event, LinkType, Parser, Tag};
use std::collections::HashMap;
use wit_bindgen_gen_core::{wit_parser, Direction, Files, Generator, Source};
use wit_parser::*;
#[derive(Default)]
pub struct Markdown {
src: Source,
opts: Opts,
sizes: SizeAlign,
hrefs: HashMap<String, String>,
funcs: usize,
types: usize,
}
#[derive(Default, Debug, Clone)]
#[cfg_attr(feature = "structopt", derive(structopt::StructOpt))]
pub struct Opts {
// ...
}
impl Opts {
pub fn build(&self) -> Markdown {
let mut r = Markdown::new();
r.opts = self.clone();
r
}
}
impl Markdown {
pub fn new() -> Markdown {
Markdown::default()
}
fn print_ty(&mut self, iface: &Interface, ty: &Type, skip_name: bool) {
match ty {
Type::Unit => self.src.push_str("`unit`"),
Type::Bool => self.src.push_str("`bool`"),
Type::U8 => self.src.push_str("`u8`"),
Type::S8 => self.src.push_str("`s8`"),
Type::U16 => self.src.push_str("`u16`"),
Type::S16 => self.src.push_str("`s16`"),
Type::U32 => self.src.push_str("`u32`"),
Type::S32 => self.src.push_str("`s32`"),
Type::U64 => self.src.push_str("`u64`"),
Type::S64 => self.src.push_str("`s64`"),
Type::Float32 => self.src.push_str("`float32`"),
Type::Float64 => self.src.push_str("`float64`"),
Type::Char => self.src.push_str("`char`"),
Type::String => self.src.push_str("`string`"),
Type::Handle(id) => {
self.src.push_str("handle<");
self.src.push_str(&iface.resources[*id].name);
self.src.push_str(">");
}
Type::Id(id) => {
let ty = &iface.types[*id];
if !skip_name {
if let Some(name) = &ty.name {
self.src.push_str("[`");
self.src.push_str(name);
self.src.push_str("`](#");
self.src.push_str(&name.to_snake_case());
self.src.push_str(")");
return;
}
}
match &ty.kind {
TypeDefKind::Type(t) => self.print_ty(iface, t, false),
TypeDefKind::Tuple(t) => {
self.src.push_str("(");
for (i, t) in t.types.iter().enumerate() {
if i > 0 {
self.src.push_str(", ");
}
self.print_ty(iface, t, false);
}
self.src.push_str(")");
}
TypeDefKind::Record(_)
| TypeDefKind::Flags(_)
| TypeDefKind::Enum(_)
| TypeDefKind::Variant(_)
| TypeDefKind::Union(_) => {
unreachable!()
}
TypeDefKind::Option(t) => {
self.src.push_str("option<");
self.print_ty(iface, t, false);
self.src.push_str(">");
}
TypeDefKind::Expected(e) => {
self.src.push_str("expected<");
self.print_ty(iface, &e.ok, false);
self.src.push_str(", ");
self.print_ty(iface, &e.err, false);
self.src.push_str(">");
}
TypeDefKind::List(t) => {
self.src.push_str("list<");
self.print_ty(iface, t, false);
self.src.push_str(">");
}
TypeDefKind::Future(t) => {
self.src.push_str("future<");
self.print_ty(iface, t, false);
self.src.push_str(">");
}
TypeDefKind::Stream(s) => {
self.src.push_str("stream<");
self.print_ty(iface, &s.element, false);
self.src.push_str(", ");
self.print_ty(iface, &s.end, false);
self.src.push_str(">");
}
}
}
}
}
fn docs(&mut self, docs: &Docs) {
let docs = match &docs.contents {
Some(docs) => docs,
None => return,
};
for line in docs.lines() {
self.src.push_str(line.trim());
self.src.push_str("\n");
}
}
fn print_type_header(&mut self, name: &str) {
if self.types == 0 {
self.src.push_str("# Types\n\n");
}
self.types += 1;
self.src.push_str(&format!(
"## <a href=\"#{}\" name=\"{0}\"></a> `{}`: ",
name.to_snake_case(),
name,
));
self.hrefs
.insert(name.to_string(), format!("#{}", name.to_snake_case()));
}
fn print_type_info(&mut self, ty: TypeId, docs: &Docs) {
self.docs(docs);
self.src.push_str("\n");
self.src
.push_str(&format!("Size: {}, ", self.sizes.size(&Type::Id(ty))));
self.src
.push_str(&format!("Alignment: {}\n", self.sizes.align(&Type::Id(ty))));
}
}
impl Generator for Markdown {
fn preprocess_one(&mut self, iface: &Interface, _dir: Direction) {
self.sizes.fill(iface);
}
fn type_record(
&mut self,
iface: &Interface,
id: TypeId,
name: &str,
record: &Record,
docs: &Docs,
) {
self.print_type_header(name);
self.src.push_str("record\n\n");
self.print_type_info(id, docs);
self.src.push_str("\n### Record Fields\n\n");
for field in record.fields.iter() {
self.src.push_str(&format!(
"- <a href=\"{r}.{f}\" name=\"{r}.{f}\"></a> [`{name}`](#{r}.{f}): ",
r = name.to_snake_case(),
f = field.name.to_snake_case(),
name = field.name,
));
self.hrefs.insert(
format!("{}::{}", name, field.name),
format!("#{}.{}", name.to_snake_case(), field.name.to_snake_case()),
);
self.print_ty(iface, &field.ty, false);
self.src.indent(1);
self.src.push_str("\n\n");
self.docs(&field.docs);
self.src.deindent(1);
self.src.push_str("\n");
}
}
fn type_tuple(
&mut self,
iface: &Interface,
id: TypeId,
name: &str,
tuple: &Tuple,
docs: &Docs,
) {
self.print_type_header(name);
self.src.push_str("tuple\n\n");
self.print_type_info(id, docs);
self.src.push_str("\n### Tuple Fields\n\n");
for (i, ty) in tuple.types.iter().enumerate() {
self.src.push_str(&format!(
"- <a href=\"{r}.{f}\" name=\"{r}.{f}\"></a> [`{name}`](#{r}.{f}): ",
r = name.to_snake_case(),
f = i,
name = i,
));
self.hrefs.insert(
format!("{}::{}", name, i),
format!("#{}.{}", name.to_snake_case(), i),
);
self.print_ty(iface, ty, false);
self.src.push_str("\n");
}
}
fn type_flags(
&mut self,
_iface: &Interface,
id: TypeId,
name: &str,
flags: &Flags,
docs: &Docs,
) {
self.print_type_header(name);
self.src.push_str("record\n\n");
self.print_type_info(id, docs);
self.src.push_str("\n### Record Fields\n\n");
for (i, flag) in flags.flags.iter().enumerate() {
self.src.push_str(&format!(
"- <a href=\"{r}.{f}\" name=\"{r}.{f}\"></a> [`{name}`](#{r}.{f}): ",
r = name.to_snake_case(),
f = flag.name.to_snake_case(),
name = flag.name,
));
self.hrefs.insert(
format!("{}::{}", name, flag.name),
format!("#{}.{}", name.to_snake_case(), flag.name.to_snake_case()),
);
self.src.indent(1);
self.src.push_str("\n\n");
self.docs(&flag.docs);
self.src.deindent(1);
self.src.push_str(&format!("Bit: {}\n", i));
self.src.push_str("\n");
}
}
fn type_variant(
&mut self,
iface: &Interface,
id: TypeId,
name: &str,
variant: &Variant,
docs: &Docs,
) {
self.print_type_header(name);
self.src.push_str("variant\n\n");
self.print_type_info(id, docs);
self.src.push_str("\n### Variant Cases\n\n");
for case in variant.cases.iter() {
self.src.push_str(&format!(
"- <a href=\"{v}.{c}\" name=\"{v}.{c}\"></a> [`{name}`](#{v}.{c})",
v = name.to_snake_case(),
c = case.name.to_snake_case(),
name = case.name,
));
self.hrefs.insert(
format!("{}::{}", name, case.name),
format!("#{}.{}", name.to_snake_case(), case.name.to_snake_case()),
);
self.src.push_str(": ");
self.print_ty(iface, &case.ty, false);
self.src.indent(1);
self.src.push_str("\n\n");
self.docs(&case.docs);
self.src.deindent(1);
self.src.push_str("\n");
}
}
fn type_union(
&mut self,
iface: &Interface,
id: TypeId,
name: &str,
union: &Union,
docs: &Docs,
) {
self.print_type_header(name);
self.src.push_str("union\n\n");
self.print_type_info(id, docs);
self.src.push_str("\n### Union Cases\n\n");
let snake = name.to_snake_case();
for (i, case) in union.cases.iter().enumerate() {
self.src.push_str(&format!(
"- <a href=\"{snake}.{i}\" name=\"{snake}.{i}\"></a> [`{i}`](#{snake}.{i})",
));
self.hrefs
.insert(format!("{name}::{i}"), format!("#{snake}.{i}"));
self.src.push_str(": ");
self.print_ty(iface, &case.ty, false);
self.src.indent(1);
self.src.push_str("\n\n");
self.docs(&case.docs);
self.src.deindent(1);
self.src.push_str("\n");
}
}
fn type_enum(&mut self, _iface: &Interface, id: TypeId, name: &str, enum_: &Enum, docs: &Docs) {
self.print_type_header(name);
self.src.push_str("enum\n\n");
self.print_type_info(id, docs);
self.src.push_str("\n### Enum Cases\n\n");
for case in enum_.cases.iter() {
self.src.push_str(&format!(
"- <a href=\"{v}.{c}\" name=\"{v}.{c}\"></a> [`{name}`](#{v}.{c})",
v = name.to_snake_case(),
c = case.name.to_snake_case(),
name = case.name,
));
self.hrefs.insert(
format!("{}::{}", name, case.name),
format!("#{}.{}", name.to_snake_case(), case.name.to_snake_case()),
);
self.src.indent(1);
self.src.push_str("\n\n");
self.docs(&case.docs);
self.src.deindent(1);
self.src.push_str("\n");
}
}
fn type_option(
&mut self,
iface: &Interface,
id: TypeId,
name: &str,
payload: &Type,
docs: &Docs,
) {
self.print_type_header(name);
self.src.push_str("option<");
self.print_ty(iface, payload, false);
self.src.push_str(">");
self.print_type_info(id, docs);
}
fn type_expected(
&mut self,
iface: &Interface,
id: TypeId,
name: &str,
expected: &Expected,
docs: &Docs,
) {
self.print_type_header(name);
self.src.push_str("expected<");
self.print_ty(iface, &expected.ok, false);
self.src.push_str(", ");
self.print_ty(iface, &expected.err, false);
self.src.push_str(">");
self.print_type_info(id, docs);
}
fn type_resource(&mut self, iface: &Interface, ty: ResourceId) {
drop((iface, ty));
}
fn type_alias(&mut self, iface: &Interface, id: TypeId, name: &str, ty: &Type, docs: &Docs) {
self.print_type_header(name);
self.print_ty(iface, ty, true);
self.src.push_str("\n\n");
self.print_type_info(id, docs);
self.src.push_str("\n");
}
fn type_list(&mut self, iface: &Interface, id: TypeId, name: &str, _ty: &Type, docs: &Docs) {
self.type_alias(iface, id, name, &Type::Id(id), docs);
}
fn type_builtin(&mut self, iface: &Interface, id: TypeId, name: &str, ty: &Type, docs: &Docs) {
self.type_alias(iface, id, name, ty, docs)
}
fn import(&mut self, iface: &Interface, func: &Function) {
if self.funcs == 0 {
self.src.push_str("# Functions\n\n");
}
self.funcs += 1;
self.src.push_str("----\n\n");
self.src.push_str(&format!(
"#### <a href=\"#{0}\" name=\"{0}\"></a> `",
func.name.to_snake_case()
));
self.hrefs
.insert(func.name.clone(), format!("#{}", func.name.to_snake_case()));
self.src.push_str(&func.name);
self.src.push_str("` ");
self.src.push_str("\n\n");
self.docs(&func.docs);
if func.params.len() > 0 {
self.src.push_str("##### Params\n\n");
for (name, ty) in func.params.iter() {
self.src.push_str(&format!(
"- <a href=\"#{f}.{p}\" name=\"{f}.{p}\"></a> `{}`: ",
name,
f = func.name.to_snake_case(),
p = name.to_snake_case(),
));
self.print_ty(iface, ty, false);
self.src.push_str("\n");
}
}
match &func.result {
Type::Unit => {}
ty => {
self.src.push_str("##### Results\n\n");
self.src.push_str(&format!(
"- <a href=\"#{f}.{p}\" name=\"{f}.{p}\"></a> `{}`: ",
"result",
f = func.name.to_snake_case(),
p = "result",
));
self.print_ty(iface, ty, false);
self.src.push_str("\n");
}
}
self.src.push_str("\n");
}
fn export(&mut self, iface: &Interface, func: &Function) {
self.import(iface, func);
}
fn finish_one(&mut self, _iface: &Interface, files: &mut Files) {
let parser = Parser::new(&self.src);
let mut events = Vec::new();
for event in parser {
if let Event::Code(code) = &event {
if let Some(dst) = self.hrefs.get(code.as_ref()) {
let tag = Tag::Link(LinkType::Inline, dst.as_str().into(), "".into());
events.push(Event::Start(tag.clone()));
events.push(event.clone());
events.push(Event::End(tag));
continue;
}
}
events.push(event);
}
let mut html_output = String::new();
html::push_html(&mut html_output, events.into_iter());
files.push("bindings.md", self.src.as_bytes());
files.push("bindings.html", html_output.as_bytes());
}
}