1use crate::filter::{AssignOp, BinaryOp, Filter, Fold, FoldType, KeyVal};
2use crate::prec_climb::{self, Associativity};
3use crate::{parse, Arg, Call, Def, Main, MathOp, OrdOp, Span, Spanned};
4use alloc::string::ToString;
5use alloc::{boxed::Box, vec::Vec};
6
7impl parse::Term<&str> {
8 fn span(&self, code: &str) -> Span {
9 match self {
10 Self::Num(s) | Self::Call(s, ..) | Self::Var(s) => crate::lex::span(code, s),
11 _ => 0..42,
12 }
13 }
14
15 fn conv(&self, s: &str) -> Filter {
16 use crate::lex::StrPart;
17 use crate::path::{Opt, Part};
18 use crate::string;
19 use Filter::*;
20
21 let span = |tm: &Self| Box::new((tm.conv(s), tm.span(s)));
22 let from_part = |(part, opt): &(Part<_>, Opt)| {
23 let part = match part {
24 Part::Index(i) => Part::Index(*span(i)),
25 Part::Range(l, h) => {
26 Part::Range(l.as_ref().map(|l| *span(l)), h.as_ref().map(|h| *span(h)))
27 }
28 };
29 (part, *opt)
30 };
31 let index_path = |k| {
32 let path = Vec::from([(Part::Index(k), Opt::Essential)]);
33 Filter::Path(span(&Self::Id), path)
34 };
35 let from_str = |part: &StrPart<&str, _>| match part {
36 StrPart::Str(s) => string::Part::Str(s.to_string()),
37 StrPart::Filter(tm) => string::Part::Fun(*span(tm)),
38 StrPart::Char(c) => string::Part::Str(c.to_string()),
39 };
40 let from_obj = |(k, v): &(_, Option<_>)| {
41 let f = || (index_path(*span(k)), 0..42);
42 let (k, v) = if let (Self::Var(x), None) = (k, v) {
43 (*span(&Self::str(&x[1..])), *span(k))
44 } else {
45 (*span(k), v.as_ref().map_or_else(f, |v| *span(v)))
46 };
47 KeyVal::Filter(k, v)
48 };
49 let from_op = |op| match op {
50 "," => BinaryOp::Comma,
51 "//" => BinaryOp::Alt,
52 "or" => BinaryOp::Or,
53 "and" => BinaryOp::And,
54 "+" => BinaryOp::Math(MathOp::Add),
55 "-" => BinaryOp::Math(MathOp::Sub),
56 "*" => BinaryOp::Math(MathOp::Mul),
57 "/" => BinaryOp::Math(MathOp::Div),
58 "%" => BinaryOp::Math(MathOp::Rem),
59 "=" => BinaryOp::Assign(AssignOp::Assign),
60 "|=" => BinaryOp::Assign(AssignOp::Update),
61 "+=" => BinaryOp::Assign(AssignOp::UpdateWith(MathOp::Add)),
62 "-=" => BinaryOp::Assign(AssignOp::UpdateWith(MathOp::Sub)),
63 "*=" => BinaryOp::Assign(AssignOp::UpdateWith(MathOp::Mul)),
64 "/=" => BinaryOp::Assign(AssignOp::UpdateWith(MathOp::Div)),
65 "%=" => BinaryOp::Assign(AssignOp::UpdateWith(MathOp::Rem)),
66 "<" => BinaryOp::Ord(OrdOp::Lt),
67 ">" => BinaryOp::Ord(OrdOp::Gt),
68 "<=" => BinaryOp::Ord(OrdOp::Le),
69 ">=" => BinaryOp::Ord(OrdOp::Ge),
70 "==" => BinaryOp::Ord(OrdOp::Eq),
71 "!=" => BinaryOp::Ord(OrdOp::Ne),
72 op => panic!("unknown operator: {op}"),
73 };
74 match self {
75 Self::Id => Id,
76 Self::Recurse => Recurse,
77 Self::Num(n) => Num(n.to_string()),
78 Self::Str(fmt, parts) => Str(Box::new(crate::Str {
79 fmt: fmt.map(|fmt| span(&Self::Call(fmt, Vec::new()))),
80 parts: parts.iter().map(from_str).collect(),
81 })),
82 Self::Arr(a) => Array(a.as_deref().map(span)),
83 Self::Obj(o) => Object(o.iter().map(from_obj).collect()),
84 Self::Neg(tm) => Neg(span(tm)),
85 Self::Pipe(l, v, r) => Binary(
86 span(l),
87 BinaryOp::Pipe(v.map(|v| v[1..].to_string())),
88 span(r),
89 ),
90 Self::BinOp(head, tail) => {
91 let head = *span(head);
92 let tail = tail.iter().map(|(op, tm)| (from_op(op), *span(tm)));
93 prec_climb::climb(head, tail).0
94 }
95
96 Self::Label(_v, ..) | Self::Break(_v) => {
97 unimplemented!("label-break is not supported yet")
98 }
99
100 Self::Fold(fold, xs, v, args) => {
101 let fold_type = match *fold {
102 "reduce" => FoldType::Reduce,
103 "foreach" => FoldType::Foreach,
104 "for" => FoldType::For,
105 _ => panic!(),
106 };
107 let (init, update) = match &args[..] {
108 [init, update] => (init, update),
109 _ => unimplemented!("folding filters currently only take two arguments"),
110 };
111 let fold = self::Fold {
112 xs: span(xs),
113 x: v[1..].to_string(),
114 init: span(init),
115 f: span(update),
116 };
117 Fold(fold_type, fold)
118 }
119 Self::TryCatch(try_, catch) => TryCatch(span(try_), catch.as_deref().map(span)),
120 Self::IfThenElse(if_thens, else_) => Ite(
121 if_thens
122 .iter()
123 .map(|(if_, then_)| (*span(if_), *span(then_)))
124 .collect(),
125 else_.as_deref().map(span),
126 ),
127
128 Self::Def(_defs, _tm) => {
129 unimplemented!("definitions inside terms are not supported yet")
130 }
131 Self::Call(c, args) => Call(c.to_string(), args.iter().map(|a| *span(a)).collect()),
132 Self::Var(v) => Var(v[1..].to_string()),
133
134 Self::Path(tm, path) => Path(span(tm), path.iter().map(from_part).collect()),
135 }
136 }
137
138 fn conv_main(&self, s: &str) -> Main {
139 match self {
140 parse::Term::Def(defs, tm) => Main {
141 defs: defs.iter().map(|def| def.conv(s)).collect(),
142 body: (tm.conv(s), tm.span(s)),
143 },
144 tm => Main {
145 defs: Vec::new(),
146 body: (tm.conv(s), tm.span(s)),
147 },
148 }
149 }
150}
151
152impl From<&parse::Term<&str>> for Filter {
153 fn from(tm: &parse::Term<&str>) -> Self {
154 tm.conv("")
155 }
156}
157
158impl prec_climb::Op for BinaryOp {
159 fn precedence(&self) -> usize {
160 match self {
161 Self::Pipe(_) => 0,
162 Self::Comma => 1,
163 Self::Assign(_) => 2,
164 Self::Alt => 3,
165 Self::Or => Self::Alt.precedence() + 1,
166 Self::And => Self::Or.precedence() + 1,
167 Self::Ord(OrdOp::Eq | OrdOp::Ne) => Self::And.precedence() + 1,
168 Self::Ord(OrdOp::Lt | OrdOp::Gt | OrdOp::Le | OrdOp::Ge) => Self::And.precedence() + 2,
169 Self::Math(MathOp::Add | MathOp::Sub) => Self::And.precedence() + 3,
170 Self::Math(MathOp::Mul | MathOp::Div) => Self::Math(MathOp::Add).precedence() + 1,
171 Self::Math(MathOp::Rem) => Self::Math(MathOp::Mul).precedence() + 1,
172 }
173 }
174
175 fn associativity(&self) -> Associativity {
176 match self {
177 Self::Pipe(_) | Self::Assign(_) => Associativity::Right,
178 _ => Associativity::Left,
179 }
180 }
181}
182
183impl prec_climb::Expr<BinaryOp> for Spanned<Filter> {
184 fn from_op(lhs: Self, op: BinaryOp, rhs: Self) -> Self {
185 Filter::binary(lhs, op, rhs)
186 }
187}
188
189impl parse::Def<&str, parse::Term<&str>> {
190 fn conv(&self, s: &str) -> Def {
191 let args = self.args.iter().map(|arg| {
192 if let Some(v) = arg.strip_prefix('$') {
193 Arg::Var(v.to_string())
194 } else {
195 Arg::Fun(arg.to_string())
196 }
197 });
198 Def {
199 lhs: Call {
200 name: self.name.to_string(),
201 args: args.collect(),
202 },
203 rhs: self.body.conv_main(s),
204 }
205 }
206}
207
208impl parse::Module<&str, Vec<parse::Def<&str, parse::Term<&str>>>> {
209 pub fn conv(&self, s: &str) -> Vec<Def> {
211 self.body.iter().map(|def| def.conv(s)).collect()
212 }
213}
214
215impl parse::Module<&str, parse::Term<&str>> {
216 pub fn conv(&self, s: &str) -> Main {
218 if !self.deps.is_empty() {
219 panic!("include / import is not supported yet");
220 }
221 self.body.conv_main(s)
222 }
223}