cortex_lang/parsing/ast/
expression.rs

1use thiserror::Error;
2
3use crate::parsing::codegen::r#trait::SimpleCodeGen;
4
5use super::{top_level::BasicBody, r#type::CortexType};
6
7macro_rules! operator_struct {
8    ($name:ident, $item: ty) => {
9        #[derive(Clone)]
10        pub struct $name {
11            pub(crate) first: $item,
12            pub(crate) rest: Vec<(BinaryOperator, $item)>,
13        }
14
15        impl SimpleCodeGen for $name {
16            fn codegen(&self, indent: usize) -> String {
17                let mut s = String::new();
18                s.push_str(&self.first.codegen(indent));
19                for (op, item) in &self.rest {
20                    s.push_str(" ");
21                    s.push_str(&op.codegen(indent));
22                    s.push_str(" ");
23                    s.push_str(&item.codegen(indent));
24                }
25                s
26            }
27        }
28    }
29}
30
31operator_struct!(MulResult, Primary);
32operator_struct!(SumResult, MulResult);
33operator_struct!(EqResult, SumResult);
34operator_struct!(Expression, EqResult);
35
36#[derive(Clone)]
37pub struct Primary {
38    pub(crate) atom: Atom,
39    pub(crate) tail: ExpressionTail,
40}
41impl SimpleCodeGen for Primary {
42    fn codegen(&self, indent: usize) -> String {
43        let mut s = String::new();
44        s.push_str(&self.atom.codegen(indent));
45        s.push_str(&self.tail.codegen(indent));
46        s
47    }
48}
49
50#[derive(Clone)]
51pub struct ConditionBody {
52    pub(crate) condition: Expression,
53    pub(crate) body: BasicBody,
54}
55impl SimpleCodeGen for ConditionBody {
56    fn codegen(&self, indent: usize) -> String {
57        let mut s = String::new();
58        s.push_str(&self.condition.codegen(indent));
59        s.push_str(" {\n");
60        s.push_str(&self.body.codegen(indent + 1));
61        s.push_str(&"    ".repeat(indent));
62        s.push_str("}");
63        s
64    }
65}
66
67#[derive(Clone)]
68pub enum Atom {
69    Number(f64),
70    Boolean(bool),
71    Void,
72    Null,
73    String(String),
74    PathIdent(PathIdent),
75    Call(PathIdent, Vec<Expression>),
76    StructConstruction {
77        name: PathIdent, 
78        assignments: Vec<(String, Expression)>
79    },
80    IfStatement {
81        first: Box<ConditionBody>,
82        conds: Vec<ConditionBody>,
83        last: Option<Box<BasicBody>>,
84    },
85    UnaryOperation {
86        op: UnaryOperator,
87        exp: Box<Expression>,
88    },
89    Expression(Box<Expression>),
90}
91impl SimpleCodeGen for Atom {
92    fn codegen(&self, indent: usize) -> String {
93        match self {
94            Atom::Number(v) => format!("{}", v),
95            Atom::Boolean(v) => format!("{}", v),
96            Atom::String(v) => format!("\"{}\"", v),
97            Atom::Void => String::from("void"),
98            Atom::Null => String::from("null"),
99            Atom::PathIdent(path) => path.codegen(indent),
100            Atom::Expression(expr) => format!("({})", expr.codegen(indent)),
101            Atom::Call(path, args) => {
102                let mut s = String::new();
103                s.push_str(&path.codegen(indent));
104                s.push_str("(");
105                for (i, arg) in args.iter().enumerate() {
106                    s.push_str(&arg.codegen(indent));
107                    if i + 1 < args.len() {
108                        s.push_str(", ");
109                    }
110                }
111                s.push_str(")");
112                s
113            },
114            Atom::StructConstruction { name, assignments } => {
115                let mut s = String::new();
116                s.push_str(&name.codegen(0));
117                s.push_str(" { ");
118                for a in assignments {
119                    s.push_str(&a.0);
120                    s.push_str(": ");
121                    s.push_str(&a.1.codegen(0));
122                    s.push_str(", ");
123                }
124                s.push_str("}");
125                s
126            },
127            Atom::IfStatement { first, conds, last } => {
128                let mut s = String::new();
129                let indent_prefix = "    ".repeat(indent);
130                s.push_str(&indent_prefix);
131                s.push_str("if ");
132                s.push_str(&first.codegen(indent));
133                for c in conds {
134                    s.push_str(" elif ");
135                    s.push_str(&c.codegen(indent));
136                }
137                if let Some(body) = last {
138                    s.push_str(" else {\n");
139                    s.push_str(&body.codegen(indent + 1));
140                    s.push_str(&indent_prefix);
141                    s.push_str("}");
142                }
143                s
144            },
145            Atom::UnaryOperation { op, exp } => {
146                let mut s = String::new();
147                s.push_str(&op.codegen(indent));
148                s.push_str(&exp.codegen(indent));
149                s
150            },
151        }
152    }
153}
154
155#[derive(Clone)]
156pub enum ExpressionTail {
157    None,
158    PostfixBang {
159        next: Box<ExpressionTail>,
160    },
161    MemberAccess {
162        member: String,
163        next: Box<ExpressionTail>,
164    },
165}
166impl SimpleCodeGen for ExpressionTail {
167    fn codegen(&self, indent: usize) -> String {
168        match self {
169            ExpressionTail::None => String::new(),
170            ExpressionTail::PostfixBang { next } => {
171                let next = next.codegen(indent);
172                format!("!{}", next)
173            },
174            ExpressionTail::MemberAccess { member, next } => {
175                let next = next.codegen(indent);
176                format!(".{}{}", member, next)
177            },
178        }
179    }
180}
181
182#[derive(Clone)]
183pub struct Parameter {
184    pub(crate) name: String,
185    pub(crate) typ: CortexType,
186}
187impl SimpleCodeGen for Parameter {
188    fn codegen(&self, indent: usize) -> String {
189        let mut s = String::new();
190        s.push_str(&self.name);
191        s.push_str(": ");
192        s.push_str(&self.typ.codegen(indent));
193        s
194    }
195}
196impl Parameter {
197    pub fn named(name: &str, typ: CortexType) -> Self {
198        Parameter {
199            name: String::from(name),
200            typ: typ,
201        }
202    }
203
204    pub fn name(&self) -> &String {
205        &self.name
206    }
207    pub fn param_type(&self) -> &CortexType {
208        &self.typ
209    }
210}
211
212#[derive(Clone)]
213pub struct IdentExpression {
214    pub(crate) base: PathIdent,
215    pub(crate) chain: Vec<String>,
216}
217impl SimpleCodeGen for IdentExpression {
218    fn codegen(&self, indent: usize) -> String {
219        let mut s = String::new();
220        s.push_str(&self.base.codegen(indent));
221        for c in &self.chain {
222            s.push_str(".");
223            s.push_str(c);
224        }
225        s
226    }
227}
228impl IdentExpression {
229    pub fn is_simple(&self) -> bool {
230        self.chain.is_empty()
231    }
232}
233
234#[derive(Clone)]
235pub enum OptionalIdentifier {
236    Ident(String), // A true identifier
237    Ignore, // The ignore token, "~"
238}
239impl SimpleCodeGen for OptionalIdentifier {
240    fn codegen(&self, _: usize) -> String {
241        match self {
242            Self::Ident(s) => s.clone(),
243            Self::Ignore => String::from("~"),
244        }
245    }
246}
247
248#[derive(Clone, Debug, PartialEq)]
249pub struct PathIdent {
250    pub(crate) path: Vec<String>,
251}
252impl SimpleCodeGen for PathIdent {
253    fn codegen(&self, _: usize) -> String {
254        let mut s = String::new();
255        for (i, p) in self.path.iter().enumerate() {
256            s.push_str(p);
257            if i + 1 < self.path.len() {
258                s.push_str("::");
259            }
260        }
261        s
262    }
263}
264#[derive(Error, Debug, PartialEq)]
265pub enum PathError {
266    #[error("Path is empty")]
267    PathEmpty,
268}
269impl PathIdent {
270    pub fn simple(name: String) -> Self {
271        Self {
272            path: vec![name],
273        }
274    }
275    pub fn new(name: Vec<&str>) -> Self {
276        Self {
277            path: name.iter().map(|s| String::from(*s)).collect(),
278        }
279    }
280    pub fn continued(first: PathIdent, next: String) -> Self {
281        let mut path = first.path.clone();
282        path.push(next);
283        Self {
284            path: path,
285        }
286    }
287
288    pub fn pop_front(&self) -> Result<PathIdent, PathError> {
289        if self.path.len() <= 0 {
290            Err(PathError::PathEmpty)
291        } else {
292            let new_path: Vec<String> = self.path.iter().skip(1).cloned().collect();
293            Ok(PathIdent {
294                path: new_path,
295            })
296        }
297    }
298    pub fn get_front(&self) -> Result<&String, PathError> {
299        if let Some(elem) = self.path.get(0) {
300            Ok(elem)
301        } else {
302            Err(PathError::PathEmpty)
303        }
304    }
305    pub fn get_back(&self) -> Result<&String, PathError> {
306        if let Some(elem) = self.path.get(self.path.len() - 1) {
307            Ok(elem)
308        } else {
309            Err(PathError::PathEmpty)
310        }
311    }
312    // Returns true if there is only one segment in this path left
313    // Error if the path is empty
314    pub fn is_final(&self) -> Result<bool, PathError> {
315        if self.path.len() <= 0 {
316            Err(PathError::PathEmpty)
317        } else {
318            Ok(self.path.len() == 1)
319        }
320    }
321    pub fn is_empty(&self) -> bool {
322        self.path.len() <= 0
323    }
324}
325
326#[derive(Clone)]
327pub enum UnaryOperator {
328    Negate,
329    Invert,
330}
331impl SimpleCodeGen for UnaryOperator {
332    fn codegen(&self, _indent: usize) -> String {
333        String::from(
334            match self {
335                UnaryOperator::Negate => "-",
336                UnaryOperator::Invert => "!",
337            }
338        )
339    }
340}
341
342#[derive(Clone)]
343pub enum BinaryOperator {
344    Add,
345    Subtract,
346    Multiply,
347    Divide,
348    Remainder,
349    LogicAnd,
350    LogicOr,
351    IsEqual,
352    IsNotEqual,
353    IsLessThan,
354    IsGreaterThan,
355    IsLessThanOrEqualTo,
356    IsGreaterThanOrEqualTo,
357}
358impl SimpleCodeGen for BinaryOperator {
359    fn codegen(&self, _: usize) -> String {
360        String::from(
361            match self {
362                BinaryOperator::Add => "+",
363                BinaryOperator::Subtract => "-",
364                BinaryOperator::Multiply => "*",
365                BinaryOperator::Divide => "/",
366                BinaryOperator::Remainder => "%",
367                BinaryOperator::LogicAnd => "&&",
368                BinaryOperator::LogicOr => "||",
369                BinaryOperator::IsEqual => "==",
370                BinaryOperator::IsNotEqual => "!=",
371                BinaryOperator::IsLessThan => "<",
372                BinaryOperator::IsGreaterThan => ">",
373                BinaryOperator::IsLessThanOrEqualTo => "<=",
374                BinaryOperator::IsGreaterThanOrEqualTo => ">=",
375            }
376        )
377    }
378}