1#[cfg(feature = "parser")]
2use computable::Computable;
3use pax_runtime_api::PaxValue;
4#[cfg(feature = "parser")]
5use pest::{
6 iterators::{Pair, Pairs},
7 pratt_parser::PrattParser,
8};
9#[cfg(feature = "parser")]
10use property_resolution::IdentifierResolver;
11use serde::{Deserialize, Serialize};
12use std::fmt::Display;
13#[cfg(feature = "parser")]
14use std::rc::Rc;
15
16#[cfg(feature = "parser")]
17use crate::{deserializer::from_pax_ast, get_pax_pratt_parser, parse_pax_pairs, Rule};
18
19pub(crate) mod computable;
20pub mod property_resolution;
21#[cfg(test)]
22mod tests;
23
24#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
25pub enum PaxExpression {
27 Primary(Box<PaxPrimary>),
28 Prefix(Box<PaxPrefix>),
29 Infix(Box<PaxInfix>),
30 Postfix(Box<PaxPostfix>),
31 Ternary(Box<PaxTernary>),
32 NullCoalesce(Box<PaxNullCoalesce>),
33}
34
35impl Default for PaxExpression {
36 fn default() -> Self {
37 Self::Primary(Box::new(PaxPrimary::default()))
38 }
39}
40
41impl PaxExpression {
42 pub fn prefix(operator: impl Into<String>, rhs: PaxExpression) -> Self {
44 Self::Prefix(Box::new(PaxPrefix {
45 operator: PaxOperator::new(operator),
46 rhs: Box::new(rhs),
47 }))
48 }
49
50 pub fn infix(lhs: PaxExpression, operator: impl Into<String>, rhs: PaxExpression) -> Self {
52 Self::Infix(Box::new(PaxInfix {
53 operator: PaxOperator::new(operator),
54 lhs: Box::new(lhs),
55 rhs: Box::new(rhs),
56 }))
57 }
58
59 pub fn postfix(lhs: PaxExpression, operator: impl Into<String>) -> Self {
61 Self::Postfix(Box::new(PaxPostfix {
62 operator: PaxOperator::new(operator),
63 lhs: Box::new(lhs),
64 }))
65 }
66
67 pub fn ternary(
69 condition: PaxExpression,
70 then_branch: PaxExpression,
71 else_branch: PaxExpression,
72 ) -> Self {
73 Self::Ternary(Box::new(PaxTernary {
74 condition: Box::new(condition),
75 then_branch: Box::new(then_branch),
76 else_branch: Box::new(else_branch),
77 }))
78 }
79
80 pub fn null_coalesce(lhs: PaxExpression, rhs: PaxExpression) -> Self {
82 Self::NullCoalesce(Box::new(PaxNullCoalesce {
83 lhs: Box::new(lhs),
84 rhs: Box::new(rhs),
85 }))
86 }
87}
88
89impl PaxExpression {
90 fn precedence(&self) -> u8 {
93 match self {
94 Self::Ternary(_) => 1,
95 Self::NullCoalesce(_) => 2,
96 Self::Infix(i) => match i.operator.name.as_str() {
97 "||" => 3,
98 "&&" => 4,
99 "==" | "!=" | "<" | "<=" | ">" | ">=" => 5,
100 "+" | "-" => 6,
101 "*" | "/" | "%%" => 7,
102 "^" => 8,
103 _ => 0,
104 },
105 Self::Prefix(p) if p.operator.name == "-" => 9,
106 Self::Prefix(_) => 10,
107 Self::Postfix(_) | Self::Primary(_) => 11,
108 }
109 }
110
111 fn fmt_operand(&self, f: &mut std::fmt::Formatter<'_>, minimum: u8) -> std::fmt::Result {
112 if self.precedence() < minimum {
113 write!(f, "({self})")
114 } else {
115 write!(f, "{self}")
116 }
117 }
118}
119
120impl Display for PaxExpression {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 match self {
123 PaxExpression::Primary(p) => write!(f, "{}", p),
124 PaxExpression::Prefix(p) => {
125 write!(f, "{}", p.operator.name)?;
126 p.rhs.fmt_operand(f, self.precedence())
127 }
128 PaxExpression::Infix(i) => {
129 let right_associative = i.operator.name == "^";
130 i.lhs.fmt_operand(f, self.precedence() + u8::from(right_associative))?;
131 write!(f, " {} ", i.operator.name)?;
132 i.rhs.fmt_operand(f, self.precedence() + u8::from(!right_associative))
133 }
134 PaxExpression::Postfix(p) => write!(f, "{}{}", p.lhs, p.operator.name),
135 PaxExpression::Ternary(t) => {
136 t.condition.fmt_operand(f, self.precedence() + 1)?;
137 write!(f, " ? {} : {}", t.then_branch, t.else_branch)
138 }
139 PaxExpression::NullCoalesce(n) => {
140 n.lhs.fmt_operand(f, self.precedence() + 1)?;
141 write!(f, " ?? ")?;
142 n.rhs.fmt_operand(f, self.precedence())
143 }
144 }
145 }
146}
147
148#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
149pub enum PaxPrimary {
151 Literal(PaxValue),
152 Grouped(Box<PaxExpression>, Option<PaxUnit>),
153 Identifier(PaxIdentifier, Vec<PaxAccessor>),
154 Object(Vec<(String, PaxExpression)>),
155 FunctionOrEnum(String, String, Vec<PaxExpression>),
156 Range(PaxExpression, PaxExpression),
157 Tuple(Vec<PaxExpression>),
158 List(Vec<PaxExpression>),
159}
160
161impl Display for PaxPrimary {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 match self {
164 PaxPrimary::Literal(l) => write!(f, "{}", l),
165 PaxPrimary::Grouped(e, u) => {
166 if let Some(u) = u {
167 write!(
168 f,
169 "({}){}",
170 e,
171 match u {
172 PaxUnit::Percent => "%",
173 PaxUnit::Pixels => "px",
174 PaxUnit::Radians => "rad",
175 PaxUnit::Degrees => "deg",
176 PaxUnit::Milliseconds => "ms",
177 PaxUnit::Seconds => "s",
178 PaxUnit::Frames => "f",
179 }
180 )
181 } else {
182 write!(f, "({})", e)
183 }
184 }
185 PaxPrimary::Identifier(i, a) => {
186 write!(f, "{}", i.name)?;
187 for accessor in a {
188 match accessor {
189 PaxAccessor::Tuple(i) => write!(f, ".{}", i)?,
190 PaxAccessor::List(e) => write!(f, "[{}]", e)?,
191 PaxAccessor::Struct(s) => write!(f, ".{}", s)?,
192 }
193 }
194 Ok(())
195 }
196 PaxPrimary::Object(o) => {
197 write!(f, "{{")?;
198 let mut o = o.iter().collect::<Vec<_>>();
199 o.sort_by(|a, b| a.0.cmp(&b.0));
200 for (i, (key, val)) in o.iter().enumerate() {
201 write!(f, "{}: {}", key, val)?;
202 if i != o.len() - 1 {
203 write!(f, ", ")?;
204 }
205 }
206 write!(f, "}}")?;
207 Ok(())
208 }
209 PaxPrimary::FunctionOrEnum(name, e, a) => {
210 if name == "Color" {
211 write!(f, "{}", e)?;
212 } else {
213 write!(f, "{}::{}", name, e)?;
214 }
215 if !a.is_empty() {
216 write!(f, "(")?;
217 for (i, arg) in a.iter().enumerate() {
218 write!(f, "{}", arg)?;
219 if i != a.len() - 1 {
220 write!(f, ", ")?;
221 }
222 }
223 write!(f, ")")?;
224 }
225 Ok(())
226 }
227 PaxPrimary::Range(s, e) => write!(f, "{}..{}", s, e),
228 PaxPrimary::Tuple(t) => {
229 write!(f, "(")?;
230 for (i, e) in t.iter().enumerate() {
231 write!(f, "{}", e)?;
232 if i != t.len() - 1 {
233 write!(f, ", ")?;
234 }
235 }
236 write!(f, ")")?;
237 Ok(())
238 }
239 PaxPrimary::List(l) => {
240 write!(f, "[")?;
241 for (i, e) in l.iter().enumerate() {
242 write!(f, "{}", e)?;
243 if i != l.len() - 1 {
244 write!(f, ", ")?;
245 }
246 }
247 write!(f, "]")?;
248 Ok(())
249 }
250 }
251 }
252}
253
254impl Default for PaxPrimary {
255 fn default() -> Self {
256 Self::Literal(PaxValue::default())
257 }
258}
259
260#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
261pub enum PaxUnit {
263 Percent,
264 Pixels,
265 Radians,
266 Degrees,
267 Milliseconds,
268 Seconds,
269 Frames,
270}
271
272#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
273pub enum PaxAccessor {
275 Tuple(usize),
276 List(PaxExpression),
277 Struct(String),
278}
279
280#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
281pub struct PaxPrefix {
283 operator: PaxOperator,
284 rhs: Box<PaxExpression>,
285}
286
287impl PaxPrefix {
288 pub fn operator_name(&self) -> &str {
290 &self.operator.name
291 }
292
293 pub fn rhs(&self) -> &PaxExpression {
295 &self.rhs
296 }
297}
298
299#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
300pub struct PaxInfix {
302 operator: PaxOperator,
303 lhs: Box<PaxExpression>,
304 rhs: Box<PaxExpression>,
305}
306
307impl PaxInfix {
308 pub fn operator_name(&self) -> &str {
310 &self.operator.name
311 }
312
313 pub fn lhs(&self) -> &PaxExpression {
315 &self.lhs
316 }
317
318 pub fn rhs(&self) -> &PaxExpression {
320 &self.rhs
321 }
322}
323
324#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
325pub struct PaxPostfix {
327 operator: PaxOperator,
328 lhs: Box<PaxExpression>,
329}
330
331impl PaxPostfix {
332 pub fn operator_name(&self) -> &str {
334 &self.operator.name
335 }
336
337 pub fn lhs(&self) -> &PaxExpression {
339 &self.lhs
340 }
341}
342
343#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
344pub struct PaxTernary {
346 condition: Box<PaxExpression>,
347 then_branch: Box<PaxExpression>,
348 else_branch: Box<PaxExpression>,
349}
350
351#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
352pub struct PaxNullCoalesce {
356 lhs: Box<PaxExpression>,
357 rhs: Box<PaxExpression>,
358}
359
360impl PaxTernary {
361 pub fn condition(&self) -> &PaxExpression {
363 &self.condition
364 }
365
366 pub fn then_branch(&self) -> &PaxExpression {
368 &self.then_branch
369 }
370
371 pub fn else_branch(&self) -> &PaxExpression {
373 &self.else_branch
374 }
375}
376
377impl PaxNullCoalesce {
378 pub fn lhs(&self) -> &PaxExpression {
380 &self.lhs
381 }
382
383 pub fn rhs(&self) -> &PaxExpression {
385 &self.rhs
386 }
387}
388
389#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
390pub struct PaxOperator {
392 name: String,
393}
394
395impl PaxOperator {
396 pub fn new(name: impl Into<String>) -> Self {
398 Self { name: name.into() }
399 }
400
401 pub fn name(&self) -> &str {
403 &self.name
404 }
405}
406
407#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
408pub struct PaxIdentifier {
410 pub name: String,
411}
412
413impl Display for PaxIdentifier {
414 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
415 write!(f, "{}", self.name)
416 }
417}
418
419impl PaxIdentifier {
420 pub fn new(name: &str) -> Self {
422 Self {
423 name: name.to_string(),
424 }
425 }
426}
427
428#[cfg(feature = "parser")]
430pub fn parse_pax_expression(expr: &str) -> Result<PaxExpression, String> {
431 let parsed_expr = parse_pax_pairs(Rule::expression_body, expr)
432 .map_err(|e| format!("Failed to parse expression: {}", e))?;
433 let pratt_parser = get_pax_pratt_parser();
434 recurse_pratt_parse(parsed_expr, &pratt_parser)
435}
436
437#[cfg(feature = "parser")]
439pub fn parse_pax_expression_from_pair(expr: Pair<Rule>) -> Result<PaxExpression, String> {
440 let pratt_parser = get_pax_pratt_parser();
441 recurse_pratt_parse(Pairs::single(expr), &pratt_parser)
442}
443
444#[cfg(feature = "parser")]
445fn recurse_pratt_parse(
446 expr: Pairs<Rule>,
447 pratt_parser: &PrattParser<Rule>,
448) -> Result<PaxExpression, String> {
449 pratt_parser
450 .map_primary(move |primary| match primary.as_rule() {
451 Rule::xo_literal => {
452 let inner = primary.into_inner().next().unwrap();
453 match inner.as_rule() {
454 Rule::literal_value => {
455 let pax_value = from_pax_ast(inner)
456 .map_err(|e| format!("Failed to parse literal value: {}", e))?;
457 let value = PaxPrimary::Literal(pax_value);
458 let exp = PaxExpression::Primary(Box::new(value));
459 Ok(exp)
460 }
461 Rule::literal_tuple_access => {
462 let mut inner = inner.into_inner();
463 let ident = inner.next().unwrap().as_str().trim().to_string();
464 let index = inner.next().unwrap().as_str().parse::<usize>().unwrap();
465 let value = PaxPrimary::Identifier(
466 PaxIdentifier { name: ident },
467 vec![PaxAccessor::Tuple(index)],
468 );
469 let exp = PaxExpression::Primary(Box::new(value));
470 Ok(exp)
471 }
472 Rule::literal_list_access => {
473 let mut inner = inner.into_inner();
474 let ident = inner.next().unwrap().as_str().trim().to_string();
475 let index = inner.next().unwrap().as_str();
476 let index = parse_pax_expression(index)?;
477 let value = PaxPrimary::Identifier(
478 PaxIdentifier { name: ident },
479 vec![PaxAccessor::List(index)],
480 );
481 let exp = PaxExpression::Primary(Box::new(value));
482 Ok(exp)
483 }
484 _ => {
485 return Err(format!("Unexpected rule: {:?}", inner.as_rule()));
486 }
487 }
488 }
489 Rule::expression_body | Rule::expression_binary => {
490 recurse_pratt_parse(primary.into_inner(), pratt_parser)
491 }
492 Rule::expression_coalesce => {
493 let mut inner = primary.into_inner();
494 let lhs = recurse_pratt_parse(Pairs::single(inner.next().unwrap()), pratt_parser)?;
495 if inner.next().is_some() {
496 let rhs =
497 recurse_pratt_parse(Pairs::single(inner.next().unwrap()), pratt_parser)?;
498 Ok(PaxExpression::NullCoalesce(Box::new(PaxNullCoalesce {
499 lhs: Box::new(lhs),
500 rhs: Box::new(rhs),
501 })))
502 } else {
503 Ok(lhs)
504 }
505 }
506 Rule::expression_ternary => {
507 let mut inner = primary.into_inner();
508 let condition =
509 recurse_pratt_parse(Pairs::single(inner.next().unwrap()), pratt_parser)?;
510 if inner.next().is_some() {
511 let then_branch =
512 recurse_pratt_parse(Pairs::single(inner.next().unwrap()), pratt_parser)?;
513 inner.next();
514 let else_branch =
515 recurse_pratt_parse(Pairs::single(inner.next().unwrap()), pratt_parser)?;
516 Ok(PaxExpression::Ternary(Box::new(PaxTernary {
517 condition: Box::new(condition),
518 then_branch: Box::new(then_branch),
519 else_branch: Box::new(else_branch),
520 })))
521 } else {
522 Ok(condition)
523 }
524 }
525 Rule::expression_grouped => {
526 let mut inner = primary.clone().into_inner();
527 let expr = inner.next().unwrap();
528 let expr_val = recurse_pratt_parse(expr.into_inner(), pratt_parser)?;
529 let ret: Result<PaxExpression, String> = if let Some(unit) = inner.next() {
530 let unit = unit.as_str().trim().trim_start_matches(')');
531 match unit {
532 "%" => Ok(PaxExpression::Primary(Box::new(PaxPrimary::Grouped(
533 Box::new(expr_val),
534 Some(PaxUnit::Percent),
535 )))),
536 "px" => Ok(PaxExpression::Primary(Box::new(PaxPrimary::Grouped(
537 Box::new(expr_val),
538 Some(PaxUnit::Pixels),
539 )))),
540 "rad" => Ok(PaxExpression::Primary(Box::new(PaxPrimary::Grouped(
541 Box::new(expr_val),
542 Some(PaxUnit::Radians),
543 )))),
544 "deg" => Ok(PaxExpression::Primary(Box::new(PaxPrimary::Grouped(
545 Box::new(expr_val),
546 Some(PaxUnit::Degrees),
547 )))),
548 "ms" => Ok(PaxExpression::Primary(Box::new(PaxPrimary::Grouped(
549 Box::new(expr_val),
550 Some(PaxUnit::Milliseconds),
551 )))),
552 "s" => Ok(PaxExpression::Primary(Box::new(PaxPrimary::Grouped(
553 Box::new(expr_val),
554 Some(PaxUnit::Seconds),
555 )))),
556 "f" => Ok(PaxExpression::Primary(Box::new(PaxPrimary::Grouped(
557 Box::new(expr_val),
558 Some(PaxUnit::Frames),
559 )))),
560 _ => Err(format!("Unsupported unit: {}", unit)),
561 }
562 } else {
563 Ok(PaxExpression::Primary(Box::new(PaxPrimary::Grouped(
564 Box::new(expr_val),
565 None,
566 ))))
567 };
568 ret
569 }
570 Rule::xo_enum_or_function_call => {
571 let mut inner = primary.into_inner();
572 while inner.len() > 3 {
573 inner.next();
574 }
575 let scope = inner.next().unwrap().as_str().trim().to_string();
576 let function_name = inner.next().unwrap().as_str().trim().to_string();
577
578 let args = if let Some(args) = inner.next() {
579 args.into_inner()
580 .map(|a| recurse_pratt_parse(a.into_inner(), pratt_parser))
581 .collect::<Result<Vec<PaxExpression>, String>>()?
582 } else {
583 vec![]
584 };
585 let exp = PaxExpression::Primary(Box::new(PaxPrimary::FunctionOrEnum(
586 scope,
587 function_name,
588 args,
589 )));
590 Ok(exp)
591 }
592 Rule::xo_color_space_func => {
593 let func = primary.as_str().trim().split("(").next().unwrap();
594 let inner = primary.into_inner();
595 let args = inner
596 .map(|a| recurse_pratt_parse(a.into_inner(), pratt_parser))
597 .collect::<Result<Vec<PaxExpression>, String>>()?;
598 let exp = PaxExpression::Primary(Box::new(PaxPrimary::FunctionOrEnum(
599 "Color".to_string(),
600 func.to_string(),
601 args,
602 )));
603 Ok(exp)
604 }
605 Rule::xo_object => {
606 let mut inner = primary.into_inner();
607 while inner.peek().unwrap().as_rule() == Rule::identifier {
608 inner.next();
609 }
610 let mut obj = vec![];
611 for pair in inner {
612 let mut pair = pair.into_inner();
613 let key = pair
615 .next()
616 .unwrap()
617 .as_str()
618 .trim()
619 .trim_end_matches(':')
620 .trim_end_matches('=')
621 .to_string();
622 let value = pair.next().unwrap();
623 let value = recurse_pratt_parse(value.into_inner(), pratt_parser)?;
624 obj.push((key, value));
625 }
626 let value = PaxPrimary::Object(obj);
627 let exp = PaxExpression::Primary(Box::new(value));
628 Ok(exp)
629 }
630 Rule::xo_range => {
631 let mut inner = primary.into_inner();
632 let start_rule = Pairs::single(inner.next().unwrap());
633 let start = recurse_pratt_parse(start_rule, pratt_parser)?;
634 inner.next();
636 let end_rule = Pairs::single(inner.next().unwrap());
637 let end = recurse_pratt_parse(end_rule, pratt_parser)?;
638 let value = PaxPrimary::Range(start, end);
639 let exp = PaxExpression::Primary(Box::new(value));
640 Ok(exp)
641 }
642 Rule::xo_tuple => {
643 let inner = primary.into_inner();
644 let tuple = inner
645 .map(|e| recurse_pratt_parse(e.into_inner(), pratt_parser))
646 .collect::<Result<Vec<PaxExpression>, String>>()?;
647 let value = PaxPrimary::Tuple(tuple);
648 let exp = PaxExpression::Primary(Box::new(value));
649 Ok(exp)
650 }
651 Rule::xo_list => {
652 let inner = primary.into_inner();
653 let list = inner
654 .map(|e| recurse_pratt_parse(e.into_inner(), pratt_parser))
655 .collect::<Result<Vec<PaxExpression>, String>>()?;
656 let value = PaxPrimary::List(list);
657 let exp = PaxExpression::Primary(Box::new(value));
658 Ok(exp)
659 }
660 Rule::xo_symbol => {
661 let builtins_prefix = if primary.as_str().starts_with("$") {
662 "$"
663 } else {
664 ""
665 }
666 .to_string();
667
668 let mut symbols = primary.into_inner();
669
670 let peek = symbols.peek().unwrap();
672 if peek.as_str().trim() == "self" || peek.as_str().trim() == "this" {
673 symbols.next();
674 }
675
676 let identifier = builtins_prefix + symbols.next().unwrap().as_str().trim();
677 let mut accessors = vec![];
678 for symbol in symbols {
679 let accessor = match symbol.as_rule() {
680 Rule::expression_body => {
682 let expr = recurse_pratt_parse(symbol.into_inner(), pratt_parser)?;
683 PaxAccessor::List(expr)
684 }
685 Rule::identifier => {
687 let field = symbol.as_str().trim().to_string();
688 PaxAccessor::Struct(field)
689 }
690 _ => {
691 return Err(format!("Unexpected rule: {:?}", symbol.as_rule()));
692 }
693 };
694 accessors.push(accessor);
695 }
696 let value = PaxPrimary::Identifier(PaxIdentifier { name: identifier }, accessors);
697 let exp = PaxExpression::Primary(Box::new(value));
698 Ok(exp)
699 }
700 _ => {
701 return Err(format!(
702 "Unexpected rule: {:?}, str: {} ",
703 primary.as_rule(),
704 primary.as_str()
705 ));
706 }
707 })
708 .map_prefix(|op, rhs| match op.as_rule() {
709 _ => {
710 let a = PaxOperator {
711 name: op.as_str().trim().to_string(),
712 };
713 let r = rhs?;
714 let exp = PaxExpression::Prefix(Box::new(PaxPrefix {
715 operator: a,
716 rhs: Box::new(r),
717 }));
718 Ok(exp)
719 }
720 })
721 .map_postfix(|lhs, op| match op.as_rule() {
722 _ => {
723 let a = PaxOperator {
724 name: op.as_str().trim().to_string(),
725 };
726 let l = lhs?;
727 let exp = PaxExpression::Postfix(Box::new(PaxPostfix {
728 operator: a,
729 lhs: Box::new(l),
730 }));
731 Ok(exp)
732 }
733 })
734 .map_infix(|lhs, op, rhs| match op.as_rule() {
735 _ => {
736 let a = PaxOperator {
737 name: op.as_str().trim().to_string(),
738 };
739 let l = lhs?;
740 let r = rhs?;
741 let exp = PaxExpression::Infix(Box::new(PaxInfix {
742 operator: a,
743 lhs: Box::new(l),
744 rhs: Box::new(r),
745 }));
746 Ok(exp)
747 }
748 })
749 .parse(expr)
750}
751
752#[cfg(feature = "parser")]
754pub fn compute_paxel(expr: &str, idr: Rc<dyn IdentifierResolver>) -> Result<PaxValue, String> {
755 let expr = parse_pax_expression(expr)?;
756 expr.compute(idr)
757}