lib/std/lang/ast/printer.rad 20.6 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
/// Convert a type signature to an S-expression.
72
fn typeSigToExpr(a: *mut alloc::Arena, sig: super::TypeSig) -> sexpr::Expr {
73
    match sig {
74
        case super::TypeSig::Void => return sexpr::sym("void"),
75
        case super::TypeSig::Opaque => return sexpr::sym("opaque"),
76
        case super::TypeSig::Bool => return sexpr::sym("bool"),
77
        case super::TypeSig::Integer { width, sign } => return sexpr::sym(intTypeName(width, sign)),
78
        case super::TypeSig::Array { itemType, length } =>
79
            return sexpr::list(a, "array", &[toExpr(a, itemType), toExpr(a, length)]),
80
        case super::TypeSig::Slice { itemType, mutable } =>
81
            return sexpr::list(a, "slice", &[sexpr::sym("mut"), toExpr(a, itemType)]) if mutable
82
                else sexpr::list(a, "slice", &[toExpr(a, itemType)]),
83
        case super::TypeSig::Pointer { valueType, mutable } =>
84
            return sexpr::list(a, "ptr", &[sexpr::sym("mut"), toExpr(a, valueType)]) if mutable
85
                else sexpr::list(a, "ptr", &[toExpr(a, valueType)]),
86
        case super::TypeSig::Optional { valueType } =>
87
            return sexpr::list(a, "?", &[toExpr(a, valueType)]),
88
        case super::TypeSig::Nominal(name) => return toExpr(a, name),
89
        case super::TypeSig::Record { fields, .. } =>
90
            return sexpr::list(a, "record", nodeListToExprs(a, &fields[..])),
91
        case super::TypeSig::Fn(sig) => {
92
            let mut ret = sexpr::sym("void");
93
            if let rt = sig.returnType {
94
                ret = toExpr(a, rt);
95
            }
96
            return sexpr::list(a, "fn", &[sexpr::list(a, "params", nodeListToExprs(a, &sig.params[..])), ret]);
97
        }
98
        case super::TypeSig::TraitObject { traitName, mutable } =>
99
            return sexpr::list(a, "obj", &[sexpr::sym("mut"), toExpr(a, traitName)]) if mutable
100
                else sexpr::list(a, "obj", &[toExpr(a, traitName)]),
101
    }
102
}
103
104
/// Convert a node slice to a slice of expressions.
105
fn nodeListToExprs(a: *mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] {
106
    if nodes.len == 0 {
107
        return &[];
108
    }
109
    let buf = try! sexpr::allocExprs(a, nodes.len as u32);
110
    for node, i in nodes {
111
        buf[i] = toExpr(a, node);
112
    }
113
    return buf;
114
}
115
116
/// Convert an optional node to an expression, or return placeholder.
117
fn toExprOpt(a: *mut alloc::Arena, opt: ?*super::Node) -> sexpr::Expr {
118
    if let n = opt {
119
        return toExpr(a, n);
120
    }
121
    return sexpr::sym("_");
122
}
123
124
/// Convert an optional node to an expression, or return `Null`.
125
fn toExprOrNull(a: *mut alloc::Arena, opt: ?*super::Node) -> sexpr::Expr {
126
    if let n = opt {
127
        return toExpr(a, n);
128
    }
129
    return sexpr::Expr::Null;
130
}
131
132
/// Convert an optional guard.
133
fn guardExpr(a: *mut alloc::Arena, guard: ?*super::Node) -> sexpr::Expr {
134
    if let g = guard {
135
        return sexpr::list(a, "guard", &[toExpr(a, g)]);
136
    }
137
    return sexpr::Expr::Null;
138
}
139
140
/// Convert a list of match prongs to expressions.
141
fn prongListToExprs(a: *mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] {
142
    if nodes.len == 0 {
143
        return &[];
144
    }
145
    let buf = try! sexpr::allocExprs(a, nodes.len as u32);
146
    for prong, i in nodes {
147
        match prong.value {
148
            case super::NodeValue::MatchProng(p) => {
149
                buf[i] = prongToExpr(a, p);
150
            }
151
            else => {
152
                buf[i] = sexpr::sym("<invalid>");
153
            }
154
        }
155
    }
156
    return buf;
157
}
158
159
/// Convert a match prong to an S-expression.
160
fn prongToExpr(a: *mut alloc::Arena, p: super::MatchProng) -> sexpr::Expr {
161
    match p.arm {
162
        case super::ProngArm::Case(patterns) => {
163
            return sexpr::block(a, "case", &[
164
                sexpr::list(a, "patterns", nodeListToExprs(a, &patterns[..])),
165
                guardExpr(a, p.guard)
166
            ], &[toExpr(a, p.body)]);
167
        }
168
        case super::ProngArm::Else => {
169
            return sexpr::block(a, "else", &[guardExpr(a, p.guard)], &[toExpr(a, p.body)]);
170
        }
171
        case super::ProngArm::Binding(pat) => {
172
            if let g = p.guard {
173
                return sexpr::block(a, "let", &[toExpr(a, pat), guardExpr(a, p.guard)], &[toExpr(a, p.body)]);
174
            }
175
            return sexpr::block(a, "bind", &[toExpr(a, pat)], &[toExpr(a, p.body)]);
176
        }
177
    }
178
}
179
180
/// Convert a record field declaration to an S-expression.
181
fn fieldToExpr(
182
    a: *mut alloc::Arena,
183
    field: ?*super::Node,
184
    type: *super::Node,
185
    value: ?*super::Node
186
) -> sexpr::Expr {
187
    return sexpr::list(a, ":", &[toExprOpt(a, field), toExpr(a, type), toExprOrNull(a, value)]);
188
}
189
190
/// Convert a list of record fields to expressions.
191
fn fieldListToExprs(a: *mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] {
192
    if nodes.len == 0 {
193
        return &[];
194
    }
195
    let buf = try! sexpr::allocExprs(a, nodes.len as u32);
196
    for node, i in nodes {
197
        match node.value {
198
            case super::NodeValue::RecordField { field, type, value } => {
199
                buf[i] = fieldToExpr(a, field, type, value);
200
            }
201
            else => {
202
                buf[i] = sexpr::sym("<invalid>");
203
            }
204
        }
205
    }
206
    return buf;
207
}
208
209
/// Convert a union variant to an S-expression.
210
fn variantToExpr(a: *mut alloc::Arena, name: *super::Node, type: ?*super::Node) -> sexpr::Expr {
211
    return sexpr::list(a, "variant", &[toExpr(a, name), toExprOrNull(a, type)]);
212
}
213
214
/// Convert a list of union variants to expressions.
215
fn variantListToExprs(a: *mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] {
216
    if nodes.len == 0 {
217
        return &[];
218
    }
219
    let buf = try! sexpr::allocExprs(a, nodes.len as u32);
220
    for node, i in nodes {
221
        match node.value {
222
            case super::NodeValue::UnionDeclVariant(v) => {
223
                buf[i] = variantToExpr(a, v.name, v.type);
224
            }
225
            else => {
226
                buf[i] = sexpr::sym("<invalid>");
227
            }
228
        }
229
    }
230
    return buf;
231
}
232
233
/// Convert an AST node to an S-expression.
234
pub fn toExpr(a: *mut alloc::Arena, node: *super::Node) -> sexpr::Expr {
235
    match node.value {
236
        case super::NodeValue::Placeholder => return sexpr::sym("_"),
237
        case super::NodeValue::Nil => return sexpr::sym("nil"),
238
        case super::NodeValue::Undef => return sexpr::sym("undefined"),
239
        case super::NodeValue::Bool(v) => {
240
            if v {
241
                return sexpr::sym("true");
242
            }
243
            return sexpr::sym("false");
244
        }
245
        case super::NodeValue::Char(c) => return sexpr::Expr::Char(c),
246
        case super::NodeValue::String(s) => return sexpr::Expr::Str(s),
247
        case super::NodeValue::Ident(name) => return sexpr::sym(name),
248
        case super::NodeValue::Number(lit) => return sexpr::sym(lit.text),
249
        case super::NodeValue::Super => return sexpr::sym("super"),
250
        case super::NodeValue::Break => return sexpr::list(a, "break", &[]),
251
        case super::NodeValue::Continue => return sexpr::list(a, "continue", &[]),
252
        case super::NodeValue::Range(r) =>
253
            return sexpr::list(a, "range", &[toExprOpt(a, r.start), toExprOpt(a, r.end)]),
254
        case super::NodeValue::BinOp(b) =>
255
            return sexpr::list(a, binOpName(b.op), &[toExpr(a, b.left), toExpr(a, b.right)]),
256
        case super::NodeValue::UnOp(u) =>
257
            return sexpr::list(a, unOpName(u.op), &[toExpr(a, u.value)]),
258
        case super::NodeValue::Call(c) => {
259
            let buf = try! sexpr::allocExprs(a, c.args.len as u32 + 1);
260
            buf[0] = toExpr(a, c.callee);
261
            for arg, i in c.args { buf[i + 1] = toExpr(a, arg); }
262
            return sexpr::Expr::List { head: "call", tail: buf, multiline: false };
263
        }
264
        case super::NodeValue::BuiltinCall { kind, args } =>
265
            return sexpr::list(a, builtinName(kind), nodeListToExprs(a, &args[..])),
266
        case super::NodeValue::Subscript { container, index } =>
267
            return sexpr::list(a, "[]", &[toExpr(a, container), toExpr(a, index)]),
268
        case super::NodeValue::FieldAccess(acc) =>
269
            return sexpr::list(a, ".", &[toExpr(a, acc.parent), toExpr(a, acc.child)]),
270
        case super::NodeValue::ScopeAccess(acc) =>
271
            return sexpr::list(a, "::", &[toExpr(a, acc.parent), toExpr(a, acc.child)]),
272
        case super::NodeValue::AddressOf(addr) =>
273
            return sexpr::list(a, "&mut", &[toExpr(a, addr.target)]) if addr.mutable
274
                else sexpr::list(a, "&", &[toExpr(a, addr.target)]),
275
        case super::NodeValue::Deref(target) =>
276
            return sexpr::list(a, "deref", &[toExpr(a, target)]),
277
        case super::NodeValue::As(cast) =>
278
            return sexpr::list(a, "as", &[toExpr(a, cast.value), toExpr(a, cast.type)]),
279
        case super::NodeValue::ArrayLit(elems) =>
280
            return sexpr::list(a, "array", nodeListToExprs(a, &elems[..])),
281
        case super::NodeValue::ArrayRepeatLit(rep) =>
282
            return sexpr::list(a, "array-repeat", &[toExpr(a, rep.item), toExpr(a, rep.count)]),
283
        case super::NodeValue::RecordLit(lit) => {
284
            let mut total: u32 = lit.fields.len as u32;
285
            if let _ = lit.typeName {
286
                total += 1;
287
            }
288
            let buf = try! sexpr::allocExprs(a, total);
289
            let mut idx: u32 = 0;
290
            if let tn = lit.typeName {
291
                buf[idx] = toExpr(a, tn); idx = idx + 1;
292
            }
293
            for field, i in lit.fields {
294
                buf[idx + i] = toExpr(a, field);
295
            }
296
            return sexpr::Expr::List { head: "record-lit", tail: buf, multiline: lit.fields.len > 2 };
297
        }
298
        case super::NodeValue::RecordLitField(f) =>
299
            return sexpr::list(a, "field", &[toExprOpt(a, f.label), toExpr(a, f.value)]),
300
        case super::NodeValue::TypeSig(sig) => return typeSigToExpr(a, sig),
301
        case super::NodeValue::FnParam(p) =>
302
            return sexpr::list(a, "param", &[toExpr(a, p.name), toExpr(a, p.type)]),
303
        case super::NodeValue::Attribute(attr) => {
304
            match attr {
305
                case super::Attribute::Pub => return sexpr::sym("@pub"),
306
                case super::Attribute::Default => return sexpr::sym("@default"),
307
                case super::Attribute::Extern => return sexpr::sym("@extern"),
308
                case super::Attribute::Test => return sexpr::sym("@test"),
309
                case super::Attribute::Intrinsic => return sexpr::sym("@intrinsic"),
310
                case super::Attribute::Unsafe => return sexpr::sym("unsafe"),
311
            }
312
        }
313
        case super::NodeValue::Try(t) => {
314
            let mut head = "try";
315
            if t.shouldPanic { head = "try!"; }
316
            if t.catches.len > 0 {
317
                let catches = nodeListToExprs(a, &t.catches[..]);
318
                return sexpr::list(a, head, &[toExpr(a, t.expr), sexpr::block(a, "catches", &[], catches)]);
319
            }
320
            return sexpr::list(a, head, &[toExpr(a, t.expr)]);
321
        }
322
        case super::NodeValue::CatchClause(clause) => {
323
            let mut head = "catch";
324
            let mut children: [sexpr::Expr; 3] = undefined;
325
            let mut len: u32 = 0;
326
            if let b = clause.binding {
327
                children[len] = toExpr(a, b);
328
                len += 1;
329
            }
330
            if let t = clause.typeNode {
331
                children[len] = toExpr(a, t);
332
                len += 1;
333
            }
334
            children[len] = toExpr(a, clause.body);
335
            len += 1;
336
            return sexpr::list(a, head, &children[..len]);
337
        }
338
        case super::NodeValue::Block(blk) => {
339
            let children = nodeListToExprs(a, &blk.statements[..]);
340
            return sexpr::block(a, "block", &[], children);
341
        }
342
        case super::NodeValue::UnsafeBlock(inner) => {
343
            return sexpr::list(a, "unsafe", &[toExpr(a, inner)]);
344
        }
345
        case super::NodeValue::Let(decl) => {
346
            let mut head = "let";
347
            if decl.mutable { head = "let-mut"; }
348
            return sexpr::list(a, head, &[
349
                toExpr(a, decl.ident),
350
                toExprOrNull(a, decl.type),
351
                toExpr(a, decl.value)
352
            ]);
353
        }
354
        case super::NodeValue::ConstDecl(decl) =>
355
            return sexpr::list(a, "const", &[toExpr(a, decl.ident), toExpr(a, decl.type), toExpr(a, decl.value)]),
356
        case super::NodeValue::StaticDecl(decl) =>
357
            return sexpr::list(a, "static", &[toExpr(a, decl.ident), toExpr(a, decl.type), toExpr(a, decl.value)]),
358
        case super::NodeValue::Assign(a_) =>
359
            return sexpr::list(a, "assign", &[toExpr(a, a_.left), toExpr(a, a_.right)]),
360
        case super::NodeValue::Return { value } =>
361
            return sexpr::list(a, "return", &[toExprOrNull(a, value)]),
362
        case super::NodeValue::Throw { expr } =>
363
            return sexpr::list(a, "throw", &[toExpr(a, expr)]),
364
        case super::NodeValue::Panic { message } =>
365
            return sexpr::list(a, "panic", &[toExprOrNull(a, message)]),
366
        case super::NodeValue::Assert { condition, message } =>
367
            return sexpr::list(a, "assert", &[toExpr(a, condition), toExprOrNull(a, message)]),
368
        case super::NodeValue::If(c) =>
369
            return sexpr::block(a, "if", &[toExpr(a, c.condition)],
370
                &[toExpr(a, c.thenBranch), toExprOrNull(a, c.elseBranch)]),
371
        case super::NodeValue::IfLet(c) => {
372
            let label = "if-let-mut" if c.pattern.mutable else "if-let";
373
            return sexpr::block(a, label, &[
374
                toExpr(a, c.pattern.pattern),
375
                toExpr(a, c.pattern.scrutinee),
376
                guardExpr(a, c.pattern.guard)
377
            ], &[
378
                toExpr(a, c.thenBranch),
379
                toExprOrNull(a, c.elseBranch)
380
            ]);
381
        }
382
        case super::NodeValue::LetElse(l) => {
383
            let label = "let-mut-else" if l.pattern.mutable else "let-else";
384
            return sexpr::block(a, label, &[
385
                toExpr(a, l.pattern.pattern),
386
                toExpr(a, l.pattern.scrutinee),
387
                guardExpr(a, l.pattern.guard)
388
            ], &[toExpr(a, l.elseBranch)]);
389
        }
390
        case super::NodeValue::While(w) =>
391
            return sexpr::block(a, "while", &[
392
                toExpr(a, w.condition)
393
            ], &[
394
                toExpr(a, w.body),
395
                toExprOrNull(a, w.elseBranch)
396
            ]),
397
        case super::NodeValue::WhileLet(w) => {
398
            let label = "while-let-mut" if w.pattern.mutable else "while-let";
399
            return sexpr::block(a, label, &[
400
                toExpr(a, w.pattern.pattern),
401
                toExpr(a, w.pattern.scrutinee),
402
                guardExpr(a, w.pattern.guard)
403
            ], &[
404
                toExpr(a, w.body),
405
                toExprOrNull(a, w.elseBranch)
406
            ]);
407
        }
408
        case super::NodeValue::For(f) =>
409
            return sexpr::block(a, "for", &[
410
                toExpr(a, f.binding),
411
                toExprOrNull(a, f.index),
412
                toExpr(a, f.iterable)
413
            ], &[toExpr(a, f.body), toExprOrNull(a, f.elseBranch)]),
414
        case super::NodeValue::Loop { body } =>
415
            return sexpr::block(a, "loop", &[], &[toExpr(a, body)]),
416
        case super::NodeValue::Match(m) => {
417
            let children = prongListToExprs(a, &m.prongs[..]);
418
            return sexpr::block(a, "match", &[toExpr(a, m.subject)], children);
419
        }
420
        case super::NodeValue::MatchProng(p) => {
421
            return prongToExpr(a, p);
422
        }
423
        case super::NodeValue::FnDecl(f) => {
424
            let params = sexpr::list(a, "params", nodeListToExprs(a, &f.sig.params[..]));
425
            let ret = toExprOrNull(a, f.sig.returnType);
426
            if let body = f.body {
427
                return sexpr::block(a, "fn", &[toExpr(a, f.name), params, ret], &[toExpr(a, body)]);
428
            }
429
            return sexpr::list(a, "fn", &[toExpr(a, f.name), params, ret]);
430
        }
431
        case super::NodeValue::Mod(m) => return sexpr::list(a, "mod", &[toExpr(a, m.name)]),
432
        case super::NodeValue::Use(u_) => return sexpr::list(a, "use", &[toExpr(a, u_.path)]),
433
        case super::NodeValue::RecordDecl(r) => {
434
            let children = fieldListToExprs(a, &r.fields[..]);
435
            return sexpr::block(a, "record", &[toExpr(a, r.name)], children);
436
        }
437
        case super::NodeValue::RecordField { field, type, value } => {
438
            return fieldToExpr(a, field, type, value);
439
        }
440
        case super::NodeValue::UnionDecl(u_) => {
441
            let children = variantListToExprs(a, &u_.variants[..]);
442
            return sexpr::block(a, "union", &[toExpr(a, u_.name)], children);
443
        }
444
        case super::NodeValue::UnionDeclVariant(v) => {
445
            return variantToExpr(a, v.name, v.type);
446
        }
447
        case super::NodeValue::ExprStmt(e) => return toExpr(a, e),
448
        case super::NodeValue::TraitDecl { name, supertraits, methods, .. } => {
449
            let children = nodeListToExprs(a, &methods[..]);
450
            let supers = sexpr::list(a, "supertraits", nodeListToExprs(a, &supertraits[..]));
451
            return sexpr::block(a, "trait", &[toExpr(a, name), supers], children);
452
        }
453
        case super::NodeValue::TraitMethodSig { name, receiver, sig } => {
454
            let params = sexpr::list(a, "params", nodeListToExprs(a, &sig.params[..]));
455
            let ret = toExprOrNull(a, sig.returnType);
456
            return sexpr::list(a, "methodSig", &[toExpr(a, receiver), toExpr(a, name), params, ret]);
457
        }
458
        case super::NodeValue::InstanceDecl { traitName, targetType, methods } => {
459
            let children = nodeListToExprs(a, &methods[..]);
460
            return sexpr::block(a, "instance", &[toExpr(a, traitName), toExpr(a, targetType)], children);
461
        }
462
        case super::NodeValue::MethodDecl { name, receiverName, receiverType, sig, body, .. } => {
463
            let params = sexpr::list(a, "params", nodeListToExprs(a, &sig.params[..]));
464
            let ret = toExprOrNull(a, sig.returnType);
465
            return sexpr::block(a, "method", &[toExpr(a, receiverType), toExpr(a, receiverName), toExpr(a, name), params, ret], &[toExpr(a, body)]);
466
        }
467
        else => return sexpr::sym("?"),
468
    }
469
}
470
471
/// Dump the tree rooted at `root`, using the provided arena for allocation.
472
pub fn printTree(root: *super::Node, arena: *mut alloc::Arena) {
473
    match root.value {
474
        case super::NodeValue::Block(blk) => {
475
            for stmt, i in blk.statements {
476
                sexpr::print(toExpr(arena, stmt), 0);
477
                if i < blk.statements.len - 1 { io::print("\n\n"); }
478
            }
479
            io::print("\n");
480
        }
481
        else => {
482
            sexpr::print(toExpr(arena, root), 0);
483
            io::print("\n");
484
        }
485
    }
486
}