std.map 은 바이트 열을 키로 받는다. 이름의 번호를 네 바이트로 써 내려놓으면 그대로 심볼 표가 된다. 감사가 권한 IntMap(V) 를 따로 만들 이유가 없고, 그 쪽이 trait 없는 v0.1 과도 덜 싸운다. intern.key_of 가 그 네 바이트를 써준다. 리졸버가 스코프마다 할 일이라 손으로 풀게 두지 않았다. scope x 10 y 20 of 2 245/245, 38/38.
74 lines
2.5 KiB
Plaintext
74 lines
2.5 KiB
Plaintext
// EXIT:0
|
|
// OUTPUT:ids 0 1 2 count 3
|
|
// OUTPUT:again 0 same yes count 3
|
|
// OUTPUT:eq yes no len 4
|
|
// OUTPUT:find 1 missing yes
|
|
// OUTPUT:hash steady yes apart yes
|
|
// OUTPUT:copied unit 4
|
|
// OUTPUT:scope x 10 y 20 of 2
|
|
// OUTPUT:balanced
|
|
unit interns;
|
|
|
|
import std.io;
|
|
import std.sys;
|
|
import std.intern;
|
|
import std.map;
|
|
|
|
// One copy of every distinct name, and a number that stands for it. Comparing
|
|
// two names is comparing two integers; storing one costs four bytes and no
|
|
// ownership.
|
|
//
|
|
// There is deliberately no way to get a `str` back out: a borrow of the text
|
|
// would be a borrow of the interner, and the interner is exactly what a parser
|
|
// wants to keep adding to while it holds names.
|
|
|
|
fn run() -> !void {
|
|
var t: intern.Interner = try intern.Interner.with_capacity(8);
|
|
let a: intern.StrId = try t.intern("unit");
|
|
let b: intern.StrId = try t.intern("fn");
|
|
let c: intern.StrId = try t.intern("struct");
|
|
@print("ids {} {} {} count {}\n", a.raw, b.raw, c.raw, t.count_of());
|
|
|
|
// The same name twice is the same number, and costs nothing new.
|
|
let again: intern.StrId = try t.intern("unit");
|
|
@print("again {} same {} count {}\n", again.raw, yesno(a.same(again)),
|
|
t.count_of());
|
|
|
|
@print("eq {} {} len {}\n", yesno(t.eq(a, "unit")), yesno(t.eq(a, "fn")),
|
|
t.len_of(a));
|
|
|
|
@print("find {} missing {}\n", t.find("fn"),
|
|
yesno(t.find("nope") == intern.NONE));
|
|
|
|
// A name hashes the same every time, and two names do not collide here.
|
|
@print("hash steady {} apart {}\n", yesno(t.hash_of(a) == t.hash_of(again)),
|
|
yesno(t.hash_of(a) != t.hash_of(b)));
|
|
|
|
// The only way to see the text: copy it somewhere you own.
|
|
var buf: [8]u8 = undefined;
|
|
let n: usize = t.copy_into(a, buf[..]);
|
|
@print("copied {} {}\n", buf[0..n], n);
|
|
|
|
// A symbol table is a Map keyed on the name's number. std.map keys on
|
|
// bytes, so no separate integer-keyed map is needed.
|
|
var scope: map.Map(i32) = try map.Map(i32).with_capacity(8);
|
|
var key: [4]u8 = undefined;
|
|
try scope.put(intern.key_of(a, key[..]), 10);
|
|
try scope.put(intern.key_of(b, key[..]), 20);
|
|
@print("scope x {} y {} of {}\n", scope.get(intern.key_of(a, key[..]), -1),
|
|
scope.get(intern.key_of(b, key[..]), -1), scope.count_of());
|
|
return;
|
|
}
|
|
|
|
fn yesno(b: bool) -> []u8 {
|
|
if b { return "yes"; }
|
|
return "no";
|
|
}
|
|
|
|
fn main() -> i32 {
|
|
run() catch |e| { @print("failed\n"); return 1; };
|
|
if sys.allocs() == sys.frees() { @print("balanced\n"); }
|
|
else { @print("leaked\n"); }
|
|
return 0;
|
|
}
|