1use crate::syntax::ast::{
35 AssertBody, AssertDecl, ConstNodeDecl, DagDecl, DeclKind, Declaration, DomainBound, Encoding,
36 Expr, ExprKind, FieldDecl, FieldInit, FigureDecl, File, GenericArg, GenericParam, IncludeDecl,
37 IndexArg, IndexDecl, IndexDeclKind, LayerDecl, MapEntry, MarkSpec, MatchArm, NodeDecl,
38 ParamBinding, ParamDecl, PlotDecl, PlotField, TypeDecl, TypeDeclBody, TypeExpr, TypeExprKind,
39 UnionMember, UnitDecl, UnitDef,
40};
41use crate::syntax::ast::{RawDeclSugar, RawExprSugar};
42use crate::syntax::phase::{Desugared, Raw};
43
44impl From<File<Raw>> for File<Desugared> {
49 fn from(f: File<Raw>) -> Self {
50 Self {
51 declarations: f.declarations.into_iter().flat_map(convert_decl).collect(),
52 }
53 }
54}
55
56fn convert_decl(d: Declaration<Raw>) -> Vec<Declaration<Desugared>> {
61 let Declaration {
62 attributes,
63 kind,
64 span,
65 } = d;
66 match kind {
67 DeclKind::Sugar(RawDeclSugar::Multi(multi)) => {
68 crate::syntax::desugar::expand_multi_decl(&multi)
73 .into_iter()
74 .map(lift_slot_decl)
75 .collect()
76 }
77 other => vec![Declaration {
78 attributes,
79 kind: convert_decl_kind_non_sugar(other),
80 span,
81 }],
82 }
83}
84
85fn lift_slot_decl(d: crate::syntax::desugar::ExpandedSlotDecl) -> Declaration<Desugared> {
90 use crate::syntax::desugar::ExpandedSlotDecl;
91 let (kind, span) = match d {
92 ExpandedSlotDecl::Param(p, span) => (DeclKind::Param(p.into()), span),
93 ExpandedSlotDecl::Node(n, span) => (DeclKind::Node(n.into()), span),
94 ExpandedSlotDecl::ConstNode(c, span) => (DeclKind::ConstNode(c.into()), span),
95 };
96 Declaration {
97 attributes: vec![],
98 kind,
99 span,
100 }
101}
102
103#[expect(
108 clippy::panic,
109 reason = "invariant: convert_decl handles Sugar separately and never calls this with Sugar"
110)]
111fn convert_decl_kind_non_sugar(k: DeclKind<Raw>) -> DeclKind<Desugared> {
112 match k {
113 DeclKind::Param(p) => DeclKind::Param(p.into()),
114 DeclKind::Node(n) => DeclKind::Node(n.into()),
115 DeclKind::ConstNode(c) => DeclKind::ConstNode(c.into()),
116 DeclKind::BaseDimension(d) => DeclKind::BaseDimension(d),
117 DeclKind::Dimension(d) => DeclKind::Dimension(d),
118 DeclKind::Unit(u) => DeclKind::Unit(u.into()),
119 DeclKind::Type(t) => DeclKind::Type(t.into()),
120 DeclKind::Index(i) => DeclKind::Index(i.into()),
121 DeclKind::Import(i) => DeclKind::Import(i),
122 DeclKind::Include(i) => DeclKind::Include(i.into()),
123 DeclKind::Dag(d) => DeclKind::Dag(d.into()),
124 DeclKind::Assert(a) => DeclKind::Assert(a.into()),
125 DeclKind::Plot(p) => DeclKind::Plot(p.into()),
126 DeclKind::Figure(f) => DeclKind::Figure(f.into()),
127 DeclKind::Layer(l) => DeclKind::Layer(l.into()),
128 DeclKind::Sugar(_) => {
131 panic!("convert_decl dispatches Sugar before calling convert_decl_kind_non_sugar")
132 }
133 }
134}
135
136impl From<ParamDecl<Raw>> for ParamDecl<Desugared> {
141 fn from(p: ParamDecl<Raw>) -> Self {
142 Self {
143 name: p.name,
144 type_ann: p.type_ann.into(),
145 value: p.value.map(Into::into),
146 }
147 }
148}
149
150impl From<NodeDecl<Raw>> for NodeDecl<Desugared> {
151 fn from(n: NodeDecl<Raw>) -> Self {
152 Self {
153 visibility: n.visibility,
154 name: n.name,
155 type_ann: n.type_ann.into(),
156 value: n.value.into(),
157 }
158 }
159}
160
161impl From<ConstNodeDecl<Raw>> for ConstNodeDecl<Desugared> {
162 fn from(c: ConstNodeDecl<Raw>) -> Self {
163 Self {
164 visibility: c.visibility,
165 name: c.name,
166 type_ann: c.type_ann.into(),
167 value: c.value.into(),
168 }
169 }
170}
171
172impl From<UnitDecl<Raw>> for UnitDecl<Desugared> {
173 fn from(u: UnitDecl<Raw>) -> Self {
174 Self {
175 visibility: u.visibility,
176 constness: u.constness,
177 name: u.name,
178 dim_type: u.dim_type,
179 definition: u.definition.map(Into::into),
180 }
181 }
182}
183
184impl From<UnitDef<Raw>> for UnitDef<Desugared> {
185 fn from(u: UnitDef<Raw>) -> Self {
186 Self {
187 scale_expr: u.scale_expr.into(),
188 unit_expr: u.unit_expr,
189 span: u.span,
190 }
191 }
192}
193
194impl From<TypeDecl<Raw>> for TypeDecl<Desugared> {
195 fn from(t: TypeDecl<Raw>) -> Self {
196 Self {
197 visibility: t.visibility,
198 name: t.name,
199 generic_params: t.generic_params.into_iter().map(Into::into).collect(),
200 body: match t.body {
201 TypeDeclBody::Required => TypeDeclBody::Required,
202 TypeDeclBody::Constructors(members) => {
203 TypeDeclBody::Constructors(members.into_iter().map(Into::into).collect())
204 }
205 },
206 }
207 }
208}
209
210impl From<UnionMember<Raw>> for UnionMember<Desugared> {
211 fn from(u: UnionMember<Raw>) -> Self {
212 Self {
213 name: u.name,
214 payload: u.payload.map(|fs| fs.into_iter().map(Into::into).collect()),
215 span: u.span,
216 }
217 }
218}
219
220impl From<FieldDecl<Raw>> for FieldDecl<Desugared> {
221 fn from(f: FieldDecl<Raw>) -> Self {
222 Self {
223 name: f.name,
224 type_ann: f.type_ann.into(),
225 }
226 }
227}
228
229impl From<GenericParam<Raw>> for GenericParam<Desugared> {
230 fn from(g: GenericParam<Raw>) -> Self {
231 Self {
232 name: g.name,
233 constraint: g.constraint,
234 default: g.default.map(Into::into),
235 }
236 }
237}
238
239impl From<IndexDecl<Raw>> for IndexDecl<Desugared> {
240 fn from(i: IndexDecl<Raw>) -> Self {
241 Self {
242 visibility: i.visibility,
243 name: i.name,
244 kind: i.kind.into(),
245 }
246 }
247}
248
249impl From<IndexDeclKind<Raw>> for IndexDeclKind<Desugared> {
250 fn from(k: IndexDeclKind<Raw>) -> Self {
251 match k {
252 IndexDeclKind::Named { variants } => Self::Named { variants },
253 IndexDeclKind::Range { start, end, step } => Self::Range {
254 start: Box::new((*start).into()),
255 end: Box::new((*end).into()),
256 step: Box::new((*step).into()),
257 },
258 IndexDeclKind::RequiredNamed => Self::RequiredNamed,
259 IndexDeclKind::RequiredRange { dimension } => Self::RequiredRange { dimension },
260 }
261 }
262}
263
264impl From<IncludeDecl<Raw>> for IncludeDecl<Desugared> {
265 fn from(i: IncludeDecl<Raw>) -> Self {
266 Self {
267 visibility: i.visibility,
268 path: i.path,
269 param_bindings: i.param_bindings.into_iter().map(Into::into).collect(),
270 kind: i.kind,
271 }
272 }
273}
274
275impl From<ParamBinding<Raw>> for ParamBinding<Desugared> {
276 fn from(p: ParamBinding<Raw>) -> Self {
277 Self {
278 name: p.name,
279 value: p.value.into(),
280 span: p.span,
281 }
282 }
283}
284
285impl From<DagDecl<Raw>> for DagDecl<Desugared> {
286 fn from(d: DagDecl<Raw>) -> Self {
287 Self {
288 visibility: d.visibility,
289 name: d.name,
290 body: d.body.into_iter().flat_map(convert_decl).collect(),
291 span: d.span,
292 }
293 }
294}
295
296impl From<AssertDecl<Raw>> for AssertDecl<Desugared> {
297 fn from(a: AssertDecl<Raw>) -> Self {
298 Self {
299 visibility: a.visibility,
300 name: a.name,
301 body: a.body.into(),
302 }
303 }
304}
305
306impl From<AssertBody<Raw>> for AssertBody<Desugared> {
307 fn from(b: AssertBody<Raw>) -> Self {
308 match b {
309 AssertBody::Expr(e) => Self::Expr(e.into()),
310 AssertBody::Tolerance {
311 actual,
312 expected,
313 tolerance,
314 is_relative,
315 } => Self::Tolerance {
316 actual: Box::new((*actual).into()),
317 expected: Box::new((*expected).into()),
318 tolerance: Box::new((*tolerance).into()),
319 is_relative,
320 },
321 }
322 }
323}
324
325impl From<PlotDecl<Raw>> for PlotDecl<Desugared> {
330 fn from(p: PlotDecl<Raw>) -> Self {
331 Self {
332 visibility: p.visibility,
333 name: p.name,
334 mark: p.mark.into(),
335 encodings: p.encodings.into_iter().map(Into::into).collect(),
336 properties: p.properties.into_iter().map(Into::into).collect(),
337 }
338 }
339}
340
341impl From<MarkSpec<Raw>> for MarkSpec<Desugared> {
342 fn from(m: MarkSpec<Raw>) -> Self {
343 Self {
344 mark_type: m.mark_type,
345 mark_type_span: m.mark_type_span,
346 properties: m.properties.into_iter().map(Into::into).collect(),
347 span: m.span,
348 }
349 }
350}
351
352impl From<Encoding<Raw>> for Encoding<Desugared> {
353 fn from(e: Encoding<Raw>) -> Self {
354 Self {
355 channel: e.channel,
356 channel_span: e.channel_span,
357 value: e.value.into(),
358 span: e.span,
359 }
360 }
361}
362
363impl From<PlotField<Raw>> for PlotField<Desugared> {
364 fn from(p: PlotField<Raw>) -> Self {
365 Self {
366 name: p.name,
367 value: p.value.into(),
368 span: p.span,
369 }
370 }
371}
372
373impl From<FigureDecl<Raw>> for FigureDecl<Desugared> {
374 fn from(f: FigureDecl<Raw>) -> Self {
375 Self {
376 visibility: f.visibility,
377 name: f.name,
378 plot_names: f.plot_names,
379 fields: f.fields.into_iter().map(Into::into).collect(),
380 }
381 }
382}
383
384impl From<LayerDecl<Raw>> for LayerDecl<Desugared> {
385 fn from(l: LayerDecl<Raw>) -> Self {
386 Self {
387 visibility: l.visibility,
388 name: l.name,
389 plot_names: l.plot_names,
390 fields: l.fields.into_iter().map(Into::into).collect(),
391 }
392 }
393}
394
395impl From<TypeExpr<Raw>> for TypeExpr<Desugared> {
400 fn from(t: TypeExpr<Raw>) -> Self {
401 Self {
402 kind: t.kind.into(),
403 constraints: t.constraints.into_iter().map(Into::into).collect(),
404 span: t.span,
405 }
406 }
407}
408
409impl From<TypeExprKind<Raw>> for TypeExprKind<Desugared> {
410 fn from(k: TypeExprKind<Raw>) -> Self {
411 match k {
412 TypeExprKind::Dimensionless => Self::Dimensionless,
413 TypeExprKind::Bool => Self::Bool,
414 TypeExprKind::Int => Self::Int,
415 TypeExprKind::Datetime => Self::Datetime,
416 TypeExprKind::DimExpr(d) => Self::DimExpr(d),
417 TypeExprKind::Indexed { base, indexes } => Self::Indexed {
418 base: Box::new((*base).into()),
419 indexes,
420 },
421 TypeExprKind::TypeApplication { name, type_args } => Self::TypeApplication {
422 name,
423 type_args: type_args.into_iter().map(Into::into).collect(),
424 },
425 TypeExprKind::DatetimeApplication { type_args } => Self::DatetimeApplication {
426 type_args: type_args.into_iter().map(Into::into).collect(),
427 },
428 }
429 }
430}
431
432impl From<DomainBound<Raw>> for DomainBound<Desugared> {
433 fn from(d: DomainBound<Raw>) -> Self {
434 Self {
435 kind: d.kind,
436 kind_span: d.kind_span,
437 value: d.value.into(),
438 span: d.span,
439 }
440 }
441}
442
443impl From<GenericArg<Raw>> for GenericArg<Desugared> {
444 fn from(g: GenericArg<Raw>) -> Self {
445 match g {
446 GenericArg::Type(t) => Self::Type(t.into()),
447 GenericArg::Nat(n) => Self::Nat(n),
448 }
449 }
450}
451
452impl From<Expr<Raw>> for Expr<Desugared> {
457 fn from(e: Expr<Raw>) -> Self {
458 crate::stack::with_stack_growth(|| Self::new(e.kind.into(), e.span))
461 }
462}
463
464impl From<ExprKind<Raw>> for ExprKind<Desugared> {
465 #[expect(
466 clippy::too_many_lines,
467 reason = "exhaustive variant pass-through over a wide enum is inherently long"
468 )]
469 fn from(k: ExprKind<Raw>) -> Self {
470 match k {
471 ExprKind::Number(n) => Self::Number(n),
473 ExprKind::Integer(n) => Self::Integer(n),
474 ExprKind::Bool(b) => Self::Bool(b),
475 ExprKind::StringLiteral(s) => Self::StringLiteral(s),
476 ExprKind::GraphRef(r) => Self::GraphRef(r),
477 ExprKind::UnitLiteral { value, unit } => Self::UnitLiteral { value, unit },
478 ExprKind::UnresolvedRef(r) => Self::UnresolvedRef(r),
479 ExprKind::BinOp { op, lhs, rhs } => Self::BinOp {
481 op,
482 lhs: Box::new((*lhs).into()),
483 rhs: Box::new((*rhs).into()),
484 },
485 ExprKind::UnaryOp { op, operand } => Self::UnaryOp {
486 op,
487 operand: Box::new((*operand).into()),
488 },
489 ExprKind::FnCall {
490 callee,
491 type_args,
492 args,
493 } => Self::FnCall {
494 callee,
495 type_args: type_args.into_iter().map(Into::into).collect(),
496 args: args.into_iter().map(Into::into).collect(),
497 },
498 ExprKind::If {
499 condition,
500 then_branch,
501 else_branch,
502 } => Self::If {
503 condition: Box::new((*condition).into()),
504 then_branch: Box::new((*then_branch).into()),
505 else_branch: Box::new((*else_branch).into()),
506 },
507 ExprKind::Convert { expr, target } => Self::Convert {
508 expr: Box::new((*expr).into()),
509 target,
510 },
511 ExprKind::DisplayTimezone { expr, timezone } => Self::DisplayTimezone {
512 expr: Box::new((*expr).into()),
513 timezone,
514 },
515 ExprKind::FieldAccess { expr, field } => Self::FieldAccess {
516 expr: Box::new((*expr).into()),
517 field,
518 },
519 ExprKind::ConstructorCall {
520 callee,
521 generic_args,
522 fields,
523 } => Self::ConstructorCall {
524 callee,
525 generic_args: generic_args.into_iter().map(Into::into).collect(),
526 fields: fields.into_iter().map(Into::into).collect(),
527 },
528 ExprKind::MapLiteral { entries } => Self::MapLiteral {
529 entries: entries.into_iter().map(Into::into).collect(),
530 },
531 ExprKind::ForComp { bindings, body } => Self::ForComp {
532 bindings,
533 body: Box::new((*body).into()),
534 },
535 ExprKind::IndexAccess { expr, args } => Self::IndexAccess {
536 expr: Box::new((*expr).into()),
537 args: args.into_iter().map(Into::into).collect(),
538 },
539 ExprKind::Scan {
540 source,
541 init,
542 acc_name,
543 val_name,
544 body,
545 } => Self::Scan {
546 source: Box::new((*source).into()),
547 init: Box::new((*init).into()),
548 acc_name,
549 val_name,
550 body: Box::new((*body).into()),
551 },
552 ExprKind::Unfold {
553 init,
554 prev_name,
555 curr_name,
556 body,
557 } => Self::Unfold {
558 init: Box::new((*init).into()),
559 prev_name,
560 curr_name,
561 body: Box::new((*body).into()),
562 },
563 ExprKind::Match { scrutinee, arms } => Self::Match {
564 scrutinee: Box::new((*scrutinee).into()),
565 arms: arms.into_iter().map(Into::into).collect(),
566 },
567 ExprKind::InlineDagRef { path, args, output } => Self::InlineDagRef {
568 path,
569 args: args.into_iter().map(Into::into).collect(),
570 output,
571 },
572 ExprKind::Sugar(RawExprSugar::TableLiteral {
573 indexes: _,
574 entries,
575 }) => {
576 Self::MapLiteral {
583 entries: entries.into_iter().map(Into::into).collect(),
584 }
585 }
586 }
587 }
588}
589
590impl From<MapEntry<Raw>> for MapEntry<Desugared> {
591 fn from(m: MapEntry<Raw>) -> Self {
592 Self {
593 keys: m.keys,
594 value: m.value.into(),
595 }
596 }
597}
598
599impl From<IndexArg<Raw>> for IndexArg<Desugared> {
600 fn from(a: IndexArg<Raw>) -> Self {
601 match a {
602 IndexArg::Variant { index, variant } => Self::Variant { index, variant },
603 IndexArg::Var(i) => Self::Var(i),
604 IndexArg::Expr(e) => Self::Expr(Box::new((*e).into())),
605 }
606 }
607}
608
609impl From<FieldInit<Raw>> for FieldInit<Desugared> {
610 fn from(f: FieldInit<Raw>) -> Self {
611 Self {
612 name: f.name,
613 value: f.value.into(),
614 }
615 }
616}
617
618impl From<MatchArm<Raw>> for MatchArm<Desugared> {
619 fn from(a: MatchArm<Raw>) -> Self {
620 Self {
621 pattern: a.pattern,
622 body: a.body.into(),
623 span: a.span,
624 }
625 }
626}