std: str 과 list, 그리고 자동 drop 이 사용자 타입까지 닿는다
std.str 은 eq/starts_with/find/trim/parse_int 을 바이트 슬라이스 위에서 한다. std.list 는 자라는 제네릭 시퀀스다 -- 버퍼를 소유하므로 리스트를 놓으면 원소도 놓인다. 성장은 두 배씩이라 push 당 복사량이 상수로 눌린다. 찾은 버그 넷: - 메서드가 자기 타입의 유닛이 아니라 호출한 유닛에 속한 것으로 계산됐다. 다른 유닛의 제네릭 타입을 쓰면 필드가 전부 private 으로 보였다. - 참조로 도달한 메서드를 찾지 못했다. self.grow() 가 안 됐다. - 이미 참조인 수신자의 주소를 한 번 더 떠서 넘겼다. 포인터의 포인터를 받은 메서드가 그것을 구조체로 읽었다. - 유닛으로 한정된 제네릭 타입(list.List(i32))이 타입 자리에서도 식 자리에서도 해석되지 않았다. drop 을 가진 타입은 인스턴스마다 그 메서드가 존재해야 한다 -- 이름으로 부르는 사람이 없어도 스코프 정리가 부른다. 그리고 자기 drop 안에서는 필드를 꺼낼 수 있다. 객체가 사라지는 중이라 뒤에 남아 읽힐 것이 없다. run.py 207/207, exec.py 19/19.
This commit is contained in:
+66
-3
@@ -1,3 +1,66 @@
|
||||
unit str;
|
||||
pub fn eq(a: str, b: str) -> bool;
|
||||
pub fn trim(s: str) -> str;
|
||||
unit std.str;
|
||||
|
||||
// `str` is `[]u8` (SPEC 4.2), so these take and give plain byte slices.
|
||||
|
||||
pub fn eq(a: []u8, b: []u8) -> bool {
|
||||
if a.n != b.n { return false; }
|
||||
var i: usize = 0;
|
||||
while i < a.n {
|
||||
if a[i] != b[i] { return false; }
|
||||
i = i + 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn starts_with(s: []u8, prefix: []u8) -> bool {
|
||||
if prefix.n > s.n { return false; }
|
||||
return eq(s[0..prefix.n], prefix);
|
||||
}
|
||||
|
||||
/// Where `needle` first appears in `s`, or the length of `s` when it does not.
|
||||
/// An index past the end is how "not found" is said without an optional.
|
||||
pub fn find(s: []u8, needle: []u8) -> usize {
|
||||
if needle.n == 0 { return 0; }
|
||||
if needle.n > s.n { return s.n; }
|
||||
var at: usize = 0;
|
||||
let last: usize = s.n - needle.n;
|
||||
while at <= last {
|
||||
if eq(s[at..at + needle.n], needle) { return at; }
|
||||
at = at + 1;
|
||||
}
|
||||
return s.n;
|
||||
}
|
||||
|
||||
pub fn trim(s: []u8) -> []u8 {
|
||||
var from: usize = 0;
|
||||
var to: usize = s.n;
|
||||
while from < to {
|
||||
if s[from] != 32 and s[from] != 9 and s[from] != 10 and s[from] != 13 {
|
||||
break;
|
||||
}
|
||||
from = from + 1;
|
||||
}
|
||||
while to > from {
|
||||
let c: u8 = s[to - 1];
|
||||
if c != 32 and c != 9 and c != 10 and c != 13 { break; }
|
||||
to = to - 1;
|
||||
}
|
||||
return s[from..to];
|
||||
}
|
||||
|
||||
pub fn parse_int(s: []u8) -> ?i32 {
|
||||
if s.n == 0 { return null; }
|
||||
var value: i32 = 0;
|
||||
var i: usize = 0;
|
||||
var negative: bool = false;
|
||||
if s[0] == 45 { negative = true; i = 1; }
|
||||
if i >= s.n { return null; }
|
||||
while i < s.n {
|
||||
let c: u8 = s[i];
|
||||
if c < 48 or c > 57 { return null; }
|
||||
value = value * 10 + ((c - 48) as i32);
|
||||
i = i + 1;
|
||||
}
|
||||
if negative { return 0 - value; }
|
||||
return value;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user