lib/std/lang/ast/printer.rad 20.4 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
            }
311
        }
312
        case super::NodeValue::Try(t) => {
313
            let mut head = "try";
314
            if t.shouldPanic { head = "try!"; }
315
            if t.catches.len > 0 {
316
                let catches = nodeListToExprs(a, &t.catches[..]);
317
                return sexpr::list(a, head, &[toExpr(a, t.expr), sexpr::block(a, "catches", &[], catches)]);
318
            }
319
            return sexpr::list(a, head, &[toExpr(a, t.expr)]);
320
        }
321
        case super::NodeValue::CatchClause(clause) => {
322
            let mut head = "catch";
323
            let mut children: [sexpr::Expr; 3] = undefined;
324
            let mut len: u32 = 0;
325
            if let b = clause.binding {
326
                children[len] = toExpr(a, b);
327
                len += 1;
328
            }
329
            if let t = clause.typeNode {
330
                children[len] = toExpr(a, t);
331
                len += 1;
332
            }
333
            children[len] = toExpr(a, clause.body);
334
            len += 1;
335
            return sexpr::list(a, head, &children[..len]);
336
        }
337
        case super::NodeValue::Block(blk) => {
338
            let children = nodeListToExprs(a, &blk.statements[..]);
339
            return sexpr::block(a, "block", &[], children);
340
        }
341
        case super::NodeValue::Let(decl) => {
342
            let mut head = "let";
343
            if decl.mutable { head = "let-mut"; }
344
            return sexpr::list(a, head, &[
345
                toExpr(a, decl.ident),
346
                toExprOrNull(a, decl.type),
347
                toExpr(a, decl.value)
348
            ]);
349
        }
350
        case super::NodeValue::ConstDecl(decl) =>
351
            return sexpr::list(a, "const", &[toExpr(a, decl.ident), toExpr(a, decl.type), toExpr(a, decl.value)]),
352
        case super::NodeValue::StaticDecl(decl) =>
353
            return sexpr::list(a, "static", &[toExpr(a, decl.ident), toExpr(a, decl.type), toExpr(a, decl.value)]),
354
        case super::NodeValue::Assign(a_) =>
355
            return sexpr::list(a, "assign", &[toExpr(a, a_.left), toExpr(a, a_.right)]),
356
        case super::NodeValue::Return { value } =>
357
            return sexpr::list(a, "return", &[toExprOrNull(a, value)]),
358
        case super::NodeValue::Throw { expr } =>
359
            return sexpr::list(a, "throw", &[toExpr(a, expr)]),
360
        case super::NodeValue::Panic { message } =>
361
            return sexpr::list(a, "panic", &[toExprOrNull(a, message)]),
362
        case super::NodeValue::Assert { condition, message } =>
363
            return sexpr::list(a, "assert", &[toExpr(a, condition), toExprOrNull(a, message)]),
364
        case super::NodeValue::If(c) =>
365
            return sexpr::block(a, "if", &[toExpr(a, c.condition)],
366
                &[toExpr(a, c.thenBranch), toExprOrNull(a, c.elseBranch)]),
367
        case super::NodeValue::IfLet(c) => {
368
            let label = "if-let-mut" if c.pattern.mutable else "if-let";
369
            return sexpr::block(a, label, &[
370
                toExpr(a, c.pattern.pattern),
371
                toExpr(a, c.pattern.scrutinee),
372
                guardExpr(a, c.pattern.guard)
373
            ], &[
374
                toExpr(a, c.thenBranch),
375
                toExprOrNull(a, c.elseBranch)
376
            ]);
377
        }
378
        case super::NodeValue::LetElse(l) => {
379
            let label = "let-mut-else" if l.pattern.mutable else "let-else";
380
            return sexpr::block(a, label, &[
381
                toExpr(a, l.pattern.pattern),
382
                toExpr(a, l.pattern.scrutinee),
383
                guardExpr(a, l.pattern.guard)
384
            ], &[toExpr(a, l.elseBranch)]);
385
        }
386
        case super::NodeValue::While(w) =>
387
            return sexpr::block(a, "while", &[
388
                toExpr(a, w.condition)
389
            ], &[
390
                toExpr(a, w.body),
391
                toExprOrNull(a, w.elseBranch)
392
            ]),
393
        case super::NodeValue::WhileLet(w) => {
394
            let label = "while-let-mut" if w.pattern.mutable else "while-let";
395
            return sexpr::block(a, label, &[
396
                toExpr(a, w.pattern.pattern),
397
                toExpr(a, w.pattern.scrutinee),
398
                guardExpr(a, w.pattern.guard)
399
            ], &[
400
                toExpr(a, w.body),
401
                toExprOrNull(a, w.elseBranch)
402
            ]);
403
        }
