xenon-codegen 0.1.0

Codegen and AST for the Xenon programming language
Documentation
use core::fmt;
use enum_as_inner::EnumAsInner;

pub mod attribute;
pub mod case;
pub mod r#enum;
pub mod expression;
pub mod function;
pub mod identifier;
pub mod if_statement;
pub mod r#impl;
pub mod loop_statement;
pub mod module;
pub mod return_statement;
pub mod scope;
pub mod statement;
pub mod r#struct;
pub mod switch_statement;
pub mod r#trait;
pub mod r#type;
pub mod r#unsafe;
pub mod variable_assignment;
pub mod variable_definition;
pub mod while_statement;

/// Defines the visibility of its owner
#[derive(Debug, Clone, EnumAsInner, Default)]
pub enum Visibility {
    Public,
    #[default]
    Private,
}
impl fmt::Display for Visibility {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if self.is_private() {
            match write!(fmt, "private") {
                Ok(_) => (),
                Err(e) => return Err(e),
            }
        } else if self.is_public() {
            match write!(fmt, "public") {
                Ok(_) => (),
                Err(e) => return Err(e),
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use core::panic;
    use std::{thread::Scope, vec};

    use galvanic_test::test_suite;

    use crate::{
        Visibility, attribute::Attribute, expression::UnaryOperation, identifier::IdentifierAccess,
        loop_statement::LoopStatement, module::Module, statement, r#type::Type,
    };

    test_suite! {
        name attribute;
        use crate::attribute::Attribute;

        test attribute_test() {
            let attribute = Attribute::new("attribute");
            assert!(attribute.to_string() == "#[attribute]\n");
        }

        test attribute_test_with_value() {
            let mut attribute = Attribute::new("attribute");
            attribute.value = Some(String::from("value"));
            assert!(attribute.to_string() == "#[attribute(value)]\n");
        }
    }

    test_suite! {
        name case;
        use crate::{expression::{Expression, IntegerLiteral}, case::Case, scope::Scope};

        test case_test() {
            let case = Case::new(
                Expression::IntegerLiteral(IntegerLiteral::new(0)),
                Scope::new(),
            );
            assert!(case.to_string() == "case 0 {\n}");
        }
    }

    test_suite! {
        name r#enum;
        use crate::{r#enum::Enum, Visibility};

        test private_enum_test() {
            let enu = Enum::new("test".to_string());
            assert!(enu.to_string() == "private enum test {}");
        }

        test public_enum_test() {
            let mut enu = Enum::new("test".to_string());
            enu.visibility = Visibility::Public;
            assert!(enu.to_string() == "public enum test {}");
        }
    }

    test_suite! {
        name expressions;
        use crate::{expression::{Expression, IntegerLiteral, FloatLiteral, StringLiteral, BooleanLiteral, Parentheses, UnaryOperation, BinaryOperation}};

        test integer_literal_test() {
            let int = IntegerLiteral::new(10);
            assert!(int.to_string() == "10");
        }

        test float_literal_test() {
            let float = FloatLiteral::new(1.0);
            assert!(float.to_string() == "1");
        }

        test string_literal_test() {
            let string = StringLiteral::new("Hello World!".to_string());
            assert!(string.to_string() == "\"Hello World!\"");
        }

        test boolean_literal_test() {
            let bol = BooleanLiteral::new(true);
            assert!(bol.to_string() == "true");
        }

        test parentheses_test() {
            let par = Parentheses::new(Expression::IntegerLiteral(IntegerLiteral::new(12)));
            assert!(par.to_string() == "(12)");
        }

        test unary_operation_test() {
            let una = UnaryOperation::new("-".to_string(), Expression::IntegerLiteral(IntegerLiteral::new(42)));
            assert!(una.to_string() == "-42");
        }

        test binary_operation_test() {
            let bin = BinaryOperation::new(Expression::IntegerLiteral(IntegerLiteral::new(2)), "+".to_string(), Expression::IntegerLiteral(IntegerLiteral::new(2)));
            assert!(bin.to_string() == "2 + 2");
        }
    }

    test_suite! {
        name function;
        use crate::{Visibility, function::Function, r#type::{Type, TypeType}, identifier::{Access, IdentifierAccess}, statement::Statement, scope::Scope};

        test public_function() {
            let mut func = Function::new("test".to_string(), Type::new(IdentifierAccess::Access(Access::new("void".to_string())), TypeType::Normal), Statement::Scope(Scope::new()));
            func.visibility = Visibility::Public;
            assert!(func.to_string() == "public fn test() -> void {\n}");
        }

        test private_function() {
            let func = Function::new("test".to_string(), Type::new(IdentifierAccess::Access(Access::new("void".to_string())), TypeType::Normal), Statement::Scope(Scope::new()));
            assert!(func.to_string() == "private fn test() -> void {\n}");
        }
    }

    test_suite! {
        name identifier;
        use crate::{identifier::{IdentifierAccess, Access, FunctionCall}, expression::{Expression, BinaryOperation, IntegerLiteral}};

        test access() {
            let ident = Access::new("identifier".to_string());
            assert!(ident.to_string() == "identifier");
        }

        test function_call() {
            let mut ident = FunctionCall::new("func".to_string(), vec![]);
            ident.arguments.push(Expression::BinaryOperation(BinaryOperation::new(Expression::IntegerLiteral(IntegerLiteral::new(2)), "+".to_string(), Expression::IntegerLiteral(IntegerLiteral::new(2)))));
            assert!(ident.to_string() == "func(2 + 2)");
        }

        test access_and_deref() {
            let mut ident = Access::new("one".to_string());
            ident.child = Some(Box::new(IdentifierAccess::DerefAccess(Access::new("two".to_string()))));
            assert!(ident.to_string() == "one->two")
        }
    }

    test_suite! {
        name if_statement;
        use crate::{if_statement::IfStatement, expression::{Expression, BooleanLiteral}, scope::Scope, statement::Statement};

        test if_statement() {
            let statement = IfStatement::new(Expression::BooleanLiteral(BooleanLiteral::new(true)), Statement::Scope(Scope::new()));
            assert!(statement.to_string() == "if (true) {\n}")
        }

        test else_statement() {
            let mut statement = IfStatement::new(Expression::BooleanLiteral(BooleanLiteral::new(true)), Statement::Scope(Scope::new()));
            statement.else_body = Some(Box::new(Statement::Scope(Scope::new())));
            assert!(statement.to_string() == "if (true) {\n}\nelse {\n}")
        }
    }

    test_suite! {
        name r#impl;
        use crate::{r#impl::Impl, r#type::{Type, TypeType}, identifier::{IdentifierAccess, Access}, r#trait::Trait};

        test r#impl() {
            let imp = Impl::new(Type::new(IdentifierAccess::Access(Access::new("Test".to_string())), TypeType::Normal));
            assert!(imp.to_string() == "impliment Test {\n}");
        }

        test impl_for() {
            let mut imp = Impl::new(Type::new(IdentifierAccess::Access(Access::new("Test".to_string())), TypeType::Normal));
            imp.r#trait = Some(Type::new(IdentifierAccess::Access(Access::new("Treat".to_string())), TypeType::Normal));
            assert!(imp.to_string() == "impliment Treat for Test {\n}");
        }
    }

    test_suite! {
        name loop_statement;
        use crate::{loop_statement::LoopStatement, statement::Statement, scope::Scope};

        test loop_statement() {
            let lop = LoopStatement::new(Statement::Scope(Scope::new()));
            assert!(lop.to_string() == "loop {\n}")
        }
    }

    test_suite! {
        name module;
        use crate::{module::{Module, ModuleItem}, Visibility};

        test public_module() {
            let mut modu = Module::new("test".to_string());
            modu.visibility = Visibility::Public;
            assert!(modu.to_string() == "public module test {}");
        }

        test private_module() {
            let modu = Module::new("test".to_string());
            assert!(modu.to_string() == "private module test {}");
        }
    }

    test_suite! {
        name return_statement;
        use crate::{return_statement::ReturnStatement, expression::{Expression, IntegerLiteral}};

        test return_no_value() {
            let ret = ReturnStatement::new();
            assert!(ret.to_string() == "return;");
        }

        test return_value() {
            let mut ret = ReturnStatement::new();
            ret.value = Some(Expression::IntegerLiteral(IntegerLiteral::new(0)));
            assert!(ret.to_string() == "return 0;");
        }
    }

    test_suite! {
        name scope;
        use crate::scope::Scope;

        test scope_test() {
            let scope = Scope::new();
            assert!(scope.to_string() == "{\n}");
        }
    }

    test_suite! {
        name r#struct;
        use crate::{Visibility, r#struct::Struct, r#type::{Type, TypeType}, identifier::{IdentifierAccess, Access}};

        test public_struct() {
            let mut struc = Struct::new(Type::new(IdentifierAccess::Access(Access::new("Test".to_string())), TypeType::Normal));
            struc.visibility = Visibility::Public;
            assert!(struc.to_string() == "public struct Test {\n}");
        }

        test private_struct() {
            let struc = Struct::new(Type::new(IdentifierAccess::Access(Access::new("Test".to_string())), TypeType::Normal));
            assert!(struc.to_string() == "private struct Test {\n}");
        }
    }

    test_suite! {
        name switch_statement;
        use crate::{switch_statement::SwitchStatement, expression::{Expression, IntegerLiteral}};

        test switch_statement() {
            let statement = SwitchStatement::new(Expression::IntegerLiteral(IntegerLiteral::new(0)));
            assert!(statement.to_string() == "switch (0) {\n}")
        }
    }

    test_suite! {
        name r#trait;
        use crate::{r#trait::Trait, r#type::{Type, TypeType}, identifier::{IdentifierAccess, Access}, Visibility};

        test public_trait() {
            let mut trai = Trait::new(Type::new(IdentifierAccess::Access(Access::new("Trait".to_string())), TypeType::Normal));
            trai.visibility = Visibility::Public;
            assert!(trai.to_string() == "public trait Trait {\n}");
        }

        test private_trait() {
            let trai = Trait::new(Type::new(IdentifierAccess::Access(Access::new("Trait".to_string())), TypeType::Normal));
            assert!(trai.to_string() == "private trait Trait {\n}");
        }
    }

    test_suite! {
        name r#type;
        use crate::{r#type::{Type, TypeType}, identifier::{IdentifierAccess, Access}};

        test r#type() {
            let typ = Type::new(IdentifierAccess::Access(Access::new("Type".to_string())), TypeType::Normal);
            assert!(typ.to_string() == "Type")
        }

        test generic_type() {
            let mut typ = Type::new(IdentifierAccess::Access(Access::new("Type".to_string())), TypeType::Normal);
            typ.generic_child = Some(Box::new(Type::new(IdentifierAccess::Access(Access::new("Type".to_string())), TypeType::Normal)));
            assert!(typ.to_string() == "Type<Type>")
        }
    }

    test_suite! {
        name r#unsafe;
        use crate::{r#unsafe::Unsafe, scope::Scope, statement::Statement};

        test r#unsafe() {
            let unsaf = Unsafe::new(Statement::Scope(Scope::new()));
            assert!(unsaf.to_string() == "unsafe {\n}");
        }
    }

    test_suite! {
        name variable_assignment;
        use crate::{variable_assignment::VariableAssignment, identifier::{IdentifierAccess, Access}, expression::{Expression, IntegerLiteral}};

        test variable_assignment() {
            let var_ass = VariableAssignment::new(IdentifierAccess::Access(Access::new("x".to_string())), "=".to_string(), Expression::IntegerLiteral(IntegerLiteral::new(0)));
            assert!(var_ass.to_string() == "x = 0")
        }
    }

    test_suite! {
        name variable_definition;
        use crate::{variable_definition::VariableDefinition, r#type::{Type, TypeType}, identifier::{IdentifierAccess, Access}};

        test variable_definition() {
            let mut var_def = VariableDefinition::new("variable".to_string());
            var_def.ty = Some(Type::new(IdentifierAccess::Access(Access::new("i32".to_string())), TypeType::Normal));
            assert!(var_def.to_string() == "let variable: i32");
        }
    }

    test_suite! {
        name while_statement;
        use crate::{statement::Statement, while_statement::WhileStatement, scope::Scope, expression::{Expression, BooleanLiteral}};

        test while_statement() {
            let statement = WhileStatement::new(Expression::BooleanLiteral(BooleanLiteral::new(true)), Statement::Scope(Scope::new()));
            assert!(statement.to_string() == "while (true) {\n}");
        }
    }
}