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 not type checked types.
//! These are generated on the first pass of the parser, to be later converted into the checked
//! ones.

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

use crate::parser::lexing::{Token, TokenKind, TokenSpan};

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

impl From<CommandSpec> for Namespace {
    fn from(value: CommandSpec) -> Self {
        Self {
            name: Token::default(),
            functions: value.functions,
            structures: value.structures,
            enumerations: value.enumerations,
            namespaces: value.namespaces,
            attributes: vec![],
        }
    }
}

#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Namespace {
    pub name: Token, // Will later become an Identifier

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

    pub attributes: Vec<Attribute>,
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Declaration {
    Function(Function),
    Structure(Structure),
    Enumeration(Enumeration),
    Namespace(Namespace),
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Attribute {
    #[allow(non_camel_case_types)]
    doc {
        content: StringLiteral,
        span: TokenSpan,
    },

    #[allow(non_camel_case_types)]
    derive { value: DeriveValue, span: TokenSpan },

    #[allow(non_camel_case_types)]
    error {
        content: StringLiteral,
        span: TokenSpan,
    },
}

impl Display for Attribute {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Attribute::doc { .. } => f.write_str("doc"),
            Attribute::derive { .. } => f.write_str("derive"),
            Attribute::error { .. } => f.write_str("error"),
        }
    }
}

impl Attribute {
    pub fn span(&self) -> TokenSpan {
        match self {
            Attribute::doc { span, .. } => *span,
            Attribute::derive { span, .. } => *span,
            Attribute::error { span, .. } => *span,
        }
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct StringLiteral {
    pub(crate) content: String,
    pub(crate) span: TokenSpan,
}

impl From<Token> for StringLiteral {
    fn from(value: Token) -> Self {
        let span = *value.span();
        let content = match value.kind {
            TokenKind::StringLiteral(content) => content,
            _ => unreachable!("A string literal was expected"),
        };

        Self { content, span }
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum DeriveValue {
    Error,
}

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

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

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Enumeration {
    pub identifier: Token,     // Will later become an Identifier
    pub states: Vec<DocToken>, // Will later become an Identifier
    pub attributes: Vec<Attribute>,
    pub namespaces: Vec<Token>, // Will later become an Identifier
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct DocToken {
    pub token: Token,
    pub attributes: Vec<Attribute>,
}

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

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

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

impl Display for NamedType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let ident = match self.name.kind() {
               crate::parser::lexing::TokenKind::Identifier(ident) => ident,
               _ => panic!("Tried to display a non identifier token in the Type display implementation. This is a bug"),
           };
        f.write_str(ident)?;
        f.write_str(": ")?;
        f.write_str(self.r#type.to_string().as_str())
    }
}

impl Display for Type {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Type::Typical {
                identifier,
                generic_args,
            } => {
                let ident = match identifier.kind() {
                    crate::parser::lexing::TokenKind::Identifier(ident) => ident,
                    _ => panic!("Tried to display a non identifier token in the Type display implementation. This is a bug"),
                };

                f.write_str(ident)?;
                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 { 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(())
            }
        }
    }
}