mist-codegen 0.3.1-alpha.0

The Mist programming language Rust code generator
Documentation
use mist_parser::ast::*;

use crate::{Context, class_decl};

use crate::{GenRust, GetRust, RustCodegen};

impl GetRust for GenericsDecl {
    fn get_rust(&self) -> String {
        if self.0.len() == 0 {
            String::new()
        } else {
            format!(
                "<{}>",
                self.0
                    .iter()
                    .map(|v| v.get_rust())
                    .collect::<Vec<_>>()
                    .join(", ")
            )
        }
    }
}

impl GetRust for GenericDecl {
    fn get_rust(&self) -> String {
        match self {
            GenericDecl::Lifetime(name) => format!("'{}", name.get_rust()),
            GenericDecl::Type(name, requirements) => {
                name.get_rust()
                    + &(if requirements.len() != 0 {
                        format!(
                            ": {}",
                            requirements
                                .into_iter()
                                .map(TypeExpr::get_rust)
                                .collect::<Vec<_>>()
                                .join("+")
                        )
                    } else {
                        String::new()
                    })
            }
        }
    }
}

impl GenRust for ImplDecl {
    fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
        if let Some(trait_) = &self.trait_ {
            cg.add_indentedln(&format!(
                "impl{} {} for {} {{",
                self.generics.get_rust(),
                trait_.get_rust(),
                self.target.get_rust()
            ));
        } else {
            cg.add_indentedln(&format!(
                "impl{} {} {{",
                self.generics.get_rust(),
                self.target.get_rust()
            ));
        }
        cg.indent += 1;

        for method in &self.methods {
            method.gen_rust(ctx, cg);
        }

        cg.indent -= 1;
        cg.add_indentedln("}");
    }
}

impl GenRust for FunctionDecl {
    fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
        cg.add(&format!(
            "{}fn {}{}(",
            self.visibility.get_rust(),
            self.name.get_rust(),
            self.generics.get_rust(),
        ));

        for (i, param) in self.params.0.iter().enumerate() {
            if i > 0 {
                cg.add(", ");
            }

            param.gen_rust(ctx, cg);
        }

        cg.add(") ");
        if let Some(return_type) = &self.return_type {
            cg.add("-> ");
            cg.add(&return_type.get_rust());
        }

        if let Some(body) = &self.body {
            cg.add(" ");
            body.gen_rust(ctx, cg);
        } else {
            cg.add(";");
        }
    }
}

impl GetRust for FieldDecl {
    fn get_rust(&self) -> String {
        format!(
            "{}{}: {},",
            self.visibility.get_rust(),
            self.name.get_rust(),
            self.type_.get_rust()
        )
    }
}

impl GetRust for EnumItem {
    fn get_rust(&self) -> String {
        match self {
            Self::Named(id) => id.get_rust(),
            Self::Struct(id, s) => format!(
                "{} {{{}}}",
                id.get_rust(),
                s.into_iter()
                    .map(|field| format!("{}: {}", field.name.get_rust(), field.type_.get_rust()))
                    .collect::<Vec<_>>()
                    .join(", ")
            ),
            Self::Tuple(id, t) => format!(
                "{} ({})",
                id.get_rust(),
                t.into_iter()
                    .map(TypeExpr::get_rust)
                    .collect::<Vec<_>>()
                    .join(", ")
            ),
        }
    }
}

impl GenRust for ParamList {
    fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
        for (i, param) in self.0.iter().enumerate() {
            if i > 0 {
                cg.add(", ");
            }

            param.gen_rust(ctx, cg);
        }
    }
}

impl GenRust for TopLevel {
    fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
        if let TopLevelKind::ModAttribute = self.0.item {
            for attr in &self.1 {
                cg.add("#![");
                attr.gen_rust(ctx, cg);
                cg.addln("]");
            }
        } else {
            for attr in &self.1 {
                cg.add("#[");
                attr.gen_rust(ctx, cg);
                cg.addln("]");
            }
        }

        self.0.gen_rust(ctx, cg);
    }
}

impl GenRust for TopLevelKind {
    fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) {
        match self {
            Self::ModAttribute => {}
            Self::Import(vis, path) => {
                cg.addln(&format!("{}use {};", vis.get_rust(), path.get_rust()))
            }
            Self::Mod(vis, id) => cg.addln(&format!("{}mod {};", vis.get_rust(), id.get_rust())),
            Self::FunctionDecl(decl) => decl.gen_rust(ctx, cg),
            Self::ImplDecl(impl_) => impl_.gen_rust(ctx, cg),
            Self::StructDecl {
                visibility,
                name,
                generics,
                fields,
            } => {
                cg.addln(&format!(
                    "{}struct {}{} {{",
                    visibility.get_rust(),
                    name.get_rust(),
                    generics.get_rust()
                ));
                cg.indent += 1;

                for field in fields {
                    cg.add_indentedln(&field.get_rust());
                }

                cg.indent -= 1;
                cg.addln("}\n");
            }
            Self::EnumDecl {
                visibility,
                name,
                generics,
                fields,
            } => {
                cg.addln(&format!(
                    "{}enum {}{} {{",
                    visibility.get_rust(),
                    name.get_rust(),
                    generics.get_rust()
                ));
                cg.indent += 1;

                for field in fields {
                    cg.add_indentedln(&(field.get_rust() + ","));
                }

                cg.indent -= 1;
                cg.addln("}\n");
            }
            Self::TraitDecl {
                visibility,
                name,
                generics,
                requirements,
                items,
            } => {
                cg.addln(&format!(
                    "{}trait {}{}{} {{",
                    visibility.get_rust(),
                    name.get_rust(),
                    generics.get_rust(),
                    if requirements.len() != 0 {
                        String::from(": ")
                            + &requirements
                                .into_iter()
                                .map(TypeExpr::get_rust)
                                .collect::<Vec<_>>()
                                .join("+")
                    } else {
                        String::new()
                    },
                ));
                cg.indent += 1;

                for item in items {
                    item.gen_rust(ctx, cg);
                }

                cg.indent -= 1;
                cg.addln("}\n");
            }
            Self::ClassDecl {
                visibility,
                name,
                generics,
                inherits,
                fields,
                constructor,
                items,
            } => class_decl::class_decl(
                ctx,
                cg,
                visibility,
                name,
                generics,
                inherits,
                fields,
                constructor,
                items,
            ),
        }
    }
}