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
205#[derive(Clone)]
206pub struct IdentExpression {
207    pub(crate) base: PathIdent,
208    pub(crate) chain: Vec<String>,
209}
210impl SimpleCodeGen for IdentExpression {
211    fn codegen(&self, indent: usize) -> String {
212        let mut s = String::new();
213        s.push_str(&self.base.codegen(indent));
214        for c in &self.chain {
215            s.push_str(".");
216            s.push_str(c);
217        }
218        s
219    }
220}
221impl IdentExpression {
222    pub fn is_simple(&self) -> bool {
223        self.chain.is_empty()
224    }
225}
226
227#[derive(Clone)]
228pub enum OptionalIdentifier {
229    Ident(String), // A true identifier
230    Ignore, // The ignore token, "~"
231}
232impl SimpleCodeGen for OptionalIdentifier {
233    fn codegen(&self, _: usize) -> String {
234        match self {
235            Self::Ident(s) => s.clone(),
236            Self::Ignore => String::from("~"),
237        }
238    }
239}
240
241#[derive(Clone, Debug, PartialEq)]
242pub struct PathIdent {
243    pub(crate) path: Vec<String>,
244}
245impl SimpleCodeGen for PathIdent {
246    fn codegen(&self, _: usize) -> String {
247        let mut s = String::new();
248        for (i, p) in self.path.iter().enumerate() {
249            s.push_str(p);
250            if i + 1 < self.path.len() {
251                s.push_str("::");
252            }
253        }
254        s
255    }
256}
257#[derive(Error, Debug, PartialEq)]
258pub enum PathError {
259    #[error("Path is empty")]
260    PathEmpty,
261}
262impl PathIdent {
263    pub fn simple(name: String) -> Self {
264        Self {
265            path: vec![name],
266        }
267    }
268    pub fn new(name: Vec<&str>) -> Self {
269        Self {
270            path: name.iter().map(|s| String::from(*s)).collect(),
271        }
272    }
273    pub fn continued(first: PathIdent, next: String) -> Self {
274        let mut path = first.path.clone();
275        path.push(next);
276        Self {
277            path: path,
278        }
279    }
280
281    pub fn pop_front(&self) -> Result<PathIdent, PathError> {
282        if self.path.len() <= 0 {
283            Err(PathError::PathEmpty)
284        } else {
285            let new_path: Vec<String> = self.path.iter().skip(1).cloned().collect();
286            Ok(PathIdent {
287                path: new_path,
288            })
289        }
290    }
291    pub fn get_front(&self) -> Result<&String, PathError> {
292        if let Some(elem) = self.path.get(0) {
293            Ok(elem)
294        } else {
295            Err(PathError::PathEmpty)
296        }
297    }
298    pub fn get_back(&self) -> Result<&String, PathError> {
299        if let Some(elem) = self.path.get(self.path.len() - 1) {
300            Ok(elem)
301        } else {
302            Err(PathError::PathEmpty)
303        }
304    }
305    // Returns true if there is only one segment in this path left
306    // Error if the path is empty
307    pub fn is_final(&self) -> Result<bool, PathError> {
308        if self.path.len() <= 0 {
309            Err(PathError::PathEmpty)
310        } else {
311            Ok(self.path.len() == 1)
312        }
313    }
314    pub fn is_empty(&self) -> bool {
315        self.path.len() <= 0
316    }
317}
318
319#[derive(Clone)]
320pub enum UnaryOperator {
321    Negate,
322    Invert,
323}
324impl SimpleCodeGen for UnaryOperator {
325    fn codegen(&self, _indent: usize) -> String {
326        String::from(
327            match self {
328                UnaryOperator::Negate => "-",
329                UnaryOperator::Invert => "!",
330            }
331        )
332    }
333}
334
335#[derive(Clone)]
336pub enum BinaryOperator {
337    Add,
338    Subtract,
339    Multiply,
340    Divide,
341    Remainder,
342    LogicAnd,
343    LogicOr,
344    IsEqual,
345    IsNotEqual,
346    IsLessThan,
347    IsGreaterThan,
348    IsLessThanOrEqualTo,
349    IsGreaterThanOrEqualTo,
350}
351impl SimpleCodeGen for BinaryOperator {
352    fn codegen(&self, _: usize) -> String {
353        String::from(
354            match self {
355                BinaryOperator::Add => "+",
356                BinaryOperator::Subtract => "-",
357                BinaryOperator::Multiply => "*",
358                BinaryOperator::Divide => "/",
359                BinaryOperator::Remainder => "%",
360                BinaryOperator::LogicAnd => "&&",
361                BinaryOperator::LogicOr => "||",
362                BinaryOperator::IsEqual => "==",
363                BinaryOperator::IsNotEqual => "!=",
364                BinaryOperator::IsLessThan => "<",
365                BinaryOperator::IsGreaterThan => ">",
366                BinaryOperator::IsLessThanOrEqualTo => "<=",
367                BinaryOperator::IsGreaterThanOrEqualTo => ">=",
368            }
369        )
370    }
371}