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