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), Ignore, }
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 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}