examples: Adapt examples/yaml to a broken C generator! woo!

This commit is contained in:
John 2025-04-16 04:13:39 -04:00
parent 8c8f1254e0
commit ef92d8b798

View File

@ -0,0 +1,932 @@
//! Pretty prints a conlang AST in yaml
use cl_ast::{File, Stmt};
use cl_lexer::Lexer;
use cl_parser::Parser;
use repline::{Repline, error::Error as RlError};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
if let Some(path) = std::env::args().nth(1) {
let f = std::fs::read_to_string(&path).expect("Path must be valid.");
let mut parser = Parser::new(path, Lexer::new(&f));
let code: File = match parser.parse() {
Ok(f) => f,
Err(e) => {
eprintln!("{e}");
return Ok(());
}
};
CLangifier::new().p(&code);
println!();
return Ok(());
}
let mut rl = Repline::new("\x1b[33m", "cl>", "? >");
loop {
let mut line = match rl.read() {
Err(RlError::CtrlC(_)) => break,
Err(RlError::CtrlD(line)) => {
rl.deny();
line
}
Ok(line) => line,
Err(e) => Err(e)?,
};
if !line.ends_with(';') {
line.push(';');
}
let mut parser = Parser::new("stdin", Lexer::new(&line));
let code = match parser.parse::<Stmt>() {
Ok(code) => {
rl.accept();
code
}
Err(e) => {
print!("\x1b[40G\x1bJ\x1b[91m{e}\x1b[0m");
continue;
}
};
print!("\x1b[G\x1b[J");
CLangifier::new().p(&code);
println!();
}
Ok(())
}
pub use yamler::CLangifier;
pub mod yamler {
use crate::yamlify::CLangify;
use std::{
fmt::Display,
io::Write,
ops::{Deref, DerefMut},
};
#[derive(Debug, Default)]
pub struct CLangifier {
depth: usize,
}
impl CLangifier {
pub fn new() -> Self {
Self::default()
}
pub fn indent(&mut self) -> Section {
Section::new(self)
}
/// Prints a [Yamlify] value
#[inline]
pub fn p<T: CLangify + ?Sized>(&mut self, yaml: &T) -> &mut Self {
yaml.print(self);
self
}
fn increase(&mut self) {
self.depth += 1;
}
fn decrease(&mut self) {
self.depth -= 1;
}
fn print_indentation(&self, writer: &mut impl Write) {
for _ in 0..self.depth {
let _ = write!(writer, " ");
}
}
pub fn endl(&mut self) -> &mut Self {
self.p("\n")
.print_indentation(&mut std::io::stdout().lock());
self
}
/// Prints a section header and increases indentation
pub fn key(&mut self, name: impl Display) -> Section {
print!("{name}");
self.indent()
}
}
/// Tracks the start and end of an indented block (a "section")
pub struct Section<'y> {
yamler: &'y mut CLangifier,
}
impl<'y> Section<'y> {
pub fn new(yamler: &'y mut CLangifier) -> Self {
yamler.increase();
Self { yamler }
}
}
impl Deref for Section<'_> {
type Target = CLangifier;
fn deref(&self) -> &Self::Target {
self.yamler
}
}
impl DerefMut for Section<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.yamler
}
}
impl Drop for Section<'_> {
fn drop(&mut self) {
let Self { yamler } = self;
yamler.decrease();
}
}
}
pub mod yamlify {
use std::iter;
use super::yamler::CLangifier;
use cl_ast::*;
pub trait CLangify {
fn print(&self, y: &mut CLangifier);
}
impl CLangify for File {
fn print(&self, y: &mut CLangifier) {
let File { name, items } = self;
// TODO: turn name into include guard
y.p("// Generated from ").p(name).endl();
y.p(items);
}
}
impl CLangify for Visibility {
fn print(&self, _y: &mut CLangifier) {}
}
impl CLangify for Mutability {
fn print(&self, y: &mut CLangifier) {
if let Mutability::Not = self {
y.p("const ");
}
}
}
impl CLangify for Attrs {
fn print(&self, y: &mut CLangifier) {
let Self { meta } = self;
y.key("Attrs").p(meta);
todo!("Attributes");
}
}
impl CLangify for Meta {
fn print(&self, y: &mut CLangifier) {
let Self { name, kind } = self;
y.key("Meta").p(name).p(kind);
todo!("Attributes");
}
}
impl CLangify for MetaKind {
fn print(&self, y: &mut CLangifier) {
match self {
MetaKind::Plain => y,
MetaKind::Equals(value) => y.p(value),
MetaKind::Func(args) => y.p(args),
};
todo!("Attributes");
}
}
impl CLangify for Item {
fn print(&self, y: &mut CLangifier) {
let Self { span: _, attrs: _, vis, kind } = self;
y.p(vis).p(kind).endl().endl();
}
}
impl CLangify for ItemKind {
fn print(&self, y: &mut CLangifier) {
match self {
ItemKind::Alias(f) => y.p(f),
ItemKind::Const(f) => y.p(f),
ItemKind::Static(f) => y.p(f),
ItemKind::Module(f) => y.p(f),
ItemKind::Function(f) => y.p(f),
ItemKind::Struct(f) => y.p(f),
ItemKind::Enum(f) => y.p(f),
ItemKind::Impl(f) => y.p(f),
ItemKind::Use(f) => y.p(f),
};
}
}
impl CLangify for Alias {
fn print(&self, y: &mut CLangifier) {
let Self { name, from } = self;
y.p("typedef ").p(from).p(" ");
y.p(name).p("; ");
}
}
impl CLangify for Const {
fn print(&self, y: &mut CLangifier) {
let Self { name, ty, init } = self;
y.p("const ").p(ty).p(" ");
y.p(name).p(" = ").p(init);
}
}
impl CLangify for Static {
fn print(&self, y: &mut CLangifier) {
let Self { mutable, name, ty, init } = self;
y.p(mutable).p(ty).p(" ");
y.p(name).p(" = ").p(init);
}
}
impl CLangify for Module {
fn print(&self, y: &mut CLangifier) {
let Self { name, file } = self;
y.key("// mod ").p(name).p(" {").endl();
y.p(file);
y.endl().p("// } mod ").p(name);
}
}
impl CLangify for Function {
fn print(&self, y: &mut CLangifier) {
let Self { name, sign, bind, body } = self;
let TyFn { args, rety } = sign;
let types = match args.as_ref() {
TyKind::Tuple(TyTuple { types }) => types.as_slice(),
TyKind::Empty => &[],
_ => panic!("Unsupported function args: {args}"),
};
match rety {
Some(ty) => y.p(ty),
None => y.p("void"),
}
.p(" ")
.p(name)
.p("(");
for (idx, (bind, ty)) in bind.iter().zip(types).enumerate() {
if idx > 0 {
y.p(", ");
}
// y.print("/* TODO: desugar pat match args */");
y.p(ty).p(" ").p(bind);
}
y.p(")").p(body);
}
}
impl CLangify for Struct {
fn print(&self, y: &mut CLangifier) {
let Self { name, kind } = self;
y.p("struct ").p(name).key(" {").p(kind);
y.endl().p("}");
}
}
impl CLangify for StructKind {
fn print(&self, y: &mut CLangifier) {
match self {
StructKind::Empty => y.endl().p("char _zero_sized_t;"),
StructKind::Tuple(k) => {
for (idx, ty) in k.iter().enumerate() {
y.endl().p(ty).p(" _").p(&idx).p(";");
}
y
}
StructKind::Struct(k) => y.p(k),
};
}
}
impl CLangify for StructMember {
fn print(&self, y: &mut CLangifier) {
let Self { vis, name, ty } = self;
y.p(vis).p(ty).p(" ").p(name).p(";");
}
}
impl CLangify for Enum {
fn print(&self, y: &mut CLangifier) {
let Self { name, variants } = self;
y.key("enum ").p(name).p(" {").endl();
match variants {
Some(v) => {
for (idx, variant) in v.iter().enumerate() {
if idx > 0 {
y.p(",").endl();
}
y.p(variant);
}
}
None => todo!(),
}
y.endl().p("\n}");
}
}
impl CLangify for Variant {
fn print(&self, y: &mut CLangifier) {
let Self { name, kind } = self;
y.p(name).p(kind);
}
}
impl CLangify for VariantKind {
fn print(&self, y: &mut CLangifier) {
match self {
VariantKind::Plain => y,
VariantKind::CLike(v) => y.p(" = ").p(v),
VariantKind::Tuple(v) => y.p("/* TODO: ").p(v).p(" */"),
VariantKind::Struct(v) => y.p("/* TODO: ").p(v).p(" */"),
};
}
}
impl CLangify for Impl {
fn print(&self, y: &mut CLangifier) {
let Self { target, body } = self;
y.key("/* TODO: impl ").p(target).p(" { */ ");
y.p(body);
y.p("/* } // impl ").p(target).p(" */ ");
}
}
impl CLangify for ImplKind {
fn print(&self, y: &mut CLangifier) {
match self {
ImplKind::Type(t) => y.p(t),
ImplKind::Trait { impl_trait, for_type } => {
todo!("impl {impl_trait} for {for_type}")
}
};
}
}
impl CLangify for Use {
fn print(&self, y: &mut CLangifier) {
let Self { absolute: _, tree } = self;
y.p(tree);
}
}
impl CLangify for UseTree {
fn print(&self, y: &mut CLangifier) {
match self {
UseTree::Tree(trees) => y.p(trees),
UseTree::Path(path, tree) => y.p("/* ").p(path).p(" */").p(tree),
UseTree::Alias(from, to) => y.p("#import <").p(from).p(">.h// ").p(to).p(" "),
UseTree::Name(name) => y.p("#import <").p(name).p(".h> "),
UseTree::Glob => y.p("/* TODO: use globbing */"),
};
}
}
impl CLangify for Block {
fn print(&self, y: &mut CLangifier) {
let Self { stmts } = self;
{
let mut y = y.key("{");
y.endl();
if let [
stmts @ ..,
Stmt { span: _, kind: StmtKind::Expr(expr), semi: Semi::Unterminated },
] = stmts.as_slice()
{
y.p(stmts).p("return ").p(expr).p(";");
} else {
y.p(stmts);
}
}
y.endl().p("}");
}
}
impl CLangify for Stmt {
fn print(&self, y: &mut CLangifier) {
let Self { span: _, kind, semi: _ } = self;
y.p(kind).p(";").endl();
}
}
impl CLangify for Semi {
fn print(&self, y: &mut CLangifier) {
y.p(";");
}
}
impl CLangify for StmtKind {
fn print(&self, y: &mut CLangifier) {
match self {
StmtKind::Empty => y,
StmtKind::Item(s) => y.p(s),
StmtKind::Expr(s) => y.p(s),
};
}
}
impl CLangify for Expr {
fn print(&self, y: &mut CLangifier) {
let Self { span: _, kind } = self;
y.p(kind);
}
}
impl CLangify for ExprKind {
fn print(&self, y: &mut CLangifier) {
match self {
ExprKind::Quote(k) => k.print(y),
ExprKind::Let(k) => k.print(y),
ExprKind::Match(k) => k.print(y),
ExprKind::Assign(k) => k.print(y),
ExprKind::Modify(k) => k.print(y),
ExprKind::Binary(k) => k.print(y),
ExprKind::Unary(k) => k.print(y),
ExprKind::Cast(k) => k.print(y),
ExprKind::Member(k) => k.print(y),
ExprKind::Index(k) => k.print(y),
ExprKind::Structor(k) => k.print(y),
ExprKind::Path(k) => k.print(y),
ExprKind::Literal(k) => k.print(y),
ExprKind::Array(k) => k.print(y),
ExprKind::ArrayRep(k) => k.print(y),
ExprKind::AddrOf(k) => k.print(y),
ExprKind::Block(k) => k.print(y),
ExprKind::Empty => {}
ExprKind::Group(k) => k.print(y),
ExprKind::Tuple(k) => k.print(y),
ExprKind::While(k) => k.print(y),
ExprKind::If(k) => k.print(y),
ExprKind::For(k) => k.print(y),
ExprKind::Break(k) => k.print(y),
ExprKind::Return(k) => k.print(y),
ExprKind::Continue => {
y.key("continue");
}
}
}
}
impl CLangify for Quote {
fn print(&self, y: &mut CLangifier) {
y.key("\"");
print!("{self}");
y.p("\"");
}
}
impl CLangify for Let {
fn print(&self, y: &mut CLangifier) {
let Self { mutable, name, ty, init } = self;
let ty = ty.as_deref().map(|ty| &ty.kind).unwrap_or(&TyKind::Infer);
match ty {
TyKind::Array(TyArray { ty, count }) => {
y.p(ty).p(" ").p(mutable).p(name).p("[").p(count).p("]");
}
TyKind::Fn(TyFn { args, rety }) => {
y.key("(").p(rety).p(" *").p(mutable).p(name).p(")(");
match args.as_ref() {
TyKind::Empty => {}
TyKind::Tuple(TyTuple { types }) => {
for (idx, ty) in types.iter().enumerate() {
if idx > 0 {
y.p(", ");
}
y.p(ty);
}
}
_ => {
y.p(args);
}
}
y.p(")");
}
_ => {
y.indent().p(ty).p(" ").p(mutable).p(name);
}
}
if let Some(init) = init {
y.p(" = ").p(init);
}
}
}
impl CLangify for Pattern {
fn print(&self, y: &mut CLangifier) {
// TODO: Pattern match desugaring!!!
match self {
Pattern::Name(name) => y.p(name),
Pattern::Literal(literal) => y.p(literal),
Pattern::Rest(name) => y.p("..").p(name),
Pattern::Ref(mutability, pattern) => y.p("&").p(mutability).p(pattern),
Pattern::Tuple(patterns) => y.key("Tuple").p(patterns),
Pattern::Array(patterns) => y.key("Array").p(patterns),
Pattern::Struct(path, items) => {
{
let mut y = y.key("Struct");
y.p(path);
for (name, item) in items {
y.p(name).p(item);
}
}
y
}
Pattern::TupleStruct(path, items) => {
{
let mut y = y.key("TupleStruct");
y.p(path).p(items);
}
y
}
};
}
}
impl CLangify for Match {
fn print(&self, y: &mut CLangifier) {
let Self { scrutinee, arms } = self;
y.p("/* match ").p(scrutinee);
y.key(" { ").p(arms);
y.p(" } */");
}
}
impl CLangify for MatchArm {
fn print(&self, y: &mut CLangifier) {
let Self(pat, expr) = self;
y.p(pat).p(" => ").p(expr).p(", ");
}
}
impl CLangify for Assign {
fn print(&self, y: &mut CLangifier) {
let Self { parts } = self;
y.p(&parts.0).p(" = ").p(&parts.1);
}
}
impl CLangify for Modify {
fn print(&self, y: &mut CLangifier) {
let Self { kind, parts } = self;
y.p(&parts.0).p(kind).p(&parts.1);
}
}
impl CLangify for ModifyKind {
fn print(&self, _y: &mut CLangifier) {
print!(" {self} ");
}
}
impl CLangify for Binary {
fn print(&self, y: &mut CLangifier) {
let Self { kind, parts } = self;
match kind {
BinaryKind::Call => y.p(&parts.0).p(&parts.1),
_ => y.p("(").p(&parts.0).p(kind).p(&parts.1).p(")"),
};
}
}
impl CLangify for BinaryKind {
fn print(&self, _y: &mut CLangifier) {
print!(" {self} ");
}
}
impl CLangify for Unary {
fn print(&self, y: &mut CLangifier) {
let Self { kind, tail } = self;
match kind {
UnaryKind::Deref => y.p("*").p(tail),
UnaryKind::Neg => y.p("-").p(tail),
UnaryKind::Not => y.p("!").p(tail),
UnaryKind::RangeInc => todo!("Unary RangeInc in C"),
UnaryKind::RangeExc => todo!("Unary RangeExc in C"),
UnaryKind::Loop => y.key("while (1) { ").p(tail).p(" }"),
UnaryKind::At => todo!(),
UnaryKind::Tilde => todo!(),
};
}
}
impl CLangify for Cast {
fn print(&self, y: &mut CLangifier) {
let Self { head, ty } = self;
y.key("(").p(ty).p(")");
y.p(head);
}
}
impl CLangify for Member {
fn print(&self, y: &mut CLangifier) {
let Self { head, kind } = self;
match kind {
MemberKind::Call(name, Tuple { exprs }) => {
y.p(name);
y.p("(");
for (idx, expr) in iter::once(head.as_ref()).chain(exprs).enumerate() {
if idx > 0 {
y.p(", ");
}
y.p(expr);
}
y.p(")")
}
MemberKind::Struct(name) => y.p(head).p(".").p(name),
MemberKind::Tuple(idx) => y.p(head).p("._").p(idx),
};
}
}
impl CLangify for Tuple {
fn print(&self, y: &mut CLangifier) {
let Self { exprs } = self;
let mut y = y.key("( ");
for (idx, expr) in exprs.iter().enumerate() {
if idx > 0 {
y.p(", ");
}
y.p(expr);
}
y.p(" )");
}
}
impl CLangify for Index {
fn print(&self, y: &mut CLangifier) {
let Self { head, indices } = self;
y.p(head);
for index in indices {
y.p("[").p(index).p("]");
}
}
}
impl CLangify for Structor {
fn print(&self, y: &mut CLangifier) {
let Self { to, init } = self;
y.key("(").p(to).p(")");
{
let mut y = y.key("{ ");
for (idx, field) in init.iter().enumerate() {
if idx > 0 {
y.p(", ");
}
y.p(field);
}
y.p(init);
}
y.p("}");
}
}
impl CLangify for Fielder {
fn print(&self, y: &mut CLangifier) {
let Self { name, init } = self;
y.p(".").p(name).p(" = ").p(init);
}
}
impl CLangify for Array {
fn print(&self, y: &mut CLangifier) {
let Self { values } = self;
{
let mut y = y.key("{");
y.endl();
for (idx, value) in values.iter().enumerate() {
if idx > 0 {
y.p(", ");
}
y.p(value);
}
}
y.endl().p("}");
}
}
impl CLangify for ArrayRep {
fn print(&self, y: &mut CLangifier) {
let Self { value, repeat } = self;
// TODO: compile time evaluation
let ExprKind::Literal(Literal::Int(count)) = &repeat.kind else {
panic!("Unsupported repeat count: {repeat}");
};
{
let mut y = y.key("{");
y.endl();
for idx in 0..*count {
if idx > 0 {
y.p(", ");
}
y.p(value);
}
}
y.endl().p("}");
}
}
impl CLangify for AddrOf {
fn print(&self, y: &mut CLangifier) {
let Self { mutable: _, expr } = self;
y.p("&").p(expr);
}
}
impl CLangify for Group {
fn print(&self, y: &mut CLangifier) {
let Self { expr } = self;
y.p("(").p(expr).p(")");
}
}
impl CLangify for While {
fn print(&self, y: &mut CLangifier) {
// TODO: to properly propagate intermediate values, a new temp variable needs to be
// declared on every line lmao. This will require type info.
let Self { cond, pass, fail } = self;
let Else { body: fail } = fail;
y.key("while(1) { if (").p(cond).p(")").p(pass);
if let Some(fail) = fail {
y.p("else { ").p(fail).p("; break; }");
}
}
}
impl CLangify for Else {
fn print(&self, y: &mut CLangifier) {
let Self { body } = self;
if let Some(body) = body {
y.key("else ").p(body);
}
}
}
impl CLangify for If {
fn print(&self, y: &mut CLangifier) {
let Self { cond, pass, fail } = self;
y.p("(").p(cond).p(")");
y.p(pass).p(fail);
}
}
impl CLangify for For {
#[rustfmt::skip]
fn print(&self, y: &mut CLangifier) {
let Self { bind, cond, pass, fail: _ } = self;
let (mode, (head, tail)) = match &cond.kind {
ExprKind::Binary(Binary { kind: BinaryKind::RangeExc, parts }) => (false, &**parts),
ExprKind::Binary(Binary { kind: BinaryKind::RangeInc, parts }) => (true, &**parts),
_ => todo!("Clangify for loops"),
};
// for (int bind = head; bind mode? < : <= tail; bind++);
y.p("for ( int ").p(bind).p(" = ").p(head).p("; ");
y.p(bind).p(if mode {"<="} else {"<"}).p(tail).p("; ");
y.p("++").p(bind).p(" ) ").p(pass);
}
}
impl CLangify for Break {
fn print(&self, y: &mut CLangifier) {
let Self { body } = self;
y.key("break ").p(body);
}
}
impl CLangify for Return {
fn print(&self, y: &mut CLangifier) {
let Self { body } = self;
y.key("return ").p(body);
}
}
impl CLangify for Literal {
fn print(&self, y: &mut CLangifier) {
match self {
Literal::Float(l) => y.p(l),
Literal::Bool(l) => y.p(l),
Literal::Int(l) => y.p(l),
Literal::Char(l) => y.p("'").p(l).p("'"),
Literal::String(l) => y.p(&'"').p(l).p(&'"'),
};
}
}
impl CLangify for Sym {
fn print(&self, y: &mut CLangifier) {
y.p(self.to_ref());
}
}
impl CLangify for Ty {
fn print(&self, y: &mut CLangifier) {
let Self { span: _, kind } = self;
y.p(kind);
}
}
impl CLangify for TyKind {
fn print(&self, y: &mut CLangifier) {
match self {
TyKind::Never => y.p("Never"),
TyKind::Empty => y.p("Empty"),
TyKind::Infer => y.p("Any"),
TyKind::Path(t) => y.p(t),
TyKind::Tuple(t) => y.p(t),
TyKind::Ref(t) => y.p(t),
TyKind::Fn(t) => y.p(t),
TyKind::Slice(t) => y.p(t),
TyKind::Array(t) => y.p(t),
};
}
}
impl CLangify for Path {
fn print(&self, y: &mut CLangifier) {
let Self { absolute: _, parts } = self;
for (idx, part) in parts.iter().enumerate() {
if idx > 0 {
y.p("_");
}
y.p(part);
}
}
}
impl CLangify for PathPart {
fn print(&self, y: &mut CLangifier) {
match self {
PathPart::SuperKw => y.p("super"),
PathPart::SelfKw => y.p("self"),
PathPart::SelfTy => y.p("Self"),
PathPart::Ident(i) => y.p(i),
};
}
}
impl CLangify for TyArray {
fn print(&self, y: &mut CLangifier) {
let Self { ty, count } = self;
y.p(ty).p("[").p(count).p("]");
}
}
impl CLangify for TySlice {
fn print(&self, y: &mut CLangifier) {
let Self { ty } = self;
y.p(ty).p("* ");
}
}
impl CLangify for TyTuple {
fn print(&self, y: &mut CLangifier) {
let Self { types } = self;
{
let mut y = y.key("struct {");
y.endl();
for (idx, ty) in types.iter().enumerate() {
if idx > 0 {
y.p(",").endl();
}
y.p(ty);
}
}
y.endl().p("}");
}
}
impl CLangify for TyRef {
fn print(&self, y: &mut CLangifier) {
let Self { count, mutable, to } = self;
y.p(mutable).p(to);
for _ in 0..*count {
y.p("*");
}
}
}
impl CLangify for TyFn {
fn print(&self, y: &mut CLangifier) {
let Self { args, rety } = self;
// TODO: function pointer syntax
y.key("*(").p(rety).p(")(");
match args.as_ref() {
TyKind::Empty => y,
TyKind::Tuple(TyTuple { types }) => {
for (idx, ty) in types.iter().enumerate() {
if idx > 0 {
y.p(", ");
}
y.p(ty);
}
y
}
_ => y.p(args),
}
.p(")");
}
}
impl<T: CLangify> CLangify for Option<T> {
fn print(&self, y: &mut CLangifier) {
if let Some(v) = self {
y.p(v);
}
}
}
impl<T: CLangify> CLangify for Box<T> {
fn print(&self, y: &mut CLangifier) {
y.p(&**self);
}
}
impl<T: CLangify> CLangify for Vec<T> {
fn print(&self, y: &mut CLangifier) {
for thing in self {
y.p(thing);
}
}
}
impl<T: CLangify> CLangify for [T] {
fn print(&self, y: &mut CLangifier) {
for thing in self {
y.p(thing);
}
}
}
impl CLangify for () {
fn print(&self, _y: &mut CLangifier) {
// TODO: C has no language support for zst
}
}
impl<T: CLangify> CLangify for &T {
fn print(&self, y: &mut CLangifier) {
(*self).print(y)
}
}
impl CLangify for std::fmt::Arguments<'_> {
fn print(&self, _y: &mut CLangifier) {
print!("{self}")
}
}
macro_rules! scalar {
($($t:ty),*$(,)?) => {
$(impl CLangify for $t {
fn print(&self, _y: &mut CLangifier) {
print!("{self}");
}
})*
};
}
scalar! {
bool, char, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, str, &str, String
}
}