use crate::ast::{
AnnotationDef, AnnotationHandler, AnnotationHandlerParam, AnnotationHandlerType,
FunctionParameter,
};
use crate::error::{Result, ShapeError};
use crate::parser::Rule;
use crate::parser::expressions::control_flow::parse_block_expr;
use crate::parser::pair_span;
use crate::parser::types::parse_type_annotation;
use pest::iterators::Pair;
pub fn parse_annotation_def(pair: Pair<Rule>) -> Result<AnnotationDef> {
let span = pair_span(&pair);
let mut inner = pair.into_inner();
let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
message: "Missing annotation name".to_string(),
location: None,
})?;
let name = name_pair.as_str().to_string();
let name_span = pair_span(&name_pair);
let mut params: Vec<FunctionParameter> = Vec::new();
let mut handlers = Vec::new();
let mut allowed_targets: Option<Vec<crate::ast::AnnotationTargetKind>> = None;
for part in inner {
match part.as_rule() {
Rule::annotation_def_params => {
for param_pair in part.into_inner() {
if param_pair.as_rule() == Rule::ident {
let pattern = crate::ast::DestructurePattern::Identifier(
param_pair.as_str().to_string(),
pair_span(¶m_pair),
);
params.push(FunctionParameter {
pattern,
is_const: false,
is_reference: false,
is_mut_reference: false,
is_out: false,
type_annotation: None,
default_value: None,
});
}
}
}
Rule::annotation_body => {
for body_item in part.into_inner() {
let item = if body_item.as_rule() == Rule::annotation_body_item {
body_item
.into_inner()
.next()
.ok_or_else(|| ShapeError::ParseError {
message: "empty annotation body item".to_string(),
location: None,
})?
} else {
body_item
};
match item.as_rule() {
Rule::annotation_handler => {
handlers.push(parse_annotation_handler(item)?);
}
Rule::annotation_targets_decl => {
let mut targets = Vec::new();
for target_pair in item.into_inner() {
if target_pair.as_rule() != Rule::annotation_target_kind {
continue;
}
let kind = match target_pair.as_str() {
"function" => crate::ast::AnnotationTargetKind::Function,
"type" => crate::ast::AnnotationTargetKind::Type,
"module" => crate::ast::AnnotationTargetKind::Module,
"expression" => crate::ast::AnnotationTargetKind::Expression,
"block" => crate::ast::AnnotationTargetKind::Block,
"await_expr" => crate::ast::AnnotationTargetKind::AwaitExpr,
"binding" => crate::ast::AnnotationTargetKind::Binding,
other => {
return Err(ShapeError::ParseError {
message: format!(
"unknown annotation target kind '{}'",
other
),
location: None,
});
}
};
targets.push(kind);
}
allowed_targets = Some(targets);
}
_ => {}
}
}
}
_ => {}
}
}
Ok(AnnotationDef {
name,
name_span,
doc_comment: None,
params,
allowed_targets,
handlers,
span,
})
}
fn parse_annotation_handler(pair: Pair<Rule>) -> Result<AnnotationHandler> {
let span = pair_span(&pair);
let mut inner = pair.into_inner();
let handler_name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
message: "Missing annotation handler name".to_string(),
location: None,
})?;
let handler_kind = handler_name_pair
.as_str()
.split_whitespace()
.collect::<Vec<_>>()
.join(" ");
let handler_type = match handler_kind.as_str() {
"on_define" => AnnotationHandlerType::OnDefine,
"before" => AnnotationHandlerType::Before,
"after" => AnnotationHandlerType::After,
"metadata" => AnnotationHandlerType::Metadata,
"comptime pre" => AnnotationHandlerType::ComptimePre,
"comptime post" => AnnotationHandlerType::ComptimePost,
other => {
return Err(ShapeError::ParseError {
message: format!(
"unknown annotation handler type '{}'. Expected `on_define`, `before`, `after`, `metadata`, `comptime pre`, or `comptime post`",
other
),
location: None,
});
}
};
let mut params = Vec::new();
let mut return_type = None;
let mut body = None;
for part in inner {
match part.as_rule() {
Rule::annotation_handler_params => {
for param_pair in part.into_inner() {
if param_pair.as_rule() == Rule::annotation_handler_param {
let raw = param_pair.as_str().trim();
let (name, is_variadic) = if let Some(rest) = raw.strip_prefix("...") {
(rest.trim().to_string(), true)
} else {
(raw.to_string(), false)
};
if !name.is_empty() {
params.push(AnnotationHandlerParam { name, is_variadic });
}
}
}
}
Rule::return_type => {
if let Some(type_pair) = part.into_inner().next() {
return_type = Some(parse_type_annotation(type_pair)?);
}
}
Rule::block_expr => {
body = Some(parse_block_expr(part)?);
}
_ => {}
}
}
let body = body.ok_or_else(|| ShapeError::ParseError {
message: "Missing annotation handler body".to_string(),
location: None,
})?;
Ok(AnnotationHandler {
handler_type,
params,
return_type,
body,
span,
})
}
pub fn parse_extend_statement(pair: Pair<Rule>) -> Result<crate::ast::ExtendStatement> {
use crate::ast::types::TypeName;
let mut inner = pair.into_inner();
let type_name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
message: "Missing type name in extend statement".to_string(),
location: None,
})?;
let type_name = {
let mut tn_inner = type_name_pair.into_inner();
let name_pair = tn_inner.next().ok_or_else(|| ShapeError::ParseError {
message: "Missing type name identifier".to_string(),
location: None,
})?;
let name = name_pair.as_str().to_string();
let type_args: Vec<_> = tn_inner
.map(|p| parse_type_annotation(p))
.collect::<Result<Vec<_>>>()?;
if type_args.is_empty() {
TypeName::Simple(name.into())
} else {
TypeName::Generic { name: name.into(), type_args }
}
};
let mut methods = Vec::new();
for method_pair in inner {
if matches!(
method_pair.as_rule(),
Rule::documented_method_def | Rule::method_def
) {
methods.push(super::types::parse_documented_method_def_shared(
method_pair,
)?);
}
}
Ok(crate::ast::ExtendStatement { type_name, methods })
}
pub fn parse_impl_block(pair: Pair<Rule>) -> Result<crate::ast::ImplBlock> {
let mut inner = pair.into_inner();
let trait_name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
message: "Missing trait name in impl block".to_string(),
location: None,
})?;
let trait_name = parse_type_name(trait_name_pair)?;
let target_type_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
message: "Missing target type in impl block".to_string(),
location: None,
})?;
let target_type = parse_type_name(target_type_pair)?;
let mut impl_name = None;
let mut methods = Vec::new();
let mut associated_type_bindings = Vec::new();
let mut where_clause = None;
for member_pair in inner {
if member_pair.as_rule() == Rule::impl_name {
let name_pair =
member_pair
.into_inner()
.next()
.ok_or_else(|| ShapeError::ParseError {
message: "Missing impl name after 'as'".to_string(),
location: None,
})?;
impl_name = Some(name_pair.as_str().to_string());
continue;
}
if member_pair.as_rule() == Rule::where_clause {
where_clause = Some(super::functions::parse_where_clause(member_pair)?);
continue;
}
if member_pair.as_rule() != Rule::impl_member {
continue;
}
for child in member_pair.into_inner() {
match child.as_rule() {
Rule::associated_type_binding => {
let binding = parse_associated_type_binding(child)?;
associated_type_bindings.push(binding);
}
Rule::documented_method_def | Rule::method_def => {
methods.push(super::types::parse_documented_method_def_shared(child)?);
}
_ => {}
}
}
}
Ok(crate::ast::ImplBlock {
trait_name,
target_type,
impl_name,
methods,
associated_type_bindings,
where_clause,
})
}
fn parse_associated_type_binding(
pair: Pair<Rule>,
) -> Result<crate::ast::types::AssociatedTypeBinding> {
let mut inner = pair.into_inner();
let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
message: "expected associated type name in binding".to_string(),
location: None,
})?;
let name = name_pair.as_str().to_string();
let type_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
message: format!("expected type annotation for associated type '{}'", name),
location: None,
})?;
let concrete_type = super::types::parse_type_annotation(type_pair)?;
Ok(crate::ast::types::AssociatedTypeBinding {
name,
concrete_type,
})
}
fn parse_type_name(pair: Pair<Rule>) -> Result<crate::ast::types::TypeName> {
use crate::ast::types::TypeName;
let mut tn_inner = pair.into_inner();
let name_pair = tn_inner.next().ok_or_else(|| ShapeError::ParseError {
message: "Missing type name identifier".to_string(),
location: None,
})?;
let name = name_pair.as_str().to_string();
let type_args: Vec<_> = tn_inner
.map(|p| super::types::parse_type_annotation(p))
.collect::<Result<Vec<_>>>()?;
if type_args.is_empty() {
Ok(TypeName::Simple(name.into()))
} else {
Ok(TypeName::Generic { name: name.into(), type_args })
}
}
pub fn parse_optimize_statement(_pair: Pair<Rule>) -> Result<crate::ast::OptimizeStatement> {
Err(ShapeError::ParseError {
message: "parse_optimize_statement not yet implemented".to_string(),
location: None,
})
}