compiler/
lib/
examples/
std/
arch/
collections/
lang/
alloc/
ast/
gen/
il/
lower/
module/
parser/
resolver/
scanner/
alloc.rad
4.2 KiB
ast.rad
22.6 KiB
gen.rad
265 B
il.rad
15.1 KiB
lower.rad
258.3 KiB
module.rad
14.1 KiB
package.rad
1.4 KiB
parser.rad
78.7 KiB
resolver.rad
227.9 KiB
scanner.rad
23.4 KiB
sexpr.rad
7.0 KiB
strings.rad
2.2 KiB
sys/
arch.rad
65 B
collections.rad
36 B
fmt.rad
3.8 KiB
intrinsics.rad
206 B
io.rad
1.2 KiB
lang.rad
222 B
mem.rad
2.2 KiB
sys.rad
167 B
testing.rad
2.4 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.1 KiB
README
2.5 KiB
std.lib
987 B
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 | /// Allocate and copy prefix items followed by suffix items. |
| 57 | pub fn concatItems(a: *mut alloc::Arena, prefix: *[Expr], suffix: *[Expr]) -> *[Expr] { |
| 58 | let total = prefix.len + suffix.len; |
| 59 | if total == 0 { |
| 60 | return &[]; |
| 61 | } |
| 62 | let buf = try! allocExprs(a, total); |
| 63 | for item, i in prefix { |
| 64 | buf[i] = item; |
| 65 | } |
| 66 | for item, i in suffix { |
| 67 | buf[prefix.len + i] = item; |
| 68 | } |
| 69 | return buf; |
| 70 | } |
| 71 | |
| 72 | /// Shorthand for creating a symbol. |
| 73 | pub fn sym(s: *[u8]) -> Expr { |
| 74 | return Expr::Sym(s); |
| 75 | } |
| 76 | |
| 77 | /// Shorthand for creating a string literal. |
| 78 | pub fn str(s: *[u8]) -> Expr { |
| 79 | return Expr::Str(s); |
| 80 | } |
| 81 | |
| 82 | /// Shorthand for creating a list. |
| 83 | pub fn list(a: *mut alloc::Arena, head: *[u8], tail: *[Expr]) -> Expr { |
| 84 | return Expr::List { head, tail: allocItems(a, tail), multiline: false }; |
| 85 | } |
| 86 | |
| 87 | /// Shorthand for creating a bracket-delimited vector. |
| 88 | pub fn vec(a: *mut alloc::Arena, items: *[Expr]) -> Expr { |
| 89 | return Expr::Vec { items: allocItems(a, items) }; |
| 90 | } |
| 91 | |
| 92 | /// Shorthand for creating a block with inline items and child expressions. |
| 93 | pub fn block(a: *mut alloc::Arena, name: *[u8], items: *[Expr], children: *[Expr]) -> Expr { |
| 94 | return Expr::Block { name, items: allocItems(a, items), children: allocItems(a, children) }; |
| 95 | } |
| 96 | |
| 97 | /// Write a string to the output target. |
| 98 | pub fn write(out: *mut Output, s: *[u8]) { |
| 99 | match *out { |
| 100 | case Output::Stdout => io::print(s), |
| 101 | case Output::Buffer { buf, pos } => { |
| 102 | let remaining = buf.len - *pos; |
| 103 | let toWrite = remaining if s.len > remaining else s.len; |
| 104 | for i in 0..toWrite { |
| 105 | buf[*pos] = s[i]; |
| 106 | *pos += 1; |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | /// Emit indentation to the output target. |
| 113 | fn indentTo(out: *mut Output, depth: u32) { |
| 114 | for _ in 0..depth { |
| 115 | write(out, " "); |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | /// Print a single character with escaping to the output target. |
| 120 | pub fn printEscapedTo(out: *mut Output, c: u8) { |
| 121 | match c { |
| 122 | case '\n' => write(out, "\\n"), |
| 123 | case '\r' => write(out, "\\r"), |
| 124 | case '\t' => write(out, "\\t"), |
| 125 | case '\\' => write(out, "\\\\"), |
| 126 | case '\'' => write(out, "\\'"), |
| 127 | else => write(out, &[c]), |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | /// Print a quoted string with escape sequences to the output target. |
| 132 | pub fn printStringTo(out: *mut Output, s: *[u8]) { |
| 133 | write(out, "\""); |
| 134 | for i in 0..s.len { |
| 135 | printEscapedTo(out, s[i]); |
| 136 | } |
| 137 | write(out, "\""); |
| 138 | } |
| 139 | |
| 140 | /// Print a character literal with escape sequences to the output target. |
| 141 | pub fn printCharTo(out: *mut Output, c: u8) { |
| 142 | write(out, "'"); |
| 143 | printEscapedTo(out, c); |
| 144 | write(out, "'"); |
| 145 | } |
| 146 | |
| 147 | /// Print an S-expression to the given output target at the given depth. |
| 148 | pub fn printTo(expr: Expr, depth: u32, out: *mut Output) { |
| 149 | match expr { |
| 150 | case Expr::Null => {}, |
| 151 | case Expr::Sym(s) => write(out, s), |
| 152 | case Expr::Str(s) => printStringTo(out, s), |
| 153 | case Expr::Char(c) => printCharTo(out, c), |
| 154 | case Expr::List { head, tail, multiline } => { |
| 155 | write(out, "("); |
| 156 | write(out, head); |
| 157 | if multiline { |
| 158 | for i in 0..tail.len { |
| 159 | if tail[i] != Expr::Null { |
| 160 | write(out, "\n"); |
| 161 | indentTo(out, depth + 1); |
| 162 | printTo(tail[i], depth + 1, out); |
| 163 | } |
| 164 | } |
| 165 | } else { |
| 166 | let mut first = head.len == 0; |
| 167 | for i in 0..tail.len { |
| 168 | if tail[i] != Expr::Null { |
| 169 | if first { |
| 170 | first = false; |
| 171 | } else { |
| 172 | write(out, " "); |
| 173 | } |
| 174 | printTo(tail[i], depth, out); |
| 175 | } |
| 176 | } |
| 177 | } |
| 178 | write(out, ")"); |
| 179 | } |
| 180 | case Expr::Vec { items } => { |
| 181 | write(out, "["); |
| 182 | for item, i in items { |
| 183 | if item != Expr::Null { |
| 184 | if i > 0 { |
| 185 | write(out, " "); |
| 186 | } |
| 187 | printTo(item, depth, out); |
| 188 | } |
| 189 | } |
| 190 | write(out, "]"); |
| 191 | } |
| 192 | case Expr::Block { name, items, children } => { |
| 193 | write(out, "("); |
| 194 | write(out, name); |
| 195 | for i in 0..items.len { |
| 196 | if items[i] != Expr::Null { |
| 197 | write(out, " "); |
| 198 | printTo(items[i], depth, out); |
| 199 | } |
| 200 | } |
| 201 | for i in 0..children.len { |
| 202 | if children[i] != Expr::Null { |
| 203 | write(out, "\n"); |
| 204 | indentTo(out, depth + 1); |
| 205 | printTo(children[i], depth + 1, out); |
| 206 | } |
| 207 | } |
| 208 | write(out, ")"); |
| 209 | } |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | /// Print an S-expression to stdout at the given indentation depth. |
| 214 | pub fn print(expr: Expr, depth: u32) { |
| 215 | let mut out = Output::Stdout; |
| 216 | printTo(expr, depth, &mut out); |
| 217 | } |
| 218 | |
| 219 | /// Emit indentation for `depth` levels to stdout. |
| 220 | pub fn indent(depth: u32) { |
| 221 | let mut out = Output::Stdout; |
| 222 | indentTo(&mut out, depth); |
| 223 | } |
| 224 | |
| 225 | /// Print a quoted string with escape sequences to stdout. |
| 226 | pub fn printString(s: *[u8]) { |
| 227 | let mut out = Output::Stdout; |
| 228 | printStringTo(&mut out, s); |
| 229 | } |
| 230 | |
| 231 | /// Print a character literal with escape sequences to stdout. |
| 232 | pub fn printChar(c: u8) { |
| 233 | let mut out = Output::Stdout; |
| 234 | printCharTo(&mut out, c); |
| 235 | } |