304 lines
8.6 KiB
Plaintext
304 lines
8.6 KiB
Plaintext
Vector :: ($N: int, $T: Type) -> Type #builtin;
|
|
write :: (str: string) -> void #builtin;
|
|
sqrt :: (x: $T) -> T #builtin;
|
|
size_of :: ($T: Type) -> s64 #builtin;
|
|
alloc :: (size: s64) -> string #builtin;
|
|
type_of :: (val: $T) -> Type #builtin;
|
|
type_name :: ($T: Type) -> string #builtin;
|
|
field_count :: ($T: Type) -> s64 #builtin;
|
|
field_name :: ($T: Type, idx: s64) -> string #builtin;
|
|
field_value :: (s: $T, idx: s64) -> Any #builtin;
|
|
|
|
int_to_string :: (n: s64) -> string {
|
|
if n == 0 { return "0"; }
|
|
neg := n < 0;
|
|
v := if neg then 0 - n else n;
|
|
tmp := v;
|
|
len := 0;
|
|
while tmp > 0 { len += 1; tmp = tmp / 10; }
|
|
total := if neg then len + 1 else len;
|
|
buf := alloc(total);
|
|
i := total - 1;
|
|
while v > 0 {
|
|
buf[i] = (v % 10) + 48;
|
|
v = v / 10;
|
|
i -= 1;
|
|
}
|
|
if neg { buf[0] = 45; }
|
|
buf;
|
|
}
|
|
|
|
bool_to_string :: (b: bool) -> string {
|
|
if b then "true" else "false";
|
|
}
|
|
|
|
float_to_string :: (f: f64) -> string {
|
|
neg := f < 0.0;
|
|
v := if neg then 0.0 - f else f;
|
|
int_part := cast(s64) v;
|
|
frac := cast(s64) ((v - cast(f64) int_part) * 1000000.0);
|
|
if frac < 0 { frac = 0 - frac; }
|
|
istr := int_to_string(int_part);
|
|
fstr := int_to_string(frac);
|
|
il := istr.len;
|
|
fl := fstr.len;
|
|
prefix := if neg then 1 else 0;
|
|
total := prefix + il + 1 + 6;
|
|
buf := alloc(total);
|
|
pos := 0;
|
|
if neg { buf[0] = 45; pos = 1; }
|
|
i := 0;
|
|
while i < il { buf[pos] = istr[i]; pos += 1; i += 1; }
|
|
buf[pos] = 46;
|
|
pos += 1;
|
|
pad := 6 - fl;
|
|
j := 0;
|
|
while j < pad { buf[pos] = 48; pos += 1; j += 1; }
|
|
k := 0;
|
|
while k < fl { buf[pos] = fstr[k]; pos += 1; k += 1; }
|
|
buf;
|
|
}
|
|
|
|
int_to_hex_string :: (n: s64) -> string {
|
|
if n == 0 { return "0"; }
|
|
|
|
// Split into four 16-bit groups for correct unsigned treatment
|
|
g0 := n % 65536;
|
|
if g0 < 0 { g0 = g0 + 65536; }
|
|
r1 := (n - g0) / 65536;
|
|
g1 := r1 % 65536;
|
|
if g1 < 0 { g1 = g1 + 65536; }
|
|
r2 := (r1 - g1) / 65536;
|
|
g2 := r2 % 65536;
|
|
if g2 < 0 { g2 = g2 + 65536; }
|
|
r3 := (r2 - g2) / 65536;
|
|
g3 := r3 % 65536;
|
|
if g3 < 0 { g3 = g3 + 65536; }
|
|
|
|
buf := alloc(16);
|
|
// Group 3: digits 0-3 (bits 48-63)
|
|
i := 3;
|
|
v := g3;
|
|
while i >= 0 {
|
|
d := v % 16;
|
|
buf[i] = if d < 10 then d + 48 else d - 10 + 97;
|
|
v = v / 16;
|
|
i -= 1;
|
|
}
|
|
// Group 2: digits 4-7 (bits 32-47)
|
|
i = 7;
|
|
v = g2;
|
|
while i >= 4 {
|
|
d := v % 16;
|
|
buf[i] = if d < 10 then d + 48 else d - 10 + 97;
|
|
v = v / 16;
|
|
i -= 1;
|
|
}
|
|
// Group 1: digits 8-11 (bits 16-31)
|
|
i = 11;
|
|
v = g1;
|
|
while i >= 8 {
|
|
d := v % 16;
|
|
buf[i] = if d < 10 then d + 48 else d - 10 + 97;
|
|
v = v / 16;
|
|
i -= 1;
|
|
}
|
|
// Group 0: digits 12-15 (bits 0-15)
|
|
i = 15;
|
|
v = g0;
|
|
while i >= 12 {
|
|
d := v % 16;
|
|
buf[i] = if d < 10 then d + 48 else d - 10 + 97;
|
|
v = v / 16;
|
|
i -= 1;
|
|
}
|
|
// Skip leading zeros (keep at least 1 digit)
|
|
start := 0;
|
|
while start < 15 {
|
|
if buf[start] != 48 { break; }
|
|
start += 1;
|
|
}
|
|
substr(buf, start, 16 - start);
|
|
}
|
|
|
|
concat :: (a: string, b: string) -> string {
|
|
al := a.len;
|
|
bl := b.len;
|
|
buf := alloc(al + bl);
|
|
i := 0;
|
|
while i < al { buf[i] = a[i]; i += 1; }
|
|
j := 0;
|
|
while j < bl { buf[al + j] = b[j]; j += 1; }
|
|
buf;
|
|
}
|
|
|
|
substr :: (s: string, start: s64, len: s64) -> string {
|
|
buf := alloc(len);
|
|
i := 0;
|
|
while i < len {
|
|
buf[i] = s[start + i];
|
|
i += 1;
|
|
}
|
|
buf;
|
|
}
|
|
|
|
struct_to_string :: (s: $T) -> string {
|
|
result := concat(type_name(T), "{");
|
|
i := 0;
|
|
while i < field_count(T) {
|
|
if i > 0 { result = concat(result, ", "); }
|
|
result = concat(result, field_name(T, i));
|
|
result = concat(result, ": ");
|
|
result = concat(result, any_to_string(field_value(s, i)));
|
|
i += 1;
|
|
}
|
|
concat(result, "}");
|
|
}
|
|
|
|
enum_to_string :: (e: $T) -> string {
|
|
concat(".", field_name(T, cast(s64) e));
|
|
}
|
|
|
|
vector_to_string :: (v: $T) -> string {
|
|
result := "[";
|
|
i := 0;
|
|
while i < field_count(T) {
|
|
if i > 0 { result = concat(result, ", "); }
|
|
result = concat(result, any_to_string(field_value(v, i)));
|
|
i += 1;
|
|
}
|
|
concat(result, "]");
|
|
}
|
|
|
|
array_to_string :: (a: $T) -> string {
|
|
result := "[";
|
|
i := 0;
|
|
while i < field_count(T) {
|
|
if i > 0 { result = concat(result, ", "); }
|
|
result = concat(result, any_to_string(field_value(a, i)));
|
|
i += 1;
|
|
}
|
|
concat(result, "]");
|
|
}
|
|
|
|
slice_to_string :: (items: []$T) -> string {
|
|
result := "[";
|
|
i := 0;
|
|
while i < items.len {
|
|
if i > 0 { result = concat(result, ", "); }
|
|
result = concat(result, any_to_string(field_value(items, i)));
|
|
i += 1;
|
|
}
|
|
concat(result, "]");
|
|
}
|
|
|
|
pointer_to_string :: (p: $T) -> string {
|
|
addr : s64 = xx p;
|
|
if addr == 0 { "null"; } else {
|
|
concat(type_name(T), concat("@0x", int_to_hex_string(addr)));
|
|
}
|
|
}
|
|
|
|
union_to_string :: (u: $T) -> string {
|
|
tag := cast(s64) u;
|
|
result := concat(".", field_name(T, tag));
|
|
payload := field_value(u, tag);
|
|
pstr := any_to_string(payload);
|
|
if pstr.len > 0 {
|
|
result = concat(result, concat("(", concat(pstr, ")")));
|
|
}
|
|
result;
|
|
}
|
|
|
|
any_to_string :: (val: Any) -> string {
|
|
result := "<?>";
|
|
type := type_of(val);
|
|
if type == {
|
|
case void: result = "";
|
|
case int: result = int_to_string(xx val);
|
|
case string: { s : string = xx val; result = s; }
|
|
case bool: result = bool_to_string(xx val);
|
|
case float: result = float_to_string(xx val);
|
|
case struct: result = struct_to_string(cast(type) val);
|
|
case enum: result = enum_to_string(cast(type) val);
|
|
case vector: result = vector_to_string(cast(type) val);
|
|
case array: result = array_to_string(cast(type) val);
|
|
case slice: result = slice_to_string(cast(type) val);
|
|
case union: result = union_to_string(cast(type) val);
|
|
case pointer: result = pointer_to_string(cast(type) val);
|
|
case type: { s : string = xx val; result = s; }
|
|
}
|
|
result;
|
|
}
|
|
|
|
build_print :: (fmt: string) -> string {
|
|
code := "result := \"\"; ";
|
|
seg_start := 0;
|
|
i := 0;
|
|
arg_idx := 0;
|
|
while i < fmt.len {
|
|
if fmt[i] == 123 {
|
|
if i + 1 < fmt.len {
|
|
if fmt[i + 1] == 125 {
|
|
if i > seg_start {
|
|
code = concat(code, "result = concat(result, substr(fmt, ");
|
|
code = concat(code, int_to_string(seg_start));
|
|
code = concat(code, ", ");
|
|
code = concat(code, int_to_string(i - seg_start));
|
|
code = concat(code, ")); ");
|
|
}
|
|
code = concat(code, "result = concat(result, any_to_string(args[");
|
|
code = concat(code, int_to_string(arg_idx));
|
|
code = concat(code, "])); ");
|
|
arg_idx += 1;
|
|
i += 2;
|
|
seg_start = i;
|
|
} else if fmt[i + 1] == 123 {
|
|
code = concat(code, "result = concat(result, substr(fmt, ");
|
|
code = concat(code, int_to_string(seg_start));
|
|
code = concat(code, ", ");
|
|
code = concat(code, int_to_string(i - seg_start + 1));
|
|
code = concat(code, ")); ");
|
|
i += 2;
|
|
seg_start = i;
|
|
} else {
|
|
i += 1;
|
|
}
|
|
} else {
|
|
i += 1;
|
|
}
|
|
} else if fmt[i] == 125 {
|
|
if i + 1 < fmt.len {
|
|
if fmt[i + 1] == 125 {
|
|
code = concat(code, "result = concat(result, substr(fmt, ");
|
|
code = concat(code, int_to_string(seg_start));
|
|
code = concat(code, ", ");
|
|
code = concat(code, int_to_string(i - seg_start + 1));
|
|
code = concat(code, ")); ");
|
|
i += 2;
|
|
seg_start = i;
|
|
} else {
|
|
i += 1;
|
|
}
|
|
} else {
|
|
i += 1;
|
|
}
|
|
} else {
|
|
i += 1;
|
|
}
|
|
}
|
|
if seg_start < fmt.len {
|
|
code = concat(code, "result = concat(result, substr(fmt, ");
|
|
code = concat(code, int_to_string(seg_start));
|
|
code = concat(code, ", ");
|
|
code = concat(code, int_to_string(fmt.len - seg_start));
|
|
code = concat(code, ")); ");
|
|
}
|
|
code = concat(code, "write(result);");
|
|
code;
|
|
}
|
|
|
|
print :: ($fmt: string, args: ..Any) {
|
|
#insert build_print(fmt);
|
|
}
|