compiler/
kernel/
lib/
examples/
std/
arch/
char/
collections/
lang/
alloc/
ast/
gen/
il/
module/
parser/
resolver/
scanner/
alloc.rad
7.1 KiB
ast.rad
26.7 KiB
gen.rad
513 B
il.rad
19.5 KiB
lower.rad
308.1 KiB
module.rad
14.9 KiB
package.rad
1.3 KiB
parser.rad
89.5 KiB
resolver.rad
439.6 KiB
scanner.rad
18.0 KiB
sexpr.rad
6.4 KiB
strings.rad
2.2 KiB
types.rad
1.6 KiB
sys/
arch.rad
68 B
char.rad
855 B
collections.rad
39 B
fmt.rad
8.3 KiB
intrinsics.rad
467 B
io.rad
1.7 KiB
lang.rad
276 B
mem.rad
2.3 KiB
sys.rad
179 B
testing.rad
2.4 KiB
tests.rad
15.7 KiB
vec.rad
3.2 KiB
std.rad
281 B
scripts/
seed/
sublime/
test/
vim/
.gitignore
336 B
.gitsigners
112 B
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
9.2 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
662 B
lib/std/lang/sexpr.rad
raw
| 1 | //! S-expression data structure and printer. |
| 2 | //! |
| 3 | //! Provides a data structure for representing S-expressions and functions |
| 4 | //! to print them with proper formatting. Uses an arena allocator for storage. |
| 5 | |
| 6 | use std::io; |
| 7 | use std::lang::alloc; |
| 8 | |
| 9 | /// Output target for S-expression printing. |
| 10 | export union Output: Copy { |
| 11 | /// Print to stdout. |
| 12 | Stdout, |
| 13 | /// Write to a buffer, tracking position. |
| 14 | Buffer { buf: *unsafe mut [u8], pos: *unsafe mut u32 }, |
| 15 | } |
| 16 | |
| 17 | /// An S-expression element. |
| 18 | export union Expr: Copy { |
| 19 | /// An empty expression. |
| 20 | Null, |
| 21 | /// A symbol/identifier. |
| 22 | Sym(*[u8]), |
| 23 | /// A quoted string literal. |
| 24 | Str(*[u8]), |
| 25 | /// A character literal. |
| 26 | Char(u8), |
| 27 | /// A list with a head and tail. If `multiline` is `true`, items are printed one per line. |
| 28 | List { head: *[u8], tail: *[Expr], multiline: bool }, |
| 29 | /// A bracket-delimited list `[...]` for block parameters and arguments. |
| 30 | Vec { items: *[Expr] }, |
| 31 | /// A block with a name, inline items, and child statements on separate lines. |
| 32 | Block { name: *[u8], items: *[Expr], children: *[Expr] }, |
| 33 | } |
| 34 | |
| 35 | /// Allocate an array of Expr in the arena. |
| 36 | export unsafe fn allocExprs(arena: &mut alloc::Arena, len: u32) -> *mut [Expr] throws (alloc::AllocError) { |
| 37 | if len == 0 { |
| 38 | throw alloc::AllocError::OutOfMemory; |
| 39 | } |
| 40 | let ptr = try alloc::allocSlice(arena, @sizeOf(Expr), @alignOf(Expr), len); |
| 41 | return ptr as *mut [Expr]; |
| 42 | } |
| 43 | |
| 44 | /// Allocate and copy items into the arena. |
| 45 | export unsafe fn allocItems(a: &mut alloc::Arena, items: &[Expr]) -> *[Expr] { |
| 46 | if items.len == 0 { |
| 47 | return &[]; |
| 48 | } |
| 49 | let buf = try! allocExprs(a, items.len); |
| 50 | for item, i in items { |
| 51 | set buf[i] = item; |
| 52 | } |
| 53 | return buf; |
| 54 | } |
| 55 | |
| 56 | /// Shorthand for creating a symbol. |
| 57 | export fn sym(s: *[u8]) -> Expr { |
| 58 | return Expr::Sym(s); |
| 59 | } |
| 60 | |
| 61 | /// Shorthand for creating a string literal. |
| 62 | export fn str(s: *[u8]) -> Expr { |
| 63 | return Expr::Str(s); |
| 64 | } |
| 65 | |
| 66 | /// Shorthand for creating a list. |
| 67 | export unsafe fn list(a: &mut alloc::Arena, head: *[u8], tail: &[Expr]) -> Expr { |
| 68 | return Expr::List { head, tail: allocItems(a, tail), multiline: false }; |
| 69 | } |
| 70 | |
| 71 | /// Shorthand for creating a bracket-delimited vector. |
| 72 | export unsafe fn vec(a: &mut alloc::Arena, items: &[Expr]) -> Expr { |
| 73 | return Expr::Vec { items: allocItems(a, items) }; |
| 74 | } |
| 75 | |
| 76 | /// Shorthand for creating a block with inline items and child expressions. |
| 77 | export unsafe fn block(a: &mut alloc::Arena, name: *[u8], items: &[Expr], children: &[Expr]) -> Expr { |
| 78 | return Expr::Block { name, items: allocItems(a, items), children: allocItems(a, children) }; |
| 79 | } |
| 80 | |
| 81 | /// Write a string to the output target. |
| 82 | export unsafe fn write(out: &mut Output, s: &[u8]) { |
| 83 | match *out { |
| 84 | case Output::Stdout => io::print(s), |
| 85 | case Output::Buffer { buf, pos } => { |
| 86 | let remaining = buf.len - *pos; |
| 87 | let toWrite = remaining if s.len > remaining else s.len; |
| 88 | for i in 0..toWrite { |
| 89 | set buf[*pos] = s[i]; |
| 90 | set *pos += 1; |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | /// Emit indentation to the output target. |
| 97 | unsafe fn indentTo(out: &mut Output, depth: u32) { |
| 98 | for _ in 0..depth { |
| 99 | write(out, " "); |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | /// Print a single character with escaping to the output target. |
| 104 | export unsafe fn printEscapedTo(out: &mut Output, c: u8) { |
| 105 | match c { |
| 106 | case '\n' => write(out, "\\n"), |
| 107 | case '\r' => write(out, "\\r"), |
| 108 | case '\t' => write(out, "\\t"), |
| 109 | case '\\' => write(out, "\\\\"), |
| 110 | case '\'' => write(out, "\\'"), |
| 111 | else => write(out, &[c]), |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | /// Print a quoted string with escape sequences to the output target. |
| 116 | export unsafe fn printStringTo(out: &mut Output, s: &[u8]) { |
| 117 | write(out, "\""); |
| 118 | for i in 0..s.len { |
| 119 | printEscapedTo(out, s[i]); |
| 120 | } |
| 121 | write(out, "\""); |
| 122 | } |
| 123 | |
| 124 | /// Print a character literal with escape sequences to the output target. |
| 125 | export unsafe fn printCharTo(out: &mut Output, c: u8) { |
| 126 | write(out, "'"); |
| 127 | printEscapedTo(out, c); |
| 128 | write(out, "'"); |
| 129 | } |
| 130 | |
| 131 | /// Print an S-expression to the given output target at the given depth. |
| 132 | export unsafe fn printTo(expr: Expr, depth: u32, out: &mut Output) { |
| 133 | match expr { |
| 134 | case Expr::Null => {}, |
| 135 | case Expr::Sym(s) => write(out, s), |
| 136 | case Expr::Str(s) => printStringTo(out, s), |
| 137 | case Expr::Char(c) => printCharTo(out, c), |
| 138 | case Expr::List { head, tail, multiline } => { |
| 139 | write(out, "("); |
| 140 | write(out, head); |
| 141 | if multiline { |
| 142 | for i in 0..tail.len { |
| 143 | if tail[i] <> Expr::Null { |
| 144 | write(out, "\n"); |
| 145 | indentTo(out, depth + 1); |
| 146 | printTo(tail[i], depth + 1, out); |
| 147 | } |
| 148 | } |
| 149 | } else { |
| 150 | let mut first = head.len == 0; |
| 151 | for i in 0..tail.len { |
| 152 | if tail[i] <> Expr::Null { |
| 153 | if first { |
| 154 | set first = false; |
| 155 | } else { |
| 156 | write(out, " "); |
| 157 | } |
| 158 | printTo(tail[i], depth, out); |
| 159 | } |
| 160 | } |
| 161 | } |
| 162 | write(out, ")"); |
| 163 | } |
| 164 | case Expr::Vec { items } => { |
| 165 | write(out, "["); |
| 166 | for item, i in items { |
| 167 | if item <> Expr::Null { |
| 168 | if i > 0 { |
| 169 | write(out, " "); |
| 170 | } |
| 171 | printTo(item, depth, out); |
| 172 | } |
| 173 | } |
| 174 | write(out, "]"); |
| 175 | } |
| 176 | case Expr::Block { name, items, children } => { |
| 177 | write(out, "("); |
| 178 | write(out, name); |
| 179 | for i in 0..items.len { |
| 180 | if items[i] <> Expr::Null { |
| 181 | write(out, " "); |
| 182 | printTo(items[i], depth, out); |
| 183 | } |
| 184 | } |
| 185 | for i in 0..children.len { |
| 186 | if children[i] <> Expr::Null { |
| 187 | write(out, "\n"); |
| 188 | indentTo(out, depth + 1); |
| 189 | printTo(children[i], depth + 1, out); |
| 190 | } |
| 191 | } |
| 192 | write(out, ")"); |
| 193 | } |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | /// Print an S-expression to stdout at the given indentation depth. |
| 198 | export unsafe fn print(expr: Expr, depth: u32) { |
| 199 | let mut out = Output::Stdout; |
| 200 | printTo(expr, depth, &mut out); |
| 201 | } |
| 202 | |
| 203 | /// Emit indentation for `depth` levels to stdout. |
| 204 | export unsafe fn indent(depth: u32) { |
| 205 | let mut out = Output::Stdout; |
| 206 | indentTo(&mut out, depth); |
| 207 | } |
| 208 |