Skip to content

Commit a1ff14d

Browse files
committed
update test, add POC
1 parent 82800a5 commit a1ff14d

File tree

4 files changed

+1375
-15
lines changed

4 files changed

+1375
-15
lines changed

std/assembly/reference.ts

Lines changed: 141 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ export type i31ref = ref_i31 | null;
77
export type structref = ref_struct | null;
88
export type arrayref = ref_array | null;
99
export type stringref = ref_string | null;
10-
export type stringview_wtf8 = ref_stringview_wtf8 | null;
11-
export type stringview_wtf16 = ref_stringview_wtf16 | null;
12-
export type stringview_iter = ref_stringview_iter | null;
10+
11+
// TODO: Conflict with the instruction namespaces
12+
// export type stringview_wtf8 = ref_stringview_wtf8 | null;
13+
// export type stringview_wtf16 = ref_stringview_wtf16 | null;
14+
// export type stringview_iter = ref_stringview_iter | null;
1315

1416
@unmanaged
1517
abstract class Ref {
@@ -43,6 +45,142 @@ export abstract class RefStruct extends Ref {
4345
export abstract class RefArray extends Ref {
4446
}
4547

48+
import { E_INDEXOUTOFRANGE } from "util/error";
49+
4650
@final @unmanaged
4751
export abstract class RefString extends Ref {
52+
53+
@lazy static readonly MAX_LENGTH: i32 = (1 << 30) - 1;
54+
55+
static fromCharCode(unit: i32, surr: i32 = -1): ref_string {
56+
if (~surr) unit = 0x10000 + ((unit & 0x3FF) << 10) | (surr & 0x3FF);
57+
return string.from_code_point(unit);
58+
}
59+
60+
static fromCodePoint(cp: i32): ref_string {
61+
if (<u32>cp > 0x10ffff) throw new Error("Invalid code point");
62+
return string.from_code_point(cp);
63+
}
64+
65+
// @ts-ignore: this on getter
66+
get length(this: ref_string): i32 {
67+
return string.measure_wtf16(this);
68+
}
69+
70+
at(this: ref_string, pos: i32): stringref {
71+
let len = string.measure_wtf16(this);
72+
pos += select(0, len, pos >= 0);
73+
if (<u32>pos >= <u32>len) throw new RangeError(E_INDEXOUTOFRANGE);
74+
return string.from_code_point(stringview_wtf16.get_codeunit(string.as_wtf16(this), pos));
75+
}
76+
77+
@operator("[]") charAt(this: ref_string, pos: i32): stringref {
78+
if (<u32>pos >= <u32>string.measure_wtf16(this)) return "";
79+
return string.from_code_point(stringview_wtf16.get_codeunit(string.as_wtf16(this), pos));
80+
}
81+
82+
charCodeAt(this: ref_string, pos: i32): i32 {
83+
if (<u32>pos >= <u32>string.measure_wtf16(this)) return -1; // (NaN)
84+
return stringview_wtf16.get_codeunit(string.as_wtf16(this), pos);
85+
}
86+
87+
codePointAt(this: ref_string, pos: i32): i32 {
88+
let len = string.measure_wtf16(this);
89+
if (<u32>pos >= <u32>len) return -1; // (undefined)
90+
let view = string.as_wtf16(this);
91+
let first = <i32>stringview_wtf16.get_codeunit(view, pos);
92+
if ((first & 0xFC00) != 0xD800 || pos + 1 == len) return first;
93+
let second = <i32>stringview_wtf16.get_codeunit(view, pos + 1);
94+
if ((second & 0xFC00) != 0xDC00) return first;
95+
return (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
96+
}
97+
98+
@operator("+")
99+
concat(this: ref_string, other: ref_string): ref_string {
100+
return string.concat(this, other);
101+
}
102+
103+
endsWith(this: ref_string, search: ref_string, end: i32 = RefString.MAX_LENGTH): bool {
104+
end = min(max(end, 0), string.measure_wtf16(this));
105+
let searchLength = string.measure_wtf16(search);
106+
let searchStart = end - searchLength;
107+
if (searchStart < 0) return false;
108+
return string.eq(
109+
stringview_wtf16.slice(string.as_wtf16(this), searchStart, searchStart + searchLength),
110+
search
111+
);
112+
}
113+
114+
@operator("==") private static __eq(left: ref_string | null, right: ref_string | null): bool {
115+
return string.eq(left, right);
116+
}
117+
118+
@operator.prefix("!")
119+
private static __not(str: ref_string | null): bool {
120+
return str == null;
121+
}
122+
123+
@operator("!=")
124+
private static __ne(left: ref_string | null, right: ref_string | null): bool {
125+
return !string.eq(left, right);
126+
}
127+
128+
@operator(">") private static __gt(left: ref_string, right: ref_string): bool {
129+
return string.compare(left, right) > 0;
130+
}
131+
132+
@operator(">=") private static __gte(left: ref_string, right: ref_string): bool {
133+
return string.compare(left, right) >= 0;
134+
}
135+
136+
@operator("<") private static __lt(left: ref_string, right: ref_string): bool {
137+
return string.compare(left, right) < 0;
138+
}
139+
140+
@operator("<=") private static __lte(left: ref_string, right: ref_string): bool {
141+
return string.compare(left, right) <= 0;
142+
}
143+
144+
includes(this: ref_string, search: ref_string, start: i32 = 0): bool {
145+
return this.indexOf(search, start) != -1;
146+
}
147+
148+
indexOf(this: ref_string, search: ref_string, start: i32 = 0): i32 {
149+
let searchLen = string.measure_wtf16(search);
150+
if (!searchLen) return 0;
151+
let len = string.measure_wtf16(this);
152+
if (!len) return -1;
153+
let searchStart = min(max(start, 0), len);
154+
let view = string.as_wtf16(this);
155+
for (len -= searchLen; searchStart <= len; ++searchStart) {
156+
// FIXME: slice is suboptimal
157+
if (string.eq(
158+
stringview_wtf16.slice(view, searchStart, searchStart + searchLen),
159+
search
160+
)) {
161+
return searchStart;
162+
}
163+
}
164+
return -1;
165+
}
166+
167+
lastIndexOf(this: ref_string, search: ref_string, start: i32 = i32.MAX_VALUE): i32 {
168+
let searchLen = string.measure_wtf16(search);
169+
if (!searchLen) return string.measure_wtf16(this);
170+
let len = string.measure_wtf16(this);
171+
if (!len) return -1;
172+
let searchStart = min(max(start, 0), len - searchLen);
173+
for (; searchStart >= 0; --searchStart) {
174+
// FIXME: slice is suboptimal
175+
if (string.eq(
176+
stringview_wtf16.slice(string.as_wtf16(this), searchStart, searchStart + searchLen),
177+
search
178+
)) {
179+
return searchStart;
180+
}
181+
}
182+
return -1;
183+
}
184+
185+
// TODO: port more
48186
}

0 commit comments

Comments
 (0)