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