1use computable::Computable;
2use pax_runtime_api::PaxValue;
3use pest::{
4 iterators::{Pair, Pairs},
5 pratt_parser::PrattParser,
6};
7use property_resolution::IdentifierResolver;
8use serde::{Deserialize, Serialize};
9use std::fmt::Display;
10use std::rc::Rc;
11
12use crate::{deserializer::from_pax_ast, get_pax_pratt_parser, parse_pax_pairs, Rule};
13
14pub(crate) mod computable;
15pub mod property_resolution;
16#[cfg(test)]
17mod tests;
18
19#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
20pub enum PaxExpression {
21 Primary(Box<PaxPrimary>),
22 Prefix(Box<PaxPrefix>),
23 Infix(Box<PaxInfix>),
24 Postfix(Box<PaxPostfix>),
25}
26
27impl Default for PaxExpression {
28 fn default() -> Self {
29 Self::Primary(Box::new(PaxPrimary::default()))
30 }
31}
32
33impl Display for PaxExpression {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 match self {
36 PaxExpression::Primary(p) => write!(f, "{}", p),
37 PaxExpression::Prefix(p) => write!(f, "{}{}", p.operator.name, p.rhs),
38 PaxExpression::Infix(i) => write!(f, "{} {} {}", i.lhs, i.operator.name, i.rhs),
39 PaxExpression::Postfix(p) => write!(f, "{}{}", p.lhs, p.operator.name),
40 }
41 }
42}
43
44#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
45pub enum PaxPrimary {
46 Literal(PaxValue),
47 Grouped(Box<PaxExpression>, Option<PaxUnit>),
48 Identifier(PaxIdentifier, Vec<PaxAccessor>),
49 Object(Vec<(String, PaxExpression)>),
50 FunctionOrEnum(String, String, Vec<PaxExpression>),
51 Range(PaxExpression, PaxExpression),
52 Tuple(Vec<PaxExpression>),
53 List(Vec<PaxExpression>),
54}
55
56impl Display for PaxPrimary {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 match self {
59 PaxPrimary::Literal(l) => write!(f, "{}", l),
60 PaxPrimary::Grouped(e, u) => {
61 if let Some(u) = u {
62 write!(
63 f,
64 "({}){}",
65 e,
66 match u {
67 PaxUnit::Percent => "%",
68 PaxUnit::Pixels => "px",
69 PaxUnit::Radians => "rad",
70 PaxUnit::Degrees => "deg",
71 }
72 )
73 } else {
74 write!(f, "({})", e)
75 }
76 }
77 PaxPrimary::Identifier(i, a) => {
78 write!(f, "{}", i.name)?;
79 for accessor in a {
80 match accessor {
81 PaxAccessor::Tuple(i) => write!(f, ".{}", i)?,
82 PaxAccessor::List(e) => write!(f, "[{}]", e)?,
83 PaxAccessor::Struct(s) => write!(f, ".{}", s)?,
84 }
85 }
86 Ok(())
87 }
88 PaxPrimary::Object(o) => {
89 write!(f, "{{")?;
90 let mut o = o.iter().collect::<Vec<_>>();
91 o.sort_by(|a, b| a.0.cmp(&b.0));
92 for (i, (key, val)) in o.iter().enumerate() {
93 write!(f, "{}: {}", key, val)?;
94 if i != o.len() - 1 {
95 write!(f, ", ")?;
96 }
97 }
98 write!(f, "}}")?;
99 Ok(())
100 }
101 PaxPrimary::FunctionOrEnum(name, e, a) => {
102 if name == "Color" {
103 write!(f, "{}", e)?;
104 } else {
105 write!(f, "{}::{}", name, e)?;
106 }
107 if !a.is_empty() {
108 write!(f, "(")?;
109 for (i, arg) in a.iter().enumerate() {
110 write!(f, "{}", arg)?;
111 if i != a.len() - 1 {
112 write!(f, ", ")?;
113 }
114 }
115 write!(f, ")")?;
116 }
117 Ok(())
118 }
119 PaxPrimary::Range(s, e) => write!(f, "{}..{}", s, e),
120 PaxPrimary::Tuple(t) => {
121 write!(f, "(")?;
122 for (i, e) in t.iter().enumerate() {
123 write!(f, "{}", e)?;
124 if i != t.len() - 1 {
125 write!(f, ", ")?;
126 }
127 }
128 write!(f, ")")?;
129 Ok(())
130 }
131 PaxPrimary::List(l) => {
132 write!(f, "[")?;
133 for (i, e) in l.iter().enumerate() {
134 write!(f, "{}", e)?;
135 if i != l.len() - 1 {
136 write!(f, ", ")?;
137 }
138 }
139 write!(f, "]")?;
140 Ok(())
141 }
142 }
143 }
144}
145
146impl Default for PaxPrimary {
147 fn default() -> Self {
148 Self::Literal(PaxValue::default())
149 }
150}
151
152#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
153pub enum PaxUnit {
154 Percent,
155 Pixels,
156 Radians,
157 Degrees,
158}
159
160#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
161pub enum PaxAccessor {
162 Tuple(usize),
163 List(PaxExpression),
164 Struct(String),
165}
166
167#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
168pub struct PaxPrefix {
169 operator: PaxOperator,
170 rhs: Box<PaxExpression>,
171}
172
173#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
174pub struct PaxInfix {
175 operator: PaxOperator,
176 lhs: Box<PaxExpression>,
177 rhs: Box<PaxExpression>,
178}
179
180#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
181pub struct PaxPostfix {
182 operator: PaxOperator,
183 lhs: Box<PaxExpression>,
184}
185
186#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
187pub struct PaxOperator {
188 name: String,
189}
190
191#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
192pub struct PaxIdentifier {
193 pub name: String,
194}
195
196impl Display for PaxIdentifier {
197 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198 write!(f, "{}", self.name)
199 }
200}
201
202impl PaxIdentifier {
203 pub fn new(name: &str) -> Self {
204 Self {
205 name: name.to_string(),
206 }
207 }
208}
209
210pub fn parse_pax_expression(expr: &str) -> Result<PaxExpression, String> {
212 let parsed_expr = parse_pax_pairs(Rule::expression_body, expr)
213 .map_err(|e| format!("Failed to parse expression: {}", e))?;
214 let pratt_parser = get_pax_pratt_parser();
215 recurse_pratt_parse(parsed_expr, &pratt_parser)
216}
217
218pub fn parse_pax_expression_from_pair(expr: Pair<Rule>) -> Result<PaxExpression, String> {
219 let pratt_parser = get_pax_pratt_parser();
220 recurse_pratt_parse(Pairs::single(expr), &pratt_parser)
221}
222
223fn recurse_pratt_parse(
224 expr: Pairs<Rule>,
225 pratt_parser: &PrattParser<Rule>,
226) -> Result<PaxExpression, String> {
227 pratt_parser
228 .map_primary(move |primary| match primary.as_rule() {
229 Rule::xo_literal => {
230 let inner = primary.into_inner().next().unwrap();
231 match inner.as_rule() {
232 Rule::literal_value => {
233 let pax_value = from_pax_ast(inner)
234 .map_err(|e| format!("Failed to parse literal value: {}", e))?;
235 let value = PaxPrimary::Literal(pax_value);
236 let exp = PaxExpression::Primary(Box::new(value));
237 Ok(exp)
238 }
239 Rule::literal_tuple_access => {
240 let mut inner = inner.into_inner();
241 let ident = inner.next().unwrap().as_str().trim().to_string();
242 let index = inner.next().unwrap().as_str().parse::<usize>().unwrap();
243 let value = PaxPrimary::Identifier(
244 PaxIdentifier { name: ident },
245 vec![PaxAccessor::Tuple(index)],
246 );
247 let exp = PaxExpression::Primary(Box::new(value));
248 Ok(exp)
249 }
250 Rule::literal_list_access => {
251 let mut inner = inner.into_inner();
252 let ident = inner.next().unwrap().as_str().trim().to_string();
253 let index = inner.next().unwrap().as_str();
254 let index = parse_pax_expression(index)?;
255 let value = PaxPrimary::Identifier(
256 PaxIdentifier { name: ident },
257 vec![PaxAccessor::List(index)],
258 );
259 let exp = PaxExpression::Primary(Box::new(value));
260 Ok(exp)
261 }
262 _ => {
263 return Err(format!("Unexpected rule: {:?}", inner.as_rule()));
264 }
265 }
266 }
267 Rule::expression_body => recurse_pratt_parse(primary.into_inner(), pratt_parser),
268 Rule::expression_grouped => {
269 let mut inner = primary.clone().into_inner();
270 let expr = inner.next().unwrap();
271 let expr_val = recurse_pratt_parse(expr.into_inner(), pratt_parser)?;
272 let ret: Result<PaxExpression, String> = if let Some(unit) = inner.next() {
273 let unit = unit.as_str().trim();
274 match unit {
275 "%" => Ok(PaxExpression::Primary(Box::new(PaxPrimary::Grouped(
276 Box::new(expr_val),
277 Some(PaxUnit::Percent),
278 )))),
279 "px" => Ok(PaxExpression::Primary(Box::new(PaxPrimary::Grouped(
280 Box::new(expr_val),
281 Some(PaxUnit::Pixels),
282 )))),
283 "rad" => Ok(PaxExpression::Primary(Box::new(PaxPrimary::Grouped(
284 Box::new(expr_val),
285 Some(PaxUnit::Radians),
286 )))),
287 "deg" => Ok(PaxExpression::Primary(Box::new(PaxPrimary::Grouped(
288 Box::new(expr_val),
289 Some(PaxUnit::Degrees),
290 )))),
291 _ => Err(format!("Unsupported unit: {}", unit)),
292 }
293 } else {
294 Ok(PaxExpression::Primary(Box::new(PaxPrimary::Grouped(
295 Box::new(expr_val),
296 None,
297 ))))
298 };
299 ret
300 }
301 Rule::xo_enum_or_function_call => {
302 let mut inner = primary.into_inner();
303 while inner.len() > 3 {
304 inner.next();
305 }
306 let scope = inner.next().unwrap().as_str().trim().to_string();
307 let function_name = inner.next().unwrap().as_str().trim().to_string();
308
309 let args = if let Some(args) = inner.next() {
310 args.into_inner()
311 .map(|a| recurse_pratt_parse(a.into_inner(), pratt_parser))
312 .collect::<Result<Vec<PaxExpression>, String>>()?
313 } else {
314 vec![]
315 };
316 let exp = PaxExpression::Primary(Box::new(PaxPrimary::FunctionOrEnum(
317 scope,
318 function_name,
319 args,
320 )));
321 Ok(exp)
322 }
323 Rule::xo_color_space_func => {
324 let func = primary.as_str().trim().split("(").next().unwrap();
325 let inner = primary.into_inner();
326 let args = inner
327 .map(|a| recurse_pratt_parse(a.into_inner(), pratt_parser))
328 .collect::<Result<Vec<PaxExpression>, String>>()?;
329 let exp = PaxExpression::Primary(Box::new(PaxPrimary::FunctionOrEnum(
330 "Color".to_string(),
331 func.to_string(),
332 args,
333 )));
334 Ok(exp)
335 }
336 Rule::xo_object => {
337 let mut inner = primary.into_inner();
338 while inner.peek().unwrap().as_rule() == Rule::identifier {
339 inner.next();
340 }
341 let mut obj = vec![];
342 for pair in inner {
343 let mut pair = pair.into_inner();
344 let key = pair
346 .next()
347 .unwrap()
348 .as_str()
349 .trim()
350 .trim_end_matches(':')
351 .trim_end_matches('=')
352 .to_string();
353 let value = pair.next().unwrap();
354 let value = recurse_pratt_parse(value.into_inner(), pratt_parser)?;
355 obj.push((key, value));
356 }
357 let value = PaxPrimary::Object(obj);
358 let exp = PaxExpression::Primary(Box::new(value));
359 Ok(exp)
360 }
361 Rule::xo_range => {
362 let mut inner = primary.into_inner();
363 let start_rule = Pairs::single(inner.next().unwrap());
364 let start = recurse_pratt_parse(start_rule, pratt_parser)?;
365 inner.next();
367 let end_rule = Pairs::single(inner.next().unwrap());
368 let end = recurse_pratt_parse(end_rule, pratt_parser)?;
369 let value = PaxPrimary::Range(start, end);
370 let exp = PaxExpression::Primary(Box::new(value));
371 Ok(exp)
372 }
373 Rule::xo_tuple => {
374 let inner = primary.into_inner();
375 let tuple = inner
376 .map(|e| recurse_pratt_parse(e.into_inner(), pratt_parser))
377 .collect::<Result<Vec<PaxExpression>, String>>()?;
378 let value = PaxPrimary::Tuple(tuple);
379 let exp = PaxExpression::Primary(Box::new(value));
380 Ok(exp)
381 }
382 Rule::xo_list => {
383 let inner = primary.into_inner();
384 let list = inner
385 .map(|e| recurse_pratt_parse(e.into_inner(), pratt_parser))
386 .collect::<Result<Vec<PaxExpression>, String>>()?;
387 let value = PaxPrimary::List(list);
388 let exp = PaxExpression::Primary(Box::new(value));
389 Ok(exp)
390 }
391 Rule::xo_symbol => {
392 let builtins_prefix = if primary.as_str().starts_with("$") {
393 "$"
394 } else {
395 ""
396 }
397 .to_string();
398
399 let mut symbols = primary.into_inner();
400
401 let peek = symbols.peek().unwrap();
403 if peek.as_str().trim() == "self" || peek.as_str().trim() == "this" {
404 symbols.next();
405 }
406
407 let identifier = builtins_prefix + symbols.next().unwrap().as_str().trim();
408 let mut accessors = vec![];
409 for symbol in symbols {
410 let accessor = match symbol.as_rule() {
411 Rule::expression_body => {
413 let expr = recurse_pratt_parse(symbol.into_inner(), pratt_parser)?;
414 PaxAccessor::List(expr)
415 }
416 Rule::identifier => {
418 let field = symbol.as_str().trim().to_string();
419 PaxAccessor::Struct(field)
420 }
421 _ => {
422 return Err(format!("Unexpected rule: {:?}", symbol.as_rule()));
423 }
424 };
425 accessors.push(accessor);
426 }
427 let value = PaxPrimary::Identifier(PaxIdentifier { name: identifier }, accessors);
428 let exp = PaxExpression::Primary(Box::new(value));
429 Ok(exp)
430 }
431 _ => {
432 return Err(format!(
433 "Unexpected rule: {:?}, str: {} ",
434 primary.as_rule(),
435 primary.as_str()
436 ));
437 }
438 })
439 .map_prefix(|op, rhs| match op.as_rule() {
440 _ => {
441 let a = PaxOperator {
442 name: op.as_str().trim().to_string(),
443 };
444 let r = rhs?;
445 let exp = PaxExpression::Prefix(Box::new(PaxPrefix {
446 operator: a,
447 rhs: Box::new(r),
448 }));
449 Ok(exp)
450 }
451 })
452 .map_postfix(|lhs, op| match op.as_rule() {
453 _ => {
454 let a = PaxOperator {
455 name: op.as_str().trim().to_string(),
456 };
457 let l = lhs?;
458 let exp = PaxExpression::Postfix(Box::new(PaxPostfix {
459 operator: a,
460 lhs: Box::new(l),
461 }));
462 Ok(exp)
463 }
464 })
465 .map_infix(|lhs, op, rhs| match op.as_rule() {
466 _ => {
467 let a = PaxOperator {
468 name: op.as_str().trim().to_string(),
469 };
470 let l = lhs?;
471 let r = rhs?;
472 let exp = PaxExpression::Infix(Box::new(PaxInfix {
473 operator: a,
474 lhs: Box::new(l),
475 rhs: Box::new(r),
476 }));
477 Ok(exp)
478 }
479 })
480 .parse(expr)
481}
482
483pub fn compute_paxel(expr: &str, idr: Rc<dyn IdentifierResolver>) -> Result<PaxValue, String> {
485 let expr = parse_pax_expression(expr)?;
486 expr.compute(idr)
487}