use crate::aaml::AAML;
use crate::commands::Command;
use crate::error::AamlError;
use crate::types::primitive_type::PrimitiveType;
use crate::types::{Type, resolve_builtin};
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TypeDefinition {
Primitive(String),
Alias(String),
Builtin(String),
}
impl Type for TypeDefinition {
fn from_name(_name: &str) -> Result<Self, AamlError>
where
Self: Sized,
{
Err(AamlError::NotFound {
key: "TypeDefinition".to_string(),
context: "TypeDefinition::from_name is not supported".to_string(),
diagnostics: None,
})
}
fn base_type(&self) -> PrimitiveType {
match self {
TypeDefinition::Builtin(path) => resolve_builtin(path)
.map(|t| t.base_type())
.unwrap_or(PrimitiveType::String),
TypeDefinition::Primitive(name) => PrimitiveType::from_name(name)
.unwrap_or(PrimitiveType::String)
.base_type(),
TypeDefinition::Alias(_) => PrimitiveType::String,
}
}
fn validate(&self, value: &str, aaml: &AAML) -> Result<(), AamlError> {
match self {
TypeDefinition::Builtin(path) => resolve_builtin(path)?.validate(value, aaml),
TypeDefinition::Primitive(name) => {
PrimitiveType::from_name(name)?.validate(value, aaml)
}
TypeDefinition::Alias(_) => Ok(()),
}
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TypeCommand;
impl Command for TypeCommand {
fn name(&self) -> &str {
"type"
}
fn execute(&self, aaml: &mut AAML, args: &str) -> Result<(), AamlError> {
let (name, definition) =
args.split_once('=')
.ok_or_else(|| AamlError::DirectiveSyntaxError {
directive: "type".to_string(),
provided_syntax: args.to_string(),
expected_syntax: "name = definition".to_string(),
diagnostics: Some(crate::error::ErrorDiagnostics::new(
"Invalid @type syntax",
"Type definition must have an '=' sign",
"Use format: @type name = primitive_type or @type name = module::type",
)),
})?;
let name = name.trim();
let definition = definition.trim();
if name.is_empty() {
return Err(AamlError::InvalidValue {
details: "Type name is empty".to_string(),
expected: "non-empty type name".to_string(),
diagnostics: Some(crate::error::ErrorDiagnostics::new(
"Empty type name",
"Type name cannot be empty before '='",
"Provide a type name: @type myType = ...",
)),
});
}
if definition.is_empty() {
return Err(AamlError::InvalidValue {
details: "Type definition is empty".to_string(),
expected: "type definition (primitive or module path)".to_string(),
diagnostics: Some(crate::error::ErrorDiagnostics::new(
"Empty type definition",
"Type definition cannot be empty after '='",
"Provide a type: @type myType = i32, f64, string, etc.",
)),
});
}
let type_def = if definition.contains("::") {
TypeDefinition::Builtin(definition.to_string())
} else {
TypeDefinition::Primitive(definition.to_string())
};
aaml.register_type(name.to_string(), type_def);
Ok(())
}
}