rooc/runtime_builtin/functions/
function_traits.rs1use crate::parser::il::PreExp;
2use crate::parser::model_transformer::TransformError;
3use crate::parser::model_transformer::TransformerContext;
4use crate::runtime_builtin::rooc_std::{std_fn_to_latex, std_fn_to_string};
5use crate::traits::{escape_latex, ToLatex};
6use crate::type_checker::type_checker_context::{FunctionContext, TypeCheckerContext};
7use crate::{
8 primitives::{Primitive, PrimitiveKind},
9 type_checker::type_checker_context::{TypeCheckable, WithType},
10 utils::InputSpan,
11};
12use core::fmt;
13use pest::Span;
14use serde::Serialize;
15use std::fmt::Debug;
16
17#[derive(Debug, Clone, Serialize)]
19pub struct FunctionCall {
20 pub args: Vec<PreExp>,
21 pub name: String,
22 span: InputSpan,
23}
24
25impl FunctionCall {
26 pub fn new(args: Vec<PreExp>, name: String, span: Span) -> Self {
33 Self {
34 args,
35 name,
36 span: InputSpan::from_span(span),
37 }
38 }
39}
40
41pub fn default_type_check(
53 args: &[PreExp],
54 expected: &[(String, PrimitiveKind)],
55 context: &mut TypeCheckerContext,
56 fn_context: &FunctionContext,
57) -> Result<(), TransformError> {
58 let type_signature = expected;
59 if type_signature.len() != args.len() {
60 return Err(TransformError::WrongNumberOfArguments {
61 signature: type_signature.to_owned(),
62 args: args.to_owned(),
63 });
64 }
65 for (arg, (_, kind)) in args.iter().zip(type_signature) {
66 if kind == &PrimitiveKind::Any {
67 continue;
68 }
69 let arg_type = arg.get_type(context, fn_context);
70 if *kind == PrimitiveKind::Iterable(Box::new(PrimitiveKind::Any)) && arg_type.is_iterable()
72 {
73 continue;
74 }
75 if kind == &PrimitiveKind::Number && arg_type.is_numeric() {
77 continue;
78 }
79 if kind == &PrimitiveKind::Integer {
80 if matches!(
82 arg_type,
83 PrimitiveKind::Integer | PrimitiveKind::PositiveInteger
84 ) {
85 continue;
86 }
87 }
88 if arg_type != *kind {
89 return Err(TransformError::WrongArgument {
90 expected: kind.clone(),
91 got: arg_type,
92 }
93 .add_span(arg.span()));
94 }
95 }
96
97 Ok(())
98}
99
100pub fn default_wrong_type(
108 args: &[PreExp],
109 fun: &dyn RoocFunction,
110 context: &TypeCheckerContext,
111 fn_context: &FunctionContext,
112) -> TransformError {
113 let type_signature = fun.type_signature(args, context, fn_context);
114 let args = args.to_owned();
115 TransformError::WrongFunctionSignature {
116 signature: type_signature,
117 got: args
118 .iter()
119 .map(|a| a.get_type(context, fn_context))
120 .collect(),
121 }
122}
123
124pub fn default_wrong_number_of_arguments(
132 fun: &dyn RoocFunction,
133 args: &[PreExp],
134 fn_context: &FunctionContext,
135) -> TransformError {
136 TransformError::WrongNumberOfArguments {
137 signature: fun.type_signature(args, &TypeCheckerContext::default(), fn_context),
138 args: vec![],
139 }
140}
141
142impl TypeCheckable for FunctionCall {
143 fn type_check(
144 &self,
145 context: &mut TypeCheckerContext,
146 fn_context: &FunctionContext,
147 ) -> Result<(), TransformError> {
148 for arg in &self.args {
149 arg.type_check(context, fn_context)
150 .map_err(|e| e.add_span(&self.span))?;
151 }
152 let f = fn_context
153 .function(&self.name)
154 .ok_or_else(|| TransformError::NonExistentFunction(self.name.clone()))?;
155 f.type_check(&self.args, context, fn_context)
156 .map_err(|e| e.add_span(&self.span))
157 }
158
159 fn populate_token_type_map(
160 &self,
161 context: &mut TypeCheckerContext,
162 fn_context: &FunctionContext,
163 ) {
164 self.args
165 .iter()
166 .for_each(|arg| arg.populate_token_type_map(context, fn_context));
167 if let Some(f) = fn_context.function(&self.name) {
168 let return_type = f.return_type(&self.args, context, fn_context);
169 context.add_token_type_or_undefined(return_type, self.span.clone(), None);
170 }
171 }
172}
173
174impl fmt::Display for FunctionCall {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 let builtin = std_fn_to_string(self);
177 if let Some(string) = builtin {
178 return write!(f, "{}", string);
179 }
180 write!(f, "{}", default_rooc_function_to_string(self))
181 }
182}
183
184impl ToLatex for FunctionCall {
185 fn to_latex(&self) -> String {
186 std_fn_to_latex(self).unwrap_or(default_rooc_function_to_latex(self))
188 }
189}
190
191pub fn default_rooc_function_to_latex(function: &FunctionCall) -> String {
196 format!(
197 "{}({})",
198 escape_latex(&function.name),
199 function
200 .args
201 .iter()
202 .map(|p| p.to_latex())
203 .collect::<Vec<String>>()
204 .join(",\\")
205 )
206}
207
208pub fn default_rooc_function_to_string(function: &FunctionCall) -> String {
213 format!(
214 "{}({})",
215 function.name,
216 function
217 .args
218 .iter()
219 .map(|p| p.to_string())
220 .collect::<Vec<String>>()
221 .join(", ")
222 )
223}
224
225pub trait RoocFunction: Debug {
229 fn call(
240 &self,
241 args: &[PreExp],
242 context: &TransformerContext,
243 fn_context: &FunctionContext,
244 ) -> Result<Primitive, TransformError>;
245
246 fn type_signature(
248 &self,
249 args: &[PreExp],
250 context: &TypeCheckerContext,
251 fn_context: &FunctionContext,
252 ) -> Vec<(String, PrimitiveKind)>;
253
254 fn return_type(
261 &self,
262 args: &[PreExp],
263 context: &TypeCheckerContext,
264 fn_context: &FunctionContext,
265 ) -> PrimitiveKind;
266
267 fn function_name(&self) -> String;
269
270 fn type_check(
277 &self,
278 args: &[PreExp],
279 context: &mut TypeCheckerContext,
280 fn_context: &FunctionContext,
281 ) -> Result<(), TransformError> {
282 default_type_check(
283 args,
284 &self.type_signature(args, context, fn_context),
285 context,
286 fn_context,
287 )
288 }
289}