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