feat: implement M4 formatting builtins

This commit is contained in:
2026-08-16 13:24:25 +09:00
parent 8e6a409637
commit 53bca214b8
22 changed files with 779 additions and 21 deletions
+6
View File
@@ -0,0 +1,6 @@
unit m4_bad_arity;
fn main() -> i32 {
@print("{} {}", 1);
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
unit m4_bad_cls;
fn main() -> i32 {
@print("}", 1);
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
unit m4_bad_many;
fn main() -> i32 {
@print("{}", 1, 2);
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
unit m4_bad_open;
fn main() -> i32 {
@print("{", 1);
return 0;
}
+7
View File
@@ -0,0 +1,7 @@
unit m4_bad_runtime;
fn main() -> i32 {
var fmt: str = "{}";
@print(fmt, 1);
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
unit m4_bad_try;
fn main() -> i32 {
try @print("nope");
return 0;
}
+9
View File
@@ -0,0 +1,9 @@
unit m4_bad_type;
struct Point { x: i32, }
fn main() -> i32 {
let p: Point = Point{ x: 1 };
@print("{}", p);
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
unit m4_bad_verb;
fn main() -> i32 {
@print("{q}", 1);
return 0;
}
+7
View File
@@ -0,0 +1,7 @@
unit m4_bad_writer;
fn main() -> i32 {
var x: i32 = 0;
@fprint(&mut x, "bad");
return 0;
}
+30
View File
@@ -0,0 +1,30 @@
unit m4_format;
const FMT: str = "n={} hex={x} c={c} s={s} b={b} {{ok}}\n";
fn main() -> i32 {
var raw: [8]u8 = [0, 0, 0, 0, 0, 0, 0, 0];
var raw2: [8]u8 = [0, 0, 0, 0, 0, 0, 0, 0];
var raw3: [8]u8 = [0, 0, 0, 0, 0, 0, 0, 0];
var raw4: [8]u8 = [0, 0, 0, 0, 0, 0, 0, 0];
var raw5: [8]u8 = [0, 0, 0, 0, 0, 0, 0, 0];
var buf: []u8 = raw[..];
var buf2: []u8 = raw2[..];
var buf3: []u8 = raw3[..];
var buf4: []u8 = raw4[..];
var buf5: []u8 = raw5[..];
let w: io.Writer = io.buf_writer(&mut buf);
const LOCAL_FMT: str = "value={}\n";
@print(FMT, 7, 15, 'A', "yes", true);
@fprint(&mut w, LOCAL_FMT, 12);
let n: usize = @sprint(buf2, "A\x42\u0043defghi");
let n2: usize = @sprint(buf3, "xy");
let inner_n: usize = @sprint(buf4, "xy");
let outer_n: usize = @sprint(buf5, "n={}", @sprint(buf4, "xy"));
if n == 8 and buf2[0] == ('A' as u8) and
buf2[1] == ('B' as u8) and buf2[2] == ('C' as u8) and
n2 == 2 and buf3[0] == ('x' as u8) and
inner_n == 2 and outer_n == 3 and
buf5[0] == ('n' as u8) and buf5[2] == ('2' as u8) { return 0; }
return 1;
}
+5
View File
@@ -0,0 +1,5 @@
unit m4_prop;
pub fn propagate(w: &mut io.Writer) -> !void {
try @fprint(w, "a{}b", 1);
}
+23
View File
@@ -0,0 +1,23 @@
#include "prop.c"
static unsigned short calls;
static unsigned short fail_write(void *ctx, const unsigned char *p,
unsigned long n)
{
(void)ctx;
(void)p;
(void)n;
++calls;
return calls == 1 ? 7 : 0;
}
int main(void)
{
fe_writer w;
unsigned short result;
w.ctx=0;
w.write_fn=fail_write;
result=fe_m4_prop_propagate(&w);
return (result==7 && calls==1) ? 0 : 1;
}
+8
View File
@@ -0,0 +1,8 @@
unit m4_try_fprint;
fn main() -> !void {
var raw: [4]u8 = [0, 0, 0, 0];
var buf: []u8 = raw[..];
let w: io.Writer = io.buf_writer(&mut buf);
try @fprint(&mut w, "ok");
}
+30
View File
@@ -61,3 +61,33 @@ for f in badfld badmat badarr badcycle badstr badchar badfield badindex; do
fi
done
echo "M3 tests: structs, enums, arrays, slices, str, match, and bounds passed"
m4tmp=$(mktemp -d)
trap 'rm -rf "$m2tmp" "$m3tmp" "$m4tmp"' EXIT HUP INT TERM
for f in format; do
"$root"/fec --target=bits32 --emit-c "$root"/tests/m4/$f.fe -o "$m4tmp/$f.c"
${CC:-cc} -std=c89 -pedantic "$m4tmp/$f.c" -o "$m4tmp/$f"
"$m4tmp/$f" >"$m4tmp/$f.out"
done
for f in try-fprint; do
"$root"/fec --target=bits32 --emit-c "$root"/tests/m4/$f.fe -o "$m4tmp/$f.c"
${CC:-cc} -std=c89 -pedantic "$m4tmp/$f.c" -o "$m4tmp/$f"
"$m4tmp/$f"
done
"$root"/fec --target=bits32 --emit-c "$root"/tests/m4/prop.fe -o "$m4tmp/prop.c"
cp "$root"/tests/m4/proptest.c "$m4tmp/proptest.c"
${CC:-cc} -std=c89 -pedantic "$m4tmp/proptest.c" -o "$m4tmp/prop"
"$m4tmp/prop"
for f in bad-arity bad-verb bad-runtime bad-type bad-try bad-writer; do
if "$root"/fec --target=bits32 --emit-c "$root"/tests/m4/$f.fe -o "$m4tmp/$f.c" >/dev/null 2>/dev/null; then
echo "FAIL (accepted M4 semantic error): $f.fe"
exit 1
fi
done
for f in bad-many bad-open bad-cls; do
if "$root"/fec --target=bits32 --emit-c "$root"/tests/m4/$f.fe -o "$m4tmp/$f.c" >/dev/null 2>/dev/null; then
echo "FAIL (accepted M4 format-brace error): $f.fe"
exit 1
fi
done
echo "M4 tests: formatting builtins passed"