crustal/
expr.rs

1// C/C++ Code Generator For Rust
2//
3//
4// MIT License
5//
6// Copyright (c) 2022 Reto Achermann
7//
8// Permission is hereby granted, free of charge, to any person obtaining a copy
9// of this software and associated documentation files (the "Software"), to deal
10// in the Software without restriction, including without limitation the rights
11// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12// copies of the Software, and to permit persons to whom the Software is
13// furnished to do so, subject to the following conditions:
14//
15// The above copyright notice and this permission notice shall be included in all
16// copies or substantial portions of the Software.
17//
18// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24// SOFTWARE.
25
26//! # Expressions
27//!
28//! The statement module provides mechanisms to express code statements.
29
30use std::fmt::{self, Display, Write};
31
32use crate::{Attribute, BaseType, Formatter, FunctionParam, MethodParam, Type};
33
34/// Defines an statement
35#[derive(Debug, Clone)]
36pub enum Expr {
37    /// represents a variable with a given type
38    Variable {
39        name: String,
40        ty: Type,
41    },
42    /// represents a constant in the expressions, e.g., 0, '1', "asdf"
43    ConstNum(u64),
44    ConstString(String),
45    ConstBool(bool),
46    NewObject {
47        name: String,
48        args: Vec<Expr>,
49    },
50    DeleteObject {
51        var: Box<Expr>,
52    },
53    /// represents a function call
54    FnCall {
55        name: String,
56        args: Vec<Expr>,
57    },
58    /// represents a method call
59    MethodCall {
60        var: Box<Expr>,
61        method: String,
62        args: Vec<Expr>,
63        is_ptr: bool,
64    },
65    /// represents the dereference operator `*(Expr)`
66    Deref(Box<Expr>),
67    /// represents the address of operation: `&(Expr)`
68    AddrOf(Box<Expr>),
69    /// represents the size of operation: `sizeof(Expr)`
70    SizeOf(Box<Expr>),
71    /// accesses the field
72    FieldAccess {
73        var: Box<Expr>,
74        field: String,
75        is_ptr: bool,
76    },
77    ArrayElementAccess {
78        var: Box<Expr>,
79        idx: Box<Expr>,
80        is_ptr: bool,
81    },
82    /// represents a binary opreation: `a + b`
83    BinOp {
84        lhs: Box<Expr>,
85        rhs: Box<Expr>,
86        op: String,
87    },
88    /// represents an uniary operator: `!(expr)`
89    UnOp {
90        expr: Box<Expr>,
91        op: String,
92    },
93    /// represents a conditional ternary expression: `cond ? then : other`
94    Ternary {
95        cond: Box<Expr>,
96        then: Box<Expr>,
97        other: Box<Expr>,
98    },
99    Cast {
100        expr: Box<Expr>,
101        ty: Type,
102    },
103    /// represents a raw expression token
104    Raw(String),
105}
106
107impl Expr {
108    pub fn new_str(s: &str) -> Self {
109        Expr::ConstString(s.to_string())
110    }
111
112    pub fn new_num(n: u64) -> Self {
113        Expr::ConstNum(n)
114    }
115
116    pub fn new_var(name: &str, ty: Type) -> Self {
117        Expr::Variable {
118            name: name.to_string(),
119            ty,
120        }
121    }
122
123    pub fn btrue() -> Self {
124        Expr::ConstBool(true)
125    }
126
127    pub fn bfalse() -> Self {
128        Expr::ConstBool(false)
129    }
130
131    pub fn uop(op: &str, expr: Expr) -> Self {
132        Expr::UnOp {
133            expr: Box::new(expr),
134            op: op.to_string(),
135        }
136    }
137
138    pub fn lnot(expr: Expr) -> Self {
139        Expr::uop("!", expr)
140    }
141
142    pub fn binop(lhs: Expr, op: &str, rhs: Expr) -> Self {
143        Expr::BinOp {
144            lhs: Box::new(lhs),
145            rhs: Box::new(rhs),
146            op: op.to_string(),
147        }
148    }
149
150    pub fn land(lhs: Expr, rhs: Expr) -> Self {
151        Self::binop(lhs, "&&", rhs)
152    }
153
154    pub fn ternary(cond: Expr, then: Expr, other: Expr) -> Self {
155        Expr::Ternary {
156            cond: Box::new(cond),
157            then: Box::new(then),
158            other: Box::new(other),
159        }
160    }
161
162    pub fn from_fn_param(p: &FunctionParam) -> Self {
163        p.to_expr()
164    }
165
166    pub fn from_method_param(p: &MethodParam) -> Self {
167        p.to_expr()
168    }
169
170    pub fn from_attribuge(p: &Attribute) -> Self {
171        p.to_expr()
172    }
173
174    pub fn this() -> Self {
175        Expr::Variable {
176            name: "this".to_string(),
177            ty: Type::to_ptr(&Type::new(BaseType::Class(String::from("auto")))),
178        }
179    }
180
181    pub fn null() -> Self {
182        Expr::Variable {
183            name: "NULL".to_string(),
184            ty: Type::to_ptr(&Type::new(BaseType::Void)),
185        }
186    }
187
188    pub fn new(class: &str, args: Vec<Expr>) -> Self {
189        Expr::NewObject {
190            name: class.to_string(),
191            args,
192        }
193    }
194
195    pub fn delete(var: Expr) -> Self {
196        Expr::DeleteObject { var: Box::new(var) }
197    }
198
199    pub fn addr_of(&self) -> Self {
200        Expr::AddrOf(Box::new(self.clone()))
201    }
202
203    pub fn size_of(&self) -> Self {
204        Expr::SizeOf(Box::new(self.clone()))
205    }
206
207    pub fn deref(&self) -> Self {
208        Expr::Deref(Box::new(self.clone()))
209    }
210
211    pub fn field_access(&self, field: &str) -> Self {
212        Expr::FieldAccess {
213            var: Box::new(self.clone()),
214            field: field.to_string(),
215            is_ptr: false,
216        }
217    }
218
219    pub fn array_access(var: &Expr, idx: &Expr) -> Self {
220        Expr::ArrayElementAccess {
221            var: Box::new(var.clone()),
222            idx: Box::new(idx.clone()),
223            is_ptr: false,
224        }
225    }
226
227    /// TODO: add type information here!
228    pub fn method_call(var: &Expr, method: &str, args: Vec<Expr>) -> Self {
229        Expr::MethodCall {
230            var: Box::new(var.clone()),
231            method: method.to_string(),
232            args,
233            is_ptr: false,
234        }
235    }
236
237    pub fn fn_call(name: &str, args: Vec<Expr>) -> Self {
238        Expr::FnCall {
239            name: String::from(name),
240            args,
241        }
242    }
243
244    pub fn cast_to(&self, ty: Type) -> Self {
245        Expr::Cast {
246            expr: Box::new(self.clone()),
247            ty,
248        }
249    }
250
251    pub fn set_ptr(&mut self) {
252        match self {
253            Expr::MethodCall { is_ptr, .. } => {
254                *is_ptr = true;
255            }
256            Expr::FieldAccess { is_ptr, .. } => {
257                *is_ptr = true;
258            }
259            Expr::ArrayElementAccess { is_ptr, .. } => {
260                *is_ptr = true;
261            }
262            _ => (),
263        }
264    }
265
266    pub fn is_ptr(&self) -> bool {
267        match self {
268            Expr::Variable { ty, .. } => ty.is_ptr(),
269            Expr::Deref(e) => e.is_ptr(),
270            Expr::AddrOf(_) => true,
271            Expr::Raw(_) => true,
272            Expr::NewObject { .. } => true,
273            Expr::MethodCall { is_ptr, .. } => *is_ptr,
274            Expr::FieldAccess { is_ptr, .. } => *is_ptr,
275            Expr::ArrayElementAccess { is_ptr, .. } => *is_ptr,
276            Expr::Cast { ty, .. } => ty.is_ptr(),
277            _ => false,
278        }
279    }
280
281    pub fn is_struct(&self) -> bool {
282        match self {
283            Expr::Variable { ty, .. } => ty.is_struct(),
284            Expr::Cast { ty, .. } => ty.is_struct(),
285            Expr::NewObject { .. } => true,
286            Expr::Raw(_) => true,
287            _ => false,
288        }
289    }
290
291    pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
292        match self {
293            Expr::Variable { name, .. } => write!(fmt, "{name}"),
294            Expr::ConstString(x) => write!(fmt, "\"{x}\""),
295            Expr::ConstNum(x) => write!(fmt, "0x{x:x}"),
296            Expr::ConstBool(true) => write!(fmt, "true"),
297            Expr::ConstBool(false) => write!(fmt, "false"),
298            Expr::FnCall { name, args } => {
299                write!(fmt, "{name}(")?;
300                for (i, v) in args.iter().enumerate() {
301                    if i != 0 {
302                        write!(fmt, ", ")?;
303                    }
304                    v.fmt(fmt)?;
305                }
306                write!(fmt, ")")
307            }
308            Expr::Deref(e) => {
309                write!(fmt, "*(")?;
310                e.as_ref().fmt(fmt)?;
311                write!(fmt, ")")
312            }
313            Expr::AddrOf(e) => {
314                write!(fmt, "&(")?;
315                e.as_ref().fmt(fmt)?;
316                write!(fmt, ")")
317            }
318            Expr::SizeOf(e) => {
319                write!(fmt, "sizeof(")?;
320                e.as_ref().fmt(fmt)?;
321                write!(fmt, ")")
322            }
323            Expr::FieldAccess { var, field, .. } => {
324                write!(fmt, "({})", var.as_ref())?;
325                if var.is_ptr() {
326                    write!(fmt, "->{field}")
327                } else {
328                    write!(fmt, ".{field}")
329                }
330            }
331            Expr::ArrayElementAccess { var, idx, is_ptr: _ } => {
332                var.as_ref().fmt(fmt)?;
333                write!(fmt, "[{idx}]")
334            }
335            Expr::MethodCall { var, method, args, .. } => {
336                var.as_ref().fmt(fmt)?;
337                if var.is_ptr() {
338                    write!(fmt, "->{method}(")?;
339                } else {
340                    write!(fmt, ".{method}(")?;
341                }
342                for (i, v) in args.iter().enumerate() {
343                    if i != 0 {
344                        write!(fmt, ", ")?;
345                    }
346                    v.fmt(fmt)?;
347                }
348                write!(fmt, ")")
349            }
350            Expr::BinOp { lhs, rhs, op } => {
351                write!(fmt, "(")?;
352                lhs.as_ref().fmt(fmt)?;
353                write!(fmt, " {op} ")?;
354                rhs.as_ref().fmt(fmt)?;
355                write!(fmt, ")")
356            }
357            Expr::UnOp { expr, op } => {
358                write!(fmt, "{op}(")?;
359                expr.as_ref().fmt(fmt)?;
360                write!(fmt, ")")
361            }
362            Expr::Ternary { cond, then, other } => {
363                write!(fmt, "(")?;
364                cond.as_ref().fmt(fmt)?;
365                write!(fmt, ") ? (")?;
366                then.as_ref().fmt(fmt)?;
367                write!(fmt, ") : (")?;
368                other.as_ref().fmt(fmt)?;
369                write!(fmt, ")")
370            }
371            Expr::NewObject { name, args } => {
372                write!(fmt, "new {}(", name)?;
373                for (i, arg) in args.iter().enumerate() {
374                    if i > 0 {
375                        write!(fmt, ", ")?;
376                    }
377                    write!(fmt, "{}", arg)?;
378                }
379                write!(fmt, ")")
380            }
381            Expr::DeleteObject { var } => {
382                write!(fmt, "delete[] {}", var)
383            }
384            Expr::Cast { expr, ty } => {
385                write!(fmt, "({ty})({expr})")
386            }
387            Expr::Raw(s) => write!(fmt, "{s}"),
388        }
389    }
390}
391
392impl Display for Expr {
393    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
394        let mut ret = String::new();
395        self.fmt(&mut Formatter::new(&mut ret)).unwrap();
396        write!(f, "{ret}")
397    }
398}