cortex_lang/parsing/ast/
expression.rs

1use thiserror::Error;
2use std::error::Error;
3
4use crate::{parsing::codegen::r#trait::SimpleCodeGen, preprocessing::ast::function_address::FunctionAddress};
5
6use super::{top_level::BasicBody, r#type::CortexType};
7
8#[derive(Clone)]
9pub struct PConditionBody {
10    pub(crate) condition: PExpression,
11    pub(crate) body: BasicBody,
12}
13impl SimpleCodeGen for PConditionBody {
14    fn codegen(&self, indent: usize) -> String {
15        let mut s = String::new();
16        s.push_str(&self.condition.codegen(indent));
17        s.push_str(" {\n");
18        s.push_str(&self.body.codegen(indent + 1));
19        s.push_str(&"    ".repeat(indent));
20        s.push_str("}");
21        s
22    }
23}
24
25#[derive(Clone)]
26pub enum PExpression {
27    Number(f64),
28    Boolean(bool),
29    Void,
30    None,
31    String(String),
32    Char(u8),
33    PathIdent(PathIdent),
34    Call {
35        name: FunctionAddress, 
36        args: Vec<PExpression>,
37        type_args: Option<Vec<CortexType>>,
38    },
39    Construction {
40        name: PathIdent,
41        type_args: Vec<CortexType>,
42        assignments: Vec<(String, PExpression)>,
43    },
44    IfStatement {
45        first: Box<PConditionBody>,
46        conds: Vec<PConditionBody>,
47        last: Option<Box<BasicBody>>,
48    },
49    UnaryOperation {
50        op: UnaryOperator,
51        exp: Box<PExpression>,
52    },
53    ListLiteral(Vec<PExpression>),
54    Bang(Box<PExpression>),
55    MemberAccess(Box<PExpression>, String),
56    MemberCall {
57        callee: Box<PExpression>,
58        member: String,
59        args: Vec<PExpression>,
60        type_args: Option<Vec<CortexType>>,
61    },
62    BinaryOperation {
63        left: Box<PExpression>,
64        op: BinaryOperator,
65        right: Box<PExpression>,
66    },
67    Tuple(Vec<PExpression>),
68}
69impl SimpleCodeGen for PExpression {
70    fn codegen(&self, indent: usize) -> String {
71        match self {
72            PExpression::Number(v) => format!("{}", v),
73            PExpression::Boolean(v) => format!("{}", v),
74            PExpression::String(v) => format!("\"{}\"", v),
75            PExpression::Void => String::from("void"),
76            PExpression::None => String::from("none"),
77            PExpression::PathIdent(path) => path.codegen(indent),
78            PExpression::Call{ name, args, type_args } => {
79                let mut s = String::new();
80                s.push_str(&name.codegen(indent));
81                if let Some(type_args) = type_args {
82                    s.push_str("<");
83                    s.push_str(&type_args.iter().map(|t| t.codegen(indent)).collect::<Vec<_>>().join(", "));
84                    s.push_str(">");
85                }
86                s.push_str("(");
87                for (i, arg) in args.iter().enumerate() {
88                    s.push_str(&arg.codegen(indent));
89                    if i + 1 < args.len() {
90                        s.push_str(", ");
91                    }
92                }
93                s.push_str(")");
94                s
95            },
96            PExpression::Construction { name, type_args, assignments } => {
97                let mut s = String::new();
98                s.push_str(&name.codegen(0));
99                if type_args.len() > 0 {
100                    s.push_str("<");
101                    s.push_str(&type_args.iter().map(|s| s.codegen(0)).collect::<Vec<_>>().join(","));
102                    s.push_str(">");
103                }
104                s.push_str(" { ");
105                for a in assignments {
106                    s.push_str(&a.0);
107                    s.push_str(": ");
108                    s.push_str(&a.1.codegen(0));
109                    s.push_str(", ");
110                }
111                s.push_str("}");
112                s
113            },
114            PExpression::IfStatement { first, conds, last } => {
115                let mut s = String::new();
116                let indent_prefix = "    ".repeat(indent);
117                s.push_str(&indent_prefix);
118                s.push_str("if ");
119                s.push_str(&first.codegen(indent));
120                for c in conds {
121                    s.push_str(" elif ");
122                    s.push_str(&c.codegen(indent));
123                }
124                if let Some(body) = last {
125                    s.push_str(" else {\n");
126                    s.push_str(&body.codegen(indent + 1));
127                    s.push_str(&indent_prefix);
128                    s.push_str("}");
129                }
130                s
131            },
132            PExpression::UnaryOperation { op, exp } => {
133                format!("{}{}", op.codegen(indent), exp.codegen_as_sub(indent))
134            },
135            PExpression::ListLiteral(items) => {
136                let mut s = String::new();
137                s.push_str("[");
138                s.push_str(
139                    &items
140                        .iter()
141                        .map(|e| e.codegen(0))
142                        .collect::<Vec<_>>()
143                        .join(", ")
144                );
145                s.push_str("]");
146                s
147            },
148            PExpression::Bang(ex) => format!("{}!", ex.codegen(indent)),
149            PExpression::BinaryOperation { left, op, right } => {
150                format!("{} {} {}", left.codegen_as_sub(indent), op.codegen(indent), right.codegen_as_sub(indent))
151            },
152            PExpression::MemberAccess(ex, member) => format!("{}.{}", ex.codegen_as_sub(indent), member),
153            PExpression::MemberCall { callee, member: member_name, args, type_args } => {
154                if let Some(type_args) = type_args {
155                    format!("{}.{}<{}>({})", 
156                        callee.codegen_as_sub(indent), 
157                        member_name, 
158                        type_args.iter().map(|t| t.codegen(indent)).collect::<Vec<_>>().join(", "),
159                        args.iter().map(|a| a.codegen(indent)).collect::<Vec<_>>().join(", ")
160                    )
161                } else {
162                    format!("{}.{}({})", 
163                        callee.codegen_as_sub(indent), 
164                        member_name, 
165                        args.iter().map(|a| a.codegen(indent)).collect::<Vec<_>>().join(", ")
166                    )
167                }
168            },
169            PExpression::Tuple(items) => {
170                if items.len() == 1 {
171                    format!("({},)", items.get(0).unwrap().codegen(indent))
172                } else {
173                    format!("({})", items.iter().map(|i| i.codegen(indent)).collect::<Vec<_>>().join(", "))
174                }
175            },
176            PExpression::Char(c) => {
177                format!("'{}'", *c as char)
178            }
179        }
180    }
181}
182impl PExpression {
183    fn is_atomic(&self) -> bool {
184        match self {
185            PExpression::Number(_) | PExpression::Boolean(_) | PExpression::Void | PExpression::None | 
186            PExpression::String(_) | PExpression::PathIdent(_) | PExpression::Call { name: _, args: _, type_args: _ } |
187            PExpression::Construction { name: _, type_args: _, assignments: _ } |
188            PExpression::IfStatement { first: _, conds: _, last: _ } | PExpression::MemberAccess(_, _) |
189            PExpression::ListLiteral(_) | PExpression::MemberCall { callee: _, member: _, args: _, type_args: _ } |
190            PExpression::Tuple(_) | PExpression::Char(_)
191                => true,
192            
193            PExpression::UnaryOperation { op: _, exp: _ } | PExpression::Bang(_) | 
194            PExpression::BinaryOperation { left: _, op: _, right: _ }
195                => false,
196        }
197    }
198    fn codegen_as_sub(&self, indent: usize) -> String {
199        let s = self.codegen(indent);
200        if !self.is_atomic() {
201            format!("({})", s)
202        } else {
203            s
204        }
205    }
206}
207
208#[derive(Clone)]
209pub struct Parameter {
210    pub(crate) name: String,
211    pub(crate) typ: CortexType,
212}
213impl SimpleCodeGen for Parameter {
214    fn codegen(&self, indent: usize) -> String {
215        let mut s = String::new();
216        s.push_str(&self.name);
217        s.push_str(": ");
218        s.push_str(&self.typ.codegen(indent));
219        s
220    }
221}
222impl Parameter {
223    pub fn named(name: &str, typ: CortexType) -> Self {
224        Parameter {
225            name: String::from(name),
226            typ: typ,
227        }
228    }
229
230    pub fn name(&self) -> &String {
231        &self.name
232    }
233    pub fn param_type(&self) -> &CortexType {
234        &self.typ
235    }
236}
237
238#[derive(Clone)]
239pub struct IdentExpression {
240    pub(crate) base: String,
241    pub(crate) chain: Vec<String>,
242}
243impl SimpleCodeGen for IdentExpression {
244    fn codegen(&self, _indent: usize) -> String {
245        let mut s = String::new();
246        s.push_str(&self.base);
247        for c in &self.chain {
248            s.push_str(".");
249            s.push_str(c);
250        }
251        s
252    }
253}
254impl IdentExpression {
255    pub fn is_simple(&self) -> bool {
256        self.chain.is_empty()
257    }
258
259    pub fn to_member_access_expr(self) -> PExpression {
260        let mut expr = PExpression::PathIdent(PathIdent::simple(self.base));
261        for link in self.chain {
262            expr = PExpression::MemberAccess(Box::new(expr), link);
263        }
264        expr
265    }
266
267    pub fn without_last(mut self) -> Result<IdentExpression, Box<dyn Error>> {
268        // TODO: should return error rather than returning self
269        if self.chain.len() > 0 {
270            self.chain.remove(self.chain.len() - 1);
271            Ok(IdentExpression {
272                base: self.base,
273                chain: self.chain,
274            })
275        } else {
276            Ok(self)
277        }
278    }
279}
280
281#[derive(Clone)]
282pub enum OptionalIdentifier {
283    Ident(String), // A true identifier
284    Ignore, // The ignore token, "~"
285}
286impl SimpleCodeGen for OptionalIdentifier {
287    fn codegen(&self, _: usize) -> String {
288        match self {
289            Self::Ident(s) => s.clone(),
290            Self::Ignore => String::from("~"),
291        }
292    }
293}
294
295#[derive(Clone, Debug, PartialEq, Eq, Hash)]
296pub struct PathIdent {
297    pub(crate) path: Vec<String>,
298}
299impl SimpleCodeGen for PathIdent {
300    fn codegen(&self, _: usize) -> String {
301        self.to_string("::")
302    }
303}
304#[derive(Error, Debug, PartialEq)]
305pub enum PathError {
306    #[error("Path is empty")]
307    PathEmpty,
308    #[error("Subtraction failed: item {0} does not match {1}")]
309    SubtractionFailed(String, String),
310}
311impl PathIdent {
312    pub fn simple(name: String) -> Self {
313        Self {
314            path: vec![name],
315        }
316    }
317    pub fn new(name: Vec<&str>) -> Self {
318        Self {
319            path: name.iter().map(|s| String::from(*s)).collect(),
320        }
321    }
322    pub fn continued(first: PathIdent, next: String) -> Self {
323        if first.is_empty() {
324            Self {
325                path: vec![next],
326            }
327        } else {
328            let mut path = first.path.clone();
329            path.push(next);
330            Self {
331                path: path,
332            }
333        }
334    }
335    pub fn empty() -> Self {
336        Self {
337            path: Vec::new(),
338        }
339    }
340    pub fn concat(first: &PathIdent, second: &PathIdent) -> Self {
341        if first.is_empty() {
342            second.clone()
343        } else if second.is_empty() {
344            first.clone()
345        } else {
346            let mut path = first.path.clone();
347            path.extend(second.path.clone());
348            Self {
349                path: path,
350            }
351        }
352    }
353
354    pub fn is_prefixed_by(&self, prefix: &PathIdent) -> bool {
355        if prefix.path.len() > self.path.len() {
356            return false;
357        }
358        for (i, p) in prefix.path.iter().enumerate() {
359            if *self.path.get(i).unwrap() != *p {
360                return false;
361            }
362        }
363        true
364    }
365
366    pub fn subtract(self, second: &PathIdent) -> Result<Self, PathError> {
367        if second.is_empty() {
368            Ok(self)
369        } else {
370            let mut path = self.path.clone();
371            for item in &second.path {
372                if let Some(first) = path.get(0) {
373                    if first != item {
374                        return Err(PathError::SubtractionFailed(first.clone(), item.clone()));
375                    }
376                    path.remove(0);
377                } else {
378                    return Err(PathError::PathEmpty);
379                }
380            }
381            Ok(
382                Self {
383                    path: path
384                }
385            )
386        }
387    }
388    pub fn subtract_if_possible(self, second: &PathIdent) -> Self {
389        if self.is_prefixed_by(second) {
390            self.subtract(second).unwrap()
391        } else {
392            self
393        }
394    }
395
396    pub fn without_last(&self) -> Self {
397        let mut new_vec = self.path.clone();
398        new_vec.remove(new_vec.len() - 1);
399        Self {
400            path: new_vec,
401        }
402    }
403
404    pub fn pop_front(&self) -> Result<PathIdent, PathError> {
405        if self.path.len() <= 0 {
406            Err(PathError::PathEmpty)
407        } else {
408            let new_path: Vec<String> = self.path.iter().skip(1).cloned().collect();
409            Ok(PathIdent {
410                path: new_path,
411            })
412        }
413    }
414    pub fn get_front(&self) -> Result<&String, PathError> {
415        if let Some(elem) = self.path.get(0) {
416            Ok(elem)
417        } else {
418            Err(PathError::PathEmpty)
419        }
420    }
421    pub fn get_back(&self) -> Result<&String, PathError> {
422        if let Some(elem) = self.path.get(self.path.len() - 1) {
423            Ok(elem)
424        } else {
425            Err(PathError::PathEmpty)
426        }
427    }
428    // Returns true if there is only one segment in this path left
429    // Error if the path is empty
430    pub fn is_final(&self) -> bool {
431        if self.path.len() <= 0 {
432            false
433        } else {
434            self.path.len() == 1
435        }
436    }
437    pub fn is_empty(&self) -> bool {
438        self.path.len() <= 0
439    }
440
441    pub fn to_string(&self, separator: &str) -> String {
442        self.path.iter().cloned().collect::<Vec<_>>().join(separator)
443    }
444}
445
446#[derive(Clone)]
447pub enum UnaryOperator {
448    Negate,
449    Invert,
450}
451impl SimpleCodeGen for UnaryOperator {
452    fn codegen(&self, _indent: usize) -> String {
453        String::from(
454            match self {
455                UnaryOperator::Negate => "-",
456                UnaryOperator::Invert => "!",
457            }
458        )
459    }
460}
461
462#[derive(Clone)]
463pub enum BinaryOperator {
464    Add,
465    Subtract,
466    Multiply,
467    Divide,
468    Remainder,
469    LogicAnd,
470    LogicOr,
471    IsEqual,
472    IsNotEqual,
473    IsLessThan,
474    IsGreaterThan,
475    IsLessThanOrEqualTo,
476    IsGreaterThanOrEqualTo,
477}
478impl SimpleCodeGen for BinaryOperator {
479    fn codegen(&self, _: usize) -> String {
480        String::from(
481            match self {
482                BinaryOperator::Add => "+",
483                BinaryOperator::Subtract => "-",
484                BinaryOperator::Multiply => "*",
485                BinaryOperator::Divide => "/",
486                BinaryOperator::Remainder => "%",
487                BinaryOperator::LogicAnd => "&&",
488                BinaryOperator::LogicOr => "||",
489                BinaryOperator::IsEqual => "==",
490                BinaryOperator::IsNotEqual => "!=",
491                BinaryOperator::IsLessThan => "<",
492                BinaryOperator::IsGreaterThan => ">",
493                BinaryOperator::IsLessThanOrEqualTo => "<=",
494                BinaryOperator::IsGreaterThanOrEqualTo => ">=",
495            }
496        )
497    }
498}