use super::utils::{fmt_long_expression, id_is_gensym, inline_export_is_empty, ty_use_is_empty};
use super::{Fmt, Formatter};
use wast::core::{Func, FuncKind, FunctionType, Local, TypeUse, ValType};
use wast::kw;
use wast::token::{Id, ItemRef, NameAnnotation};
impl<'src> Fmt for &Func<'src> {
fn fmt(&self, formatter: &mut Formatter) {
formatter.start_line();
formatter.write("(func");
if let Some(id) = &self.id {
if !id_is_gensym(id) {
formatter.write(" ");
formatter.fmt(id);
}
}
if !inline_export_is_empty(&self.exports) {
formatter.write(" ");
formatter.fmt(&self.exports);
}
if let FuncKind::Import(inline_import) = &self.kind {
formatter.write(" ");
formatter.fmt(inline_import);
}
if !ty_use_is_empty(&self.ty) {
formatter.write(" ");
formatter.fmt(&self.ty);
}
if let FuncKind::Inline { locals, expression } = &self.kind {
if !locals.is_empty() || !expression.instrs.is_empty() {
formatter.end_line();
formatter.indent();
formatter.fmt(locals);
fmt_long_expression(expression, formatter);
formatter.deindent();
formatter.start_line();
}
}
formatter.write(")");
formatter.end_line();
}
}
impl<'src> Fmt for &TypeUse<'src, FunctionType<'src>> {
fn fmt(&self, formatter: &mut Formatter) {
if let Some(index) = &self.index {
formatter.write("(type ");
formatter.fmt(index);
formatter.write(")");
};
if let Some(functy) = &self.inline {
if !functy.params.is_empty() {
if self.index.is_some() {
formatter.write(" ");
}
formatter.fmt(&*functy.params);
}
if !functy.results.is_empty() {
if self.index.is_some() || !functy.params.is_empty() {
formatter.write(" ");
}
formatter.fmt(&*functy.results);
}
};
}
}
impl<'src> Fmt for &ItemRef<'src, kw::r#type> {
fn fmt(&self, formatter: &mut Formatter) {
formatter.write("(type ");
formatter.fmt(&self.idx);
formatter.write(")");
}
}
type Param<'src> = (
Option<Id<'src>>,
Option<NameAnnotation<'src>>,
ValType<'src>,
);
impl<'src> Fmt for &[Param<'src>] {
fn fmt(&self, formatter: &mut Formatter) {
if !self.is_empty() {
if params_can_be_abbreviated(self) {
formatter.write("(param");
for param in self.iter() {
formatter.write(" ");
formatter.fmt(¶m.2);
}
formatter.write(")");
} else {
let mut params = self.iter();
if let Some((id, _, ty)) = params.next() {
formatter.write("(param ");
if let Some(id) = id {
formatter.fmt(id);
formatter.write(" ");
}
formatter.fmt(ty);
formatter.write(")");
}
for (id, _, ty) in params {
formatter.write(" (param ");
if let Some(id) = id {
formatter.fmt(id);
formatter.write(" ");
}
formatter.fmt(ty);
formatter.write(")");
}
}
}
}
}
fn params_can_be_abbreviated(params: &[Param]) -> bool {
params.iter().all(param_is_anonymous)
}
fn param_is_anonymous(param: &Param) -> bool {
param.0.is_none()
}
impl<'src> Fmt for &[ValType<'src>] {
fn fmt(&self, formatter: &mut Formatter) {
if !self.is_empty() {
formatter.write("(result");
for result in self.iter() {
formatter.write(" ");
formatter.fmt(result);
}
formatter.write(")");
}
}
}
impl<'src> Fmt for &ValType<'src> {
fn fmt(&self, formatter: &mut Formatter) {
match self {
ValType::I32 => formatter.write("i32"),
ValType::I64 => formatter.write("i64"),
ValType::F32 => formatter.write("f32"),
ValType::F64 => formatter.write("f64"),
ValType::V128 => unimplemented!(),
ValType::Ref(..) => unimplemented!(),
};
}
}
impl<'src> Fmt for &Vec<Local<'src>> {
fn fmt(&self, formatter: &mut Formatter) {
if !self.is_empty() {
if locals_can_be_abbreviated(self) {
formatter.start_line();
formatter.write("(local");
for local in self.iter() {
formatter.write(" ");
formatter.fmt(&local.ty);
}
formatter.write(")");
formatter.end_line();
} else {
for local in self.iter() {
formatter.start_line();
formatter.write("(local ");
if let Some(id) = &local.id {
formatter.fmt(id);
formatter.write(" ");
}
formatter.fmt(&local.ty);
formatter.write(")");
formatter.end_line();
}
}
}
}
}
fn locals_can_be_abbreviated(locals: &[Local]) -> bool {
locals.iter().all(local_is_anonymous)
}
fn local_is_anonymous(local: &Local) -> bool {
local.id.is_none()
}