compiler/
lib/
examples/
std/
arch/
collections/
lang/
alloc/
ast/
gen/
il/
module/
parser/
resolver/
scanner/
alloc.rad
4.2 KiB
ast.rad
22.4 KiB
gen.rad
489 B
il.rad
15.1 KiB
lower.rad
259.5 KiB
module.rad
13.4 KiB
package.rad
1.2 KiB
parser.rad
78.5 KiB
resolver.rad
244.3 KiB
scanner.rad
18.1 KiB
sexpr.rad
6.3 KiB
strings.rad
2.2 KiB
sys/
arch.rad
65 B
collections.rad
36 B
fmt.rad
3.8 KiB
intrinsics.rad
399 B
io.rad
1.2 KiB
lang.rad
222 B
mem.rad
2.1 KiB
sys.rad
167 B
testing.rad
2.3 KiB
tests.rad
11.6 KiB
vec.rad
3.1 KiB
std.rad
231 B
scripts/
seed/
test/
vim/
.gitignore
353 B
.gitsigners
112 B
LICENSE
1.1 KiB
Makefile
3.0 KiB
README
2.5 KiB
std.lib
1.0 KiB
std.lib.test
252 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 | pub union Output { |
| 11 | /// Print to stdout. |
| 12 | Stdout, |
| 13 | /// Write to a buffer, tracking position. |
| 14 | Buffer { buf: *mut [u8], pos: *mut u32 }, |
| 15 | } |
| 16 | |
| 17 | /// An S-expression element. |
| 18 | pub union Expr { |
| 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 | pub 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 | pub 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 | buf[i] = item; |
| 52 | } |
| 53 | return buf; |
| 54 | } |
| 55 | |
| 56 | /// Shorthand for creating a symbol. |
| 57 | pub fn sym(s: *[u8]) -> Expr { |
| 58 | return Expr::Sym(s); |
| 59 | } |
| 60 | |
| 61 | /// Shorthand for creating a string literal. |
| 62 | pub fn str(s: *[u8]) -> Expr { |
| 63 | return Expr::Str(s); |
| 64 | } |
| 65 | |
| 66 | /// Shorthand for creating a list. |
| 67 | pub 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 | pub 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 | pub 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 | pub 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 | buf[*pos] = s[i]; |
| 90 | *pos += 1; |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | /// Emit indentation to the output target. |
| 97 | 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 | pub 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 | pub 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 | pub 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 | pub 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 | 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 | pub 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 | pub fn indent(depth: u32) { |
| 205 | let mut out = Output::Stdout; |
| 206 | indentTo(&mut out, depth); |
| 207 | } |
| 208 |