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