trixy 0.4.0

A rust crate used to generate multi-language apis for your application
Documentation
/*
* Copyright (C) 2023 - 2024:
* The Trinitrix Project <soispha@vhack.eu, antifallobst@systemausfall.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* This file is part of the Trixy crate for Trinitrix.
*
* Trixy is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
*/

//! This module contains the already type checked types.

use std::fmt::{Display, Write};

use crate::parser::lexing::TokenKind;

use super::unchecked::{self, DeriveValue};

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Variant {
    Structure {
        namespace: Vec<Identifier>,
    },
    Enumeration {
        namespace: Vec<Identifier>,
    },
    Result {
        namespace: Vec<Identifier>,
    },
    Option {
        namespace: Vec<Identifier>,
    },
    Vec {
        namespace: Vec<Identifier>,
    },

    Namespace,
    /// The first (implicit) namespace, containing everything
    RootNamespace,

    Function,
    Primitive,
    NamedType,
    DocNamedType,

    /// Implicit default, this is not something that _should_ never be exposed to the public API
    Void,
}

impl Default for Variant {
    fn default() -> Self {
        Self::Void
    }
}
impl Variant {
    pub fn new() -> Self {
        Self::default()
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Namespace {
    pub name: Identifier,

    pub functions: Vec<Function>,
    pub structures: Vec<Structure>,
    pub enumerations: Vec<Enumeration>,
    pub namespaces: Vec<Namespace>,
    pub attributes: Vec<Attribute>,
}

impl From<&CommandSpec> for Namespace {
    fn from(value: &CommandSpec) -> Self {
        Self {
            name: Identifier {
                // NOTE: The '<root>' has been chosen on purpose
                // to avoid it being de-serialized able as an identifier in `format_ident` <2024-07-05>
                name: "<root>".to_owned(),
                variant: Variant::RootNamespace,
            },
            functions: value.functions.clone(),
            structures: value.structures.clone(),
            enumerations: value.enumerations.clone(),
            namespaces: value.namespaces.clone(),
            attributes: vec![],
        }
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct CommandSpec {
    pub structures: Vec<Structure>,
    pub enumerations: Vec<Enumeration>,
    pub functions: Vec<Function>,
    pub namespaces: Vec<Namespace>,
}

impl From<Namespace> for CommandSpec {
    fn from(value: Namespace) -> Self {
        Self {
            structures: value.structures,
            enumerations: value.enumerations,
            functions: value.functions,
            namespaces: value.namespaces,
        }
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Structure {
    pub identifier: Identifier,
    pub contents: Vec<DocNamedType>,
    pub attributes: Vec<Attribute>,
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Enumeration {
    pub identifier: Identifier,
    pub states: Vec<DocIdentifier>,
    pub attributes: Vec<Attribute>,
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Function {
    pub identifier: Identifier,
    pub inputs: Vec<NamedType>,
    pub output: Option<Type>,
    pub attributes: Vec<Attribute>,
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Type {
    Typical {
        identifier: Identifier,
        generic_args: Vec<Type>,
    },
    Function {
        inputs: Vec<NamedType>,
        output: Option<Box<Type>>,
    },
}

impl Type {
    pub fn print_generics(&self) -> String {
        let mut output = String::new();
        self.display_generics(&mut output)
            .expect("This should fail");
        output
    }
    pub fn display_generics<T: Write>(&self, f: &mut T) -> std::fmt::Result {
        match self {
            Type::Typical {
                identifier: _,
                generic_args,
            } => {
                if !generic_args.is_empty() {
                    f.write_char('<')?;
                    let mut first_run = true;
                    for arg in generic_args {
                        if !first_run {
                            f.write_str(", ")?;
                        } else {
                            first_run = false;
                        }
                        write!(f, "{}", arg)?;
                    }
                    f.write_char('>')
                } else {
                    f.write_str("")
                }
            }
            Type::Function { .. } => {
                unimplemented!("This function should only be called for the 'Typical' enum variant")
            }
        }
    }
}

impl Display for Type {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Type::Typical {
                identifier,
                generic_args: _,
            } => {
                f.write_str(&identifier.name)?;
                self.display_generics(f)
            }
            Type::Function { inputs, output } => {
                f.write_str("fn(")?;
                if !inputs.is_empty() {
                    f.write_str(
                        &inputs
                            .iter()
                            .map(|ty| ty.to_string())
                            .collect::<Vec<_>>()
                            .join(", "),
                    )?;
                }

                f.write_str(")")?;
                if let Some(output) = output {
                    f.write_str("-> ")?;
                    f.write_str(output.to_string().as_str())?;
                }
                Ok(())
            }
        }
    }
}

impl Display for NamedType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.name.name)?;
        f.write_str(": ")?;
        f.write_str(self.r#type.to_string().as_str())
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct NamedType {
    pub name: Identifier,
    pub r#type: Type,
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct DocNamedType {
    pub name: Identifier,
    pub r#type: Type,
    pub attributes: Vec<Attribute>,
}

impl From<&DocNamedType> for NamedType {
    fn from(value: &DocNamedType) -> Self {
        Self {
            name: value.name.to_owned(),
            r#type: value.r#type.to_owned(),
        }
    }
}

impl TokenKind {
    pub fn to_identifier(self: TokenKind, variant: Variant) -> Identifier {
        match self {
            TokenKind::Identifier(ident) => Identifier {
                name: ident,
                variant,
            },
            _ => {
                panic!(
                    "
                        Tried to convert a non Identifier TokenKind to a
                        Identifier. This is a bug. The token was: '{}'
                    ",
                    self
                )
            }
        }
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Attribute {
    #[allow(non_camel_case_types)]
    doc(String),

    #[allow(non_camel_case_types)]
    derive(DeriveValue),

    #[allow(non_camel_case_types)]
    error(String),
}
impl From<unchecked::Attribute> for Attribute {
    fn from(value: unchecked::Attribute) -> Self {
        match value {
            unchecked::Attribute::doc { content: name, .. } => Self::doc(name.content),
            unchecked::Attribute::derive { value, .. } => Self::derive(value),
            unchecked::Attribute::error { content, .. } => Self::error(content.content),
        }
    }
}

/// An Identifier
/// These include:
/// - Variable names
/// - Function names
/// - Namespace names
/// - Type names
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Identifier {
    pub name: String,
    pub variant: Variant,
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct DocIdentifier {
    pub name: String,
    pub variant: Variant,
    pub attributes: Vec<Attribute>,
}

impl From<&DocIdentifier> for Identifier {
    fn from(value: &DocIdentifier) -> Self {
        Self {
            name: value.name.to_owned(),
            variant: value.variant.clone(),
        }
    }
}

impl Display for Identifier {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.name)
    }
}