cpclib_asm/implementation/
expression.rs

1use std::fmt::Display;
2
3use cpclib_common::itertools::Itertools;
4use cpclib_tokens::symbols::*;
5use cpclib_tokens::tokens::*;
6
7use crate::assembler::Env;
8use crate::error::{ExpressionError, *};
9use crate::implementation::tokens::TokenExt;
10use crate::{SymbolFor, UnaryFunction};
11
12/// XXX Orgams only handles integer values and strings
13pub fn ensure_orgams_type(e: ExprResult, env: &Env) -> Result<ExprResult, AssemblerError> {
14    let e = if env.options().parse_options().is_orgams() {
15        match &e {
16            ExprResult::Float(_)
17            | ExprResult::Value(_)
18            | ExprResult::Char(_)
19            | ExprResult::Bool(_) => ExprResult::Value(e.int()?),
20            ExprResult::String(s) => e,
21            _ => {
22                return Err(AssemblerError::AlreadyRenderedError(format!(
23                    "Incompatible type with orgams {:?}",
24                    e
25                )));
26            }
27        }
28    }
29    else {
30        e
31    };
32
33    Ok(e)
34}
35
36/// ! Add all important methods to expresison-like structure sthat are not availalbe in the cpclib_tokens crate.
37
38/// The result of expression (without taking into account the strings) is either a int (no complex mathematical expression) or a float (division/sinus and so on)
39
40/// Evaluate an expression
41pub trait ExprEvaluationExt: Display {
42    /// Simple evaluation without context => can only evaluate number based operations.
43    fn eval(&self) -> Result<ExprResult, AssemblerError> {
44        let mut env = Env::default();
45        self.resolve(&mut env)
46    }
47
48    /// Resolve the expression base on the env context
49    fn resolve(&self, env: &mut Env) -> Result<ExprResult, AssemblerError>;
50
51    /// Get all the symbols used
52    fn symbols_used(&self) -> Vec<&str>;
53}
54
55#[macro_export]
56macro_rules! resolve_impl {
57
58    ($self: ident, $env: ident) => { {
59        use std::ops::Neg;
60        use cpclib_tokens::symbols::SymbolsTableTrait;
61
62
63/// utility class for unary function evaluation
64struct UnaryFunctionWrapper<'a, E:ExprEvaluationExt> {
65    func:  UnaryFunction,
66    arg: &'a E
67}
68
69
70impl<'a, E:ExprEvaluationExt>  std::fmt::Display for  UnaryFunctionWrapper<'a,E> {
71    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
72        write!(f, "{}({})", self.func, self.arg)
73    }
74}
75
76impl<'a, E:ExprEvaluationExt> UnaryFunctionWrapper<'a, E> {
77    fn new(func:  UnaryFunction, arg: &'a E) -> UnaryFunctionWrapper<'a,E> {
78        UnaryFunctionWrapper { func, arg }
79    }
80}
81
82impl<'a, E:ExprEvaluationExt> ExprEvaluationExt for UnaryFunctionWrapper<'a,E> {
83
84
85    fn symbols_used(&self) -> Vec<&str> {
86        self.arg.symbols_used()
87    }
88
89    /// TODO handle float numbers
90    fn resolve(&self, env: &mut Env) -> Result<ExprResult, AssemblerError> {
91        let arg = self.arg.resolve(env)?;
92
93        let res = match self.func {
94            UnaryFunction::High => {
95                ((arg >> 8.into())? & 0xFF.into())
96                    .map_err(|e| AssemblerError::ExpressionTypeError(e))
97            }
98            UnaryFunction::Low => {
99                (arg & 0xFF.into()).map_err(|e| AssemblerError::ExpressionTypeError(e))
100            }
101            UnaryFunction::Memory => {
102                if arg < 0.into() || arg > 0xFFFF.into() {
103                    return Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
104                        Box::new(AssemblerError::AssemblingError {
105                            msg: format!("Impossible to read memory address 0x{:X}", arg)
106                        })
107                    )));
108                }
109                else {
110                    Ok(env
111                        .peek(&env.logical_to_physical_address(arg.int()? as _))
112                        .into())
113                }
114            }
115            UnaryFunction::Floor => {
116                (arg.floor()).map_err(|e| AssemblerError::ExpressionTypeError(e))
117            }
118            UnaryFunction::Ceil => (arg.ceil()).map_err(|e| AssemblerError::ExpressionTypeError(e)),
119            UnaryFunction::Frac => (arg.frac()).map_err(|e| AssemblerError::ExpressionTypeError(e)),
120            UnaryFunction::Int => {
121                (arg.int())
122                    .map(|i| i.into())
123                    .map_err(|e| AssemblerError::ExpressionTypeError(e))
124            }
125            UnaryFunction::Char => {
126                (arg.char())
127                    .map(|i| i.into())
128                    .map_err(|e| AssemblerError::ExpressionTypeError(e))
129            }
130            UnaryFunction::Sin => {
131                if env.options().parse_options().is_orgams() {
132                    dbg!("We need to check things here");
133                    dbg!(Ok((512.0*(arg.float()? * 3.1415926545 / (256.0/2.0)).sin()).into()))
134                } else {
135                    arg.sin()
136                }.map_err(|e| AssemblerError::ExpressionTypeError(e))
137            },
138            UnaryFunction::Cos => (arg.cos()).map_err(|e| AssemblerError::ExpressionTypeError(e)),
139            UnaryFunction::ASin => (arg.asin()).map_err(|e| AssemblerError::ExpressionTypeError(e)),
140            UnaryFunction::ACos => (arg.acos()).map_err(|e| AssemblerError::ExpressionTypeError(e)),
141            UnaryFunction::Abs => (arg.abs()).map_err(|e| AssemblerError::ExpressionTypeError(e)),
142            UnaryFunction::Ln => (arg.ln()).map_err(|e| AssemblerError::ExpressionTypeError(e)),
143            UnaryFunction::Log10 => {
144                (arg.log10()).map_err(|e| AssemblerError::ExpressionTypeError(e))
145            }
146            UnaryFunction::Exp => (arg.exp()).map_err(|e| AssemblerError::ExpressionTypeError(e)),
147            UnaryFunction::Sqrt => (arg.sqrt()).map_err(|e| AssemblerError::ExpressionTypeError(e))
148        }?;
149
150
151        ensure_orgams_type(res, env)
152
153
154    }
155}
156
157
158/// utility class for binary function evaluation
159struct BinaryFunctionWrapper<'a,  E:ExprEvaluationExt> {
160    func: BinaryFunction,
161    arg1: &'a E,
162    arg2: &'a E
163}
164
165
166impl<'a, E:ExprEvaluationExt>  std::fmt::Display for  BinaryFunctionWrapper<'a,E> {
167    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
168        write!(f, "{}({},{})", self.func, self.arg1, self.arg2)
169    }
170}
171
172
173
174impl<'a,  E:ExprEvaluationExt> BinaryFunctionWrapper<'a, E> {
175    fn new(func:  BinaryFunction, arg1: &'a E, arg2: &'a E) -> Self {
176        BinaryFunctionWrapper { func, arg1, arg2 }
177    }
178}
179
180impl<'a,  E:ExprEvaluationExt> ExprEvaluationExt for BinaryFunctionWrapper<'a, E> {
181    fn symbols_used(&self) -> Vec<&str> {
182        self.arg1
183            .symbols_used()
184            .into_iter()
185            .chain(self.arg2.symbols_used().into_iter())
186            .collect_vec()
187    }
188
189    fn resolve(&self, env: &mut Env) -> Result<ExprResult, AssemblerError> {
190        let arg1 = self.arg1.resolve(env)?;
191        let arg2 = self.arg2.resolve(env)?;
192
193        let res = match self.func {
194            BinaryFunction::Min => Ok(arg1.min(arg2)),
195            BinaryFunction::Max => Ok(arg1.max(arg2)),
196            BinaryFunction::Pow => {
197                let power = arg2.int()?;
198                match arg1 {
199                    ExprResult::Float(f) => Ok(f.into_inner().powf(power as f64).into()),
200                    ExprResult::Value(v) => Ok(v.pow(power as _).into()),
201
202                    ExprResult::List(_) => {
203                        Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
204                            Box::new(AssemblerError::AssemblingError {
205                                msg: format!("pow cannot be applied to a list")
206                            })
207                        )))
208                    },
209
210                    _ => {
211                        Err(AssemblerError::ExpressionError(ExpressionError::OwnError(
212                            Box::new(AssemblerError::AssemblingError {
213                                msg: format!("pow cannot be applied to a string")
214                            })
215                        )))
216                    }
217                }
218            }
219        }?;
220
221        let res = ensure_orgams_type(res, env);
222        res
223
224    }
225}
226
227
228
229
230
231        let mut binary_operation = |left: &Self, right: &Self, oper: cpclib_tokens::BinaryOperation| -> Result<ExprResult, AssemblerError> {
232            let res_left = left.resolve($env);
233            let res_right = right.resolve($env);
234
235            match (res_left, res_right) {
236                (Ok(a), Ok(b)) => {
237                    match oper {
238                        cpclib_tokens::BinaryOperation::Add => (a + b).map_err(|e| AssemblerError::ExpressionTypeError(e)),
239                        cpclib_tokens::BinaryOperation::Sub => (a - b).map_err(|e| AssemblerError::ExpressionTypeError(e)),
240                        cpclib_tokens::BinaryOperation::Div => (a / b).map_err(|e| AssemblerError::ExpressionTypeError(e)),
241                        cpclib_tokens::BinaryOperation::Mod => (a % b).map_err(|e| AssemblerError::ExpressionTypeError(e)),
242                        cpclib_tokens::BinaryOperation::Mul => (a * b).map_err(|e| AssemblerError::ExpressionTypeError(e)),
243                        cpclib_tokens::BinaryOperation::RightShift => {
244                            (a >> b).map_err(|e| AssemblerError::ExpressionTypeError(e))
245                        }
246                        cpclib_tokens::BinaryOperation::LeftShift => {
247                            (a << b).map_err(|e| AssemblerError::ExpressionTypeError(e))
248                        }
249
250                        cpclib_tokens::BinaryOperation::BinaryAnd => {
251                            (a & b).map_err(|e| AssemblerError::ExpressionTypeError(e))
252                        }
253                        cpclib_tokens::BinaryOperation::BinaryOr => {
254                            (a | b).map_err(|e| AssemblerError::ExpressionTypeError(e))
255                        }
256                        cpclib_tokens::BinaryOperation::BinaryXor => {
257                            (a ^ b).map_err(|e| AssemblerError::ExpressionTypeError(e))
258                        }
259
260                        cpclib_tokens::BinaryOperation::BooleanAnd => Ok(ExprResult::from(a.bool()? && (b.bool()?))),
261                        cpclib_tokens::BinaryOperation::BooleanOr => Ok(ExprResult::from(a.bool()? || (b.bool()?))),
262
263                        cpclib_tokens::BinaryOperation::Equal => Ok((a == b).into()),
264                        cpclib_tokens::BinaryOperation::Different => Ok((a != b).into()),
265
266                        cpclib_tokens::BinaryOperation::LowerOrEqual => Ok((a <= b).into()),
267                        cpclib_tokens::BinaryOperation::StrictlyLower => Ok((a < b).into()),
268                        cpclib_tokens::BinaryOperation::GreaterOrEqual => Ok((a >= b).into()),
269                        cpclib_tokens::BinaryOperation::StrictlyGreater => Ok((a > b).into())
270                    }
271                }
272                (Err(a), Ok(_b)) => {
273                    Err(AssemblerError::ExpressionError(ExpressionError::LeftError(
274                        oper, Box::new(a)
275                    )))
276                }
277
278                (Ok(_a), Err(b)) => {
279                    Err(AssemblerError::ExpressionError(
280                        ExpressionError::RightError(oper, Box::new(b))
281                    ))
282                }
283                (Err(a), Err(b)) => {
284                    Err(AssemblerError::ExpressionError(
285                        ExpressionError::LeftAndRightError(oper, Box::new(a), Box::new(b))
286                    ))
287                }
288            }
289        };
290
291        if $self.is_binary_operation() {
292            binary_operation($self.arg1(), $self.arg2(), $self.binary_operation())
293        }
294        else if $self.is_paren() {
295            let e = $self.arg1();
296            e.resolve($env)
297        }
298        else if $self.is_relative() {
299            (Expr::Label("$".into()).resolve($env)? + ExprResult::from($self.relative_delta()))
300                .map_err(|e| AssemblerError::ExpressionTypeError(e))
301        }
302        else if $self.is_value(){
303            Ok($self.value().into())
304        }
305        else if $self.is_char() {
306            Ok($self.char().into())
307        }
308        else if $self.is_bool() {
309            Ok($self.bool().into())
310        } else if $self.is_string() {
311            Ok(ExprResult::String($self.string().into()))
312        }
313        else if $self.is_float() {
314            Ok($self.float().into_inner().into())
315        }
316        else if $self.is_list() {
317            Ok(ExprResult::List(
318                $self.list().iter()
319                    .map(|e| e.resolve($env))
320                    .collect::<Result<Vec<_>, _>>()?
321                )
322            )
323        }
324        else if $self.is_label() {
325            let label = $self.label();
326            match  $env.symbols().any_value(label)?.map(|vl| vl.value()) {
327                Some(cpclib_tokens::symbols::Value::Expr( val)) => Ok(val.clone().into()),
328                Some(cpclib_tokens::symbols::Value::Address( val)) => Ok(val.address().into()),
329                Some(cpclib_tokens::symbols::Value::Struct(s)) => Ok(s.len($env.symbols()).into()),
330                Some(cpclib_tokens::symbols::Value::String( val)) => Ok(val.into()),
331                Some(e) => { Err(AssemblerError::WrongSymbolType {
332                    symbol: label.into(),
333                    isnot: "a value".into(),
334                })},
335                None => Err(if $env.pass().is_first_pass() {
336                    // no need to lost time to make the leveinstein search
337                    AssemblerError::UnknownSymbol {
338                        symbol: label.into(),
339                        closest: None,
340                    }
341                } else {
342                    // here it is more problematic
343                    AssemblerError::UnknownSymbol {
344                        symbol: label.into(),
345                        closest:  $env.symbols().closest_symbol(label, SymbolFor::Number)?,
346                    }
347                })
348            }
349
350        }
351        else if $self.is_prefix_label() {
352            let label = $self.label();
353            let prefix = $self.prefix();
354
355            let val = $env.symbols()
356                                    .prefixed_value(prefix, label)?;
357            match  val  {
358                Some(val) => Ok(val.into()),
359                None => Err(AssemblerError::AssemblingError {
360                    msg: format!("Unable to use prefix {} for {}", prefix, label)
361                })
362            }
363        }
364
365        else if $self.is_token_operation() {
366            let token = $self.token();
367            match $self.token_operation() {
368                cpclib_tokens::UnaryTokenOperation::Duration => {
369                    let duration = token.estimated_duration()?;
370                    let duration = duration as i32;
371                    Ok(duration.into())
372                },
373
374                cpclib_tokens::UnaryTokenOperation::Opcode => {
375                    let bytes = token.to_bytes()?;
376                    match bytes.len() {
377                        0 => Err(
378                            AssemblerError::ExpressionError(
379                                ExpressionError::OwnError(
380                                    Box::new(AssemblerError::AssemblingError{msg:format!("{} is assembled with 0 bytes", token)})
381                                )
382                            )
383                        ),
384                        1 => Ok(i32::from(bytes[0]).into()),
385                        2 => Ok((i32::from(bytes[0]) * 256 + i32::from(bytes[1])).into()),
386                        val => Err(
387                            AssemblerError::ExpressionError(
388                                ExpressionError::OwnError(
389                                    Box::new(AssemblerError::AssemblingError{msg:format!("{} is assembled with {} bytes", token, val)})
390                                )
391                            )
392                        )
393                    }
394                }
395            }
396        }
397        else if $self.is_unary_operation() {
398            let e = $self.arg1();
399
400            match $self.unary_operation() {
401                cpclib_tokens::UnaryOperation::BinaryNot => {
402                    e.resolve($env)?
403                    .binary_not()
404                    .map_err(|e| AssemblerError::ExpressionTypeError(e))
405                },
406                cpclib_tokens::UnaryOperation::Not => {
407                    e.resolve($env)?
408                    .not()
409                    .map_err(|e| AssemblerError::ExpressionTypeError(e))
410                },
411                cpclib_tokens::UnaryOperation::Neg => {
412                    (e.resolve($env)?)
413                        .neg()
414                        .map_err(|e| AssemblerError::ExpressionTypeError(e))
415                }
416            }
417        }
418        else if $self.is_unary_function() {
419            let func = $self.unary_function();
420            let arg = $self.arg1();
421            UnaryFunctionWrapper::new(func, arg).resolve($env)
422        }
423        else if $self.is_binary_function() {
424            let func = $self.binary_function();
425            let arg1 = $self.arg1();
426            let arg2 = $self.arg2();
427            BinaryFunctionWrapper::new(func, arg1, arg2).resolve($env)
428        }
429
430        else if $self.is_rnd() {
431            unimplemented!("Env need to maintain a counter of call with its value to ensure a consistant generation among the passes")
432        }
433        else if $self.is_any_function(){
434            let d = $self.function_name();
435            let expr = $self.function_args();
436
437
438            let mut params = Vec::with_capacity(expr.len());
439            for p in expr.iter() {
440                let v = $env.resolve_expr_may_fail_in_first_pass(p) ?;
441                params.push(v);
442            }
443
444            let f = $env.any_function(d)?;
445            f.eval($env, &params)
446
447
448        } else {
449            unreachable!()
450        }
451    }
452    };
453}
454
455impl ExprEvaluationExt for Expr {
456    /// XXX Be sure it is well synchronized with LocatedExpr
457    fn symbols_used(&self) -> Vec<&str> {
458        match self {
459            Expr::RelativeDelta(_)
460            | Expr::Value(_)
461            | Expr::Float(_)
462            | Expr::Char(_)
463            | Expr::Bool(_)
464            | Expr::String(_)
465            | Expr::Rnd => Vec::new(),
466
467            Expr::Label(label) | Expr::PrefixedLabel(_, label) => vec![label.as_str()],
468
469            Expr::BinaryFunction(_, box a, box b) | Expr::BinaryOperation(_, box a, box b) => {
470                a.symbols_used()
471                    .into_iter()
472                    .chain(b.symbols_used())
473                    .collect_vec()
474            },
475
476            Expr::Paren(a) | Expr::UnaryFunction(_, a) | Expr::UnaryOperation(_, a) => {
477                a.symbols_used()
478            },
479
480            Expr::AnyFunction(_, l) | Expr::List(l) => {
481                l.iter().flat_map(|e| e.symbols_used()).collect_vec()
482            },
483
484            Expr::UnaryTokenOperation(_, box _t) => {
485                unimplemented!("Need to retreive the symbols from the operation")
486            }
487        }
488    }
489
490    fn resolve(&self, env: &mut Env) -> Result<ExprResult, AssemblerError> {
491        resolve_impl!(self, env)
492    }
493}