1use std::fmt;
21use std::fmt::Debug;
22use std::fmt::Display;
23use std::fmt::Formatter;
24
25use blueprint_allocative::Allocative;
26use blueprint_dupe::Dupe;
27
28use crate::codemap::Pos;
29use crate::codemap::Span;
30use crate::codemap::Spanned;
31use crate::lexer::TokenInt;
32
33pub trait AstPayload: Debug {
35 type LoadPayload: Debug + Clone;
37 type IdentPayload: Debug + Clone;
38 type IdentAssignPayload: Debug + Clone;
39 type DefPayload: Debug + Clone;
40 type TypeExprPayload: Debug + Clone;
41}
42
43#[derive(Debug, Copy, Clone, Dupe, Eq, PartialEq)]
46pub struct AstNoPayload;
47impl AstPayload for AstNoPayload {
48 type LoadPayload = ();
49 type IdentPayload = ();
50 type IdentAssignPayload = ();
51 type DefPayload = ();
52 type TypeExprPayload = ();
53}
54
55#[derive(Copy, Clone, Dupe, Debug)]
57pub struct Comma;
58
59pub type Expr = ExprP<AstNoPayload>;
60pub type TypeExpr = TypeExprP<AstNoPayload>;
61pub type AssignTarget = AssignTargetP<AstNoPayload>;
62pub type AssignIdent = AssignIdentP<AstNoPayload>;
63pub type Ident = IdentP<AstNoPayload>;
64pub type Clause = ClauseP<AstNoPayload>;
65pub type ForClause = ForClauseP<AstNoPayload>;
66pub type Argument = ArgumentP<AstNoPayload>;
67pub type Parameter = ParameterP<AstNoPayload>;
68pub type Load = LoadP<AstNoPayload>;
69pub type Stmt = StmtP<AstNoPayload>;
70
71pub type AstExprP<P> = Spanned<ExprP<P>>;
74pub type AstTypeExprP<P> = Spanned<TypeExprP<P>>;
75pub type AstAssignTargetP<P> = Spanned<AssignTargetP<P>>;
76pub type AstAssignIdentP<P> = Spanned<AssignIdentP<P>>;
77pub type AstIdentP<P> = Spanned<IdentP<P>>;
78pub type AstArgumentP<P> = Spanned<ArgumentP<P>>;
79pub type AstParameterP<P> = Spanned<ParameterP<P>>;
80pub type AstStmtP<P> = Spanned<StmtP<P>>;
81pub type AstFStringP<P> = Spanned<FStringP<P>>;
82
83pub type AstExpr = AstExprP<AstNoPayload>;
84pub type AstTypeExpr = AstTypeExprP<AstNoPayload>;
85pub type AstAssignTarget = AstAssignTargetP<AstNoPayload>;
86pub type AstAssignIdent = AstAssignIdentP<AstNoPayload>;
87pub type AstIdent = AstIdentP<AstNoPayload>;
88pub type AstArgument = AstArgumentP<AstNoPayload>;
89pub type AstString = Spanned<String>;
90pub type AstParameter = AstParameterP<AstNoPayload>;
91pub type AstInt = Spanned<TokenInt>;
92pub type AstFloat = Spanned<f64>;
93pub type AstFString = AstFStringP<AstNoPayload>;
94pub type AstStmt = AstStmtP<AstNoPayload>;
95
96pub trait ToAst: Sized {
98 fn ast(self, begin: usize, end: usize) -> Spanned<Self> {
99 Spanned {
100 span: Span::new(Pos::new(begin as u32), Pos::new(end as u32)),
101 node: self,
102 }
103 }
104}
105
106impl<T> ToAst for T {}
107
108#[derive(Debug, Clone)]
109pub enum ArgumentP<P: AstPayload> {
110 Positional(AstExprP<P>),
111 Named(AstString, AstExprP<P>),
112 Args(AstExprP<P>),
113 KwArgs(AstExprP<P>),
114}
115
116#[derive(Debug, Clone)]
117pub enum ParameterP<P: AstPayload> {
118 Slash,
120 Normal(
121 AstAssignIdentP<P>,
123 Option<Box<AstTypeExprP<P>>>,
125 Option<Box<AstExprP<P>>>,
127 ),
128 NoArgs,
130 Args(AstAssignIdentP<P>, Option<Box<AstTypeExprP<P>>>),
131 KwArgs(AstAssignIdentP<P>, Option<Box<AstTypeExprP<P>>>),
132}
133
134impl<P: AstPayload> ParameterP<P> {
135 pub fn ident(&self) -> Option<&AstAssignIdentP<P>> {
136 match self {
137 ParameterP::Normal(x, _, _) | ParameterP::Args(x, _) | ParameterP::KwArgs(x, _) => {
138 Some(x)
139 }
140 ParameterP::NoArgs | ParameterP::Slash => None,
141 }
142 }
143}
144
145#[derive(Debug, Clone)]
146pub enum AstLiteral {
147 Int(AstInt),
148 Float(AstFloat),
149 String(AstString),
150 Ellipsis,
151}
152
153#[derive(Debug, Clone)]
154pub struct LambdaP<P: AstPayload> {
155 pub params: Vec<AstParameterP<P>>,
156 pub body: Box<AstExprP<P>>,
157 pub payload: P::DefPayload,
158}
159
160impl<P: AstPayload> LambdaP<P> {
161 pub fn signature_span(&self) -> Span {
162 self.params
163 .iter()
164 .map(|p| p.span)
165 .reduce(|a, b| a.merge(b))
166 .unwrap_or(
167 self.body.span,
169 )
170 }
171}
172
173#[derive(Debug, Clone)]
174pub struct CallArgsP<P: AstPayload> {
175 pub args: Vec<AstArgumentP<P>>,
176}
177
178#[derive(Debug, Clone)]
179pub enum ExprP<P: AstPayload> {
180 Tuple(Vec<AstExprP<P>>),
181 Dot(Box<AstExprP<P>>, AstString),
182 Call(Box<AstExprP<P>>, CallArgsP<P>),
183 Index(Box<(AstExprP<P>, AstExprP<P>)>),
184 Index2(Box<(AstExprP<P>, AstExprP<P>, AstExprP<P>)>),
185 Slice(
186 Box<AstExprP<P>>,
187 Option<Box<AstExprP<P>>>,
188 Option<Box<AstExprP<P>>>,
189 Option<Box<AstExprP<P>>>,
190 ),
191 Identifier(AstIdentP<P>),
192 Lambda(LambdaP<P>),
193 Literal(AstLiteral),
194 Not(Box<AstExprP<P>>),
195 Minus(Box<AstExprP<P>>),
196 Plus(Box<AstExprP<P>>),
197 BitNot(Box<AstExprP<P>>),
198 Op(Box<AstExprP<P>>, BinOp, Box<AstExprP<P>>),
199 If(Box<(AstExprP<P>, AstExprP<P>, AstExprP<P>)>), List(Vec<AstExprP<P>>),
201 Dict(Vec<(AstExprP<P>, AstExprP<P>)>),
202 Set(Vec<AstExprP<P>>),
203 ListComprehension(Box<AstExprP<P>>, Box<ForClauseP<P>>, Vec<ClauseP<P>>),
204 SetComprehension(Box<AstExprP<P>>, Box<ForClauseP<P>>, Vec<ClauseP<P>>),
205 DictComprehension(
206 Box<(AstExprP<P>, AstExprP<P>)>,
207 Box<ForClauseP<P>>,
208 Vec<ClauseP<P>>,
209 ),
210 FString(AstFStringP<P>),
211}
212
213#[derive(Debug, Clone)]
215pub struct TypeExprP<P: AstPayload> {
216 pub expr: AstExprP<P>,
220 pub payload: P::TypeExprPayload,
221}
222
223#[derive(Debug, Clone)]
225pub enum AssignTargetP<P: AstPayload> {
226 Tuple(Vec<AstAssignTargetP<P>>),
229 Index(Box<(AstExprP<P>, AstExprP<P>)>),
230 Dot(Box<AstExprP<P>>, AstString),
231 Identifier(AstAssignIdentP<P>),
232}
233
234#[derive(Debug, Clone)]
236pub struct AssignP<P: AstPayload> {
237 pub lhs: AstAssignTargetP<P>,
238 pub ty: Option<AstTypeExprP<P>>,
239 pub rhs: AstExprP<P>,
240}
241
242#[derive(Debug, Eq, PartialEq, Clone)]
244pub struct AssignIdentP<P: AstPayload> {
245 pub ident: String,
246 pub payload: P::IdentAssignPayload,
247}
248
249#[derive(Debug, Eq, PartialEq, Clone)]
252pub struct IdentP<P: AstPayload> {
253 pub ident: String,
254 pub payload: P::IdentPayload,
255}
256
257#[derive(Debug, Clone)]
259pub struct LoadArgP<P: AstPayload> {
260 pub local: AstAssignIdentP<P>,
262 pub their: AstString,
264 pub comma: Option<Spanned<Comma>>,
266}
267
268impl<P: AstPayload> LoadArgP<P> {
269 pub fn span(&self) -> Span {
270 self.local.span.merge(self.their.span)
271 }
272
273 pub fn span_with_trailing_comma(&self) -> Span {
274 if let Some(comma) = &self.comma {
275 self.span().merge(comma.span)
276 } else {
277 self.span()
278 }
279 }
280}
281
282#[derive(Debug, Clone)]
284pub struct LoadP<P: AstPayload> {
285 pub module: AstString,
286 pub args: Vec<LoadArgP<P>>,
287 pub payload: P::LoadPayload,
288}
289
290#[derive(Debug, Clone)]
291pub struct ForClauseP<P: AstPayload> {
292 pub var: AstAssignTargetP<P>,
293 pub over: AstExprP<P>,
294}
295
296#[derive(Debug, Clone)]
297pub enum ClauseP<P: AstPayload> {
298 For(ForClauseP<P>),
299 If(AstExprP<P>),
300}
301
302#[derive(Debug, Clone, Copy, Dupe, Eq, PartialEq)]
303pub enum BinOp {
304 Or,
305 And,
306 Equal,
307 NotEqual,
308 Less,
309 Greater,
310 LessOrEqual,
311 GreaterOrEqual,
312 In,
313 NotIn,
314 Subtract,
315 Add,
316 Multiply,
317 Percent,
318 Divide,
319 FloorDivide,
320 BitAnd,
321 BitOr,
322 BitXor,
323 LeftShift,
324 RightShift,
325}
326
327#[derive(Debug, Clone, Copy, Dupe, PartialEq, Eq)]
328pub enum AssignOp {
329 Add, Subtract, Multiply, Divide, FloorDivide, Percent, BitAnd, BitOr, BitXor, LeftShift, RightShift, }
341
342#[derive(Debug, Copy, Clone, Dupe, Eq, PartialEq, Allocative)]
343pub enum Visibility {
344 Private,
345 Public,
346}
347
348#[derive(Debug, Clone)]
349pub struct DefP<P: AstPayload> {
350 pub name: AstAssignIdentP<P>,
351 pub params: Vec<AstParameterP<P>>,
352 pub return_type: Option<Box<AstTypeExprP<P>>>,
353 pub body: Box<AstStmtP<P>>,
354 pub payload: P::DefPayload,
355}
356
357impl<P: AstPayload> DefP<P> {
358 pub fn signature_span(&self) -> Span {
359 let mut span = self.name.span;
360 for param in &self.params {
361 span = span.merge(param.span);
362 }
363 if let Some(return_type) = &self.return_type {
364 span = span.merge(return_type.span);
365 }
366 span
367 }
368}
369
370#[derive(Debug, Clone)]
371pub struct ForP<P: AstPayload> {
372 pub var: AstAssignTargetP<P>,
373 pub over: AstExprP<P>,
374 pub body: Box<AstStmtP<P>>,
375}
376
377#[derive(Debug, Clone)]
378pub struct FStringP<P: AstPayload> {
379 pub format: AstString,
381 pub expressions: Vec<AstExprP<P>>,
383}
384
385#[derive(Debug, Clone)]
387pub struct StructFieldP<P: AstPayload> {
388 pub name: AstAssignIdentP<P>,
390 pub typ: AstTypeExprP<P>,
392 pub default: Option<AstExprP<P>>,
394}
395
396pub type AstStructFieldP<P> = Spanned<StructFieldP<P>>;
397pub type AstStructField = AstStructFieldP<AstNoPayload>;
398pub type StructField = StructFieldP<AstNoPayload>;
399
400#[derive(Debug, Clone)]
402pub struct StructP<P: AstPayload> {
403 pub name: AstAssignIdentP<P>,
405 pub fields: Vec<AstStructFieldP<P>>,
407}
408
409#[derive(Debug, Clone)]
411pub struct CaseClauseP<P: AstPayload> {
412 pub pattern: AstExprP<P>,
414 pub guard: Option<AstExprP<P>>,
416 pub body: AstStmtP<P>,
418}
419
420pub type AstCaseClauseP<P> = Spanned<CaseClauseP<P>>;
421pub type AstCaseClause = AstCaseClauseP<AstNoPayload>;
422pub type CaseClause = CaseClauseP<AstNoPayload>;
423
424#[derive(Debug, Clone)]
426pub struct MatchP<P: AstPayload> {
427 pub subject: AstExprP<P>,
429 pub cases: Vec<AstCaseClauseP<P>>,
431}
432
433#[derive(Debug, Clone)]
434pub enum StmtP<P: AstPayload> {
435 Break,
436 Continue,
437 Pass,
438 Return(Option<AstExprP<P>>),
439 Yield(Option<AstExprP<P>>),
440 Expression(AstExprP<P>),
441 Assign(AssignP<P>),
442 AssignModify(AstAssignTargetP<P>, AssignOp, Box<AstExprP<P>>),
443 Statements(Vec<AstStmtP<P>>),
444 If(AstExprP<P>, Box<AstStmtP<P>>),
445 IfElse(AstExprP<P>, Box<(AstStmtP<P>, AstStmtP<P>)>),
446 For(ForP<P>),
447 Def(DefP<P>),
448 Load(LoadP<P>),
449 Struct(StructP<P>),
450 Match(MatchP<P>),
451}
452
453impl<P: AstPayload> ArgumentP<P> {
454 pub fn expr(&self) -> &AstExprP<P> {
455 match self {
456 ArgumentP::Positional(x) => x,
457 ArgumentP::Named(_, x) => x,
458 ArgumentP::Args(x) => x,
459 ArgumentP::KwArgs(x) => x,
460 }
461 }
462
463 pub fn expr_mut(&mut self) -> &mut AstExprP<P> {
464 match self {
465 ArgumentP::Positional(x) => x,
466 ArgumentP::Named(_, x) => x,
467 ArgumentP::Args(x) => x,
468 ArgumentP::KwArgs(x) => x,
469 }
470 }
471
472 pub fn name(&self) -> Option<&str> {
474 match self {
475 ArgumentP::Named(name, _) => Some(&name.node),
476 _ => None,
477 }
478 }
479}
480
481impl Display for BinOp {
482 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
483 match *self {
484 BinOp::Or => f.write_str(" or "),
485 BinOp::And => f.write_str(" and "),
486 BinOp::Equal => f.write_str(" == "),
487 BinOp::NotEqual => f.write_str(" != "),
488 BinOp::Less => f.write_str(" < "),
489 BinOp::Greater => f.write_str(" > "),
490 BinOp::LessOrEqual => f.write_str(" <= "),
491 BinOp::GreaterOrEqual => f.write_str(" >= "),
492 BinOp::In => f.write_str(" in "),
493 BinOp::NotIn => f.write_str(" not in "),
494 BinOp::Subtract => f.write_str(" - "),
495 BinOp::Add => f.write_str(" + "),
496 BinOp::Multiply => f.write_str(" * "),
497 BinOp::Percent => f.write_str(" % "),
498 BinOp::Divide => f.write_str(" / "),
499 BinOp::FloorDivide => f.write_str(" // "),
500 BinOp::BitAnd => f.write_str(" & "),
501 BinOp::BitOr => f.write_str(" | "),
502 BinOp::BitXor => f.write_str(" ^ "),
503 BinOp::LeftShift => f.write_str(" << "),
504 BinOp::RightShift => f.write_str(" >> "),
505 }
506 }
507}
508
509impl Display for AssignOp {
510 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
511 match *self {
512 AssignOp::Add => f.write_str(" += "),
513 AssignOp::Subtract => f.write_str(" -= "),
514 AssignOp::Multiply => f.write_str(" *= "),
515 AssignOp::Divide => f.write_str(" /= "),
516 AssignOp::FloorDivide => f.write_str(" //= "),
517 AssignOp::Percent => f.write_str(" %= "),
518 AssignOp::BitAnd => f.write_str(" &= "),
519 AssignOp::BitOr => f.write_str(" |= "),
520 AssignOp::BitXor => f.write_str(" ^= "),
521 AssignOp::LeftShift => f.write_str(" <<= "),
522 AssignOp::RightShift => f.write_str(" >>= "),
523 }
524 }
525}
526
527fn comma_separated_fmt<I, F>(
528 f: &mut Formatter<'_>,
529 v: &[I],
530 converter: F,
531 for_tuple: bool,
532) -> fmt::Result
533where
534 F: Fn(&I, &mut Formatter<'_>) -> fmt::Result,
535{
536 for (i, e) in v.iter().enumerate() {
537 f.write_str(if i == 0 { "" } else { ", " })?;
538 converter(e, f)?;
539 }
540 if v.len() == 1 && for_tuple {
541 f.write_str(",")?;
542 }
543 Ok(())
544}
545
546fn fmt_string_literal(f: &mut Formatter<'_>, s: &str) -> fmt::Result {
547 f.write_str("\"")?;
548 for c in s.chars() {
549 match c {
550 '\n' => f.write_str("\\n")?,
551 '\t' => f.write_str("\\t")?,
552 '\r' => f.write_str("\\r")?,
553 '\0' => f.write_str("\\0")?,
554 '"' => f.write_str("\\\"")?,
555 '\\' => f.write_str("\\\\")?,
556 x => f.write_str(&x.to_string())?,
557 }
558 }
559 f.write_str("\"")
560}
561
562impl Display for AstLiteral {
563 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
564 match self {
565 AstLiteral::Int(i) => write!(f, "{}", &i.node),
566 AstLiteral::Float(n) => write!(f, "{}", &n.node),
567 AstLiteral::String(s) => fmt_string_literal(f, &s.node),
568 AstLiteral::Ellipsis => f.write_str("..."),
569 }
570 }
571}
572
573impl Display for Expr {
574 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
575 match self {
576 Expr::Tuple(e) => {
577 f.write_str("(")?;
578 comma_separated_fmt(f, e, |x, f| write!(f, "{}", x.node), true)?;
579 f.write_str(")")
580 }
581 Expr::Dot(e, s) => write!(f, "{}.{}", e.node, s.node),
582 Expr::Lambda(LambdaP {
583 params,
584 body,
585 payload: _,
586 }) => {
587 f.write_str("(lambda ")?;
588 comma_separated_fmt(f, params, |x, f| write!(f, "{}", x.node), false)?;
589 f.write_str(": ")?;
590 write!(f, "{}", body.node)?;
591 f.write_str(")")
592 }
593 Expr::Call(e, args) => {
594 write!(f, "{}(", e.node)?;
595 for (i, x) in args.args.iter().enumerate() {
596 if i != 0 {
597 f.write_str(", ")?;
598 }
599 write!(f, "{}", x.node)?;
600 }
601 f.write_str(")")
602 }
603 Expr::Index(e_i) => {
604 let (e, i) = &**e_i;
605 write!(f, "{}[{}]", e.node, i.node)
606 }
607 Expr::Index2(a_i0_i1) => {
608 let (a, i0, i1) = &**a_i0_i1;
609 write!(f, "{}[{}, {}]", a.node, i0.node, i1.node)
610 }
611 Expr::Slice(e, i1, i2, i3) => {
612 write!(f, "{}[]", e.node)?;
613 if let Some(x) = i1 {
614 write!(f, "{}:", x.node)?
615 } else {
616 f.write_str(":")?
617 }
618 if let Some(x) = i2 {
619 write!(f, "{}", x.node)?
620 }
621 if let Some(x) = i3 {
622 write!(f, ":{}", x.node)?
623 }
624 Ok(())
625 }
626 Expr::Identifier(s) => Display::fmt(&s.node, f),
627 Expr::Not(e) => write!(f, "(not {})", e.node),
628 Expr::Minus(e) => write!(f, "-{}", e.node),
629 Expr::Plus(e) => write!(f, "+{}", e.node),
630 Expr::BitNot(e) => write!(f, "~{}", e.node),
631 Expr::Op(l, op, r) => write!(f, "({}{}{})", l.node, op, r.node),
632 Expr::If(cond_v1_v2) => {
633 let (cond, v1, v2) = &**cond_v1_v2;
634 write!(f, "({} if {} else {})", v1.node, cond.node, v2.node)
635 }
636 Expr::List(v) => {
637 f.write_str("[")?;
638 comma_separated_fmt(f, v, |x, f| write!(f, "{}", x.node), false)?;
639 f.write_str("]")
640 }
641 Expr::Dict(v) => {
642 f.write_str("{")?;
643 comma_separated_fmt(f, v, |x, f| write!(f, "{}: {}", x.0.node, x.1.node), false)?;
644 f.write_str("}")
645 }
646 Expr::Set(v) => {
647 f.write_str("{")?;
648 comma_separated_fmt(f, v, |x, f| write!(f, "{}", x.node), false)?;
649 f.write_str("}")
650 }
651 Expr::ListComprehension(e, for_, c) => {
652 write!(f, "[{}", e.node)?;
653 write!(f, "{for_}")?;
654 for x in c {
655 write!(f, "{x}")?;
656 }
657 f.write_str("]")
658 }
659 Expr::SetComprehension(e, for_, c) => {
660 write!(f, "{{{}", e.node)?;
661 write!(f, "{for_}")?;
662 for x in c {
663 write!(f, "{x}")?;
664 }
665 f.write_str("}")
666 }
667 Expr::DictComprehension(k_v, for_, c) => {
668 let (k, v) = &**k_v;
669 write!(f, "{{{}: {}", k.node, v.node)?;
670 write!(f, "{for_}")?;
671 for x in c {
672 write!(f, "{x}")?;
673 }
674 f.write_str("}")
675 }
676 Expr::Literal(x) => write!(f, "{x}"),
677 Expr::FString(x) => {
678 write!(f, "{}.format(", x.format.node)?;
680 comma_separated_fmt(f, &x.expressions, |x, f| write!(f, "{}", x.node), false)?;
681 f.write_str(")")
682 }
683 }
684 }
685}
686
687impl Display for TypeExpr {
688 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
689 Display::fmt(&self.expr.node, f)
690 }
691}
692
693impl Display for AssignTarget {
694 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
695 match self {
696 AssignTarget::Tuple(e) => {
697 f.write_str("(")?;
698 comma_separated_fmt(f, e, |x, f| write!(f, "{}", x.node), true)?;
699 f.write_str(")")
700 }
701 AssignTarget::Dot(e, s) => write!(f, "{}.{}", e.node, s.node),
702 AssignTarget::Index(e_i) => {
703 let (e, i) = &**e_i;
704 write!(f, "{}[{}]", e.node, i.node)
705 }
706 AssignTarget::Identifier(s) => write!(f, "{}", s.node),
707 }
708 }
709}
710
711impl Display for AssignIdent {
712 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
713 write!(f, "{}", self.ident)
714 }
715}
716
717impl Display for Ident {
718 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
719 write!(f, "{}", self.ident)
720 }
721}
722
723impl Display for Argument {
724 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
725 match self {
726 Argument::Positional(s) => write!(f, "{}", s.node),
727 Argument::Named(s, e) => write!(f, "{} = {}", s.node, e.node),
728 Argument::Args(s) => write!(f, "*{}", s.node),
729 Argument::KwArgs(s) => write!(f, "**{}", s.node),
730 }
731 }
732}
733
734impl Display for Parameter {
735 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
736 let (prefix, name, typ, default) = match self {
737 Parameter::Slash => return write!(f, "/"),
738 Parameter::Normal(s, t, e) => ("", s, t, e.as_ref()),
739 Parameter::NoArgs => return write!(f, "*"),
740 Parameter::Args(s, t) => ("*", s, t, None),
741 Parameter::KwArgs(s, t) => ("**", s, t, None),
742 };
743 write!(f, "{}{}", prefix, name.node)?;
744 if let Some(t) = typ {
745 write!(f, ": {}", t.node)?;
746 }
747 if let Some(d) = default {
748 write!(f, " = {}", d.node)?;
749 }
750 Ok(())
751 }
752}
753
754impl Display for ForClause {
755 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
756 write!(f, " for {} in {}", self.var.node, self.over.node)
757 }
758}
759
760impl Display for Clause {
761 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
762 match self {
763 Clause::For(x) => write!(f, "{x}"),
764 Clause::If(x) => write!(f, " if {}", x.node),
765 }
766 }
767}
768
769impl Stmt {
770 fn fmt_with_tab(&self, f: &mut Formatter<'_>, tab: String) -> fmt::Result {
771 match self {
772 Stmt::Break => writeln!(f, "{tab}break"),
773 Stmt::Continue => writeln!(f, "{tab}continue"),
774 Stmt::Pass => writeln!(f, "{tab}pass"),
775 Stmt::Return(Some(e)) => writeln!(f, "{}return {}", tab, e.node),
776 Stmt::Return(None) => writeln!(f, "{tab}return"),
777 Stmt::Yield(Some(e)) => writeln!(f, "{}yield {}", tab, e.node),
778 Stmt::Yield(None) => writeln!(f, "{tab}yield"),
779 Stmt::Expression(e) => writeln!(f, "{}{}", tab, e.node),
780 Stmt::Assign(AssignP { lhs, ty, rhs }) => {
781 write!(f, "{}{} ", tab, lhs.node)?;
782 if let Some(ty) = ty {
783 write!(f, ": {} ", ty.node)?;
784 }
785 writeln!(f, "= {}", rhs.node)
786 }
787 Stmt::AssignModify(l, op, r) => writeln!(f, "{}{}{}{}", tab, l.node, op, r.node),
788 Stmt::Statements(v) => {
789 for s in v {
790 s.node.fmt_with_tab(f, tab.clone())?;
791 }
792 Ok(())
793 }
794 Stmt::If(cond, suite) => {
795 writeln!(f, "{}if {}:", tab, cond.node)?;
796 suite.node.fmt_with_tab(f, tab + " ")
797 }
798 Stmt::IfElse(cond, suite_1_2) => {
799 let (suite1, suite2) = &**suite_1_2;
800 writeln!(f, "{}if {}:", tab, cond.node)?;
801 suite1.node.fmt_with_tab(f, tab.clone() + " ")?;
802 writeln!(f, "{tab}else:")?;
803 suite2.node.fmt_with_tab(f, tab + " ")
804 }
805 Stmt::For(ForP { var, over, body }) => {
806 writeln!(f, "{}for {} in {}:", tab, var.node, over.node)?;
807 body.node.fmt_with_tab(f, tab + " ")
808 }
809 Stmt::Def(DefP {
810 name,
811 params,
812 return_type,
813 body,
814 payload: _,
815 }) => {
816 write!(f, "{}def {}(", tab, name.node)?;
817 comma_separated_fmt(f, params, |x, f| write!(f, "{}", x.node), false)?;
818 f.write_str(")")?;
819 if let Some(rt) = return_type {
820 write!(f, " -> {}", rt.node)?;
821 }
822 f.write_str(":\n")?;
823 body.node.fmt_with_tab(f, tab + " ")
824 }
825 Stmt::Load(load) => {
826 write!(f, "{tab}load(")?;
827 fmt_string_literal(f, &load.module.node)?;
828 f.write_str(", ")?;
829 comma_separated_fmt(
830 f,
831 &load.args,
832 |x, f| {
833 write!(f, "{} = ", x.local.node)?;
834 fmt_string_literal(f, &(x.their.node))
835 },
836 false,
837 )?;
838 f.write_str(")\n")
839 }
840 Stmt::Struct(StructP { name, fields }) => {
841 writeln!(f, "{}struct {}:", tab, name.node)?;
842 for field in fields {
843 write!(f, "{} {}: {}", tab, field.node.name.node, field.node.typ.expr.node)?;
844 if let Some(default) = &field.node.default {
845 write!(f, " = {}", default.node)?;
846 }
847 writeln!(f)?;
848 }
849 Ok(())
850 }
851 Stmt::Match(MatchP { subject, cases }) => {
852 writeln!(f, "{}match {}:", tab, subject.node)?;
853 for case in cases {
854 write!(f, "{} case {}", tab, case.node.pattern.node)?;
855 if let Some(guard) = &case.node.guard {
856 write!(f, " if {}", guard.node)?;
857 }
858 writeln!(f, ":")?;
859 case.node.body.node.fmt_with_tab(f, tab.clone() + " ")?;
860 }
861 Ok(())
862 }
863 }
864 }
865}
866
867impl Display for Stmt {
868 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
869 self.fmt_with_tab(f, "".to_owned())
870 }
871}