lib/std/lang/ast/printer.rad 25.3 KiB raw
1
//! AST pretty printer using S-expression syntax.
2
3
use std::io;
4
use std::lang::sexpr;
5
use std::lang::alloc;
6
7
/// Return the symbol for a binary operator.
8
fn binOpName(op: super::BinaryOp) -> *[u8] {
9
    match op {
10
        case super::BinaryOp::Add => return "+",
11
        case super::BinaryOp::Sub => return "-",
12
        case super::BinaryOp::Mul => return "*",
13
        case super::BinaryOp::Div => return "/",
14
        case super::BinaryOp::Mod => return "%",
15
        case super::BinaryOp::BitAnd => return "&",
16
        case super::BinaryOp::BitOr => return "|",
17
        case super::BinaryOp::BitXor => return "^",
18
        case super::BinaryOp::Shl => return "<<",
19
        case super::BinaryOp::Shr => return ">>",
20
        case super::BinaryOp::Eq => return "==",
21
        case super::BinaryOp::Ne => return "<>",
22
        case super::BinaryOp::Lt => return "<",
23
        case super::BinaryOp::Gt => return ">",
24
        case super::BinaryOp::Lte => return "<=",
25
        case super::BinaryOp::Gte => return ">=",
26
        case super::BinaryOp::And => return "and",
27
        case super::BinaryOp::Or => return "or",
28
        case super::BinaryOp::Xor => return "xor",
29
    }
30
}
31
32
/// Return the symbol for a unary operator.
33
fn unOpName(op: super::UnaryOp) -> *[u8] {
34
    match op {
35
        case super::UnaryOp::Not => return "not",
36
        case super::UnaryOp::Neg => return "-",
37
        case super::UnaryOp::BitNot => return "~",
38
    }
39
}
40
41
/// Return the name for a builtin.
42
fn builtinName(kind: super::Builtin) -> *[u8] {
43
    match kind {
44
        case super::Builtin::SizeOf => return "@sizeOf",
45
        case super::Builtin::AlignOf => return "@alignOf",
46
        case super::Builtin::SliceOf => return "@sliceOf",
47
    }
48
}
49
50
/// Return the name for an integer type.
51
fn intTypeName(width: u8, sign: super::Signedness) -> *[u8] {
52
    if let case super::Signedness::Signed = sign {
53
        match width {
54
            case 1 => return "i8",
55
            case 2 => return "i16",
56
            case 4 => return "i32",
57
            case 8 => return "i64",
58
            else => panic,
59
        }
60
    } else {
61
        match width {
62
            case 1 => return "u8",
63
            case 2 => return "u16",
64
            case 4 => return "u32",
65
            case 8 => return "u64",
66
            else => panic,
67
        }
68
    }
69
}
70
71
/// Return the S-expression head for a pointer class.
72
fn pointerClassHead(
73
    class: super::PointerClass,
74
    ownedHead: *[u8],
75
    refHead: *[u8],
76
    unsafeHead: *[u8],
77
) -> *[u8] {
78
    match class {
79
        case super::PointerClass::Owned => return ownedHead,
80
        case super::PointerClass::Ref => return refHead,
81
        case super::PointerClass::Unsafe => return unsafeHead,
82
    }
83
}
84
85
/// Convert a type signature to an S-expression.
86
unsafe fn typeSigToExpr(a: &mut alloc::Arena, sig: super::TypeSig) -> sexpr::Expr {
87
    match sig {
88
        case super::TypeSig::Void => return sexpr::sym("void"),
89
        case super::TypeSig::Never => return sexpr::sym("!"),
90
        case super::TypeSig::Opaque => return sexpr::sym("opaque"),
91
        case super::TypeSig::Bool => return sexpr::sym("bool"),
92
        case super::TypeSig::Integer { width, sign } => return sexpr::sym(intTypeName(width, sign)),
93
        case super::TypeSig::Array { itemType, length } =>
94
            return sexpr::list(a, "array", &[toExpr(a, itemType), toExpr(a, length)]),
95
        case super::TypeSig::Slice { class, itemType, mutable } => {
96
            let head = pointerClassHead(class, "slice", "slice-ref", "unsafe-slice");
97
            return sexpr::list(a, head, &[sexpr::sym("mut"), toExpr(a, itemType)]) if mutable
98
                else sexpr::list(a, head, &[toExpr(a, itemType)]);
99
        }
100
        case super::TypeSig::Pointer { class, valueType, mutable } => {
101
            let head = pointerClassHead(class, "ptr", "ref", "unsafe-ptr");
102
            return sexpr::list(a, head, &[sexpr::sym("mut"), toExpr(a, valueType)]) if mutable
103
                else sexpr::list(a, head, &[toExpr(a, valueType)]);
104
        }
105
        case super::TypeSig::Optional { valueType } =>
106
            return sexpr::list(a, "?", &[toExpr(a, valueType)]),
107
        case super::TypeSig::Cell { class, payload } =>
108
            return sexpr::list(a, pointerClassHead(class, "cell-ptr", "cell-ref", "unsafe-cell-ptr"), &[toExpr(a, payload)]),
109
        case super::TypeSig::Nominal(name) => return toExpr(a, name),
110
        case super::TypeSig::RegionRef { region, type } =>
111
            return sexpr::list(a, "region-ref", &[toExpr(a, region), toExpr(a, type)]),
112
        case super::TypeSig::Applied { name, regions } =>
113
            return sexpr::list(a, "apply", &[toExpr(a, name), sexpr::list(a, "regions", nodeListToExprs(a, regions))]),
114
        case super::TypeSig::Record { fields, .. } =>
115
            return sexpr::list(a, "record", nodeListToExprs(a, fields)),
116
        case super::TypeSig::Fn { sig, isUnsafe } => {
117
            let mut ret = sexpr::sym("void");
118
            if let rt = sig.returnType {
119
                set ret = toExpr(a, rt);
120
            }
121
            let head = "unsafe-fn" if isUnsafe else "fn";
122
            return sexpr::list(a, head, &[sexpr::list(a, "params", nodeListToExprs(a, sig.params)), ret]);
123
        }
124
        case super::TypeSig::TraitObject { class, traitName, mutable } => {
125
            let head = pointerClassHead(class, "obj", "obj-ref", "unsafe-obj");
126
            return sexpr::list(a, head, &[sexpr::sym("mut"), toExpr(a, traitName)]) if mutable
127
                else sexpr::list(a, head, &[toExpr(a, traitName)]);
128
        }
129
    }
130
}
131
132
/// Convert a node slice to a slice of expressions.
133
unsafe fn nodeListToExprs(a: &mut alloc::Arena, nodes: &[*super::Node]) -> *[sexpr::Expr] {
134
    if nodes.len == 0 {
135
        return &[];
136
    }
137
    let buf = try! sexpr::allocExprs(a, nodes.len as u32);
138
    for node, i in nodes {
139
        set buf[i] = toExpr(a, node);
140
    }
141
    return buf;
142
}
143
144
/// Convert optional attributes to an attribute list expression.
145
unsafe fn attributesToExpr(a: &mut alloc::Arena, attrs: ?super::Attributes) -> sexpr::Expr {
146
    let mut exprs: *[sexpr::Expr] = &[];
147
    if let list = attrs {
148
        set exprs = nodeListToExprs(a, list.list);
149
    }
150
    return sexpr::list(a, "attrs", exprs);
151
}
152
153
/// Convert an optional node to an expression, or return placeholder.
154
unsafe fn toExprOpt(a: &mut alloc::Arena, opt: ?*super::Node) -> sexpr::Expr {
155
    if let n = opt {
156
        return toExpr(a, n);
157
    }
158
    return sexpr::sym("_");
159
}
160
161
/// Convert an optional node to an expression, or return `Null`.
162
unsafe fn toExprOrNull(a: &mut alloc::Arena, opt: ?*super::Node) -> sexpr::Expr {
163
    if let n = opt {
164
        return toExpr(a, n);
165
    }
166
    return sexpr::Expr::Null;
167
}
168
169
/// Convert an optional guard.
170
unsafe fn guardExpr(a: &mut alloc::Arena, guard: ?*super::Node) -> sexpr::Expr {
171
    if let g = guard {
172
        return sexpr::list(a, "guard", &[toExpr(a, g)]);
173
    }
174
    return sexpr::Expr::Null;
175
}
176
177
/// Convert a list of match prongs to expressions.
178
unsafe fn prongListToExprs(a: &mut alloc::Arena, nodes: &[*super::Node]) -> *[sexpr::Expr] {
179
    if nodes.len == 0 {
180
        return &[];
181
    }
182
    let buf = try! sexpr::allocExprs(a, nodes.len as u32);
183
    for prong, i in nodes {
184
        match prong.value {
185
            case super::NodeValue::MatchProng(p) => {
186
                set buf[i] = prongToExpr(a, p);
187
            }
188
            else => {
189
                set buf[i] = sexpr::sym("<invalid>");
190
            }
191
        }
192
    }
193
    return buf;
194
}
195
196
/// Convert a match prong to an S-expression.
197
unsafe fn prongToExpr(a: &mut alloc::Arena, p: super::MatchProng) -> sexpr::Expr {
198
    match p.arm {
199
        case super::ProngArm::Case(patterns) => {
200
            return sexpr::block(a, "case", &[
201
                sexpr::list(a, "patterns", nodeListToExprs(a, patterns)),
202
                guardExpr(a, p.guard)
203
            ], &[toExpr(a, p.body)]);
204
        }
205
        case super::ProngArm::Else => {
206
            return sexpr::block(a, "else", &[guardExpr(a, p.guard)], &[toExpr(a, p.body)]);
207
        }
208
        case super::ProngArm::Binding(pat) => {
209
            if let g = p.guard {
210
                return sexpr::block(a, "let", &[toExpr(a, pat), guardExpr(a, p.guard)], &[toExpr(a, p.body)]);
211
            }
212
            return sexpr::block(a, "bind", &[toExpr(a, pat)], &[toExpr(a, p.body)]);
213
        }
214
    }
215
}
216
217
/// Convert a record field declaration to an S-expression.
218
unsafe fn fieldToExpr(
219
    a: &mut alloc::Arena,
220
    field: ?*super::Node,
221
    type: *super::Node,
222
    value: ?*super::Node
223
) -> sexpr::Expr {
224
    return sexpr::list(a, ":", &[toExprOpt(a, field), toExpr(a, type), toExprOrNull(a, value)]);
225
}
226
227
/// Convert a list of record fields to expressions.
228
unsafe fn fieldListToExprs(a: &mut alloc::Arena, nodes: &[*super::Node]) -> *[sexpr::Expr] {
229
    if nodes.len == 0 {
230
        return &[];
231
    }
232
    let buf = try! sexpr::allocExprs(a, nodes.len as u32);
233
    for node, i in nodes {
234
        match node.value {
235
            case super::NodeValue::RecordField { field, type, value } => {
236
                set buf[i] = fieldToExpr(a, field, type, value);
237
            }
238
            else => {
239
                set buf[i] = sexpr::sym("<invalid>");
240
            }
241
        }
242
    }
243
    return buf;
244
}
245
246
/// Convert a union variant to an S-expression.
247
unsafe fn variantToExpr(a: &mut alloc::Arena, name: *super::Node, type: ?*super::Node) -> sexpr::Expr {
248
    return sexpr::list(a, "variant", &[toExpr(a, name), toExprOrNull(a, type)]);
249
}
250
251
/// Convert a list of union variants to expressions.
252
unsafe fn variantListToExprs(a: &mut alloc::Arena, nodes: &[*super::Node]) -> *[sexpr::Expr] {
253
    if nodes.len == 0 {
254
        return &[];
255
    }
256
    let buf = try! sexpr::allocExprs(a, nodes.len as u32);
257
    for node, i in nodes {
258
        match node.value {
259
            case super::NodeValue::UnionDeclVariant(v) => {
260
                set buf[i] = variantToExpr(a, v.name, v.type);
261
            }
262
            else => {
263
                set buf[i] = sexpr::sym("<invalid>");
264
            }
265
        }
266
    }
267
    return buf;
268
}
269
270
/// Convert an AST node to an S-expression.
271
export unsafe fn toExpr(a: &mut alloc::Arena, node: *super::Node) -> sexpr::Expr {
272
    match node.value {
273
        case super::NodeValue::Placeholder => return sexpr::sym("_"),
274
        case super::NodeValue::Nil => return sexpr::sym("nil"),
275
        case super::NodeValue::Undef => return sexpr::sym("undefined"),
276
        case super::NodeValue::Bool(v) => {
277
            if v {
278
                return sexpr::sym("true");
279
            }
280
            return sexpr::sym("false");
281
        }
282
        case super::NodeValue::Char(c) => return sexpr::Expr::Char(c),
283
        case super::NodeValue::String(s) => return sexpr::Expr::Str(s),
284
        case super::NodeValue::Ident(name) => return sexpr::sym(name),
285
        case super::NodeValue::Number(lit) => return sexpr::sym(lit.text),
286
        case super::NodeValue::Super => return sexpr::sym("super"),
287
        case super::NodeValue::Break => return sexpr::list(a, "break", &[]),
288
        case super::NodeValue::Continue => return sexpr::list(a, "continue", &[]),
289
        case super::NodeValue::Range(r) =>
290
            return sexpr::list(a, "range", &[toExprOpt(a, r.start), toExprOpt(a, r.end)]),
291
        case super::NodeValue::BinOp(b) =>
292
            return sexpr::list(a, binOpName(b.op), &[toExpr(a, b.left), toExpr(a, b.right)]),
293
        case super::NodeValue::UnOp(u) =>
294
            return sexpr::list(a, unOpName(u.op), &[toExpr(a, u.value)]),
295
        case super::NodeValue::Call(c) => {
296
            let buf = try! sexpr::allocExprs(a, c.args.len as u32 + 1);
297
            set buf[0] = toExpr(a, c.callee);
298
            for arg, i in c.args { set buf[i + 1] = toExpr(a, arg); }
299
            return sexpr::Expr::List { head: "call", tail: buf, multiline: false };
300
        }
301
        case super::NodeValue::BuiltinCall { kind, args } =>
302
            return sexpr::list(a, builtinName(kind), nodeListToExprs(a, args)),
303
        case super::NodeValue::Subscript { container, index } =>
304
            return sexpr::list(a, "[]", &[toExpr(a, container), toExpr(a, index)]),
305
        case super::NodeValue::FieldAccess(acc) =>
306
            return sexpr::list(a, ".", &[toExpr(a, acc.parent), toExpr(a, acc.child)]),
307
        case super::NodeValue::ScopeAccess(acc) =>
308
            return sexpr::list(a, "::", &[toExpr(a, acc.parent), toExpr(a, acc.child)]),
309
        case super::NodeValue::AddressOf(addr) =>
310
            return sexpr::list(a, "&cell", &[toExpr(a, addr.target)]) if addr.kind == super::AddressKind::Cell
311
                else sexpr::list(a, "&mut", &[toExpr(a, addr.target)]) if addr.kind == super::AddressKind::Mutable
312
                else sexpr::list(a, "&", &[toExpr(a, addr.target)]),
313
        case super::NodeValue::Deref(target) =>
314
            return sexpr::list(a, "deref", &[toExpr(a, target)]),
315
        case super::NodeValue::As(cast) =>
316
            return sexpr::list(a, "as", &[toExpr(a, cast.value), toExpr(a, cast.type)]),
317
        case super::NodeValue::ArrayLit(elems) =>
318
            return sexpr::list(a, "array", nodeListToExprs(a, elems)),
319
        case super::NodeValue::ArrayRepeatLit(rep) =>
320
            return sexpr::list(a, "array-repeat", &[toExpr(a, rep.item), toExpr(a, rep.count)]),
321
        case super::NodeValue::RecordLit(lit) => {
322
            let mut total: u32 = lit.fields.len as u32;
323
            if let _ = lit.typeName {
324
                set total += 1;
325
            }
326
            let buf = try! sexpr::allocExprs(a, total);
327
            let mut idx: u32 = 0;
328
            if let tn = lit.typeName {
329
                set buf[idx] = toExpr(a, tn); set idx = idx + 1;
330
            }
331
            for field, i in lit.fields {
332
                set buf[idx + i] = toExpr(a, field);
333
            }
334
            return sexpr::Expr::List { head: "record-lit", tail: buf, multiline: lit.fields.len > 2 };
335
        }
336
        case super::NodeValue::RecordLitField(f) =>
337
            return sexpr::list(a, "field", &[toExprOpt(a, f.label), toExpr(a, f.value)]),
338
        case super::NodeValue::TypeSig(sig) => return typeSigToExpr(a, sig),
339
        case super::NodeValue::FnParam(p) =>
340
            return sexpr::list(a, "param", &[toExpr(a, p.name), toExpr(a, p.type)]),
341
        case super::NodeValue::Attribute(attr) => {
342
            match attr {
343
                case super::Attribute::Export => return sexpr::sym("@export"),
344
                case super::Attribute::Default => return sexpr::sym("@default"),
345
                case super::Attribute::Extern => return sexpr::sym("@extern"),
346
                case super::Attribute::Test => return sexpr::sym("@test"),
347
                case super::Attribute::Intrinsic => return sexpr::sym("@intrinsic"),
348
                case super::Attribute::Unsafe => return sexpr::sym("@unsafe"),
349
            }
350
        }
351
        case super::NodeValue::Try(t) => {
352
            let mut head = "try";
353
            if t.shouldPanic { set head = "try!"; }
354
            if t.catches.len > 0 {
355
                let catches = nodeListToExprs(a, t.catches);
356
                return sexpr::list(a, head, &[toExpr(a, t.expr), sexpr::block(a, "catches", &[], catches)]);
357
            }
358
            return sexpr::list(a, head, &[toExpr(a, t.expr)]);
359
        }
360
        case super::NodeValue::CatchClause(clause) => {
361
            let mut head = "catch";
362
            let mut children: [sexpr::Expr; 3] = undefined;
363
            let mut len: u32 = 0;
364
            if let b = clause.binding {
365
                set children[len] = toExpr(a, b);
366
                set len += 1;
367
            }
368
            if let t = clause.typeNode {
369
                set children[len] = toExpr(a, t);
370
                set len += 1;
371
            }
372
            set children[len] = toExpr(a, clause.body);
373
            set len += 1;
374
            return sexpr::list(a, head, &children[..len]);
375
        }
376
        case super::NodeValue::Block(blk) => {
377
            let children = nodeListToExprs(a, blk.statements);
378
            let name = "unsafe" if blk.isUnsafe else "block";
379
            return sexpr::block(a, name, &[], children);
380
        }
381
        case super::NodeValue::Let(decl) => {
382
            let mut head = "let";
383
            if decl.mutable { set head = "let-mut"; }
384
            return sexpr::list(a, head, &[
385
                toExpr(a, decl.ident),
386
                toExprOrNull(a, decl.type),
387
                toExpr(a, decl.value)
388
            ]);
389
        }
390
        case super::NodeValue::ConstDecl(decl) =>
391
            return sexpr::list(a, "constant", &[toExpr(a, decl.ident), toExpr(a, decl.type), toExpr(a, decl.value)]),
392
        case super::NodeValue::StaticDecl(decl) =>
393
            return sexpr::list(a, "static", &[toExpr(a, decl.ident), toExpr(a, decl.type), toExpr(a, decl.value)]),
394
        case super::NodeValue::Assign(a_) =>
395
            return sexpr::list(a, "assign", &[toExpr(a, a_.left), toExpr(a, a_.right)]),
396
        case super::NodeValue::Return { value } =>
397
            return sexpr::list(a, "return", &[toExprOrNull(a, value)]),
398
        case super::NodeValue::Throw { expr } =>
399
            return sexpr::list(a, "throw", &[toExpr(a, expr)]),
400
        case super::NodeValue::Panic { message } =>
401
            return sexpr::list(a, "panic", &[toExprOrNull(a, message)]),
402
        case super::NodeValue::Assert { condition, message } =>
403
            return sexpr::list(a, "assert", &[toExpr(a, condition), toExprOrNull(a, message)]),
404
        case super::NodeValue::If(c) =>
405
            return sexpr::block(a, "if", &[toExpr(a, c.condition)],
406
                &[toExpr(a, c.thenBranch), toExprOrNull(a, c.elseBranch)]),
407
        case super::NodeValue::IfLet(c) => {
408
            let label = "if-let-mut" if c.pattern.mutable else "if-let";
409
            return sexpr::block(a, label, &[
410
                toExpr(a, c.pattern.pattern),
411
                toExpr(a, c.pattern.scrutinee),
412
                guardExpr(a, c.pattern.guard)
413
            ], &[
414
                toExpr(a, c.thenBranch),
415
                toExprOrNull(a, c.elseBranch)
416
            ]);
417
        }
418
        case super::NodeValue::LetElse(l) => {
419
            let label = "let-mut-else" if l.pattern.mutable else "let-else";
420
            return sexpr::block(a, label, &[
421
                toExpr(a, l.pattern.pattern),
422
                toExpr(a, l.pattern.scrutinee),
423
                guardExpr(a, l.pattern.guard)
424
            ], &[toExpr(a, l.elseBranch)]);
425
        }
426
        case super::NodeValue::While(w) =>
427
            return sexpr::block(a, "while", &[
428
                toExpr(a, w.condition)
429
            ], &[
430
                toExpr(a, w.body),
431
                toExprOrNull(a, w.elseBranch)
432
            ]),
433
        case super::NodeValue::WhileLet(w) => {
434
            let label = "while-let-mut" if w.pattern.mutable else "while-let";
435
            return sexpr::block(a, label, &[
436
                toExpr(a, w.pattern.pattern),
437
                toExpr(a, w.pattern.scrutinee),
438
                guardExpr(a, w.pattern.guard)
439
            ], &[
440
                toExpr(a, w.body),
441
                toExprOrNull(a, w.elseBranch)
442
            ]);
443
        }
444
        case super::NodeValue::For(f) =>
445
            return sexpr::block(a, "for", &[
446
                toExpr(a, f.binding),
447
                toExprOrNull(a, f.index),
448
                toExpr(a, f.iterable)
449
            ], &[toExpr(a, f.body), toExprOrNull(a, f.elseBranch)]),
450
        case super::NodeValue::Loop { body } =>
451
            return sexpr::block(a, "loop", &[], &[toExpr(a, body)]),
452
        case super::NodeValue::Match(m) => {
453
            let children = prongListToExprs(a, m.prongs);
454
            return sexpr::block(a, "match", &[toExpr(a, m.subject)], children);
455
        }
456
        case super::NodeValue::MatchProng(p) => {
457
            return prongToExpr(a, p);
458
        }
459
        case super::NodeValue::RegionApply { value, regions } =>
460
            return sexpr::list(a, "apply", &[toExpr(a, value), sexpr::list(a, "regions", nodeListToExprs(a, regions))]),
461
        case super::NodeValue::RegionBinding(b) =>
462
            return sexpr::list(a, "binding", &[toExprOrNull(a, b.label), toExpr(a, b.value)]),
463
        case super::NodeValue::Region { name, parent } => {
464
            if let p = parent {
465
                return sexpr::list(a, "region", &[sexpr::sym(name), toExpr(a, p)]);
466
            }
467
            return sexpr::sym(name);
468
        }
469
        case super::NodeValue::RegionBlock { region, bindings, body, isSession } => {
470
            let head = "use-region" if isSession else "let-region";
471
            return sexpr::block(a, head, &[toExpr(a, region), sexpr::list(a, "bindings", nodeListToExprs(a, bindings))], &[toExpr(a, body)]);
472
        }
473
        case super::NodeValue::FnDecl(f) => {
474
            let params = sexpr::list(a, "params", nodeListToExprs(a, f.sig.params));
475
            let ret = toExprOrNull(a, f.sig.returnType);
476
            if f.regions.len > 0 {
477
                let regions = sexpr::list(a, "regions", nodeListToExprs(a, f.regions));
478
                if let body = f.body {
479
                    return sexpr::block(a, "fn", &[toExpr(a, f.name), regions, params, ret], &[toExpr(a, body)]);
480
                }
481
                return sexpr::list(a, "fn", &[toExpr(a, f.name), regions, params, ret]);
482
            }
483
            if let body = f.body {
484
                return sexpr::block(a, "fn", &[toExpr(a, f.name), params, ret], &[toExpr(a, body)]);
485
            }
486
            return sexpr::list(a, "fn", &[toExpr(a, f.name), params, ret]);
487
        }
488
        case super::NodeValue::Mod(m) => return sexpr::list(a, "mod", &[toExpr(a, m.name)]),
489
        case super::NodeValue::Use(u_) => return sexpr::list(a, "use", &[toExpr(a, u_.path)]),
490
        case super::NodeValue::RecordDecl(r) => {
491
            let children = fieldListToExprs(a, r.fields);
492
            if r.regions.len > 0 or r.derives.len > 0 {
493
                return sexpr::block(a, "record", &[
494
                    toExpr(a, r.name),
495
                    sexpr::list(a, "regions", nodeListToExprs(a, r.regions)),
496
                    sexpr::list(a, "derives", nodeListToExprs(a, r.derives)),
497
                ], children);
498
            }
499
            return sexpr::block(a, "record", &[toExpr(a, r.name)], children);
500
        }
501
        case super::NodeValue::RecordField { field, type, value } => {
502
            return fieldToExpr(a, field, type, value);
503
        }
504
        case super::NodeValue::UnionDecl(u_) => {
505
            let children = variantListToExprs(a, u_.variants);
506
            if u_.regions.len > 0 or u_.derives.len > 0 {
507
                return sexpr::block(a, "union", &[
508
                    toExpr(a, u_.name),
509
                    sexpr::list(a, "regions", nodeListToExprs(a, u_.regions)),
510
                    sexpr::list(a, "derives", nodeListToExprs(a, u_.derives)),
511
                ], children);
512
            }
513
            return sexpr::block(a, "union", &[toExpr(a, u_.name)], children);
514
        }
515
        case super::NodeValue::UnionDeclVariant(v) => {
516
            return variantToExpr(a, v.name, v.type);
517
        }
518
        case super::NodeValue::ExprStmt(e) => return toExpr(a, e),
519
        case super::NodeValue::TraitDecl { name, supertraits, methods, .. } => {
520
            let children = nodeListToExprs(a, methods);
521
            let supers = sexpr::list(a, "supertraits", nodeListToExprs(a, supertraits));
522
            return sexpr::block(a, "trait", &[toExpr(a, name), supers], children);
523
        }
524
        case super::NodeValue::TraitMethodSig { name, modifiers, receiver, sig } => {
525
            let regions = modifiers.regions;
526
            let attrs = modifiers.attrs;
527
            let params = sexpr::list(a, "params", nodeListToExprs(a, sig.params));
528
            let ret = toExprOrNull(a, sig.returnType);
529
            let attributes = attributesToExpr(a, attrs);
530
            return sexpr::list(
531
                a,
532
                "methodSig",
533
                &[
534
                    attributes,
535
                    toExpr(a, receiver),
536
                    toExpr(a, name),
537
                    sexpr::list(a, "regions", nodeListToExprs(a, regions)),
538
                    params,
539
                    ret,
540
                ],
541
            );
542
        }
543
        case super::NodeValue::InstanceDecl { traitName, targetType, regions, methods } => {
544
            let children = nodeListToExprs(a, methods);
545
            return sexpr::block(a, "instance", &[
546
                toExpr(a, traitName),
547
                toExpr(a, targetType),
548
                sexpr::list(a, "regions", nodeListToExprs(a, regions)),
549
            ], children);
550
        }
551
        case super::NodeValue::MethodDecl {
552
            name, modifiers, receiverName, receiverType, sig, body,
553
        } => {
554
            let regions = modifiers.regions;
555
            let attrs = modifiers.attrs;
556
            let params = sexpr::list(a, "params", nodeListToExprs(a, sig.params));
557
            let ret = toExprOrNull(a, sig.returnType);
558
            let attributes = attributesToExpr(a, attrs);
559
            return sexpr::block(
560
                a,
561
                "method",
562
                &[
563
                    attributes,
564
                    toExpr(a, receiverType),
565
                    toExpr(a, receiverName),
566
                    toExpr(a, name),
567
                    sexpr::list(a, "regions", nodeListToExprs(a, regions)),
568
                    params,
569
                    ret,
570
                ],
571
                &[toExpr(a, body)],
572
            );
573
        }
574
        else => return sexpr::sym("?"),
575
    }
576
}
577
578
/// Dump the tree rooted at `root`, using the provided arena for allocation.
579
export unsafe fn printTree(root: *super::Node, arena: &mut alloc::Arena) {
580
    match root.value {
581
        case super::NodeValue::Block(blk) => {
582
            for stmt, i in blk.statements {
583
                sexpr::print(toExpr(arena, stmt), 0);
584
                if i < blk.statements.len - 1 { io::print("\n\n"); }
585
            }
586
            io::print("\n");
587
        }
588
        else => {
589
            sexpr::print(toExpr(arena, root), 0);
590
            io::print("\n");
591
        }
592
    }
593
}