use super::DocComment;
use super::expressions::Expr;
use super::span::Span;
use super::statements::Statement;
use super::types::TypeAnnotation;
use serde::{Deserialize, Serialize};
pub use super::types::TypeParam;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FunctionDef {
pub name: String,
pub name_span: Span,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub declaring_module_path: Option<String>,
#[serde(default)]
pub doc_comment: Option<DocComment>,
pub type_params: Option<Vec<TypeParam>>,
pub params: Vec<FunctionParameter>,
pub return_type: Option<TypeAnnotation>,
pub where_clause: Option<Vec<super::types::WherePredicate>>,
pub body: Vec<Statement>,
pub annotations: Vec<Annotation>,
pub is_async: bool,
#[serde(default)]
pub is_comptime: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ForeignFunctionDef {
pub language: String,
pub language_span: Span,
pub name: String,
pub name_span: Span,
#[serde(default)]
pub doc_comment: Option<DocComment>,
pub type_params: Option<Vec<TypeParam>>,
pub params: Vec<FunctionParameter>,
pub return_type: Option<TypeAnnotation>,
pub body_text: String,
pub body_span: Span,
pub annotations: Vec<Annotation>,
#[serde(default)]
pub is_async: bool,
#[serde(default)]
pub native_abi: Option<NativeAbiBinding>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NativeAbiBinding {
pub abi: String,
pub library: String,
pub symbol: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub package_key: Option<String>,
}
impl ForeignFunctionDef {
pub fn returns_result(&self) -> bool {
matches!(
&self.return_type,
Some(TypeAnnotation::Generic { name, .. }) if name == "Result"
)
}
pub fn is_native_abi(&self) -> bool {
self.native_abi.is_some()
}
pub fn validate_type_annotations(&self, dynamic_language: bool) -> Vec<(String, Span)> {
let mut errors = Vec::new();
for param in &self.params {
if param.type_annotation.is_none() {
let name = param.simple_name().unwrap_or("_");
errors.push((
format!(
"Foreign function '{}': parameter '{}' requires a type annotation \
(type inference is not available for foreign function bodies)",
self.name, name
),
param.span(),
));
}
}
if self.return_type.is_none() {
errors.push((
format!(
"Foreign function '{}' requires an explicit return type annotation \
(type inference is not available for foreign function bodies)",
self.name
),
self.name_span,
));
} else if dynamic_language && !self.returns_result() {
let inner_type = self
.return_type
.as_ref()
.map(|t| t.to_type_string())
.unwrap_or_else(|| "T".to_string());
errors.push((
format!(
"Foreign function '{}': return type must be Result<{}> \
(dynamic language runtimes can fail on every call)",
self.name, inner_type
),
self.name_span,
));
}
errors
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FunctionParameter {
pub pattern: super::patterns::DestructurePattern,
#[serde(default)]
pub is_const: bool,
#[serde(default)]
pub is_reference: bool,
#[serde(default)]
pub is_mut_reference: bool,
#[serde(default)]
pub is_out: bool,
pub type_annotation: Option<TypeAnnotation>,
pub default_value: Option<Expr>,
}
impl FunctionParameter {
pub fn simple_name(&self) -> Option<&str> {
self.pattern.as_identifier()
}
pub fn get_identifiers(&self) -> Vec<String> {
self.pattern.get_identifiers()
}
pub fn span(&self) -> Span {
match &self.pattern {
super::patterns::DestructurePattern::Identifier(_, span) => *span,
super::patterns::DestructurePattern::Array(_) => Span::default(),
super::patterns::DestructurePattern::Object(_) => Span::default(),
super::patterns::DestructurePattern::Rest(_) => Span::default(),
super::patterns::DestructurePattern::Decomposition(_) => Span::default(),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Annotation {
pub name: String,
pub args: Vec<Expr>,
pub span: Span,
}
impl Annotation {
pub fn get<'a>(annotations: &'a [Annotation], name: &str) -> Option<&'a Annotation> {
annotations.iter().find(|a| a.name == name)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AnnotationDef {
pub name: String,
pub name_span: Span,
#[serde(default)]
pub doc_comment: Option<DocComment>,
pub params: Vec<FunctionParameter>,
pub allowed_targets: Option<Vec<AnnotationTargetKind>>,
pub handlers: Vec<AnnotationHandler>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum AnnotationHandlerType {
OnDefine,
Before,
After,
Metadata,
ComptimePre,
ComptimePost,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AnnotationTargetKind {
Function,
Type,
Module,
Expression,
Block,
AwaitExpr,
Binding,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AnnotationHandler {
pub handler_type: AnnotationHandlerType,
pub params: Vec<AnnotationHandlerParam>,
pub return_type: Option<TypeAnnotation>,
pub body: Expr,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AnnotationHandlerParam {
pub name: String,
#[serde(default)]
pub is_variadic: bool,
}