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,
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, 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, pub contents: Vec<DocNamedType>,
pub attributes: Vec<Attribute>,
pub namespaces: Vec<Token>, }
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct Enumeration {
pub identifier: Token, pub states: Vec<DocToken>, pub attributes: Vec<Attribute>,
pub namespaces: Vec<Token>, }
#[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, pub r#type: Type,
pub attributes: Vec<Attribute>,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct NamedType {
pub name: Token, pub r#type: Type,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Type {
Typical {
identifier: Token, 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(())
}
}
}
}