std: io 와 fmt 를 Ferro 로 쓰고, 컴파일된 프로그램이 출력한다

io.Writer 는 핸들 하나짜리 enum 이다. 참조도 컨텍스트 포인터도 담지 않으므로
Copy 이고 자유롭게 오간다 (SPEC 5 R8). fmt 는 sink 를 소유하지 않는다 --
호출자가 버퍼를 주고 앞에서 몇 바이트가 쓰였는지 돌려받는다.

lowering 에 추가: enum 변이 상수, match, 정수 캐스트, 문자열 이스케이프.

프론트엔드 정밀도 하나: 항상 빠져나가는 분기의 상태를 병합하지 않는다. 그
분기가 소비한 값이 그 분기를 지나지 않은 경로에서도 소비된 것처럼 보였다.
fmt_i32 가 이것 때문에 못 쓰였다.

extern "c" 이름은 유닛 접두사를 붙이지 않는다. 링커가 이미 아는 이름이라는
것이 그 선언의 요점이다.

run.py 199/199, exec.py 11/11.
This commit is contained in:
2026-08-17 06:18:16 +09:00
parent 4624c6d0ec
commit 0de10f37b5
8 changed files with 184 additions and 22 deletions
+32 -6
View File
@@ -1,6 +1,32 @@
unit fmt;
pub fn fmt_int_i32(buf: []mut u8, v: i32) -> str;
pub fn fmt_hex_i32(buf: []mut u8, v: i32) -> str;
pub fn fmt_char(buf: []mut u8, v: char) -> str;
pub fn fmt_bool(buf: []mut u8, v: bool) -> str;
pub fn fmt_error(buf: []mut u8, v: core.Error) -> str;
unit std.fmt;
// Pure conversion. Nothing here owns a sink: the caller supplies the buffer
// and is told how many bytes at the front of it were written (SPEC 10).
pub fn fmt_u32(buf: []mut u8, v: u32) -> usize {
var tmp: [10]u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var value: u32 = v;
var count: usize = 0;
while true {
tmp[count] = ((value % 10) as u8) + ('0' as u8);
count = count + 1;
value = value / 10;
if value == 0 { break; }
if count == 10 { break; }
}
var i: usize = 0;
while i < count {
if i < buf.n { buf[i] = tmp[count - 1 - i]; }
i = i + 1;
}
return count;
}
pub fn fmt_i32(buf: []mut u8, v: i32) -> usize {
if v >= 0 { return fmt_u32(buf, v as u32); }
if buf.n == 0 { return 0; }
buf[0] = '-' as u8;
var rest: []mut u8 = buf[1..buf.n];
let digits: usize = fmt_u32(rest, (0 - v) as u32);
return digits + 1;
}
+24 -9
View File
@@ -1,10 +1,25 @@
unit io;
pub enum Writer { Stdout, Stderr, File(u16), Null }
pub enum Reader { Stdin, File(u16) }
pub fn write(w: Writer, bytes: []u8) -> !usize;
pub fn read(r: Reader, bytes: []mut u8) -> !usize;
pub struct File {
handle: u16,
pub fn close(self: Self) -> !void;
pub fn drop(self: &mut Self) { }
unit std.io;
import std.sys;
// A writer is a handle and nothing else: an integer the runtime understands.
// It stores no reference and no context pointer, so it is Copy and can be
// passed and returned freely (SPEC 5 R8).
pub enum Writer { Null, Stdout, Stderr }
pub fn write(w: Writer, bytes: []u8) -> usize {
if w == Writer.Null { return bytes.n; }
var handle: i32 = 1;
if w == Writer.Stderr { handle = 2; }
let done: i32 = sys.raw_write(handle, &bytes[0], bytes.n);
if done < 0 { return 0; }
return done as usize;
}
pub fn print(bytes: []u8) -> usize {
return write(Writer.Stdout, bytes);
}
pub fn println(bytes: []u8) -> usize {
let n: usize = write(Writer.Stdout, bytes);
return n + write(Writer.Stdout, "\n");
}