1use std::error::Error;
4use std::fmt::{Display, Formatter};
5
6use crate::CellStream;
7use crate::fold::{self, Fold};
8use crate::nodes::{Expr, ExprAssignInstallMethod, ExprLambda, ExprLiteral, TypeAnnotation};
9use crate::{CellStreamError, NativeParseError, NativeParser, Parser, Tokenize, parse_quote_m2};
10
11pub trait ProcMacro<Args = ()> {
18 type Error: Error;
20
21 fn expand(&mut self, input: CellStream, args: &Args) -> Result<CellStream, Self::Error>;
23}
24
25#[derive(Debug, Default)]
26pub struct LiteralReturnTypes;
43
44#[derive(Debug)]
45pub enum LiteralReturnTypesError {
47 Parse(NativeParseError),
49 Tokenize(CellStreamError),
51}
52
53impl Display for LiteralReturnTypesError {
54 fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
55 match self {
56 Self::Parse(error) => Display::fmt(error, formatter),
57 Self::Tokenize(error) => Display::fmt(error, formatter),
58 }
59 }
60}
61
62impl Error for LiteralReturnTypesError {
63 fn source(&self) -> Option<&(dyn Error + 'static)> {
64 match self {
65 Self::Parse(error) => Some(error),
66 Self::Tokenize(error) => Some(error),
67 }
68 }
69}
70
71impl ProcMacro for LiteralReturnTypes {
72 type Error = LiteralReturnTypesError;
73
74 fn expand(&mut self, input: CellStream, _args: &()) -> Result<CellStream, Self::Error> {
75 let mut parser = NativeParser;
76 let syntax = parser
77 .parse_cells(input)
78 .map_err(LiteralReturnTypesError::Parse)?;
79 self.fold_source_file(syntax)
80 .to_cell_stream()
81 .map_err(LiteralReturnTypesError::Tokenize)
82 }
83}
84
85impl Fold for LiteralReturnTypes {
86 fn fold_expr_assign_install_method(
87 &mut self,
88 node: ExprAssignInstallMethod,
89 ) -> ExprAssignInstallMethod {
90 let mut node = fold::fold_expr_assign_install_method(self, node);
91 if node.typical_value.is_none() {
92 node.typical_value = literal_return_annotation(&node.function);
93 }
94 node
95 }
96}
97
98fn literal_return_annotation(function: &Expr) -> Option<TypeAnnotation> {
100 let Expr::Lambda(lambda) = function else {
101 return None;
102 };
103 let body = match lambda {
104 ExprLambda::Variadic(lambda) => lambda.body.as_ref(),
105 ExprLambda::List(lambda) => lambda.body.as_ref(),
106 };
107 let Expr::Literal(literal) = body else {
108 return None;
109 };
110 let typical_value = match literal {
111 ExprLiteral::Integer(_) => parse_quote_m2!(ZZ),
112 ExprLiteral::Float(_) => parse_quote_m2!(RR),
113 ExprLiteral::String(_) | ExprLiteral::RawString(_) => parse_quote_m2!(String),
114 };
115 Some(TypeAnnotation::new(typical_value, parse_quote_m2!(=>)))
116}