404
        case super::NodeValue::For(f) =>
405
            return sexpr::block(a, "for", &[
406
                toExpr(a, f.binding),
407
                toExprOrNull(a, f.index),
408
                toExpr(a, f.iterable)
409
            ], &[toExpr(a, f.body), toExprOrNull(a, f.elseBranch)]),
410
        case super::NodeValue::Loop { body } =>
411
            return sexpr::block(a, "loop", &[], &[toExpr(a, body)]),
412
        case super::NodeValue::Match(m) => {
413
            let children = prongListToExprs(a, &m.prongs[..]);
414
            return sexpr::block(a, "match", &[toExpr(a, m.subject)], children);
415
        }
416
        case super::NodeValue::MatchProng(p) => {
417
            return prongToExpr(a, p);
418
        }
419
        case super::NodeValue::FnDecl(f) => {
420
            let params = sexpr::list(a, "params", nodeListToExprs(a, &f.sig.params[..]));
421
            let ret = toExprOrNull(a, f.sig.returnType);
422
            if let body = f.body {
423
                return sexpr::block(a, "fn", &[toExpr(a, f.name), params, ret], &[toExpr(a, body)]);
424
            }
425
            return sexpr::list(a, "fn", &[toExpr(a, f.name), params, ret]);
426
        }
427
        case super::NodeValue::Mod(m) => return sexpr::list(a, "mod", &[toExpr(a, m.name)]),
428
        case super::NodeValue::Use(u_) => return sexpr::list(a, "use", &[toExpr(a, u_.path)]),
429
        case super::NodeValue::RecordDecl(r) => {
430
            let children = fieldListToExprs(a, &r.fields[..]);
431
            return sexpr::block(a, "record", &[toExpr(a, r.name)], children);
432
        }
433
        case super::NodeValue::RecordField { field, type, value } => {
434
            return fieldToExpr(a, field, type, value);
435
        }
436
        case super::NodeValue::UnionDecl(u_) => {
437
            let children = variantListToExprs(a, &u_.variants[..]);
438
            return sexpr::block(a, "union", &[toExpr(a, u_.name)], children);
439
        }
440
        case super::NodeValue::UnionDeclVariant(v) => {
441
            return variantToExpr(a, v.name, v.type);
442
        }
443
        case super::NodeValue::ExprStmt(e) => return toExpr(a, e),
444
        case super::NodeValue::TraitDecl { name, supertraits, methods, .. } => {
445
            let children = nodeListToExprs(a, &methods[..]);
446
            let supers = sexpr::list(a, "supertraits", nodeListToExprs(a, &supertraits[..]));
447
            return sexpr::block(a, "trait", &[toExpr(a, name), supers], children);
448
        }
449
        case super::NodeValue::TraitMethodSig { name, receiver, sig } => {
450
            let params = sexpr::list(a, "params", nodeListToExprs(a, &sig.params[..]));
451
            let ret = toExprOrNull(a, sig.returnType);
452
            return sexpr::list(a, "methodSig", &[toExpr(a, receiver), toExpr(a, name), params, ret]);
453
        }
454
        case super::NodeValue::InstanceDecl { traitName, targetType, methods } => {
455
            let children = nodeListToExprs(a, &methods[..]);
456
            return sexpr::block(a, "instance", &[toExpr(a, traitName), toExpr(a, targetType)], children);
457
        }
458
        case super::NodeValue::InstanceMethodDecl { name, receiverName, receiverType, sig, body } => {
459
            let params = sexpr::list(a, "params", nodeListToExprs(a, &sig.params[..]));
460
            let ret = toExprOrNull(a, sig.returnType);
461
            return sexpr::block(a, "method", &[toExpr(a, receiverType), toExpr(a, receiverName), toExpr(a, name), params, ret], &[toExpr(a, body)]);
462
        }
463
        else => return sexpr::sym("?"),
464
    }
465
}
466
467
/// Dump the tree rooted at `root`, using the provided arena for allocation.
468
pub fn printTree(root: *super::Node, arena: *mut alloc::Arena) {
469
    match root.value {
470
        case super::NodeValue::Block(blk) => {
471
            for stmt, i in blk.statements {
472
                sexpr::print(toExpr(arena, stmt), 0);
473
                if i < blk.statements.len - 1 { io::print("\n\n"); }
474
            }
475
            io::print("\n");
476
        }
477
        else => {
478
            sexpr::print(toExpr(arena, root), 0);
479
            io::print("\n");
480
        }
481
    }
482
}