code wiki / (root) / runtime.nx

runtime.nx source

↩ module page · 179 lines · 4618 B

1// runtime.nx -- core NishiLang runtime. 2// 3// Intended to be used via copy-paste or future module-import. All 4// routines here call only __syscall for their primitives; no libc. 5// 6// Contents: 7// * Arena allocator (bump pointer, never frees) 8// * strlen / strcmp / strneq / memcpy / memset 9// * itoa / atoi (base 10 and hex) 10// * print / println helpers using syscall write to stdout 11// * die() -- print message + exit(1) 12 13// Syscalls live in syscalls.nx now (shared across all modules). 14import "syscalls.nx" 15 16// ===== arena allocator ============================================== 17// 18// A single mmap-backed bump region. Fast, never frees. Fine for a 19// compiler that runs once, allocates, writes output, exits. 20// 21// Layout: 64-byte header + payload. Caller allocates and manages 22// a pointer to the Arena struct. 23 24struct Arena { 25 base: *u8, // start of payload 26 pos: i64, // next allocation offset (bytes) 27 cap: i64, // total bytes 28} 29 30func arena_new(size: i64) -> *Arena { 31 let raw: *u8 = sys_mmap(size + 64) 32 let a: *Arena = raw as *Arena 33 let base: *u8 = (raw as i64 + 64) as *u8 34 a.base = base 35 a.pos = 0 36 a.cap = size 37 return a 38} 39 40// Allocate `n` bytes, 8-byte aligned. Returns a byte pointer. 41func arena_alloc(a: *Arena, n: i64) -> *u8 { 42 let p: i64 = (a.pos + 7) & -8 // round up to 8 43 if p + n > a.cap { 44 // OOM -- grow would need another mmap; for now just crash 45 // politely by returning 0 (dereferenced access will SEGV). 46 return 0 as *u8 47 } 48 a.pos = p + n 49 let base: *u8 = a.base 50 return (base as i64 + p) as *u8 51} 52 53// ===== string primitives ============================================ 54 55func strlen(s: *u8) -> i64 { 56 var n: i64 = 0 57 while s[n] != 0 { n = n + 1 } 58 return n 59} 60 61// Equal-length byte compare. Returns 1 on match, 0 otherwise. 62func strneq(a: *u8, b: *u8, n: i64) -> i64 { 63 var i: i64 = 0 64 while i < n { 65 if a[i] != b[i] { return 0 } 66 i = i + 1 67 } 68 return 1 69} 70 71// Full equality including terminator. 72func streq(a: *u8, b: *u8) -> i64 { 73 let la: i64 = strlen(a) 74 let lb: i64 = strlen(b) 75 if la != lb { return 0 } 76 return strneq(a, b, la) 77} 78 79func memcpy(dst: *u8, src: *u8, n: i64) -> i64 { 80 var i: i64 = 0 81 while i < n { 82 dst[i] = src[i] 83 i = i + 1 84 } 85 return 0 86} 87 88func memset(dst: *u8, v: i64, n: i64) -> i64 { 89 var i: i64 = 0 90 while i < n { 91 dst[i] = v & 0xFF 92 i = i + 1 93 } 94 return 0 95} 96 97// ===== number parsing / formatting ================================== 98 99// Decode decimal digits at s[0..] until a non-digit byte. Negative 100// sign allowed as the first character. Stops on first non-digit. 101func atoi(s: *u8) -> i64 { 102 var i: i64 = 0 103 var sign: i64 = 1 104 if s[0] == 0x2D { 105 sign = -1 106 i = 1 107 } 108 var v: i64 = 0 109 while s[i] >= 0x30 { 110 if s[i] > 0x39 { break } 111 v = v * 10 + (s[i] - 0x30) 112 i = i + 1 113 } 114 return v * sign 115} 116 117// Write decimal representation of `n` into buf, returns length. 118// buf must have >= 24 bytes for i64 range. Null-terminates. 119func itoa(n: i64, buf: *u8) -> i64 { 120 if n == 0 { 121 buf[0] = 0x30 122 buf[1] = 0 123 return 1 124 } 125 var x: i64 = n 126 var neg: i64 = 0 127 if x < 0 { 128 neg = 1 129 x = 0 - x 130 } 131 // Generate digits in reverse into a scratch. 132 let scratch_raw: *u8 = sys_mmap(64) 133 var sp: i64 = 0 134 while x > 0 { 135 scratch_raw[sp] = 0x30 + (x % 10) 136 x = x / 10 137 sp = sp + 1 138 } 139 var out: i64 = 0 140 if neg { 141 buf[0] = 0x2D 142 out = 1 143 } 144 var i: i64 = sp - 1 145 while i >= 0 { 146 buf[out] = scratch_raw[i] 147 out = out + 1 148 i = i - 1 149 } 150 buf[out] = 0 151 return out 152} 153 154// ===== printing ===================================================== 155 156func print(s: *u8) -> i64 { 157 return sys_write(1, s, strlen(s)) 158} 159 160func println(s: *u8) -> i64 { 161 sys_write(1, s, strlen(s)) 162 let nl_raw: *u8 = sys_mmap(8) 163 nl_raw[0] = 0x0A 164 return sys_write(1, nl_raw, 1) 165} 166 167func print_i64(n: i64) -> i64 { 168 let buf: *u8 = sys_mmap(32) 169 let len: i64 = itoa(n, buf) 170 return sys_write(1, buf, len) 171} 172 173// Abort with a message. Writes to stderr (fd 2), exits 1. 174func die(msg: *u8) -> i64 { 175 sys_write(2, msg, strlen(msg)) 176 return sys_exit(1) 177} 178 179// Library only; self-test lives in runtime_test.nx.