1use super::{FormattingContext, FormattingError};
2use crate::core::expression::smart_display::SmartDisplayFormatter;
3use crate::core::expression::{CalculusData, RelationType};
4use crate::core::{Expression, Number};
5use crate::functions::intelligence::get_universal_registry;
6
7const MAX_RECURSION_DEPTH: usize = 1000;
8const MAX_TERMS_PER_OPERATION: usize = 10000;
9
10#[derive(Debug, Default, Clone)]
12pub struct WolframContext {
13 pub needs_parentheses: bool,
14}
15
16impl FormattingContext for WolframContext {}
17
18pub trait WolframFormatter {
20 fn to_wolfram(&self, context: &WolframContext) -> Result<String, FormattingError> {
48 self.to_wolfram_with_depth(context, 0)
49 }
50
51 fn to_wolfram_with_depth(
69 &self,
70 context: &WolframContext,
71 depth: usize,
72 ) -> Result<String, FormattingError>;
73
74 fn format_function_with_depth(
76 &self,
77 name: &str,
78 args: &[Expression],
79 context: &WolframContext,
80 depth: usize,
81 ) -> Result<String, FormattingError>;
82}
83
84impl WolframFormatter for Expression {
85 fn to_wolfram_with_depth(
86 &self,
87 context: &WolframContext,
88 depth: usize,
89 ) -> Result<String, FormattingError> {
90 if depth > MAX_RECURSION_DEPTH {
91 return Err(FormattingError::RecursionLimitExceeded {
92 depth,
93 limit: MAX_RECURSION_DEPTH,
94 });
95 }
96
97 match self {
98 Expression::Number(Number::Integer(n)) => Ok(n.to_string()),
99 Expression::Number(Number::BigInteger(n)) => Ok(n.to_string()),
100 Expression::Number(Number::Rational(r)) => {
101 if r.denom() == &num_bigint::BigInt::from(1) {
102 Ok(r.numer().to_string())
103 } else {
104 Ok(format!("Times[{}, Power[{}, -1]]", r.numer(), r.denom()))
106 }
107 }
108 Expression::Number(Number::Float(f)) => Ok(f.to_string()),
109 Expression::Symbol(s) => Ok(s.name().to_owned()),
110 Expression::Add(terms) => {
111 if terms.len() > MAX_TERMS_PER_OPERATION {
112 return Err(FormattingError::TooManyTerms {
113 count: terms.len(),
114 limit: MAX_TERMS_PER_OPERATION,
115 });
116 }
117
118 if terms.len() == 1 {
119 terms[0].to_wolfram_with_depth(context, depth + 1)
120 } else if terms.len() == 2
121 && SmartDisplayFormatter::is_negated_expression(&terms[1])
122 {
123 if let Some(positive_part) =
125 SmartDisplayFormatter::extract_negated_expression(&terms[1])
126 {
127 Ok(format!(
128 "Subtract[{}, {}]",
129 terms[0].to_wolfram_with_depth(context, depth + 1)?,
130 positive_part.to_wolfram_with_depth(context, depth + 1)?
131 ))
132 } else {
133 let mut term_strs = Vec::with_capacity(terms.len());
134 for term in terms.iter() {
135 term_strs.push(term.to_wolfram_with_depth(context, depth + 1)?);
136 }
137 Ok(format!("Plus[{}]", term_strs.join(", ")))
138 }
139 } else {
140 let mut term_strs = Vec::with_capacity(terms.len());
141 for term in terms.iter() {
142 term_strs.push(term.to_wolfram_with_depth(context, depth + 1)?);
143 }
144 Ok(format!("Plus[{}]", term_strs.join(", ")))
145 }
146 }
147 Expression::Mul(factors) => {
148 if factors.len() > MAX_TERMS_PER_OPERATION {
149 return Err(FormattingError::TooManyTerms {
150 count: factors.len(),
151 limit: MAX_TERMS_PER_OPERATION,
152 });
153 }
154
155 if factors.len() == 1 {
156 factors[0].to_wolfram_with_depth(context, depth + 1)
157 } else if let Some((dividend, divisor)) =
158 SmartDisplayFormatter::extract_division_parts(factors)
159 {
160 Ok(format!(
162 "Divide[{}, {}]",
163 dividend.to_wolfram_with_depth(context, depth + 1)?,
164 divisor.to_wolfram_with_depth(context, depth + 1)?
165 ))
166 } else {
167 let mut factor_strs = Vec::with_capacity(factors.len());
168 for factor in factors.iter() {
169 factor_strs.push(factor.to_wolfram_with_depth(context, depth + 1)?);
170 }
171 Ok(format!("Times[{}]", factor_strs.join(", ")))
172 }
173 }
174 Expression::Pow(base, exp) => Ok(format!(
175 "Power[{}, {}]",
176 base.to_wolfram_with_depth(context, depth + 1)?,
177 exp.to_wolfram_with_depth(context, depth + 1)?
178 )),
179 Expression::Function { name, args } => {
180 self.format_function_with_depth(name, args, context, depth + 1)
181 }
182 Expression::Complex(complex_data) => Ok(format!(
183 "Complex[{}, {}]",
184 complex_data
185 .real
186 .to_wolfram_with_depth(context, depth + 1)?,
187 complex_data
188 .imag
189 .to_wolfram_with_depth(context, depth + 1)?
190 )),
191 Expression::Matrix(_) => Ok("matrix".to_owned()),
192 Expression::Constant(c) => Ok(format!("{:?}", c)),
193 Expression::Relation(relation_data) => {
194 let left_wolfram = relation_data
195 .left
196 .to_wolfram_with_depth(context, depth + 1)?;
197 let right_wolfram = relation_data
198 .right
199 .to_wolfram_with_depth(context, depth + 1)?;
200 let operator = match relation_data.relation_type {
201 RelationType::Equal => "Equal",
202 RelationType::NotEqual => "Unequal",
203 RelationType::Less => "Less",
204 RelationType::LessEqual => "LessEqual",
205 RelationType::Greater => "Greater",
206 RelationType::GreaterEqual => "GreaterEqual",
207 RelationType::Approximate => "TildeEqual",
208 RelationType::Similar => "Tilde",
209 RelationType::Proportional => "Proportional",
210 RelationType::Congruent => "Congruent",
211 };
212 Ok(format!("{}[{}, {}]", operator, left_wolfram, right_wolfram))
213 }
214 Expression::Piecewise(piecewise_data) => {
215 let mut conditions = Vec::new();
216 let mut values = Vec::new();
217
218 for (condition, value) in &piecewise_data.pieces {
219 conditions.push(condition.to_wolfram_with_depth(context, depth + 1)?);
220 values.push(value.to_wolfram_with_depth(context, depth + 1)?);
221 }
222
223 if let Some(default_value) = &piecewise_data.default {
224 conditions.push("True".to_owned());
225 values.push(default_value.to_wolfram_with_depth(context, depth + 1)?);
226 }
227
228 let conditions_list = format!("{{{}}}", conditions.join(", "));
229 let values_list = format!("{{{}}}", values.join(", "));
230 Ok(format!("Piecewise[{}, {}]", values_list, conditions_list))
231 }
232 Expression::Set(elements) => {
233 if elements.len() > MAX_TERMS_PER_OPERATION {
234 return Err(FormattingError::TooManyTerms {
235 count: elements.len(),
236 limit: MAX_TERMS_PER_OPERATION,
237 });
238 }
239
240 if elements.is_empty() {
241 Ok("{}".to_owned())
242 } else {
243 let mut element_strs = Vec::with_capacity(elements.len());
244 for elem in elements.iter() {
245 element_strs.push(elem.to_wolfram_with_depth(context, depth + 1)?);
246 }
247 Ok(format!("{{{}}}", element_strs.join(", ")))
248 }
249 }
250 Expression::Interval(_) => Ok("interval".to_owned()),
251 Expression::Calculus(calculus_data) => {
252 Ok(match calculus_data.as_ref() {
253 CalculusData::Derivative {
254 expression,
255 variable,
256 order,
257 } => {
258 if *order == 1 {
259 format!(
260 "D[{}, {}]",
261 expression.to_wolfram_with_depth(context, depth + 1)?,
262 variable.name()
263 )
264 } else {
265 format!(
266 "D[{}, {{{}, {}}}]",
267 expression.to_wolfram_with_depth(context, depth + 1)?,
268 variable.name(),
269 order
270 )
271 }
272 }
273 CalculusData::Integral {
274 integrand,
275 variable,
276 bounds,
277 } => match bounds {
278 None => format!(
279 "Integrate[{}, {}]",
280 integrand.to_wolfram_with_depth(context, depth + 1)?,
281 variable.name()
282 ),
283 Some((start, end)) => format!(
284 "Integrate[{}, {{{}, {}, {}}}]",
285 integrand.to_wolfram_with_depth(context, depth + 1)?,
286 variable.name(),
287 start.to_wolfram_with_depth(context, depth + 1)?,
288 end.to_wolfram_with_depth(context, depth + 1)?
289 ),
290 },
291 CalculusData::Limit {
292 expression,
293 variable,
294 point,
295 direction: _,
296 } => {
297 format!(
299 "Limit[{}, {} -> {}]",
300 expression.to_wolfram_with_depth(context, depth + 1)?,
301 variable.name(),
302 point.to_wolfram_with_depth(context, depth + 1)?
303 )
304 }
305 CalculusData::Sum {
306 expression,
307 variable,
308 start,
309 end,
310 } => {
311 format!(
312 "Sum[{}, {{{}, {}, {}}}]",
313 expression.to_wolfram_with_depth(context, depth + 1)?,
314 variable.name(),
315 start.to_wolfram_with_depth(context, depth + 1)?,
316 end.to_wolfram_with_depth(context, depth + 1)?
317 )
318 }
319 CalculusData::Product {
320 expression,
321 variable,
322 start,
323 end,
324 } => {
325 format!(
326 "Product[{}, {{{}, {}, {}}}]",
327 expression.to_wolfram_with_depth(context, depth + 1)?,
328 variable.name(),
329 start.to_wolfram_with_depth(context, depth + 1)?,
330 end.to_wolfram_with_depth(context, depth + 1)?
331 )
332 }
333 })
334 }
335 Expression::MethodCall(method_data) => {
336 let object_str = method_data
337 .object
338 .to_wolfram_with_depth(context, depth + 1)?;
339 let args_str = method_data
340 .args
341 .iter()
342 .map(|arg| arg.to_wolfram_with_depth(context, depth + 1))
343 .collect::<Result<Vec<_>, _>>()?
344 .join(", ");
345 Ok(format!(
346 "{}.{}[{}]",
347 object_str, method_data.method_name, args_str
348 ))
349 }
350 }
351 }
352
353 fn format_function_with_depth(
355 &self,
356 name: &str,
357 args: &[Expression],
358 context: &WolframContext,
359 depth: usize,
360 ) -> Result<String, FormattingError> {
361 if args.len() > MAX_TERMS_PER_OPERATION {
362 return Err(FormattingError::TooManyTerms {
363 count: args.len(),
364 limit: MAX_TERMS_PER_OPERATION,
365 });
366 }
367
368 let registry = get_universal_registry();
369 let wolfram_name = registry
370 .get_properties(name)
371 .and_then(|props| match props {
372 crate::functions::properties::FunctionProperties::Elementary(elem_props) => {
373 elem_props.wolfram_name
374 }
375 crate::functions::properties::FunctionProperties::Special(spec_props) => {
376 spec_props.wolfram_name
377 }
378 _ => None,
379 })
380 .unwrap_or(name);
381
382 if args.is_empty() {
383 Ok(wolfram_name.to_owned())
384 } else {
385 let mut arg_strs = Vec::with_capacity(args.len());
386 for arg in args.iter() {
387 arg_strs.push(arg.to_wolfram_with_depth(context, depth + 1)?);
388 }
389 Ok(format!("{}[{}]", wolfram_name, arg_strs.join(", ")))
390 }
391 }
392}