Skip to content

Commit a8159c2

Browse files
committed
feat(jit): spec-driven family 2 string bytes transformations
1 parent 57672fe commit a8159c2

2 files changed

Lines changed: 287 additions & 388 deletions

File tree

src/vm/jit/builtin_spec.rs

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,152 @@ pub(crate) const ARRAY_HAS_SPEC: BuiltinSpec = BuiltinSpec {
223223
needs_failure_exit: false,
224224
};
225225

226+
// ── Family 2: string/bytes pure transformations ─────────────────────
227+
228+
/// `string.slice(start, length)` — pure transformation.
229+
pub(crate) const STRING_SLICE_SPEC: BuiltinSpec = BuiltinSpec {
230+
name: "string_slice",
231+
arity: 3,
232+
inputs: &[
233+
InputRepr::Int, // length (popped third)
234+
InputRepr::Int, // start (popped second)
235+
InputRepr::HeapPtr(HeapInputKind::String), // text (popped first)
236+
],
237+
output: OutputKind::Tagged(ValueType::String),
238+
effect: BuiltinEffect::Pure,
239+
needs_failure_exit: false,
240+
};
241+
242+
/// `bytes.slice(start, length)` — pure transformation.
243+
pub(crate) const BYTES_SLICE_SPEC: BuiltinSpec = BuiltinSpec {
244+
name: "bytes_slice",
245+
arity: 3,
246+
inputs: &[
247+
InputRepr::Int, // length (popped third)
248+
InputRepr::Int, // start (popped second)
249+
InputRepr::HeapPtr(HeapInputKind::Bytes), // bytes (popped first)
250+
],
251+
output: OutputKind::Tagged(ValueType::Bytes),
252+
effect: BuiltinEffect::Pure,
253+
needs_failure_exit: false,
254+
};
255+
256+
/// `string.get(index)` — pure read, string result.
257+
pub(crate) const STRING_GET_SPEC: BuiltinSpec = BuiltinSpec {
258+
name: "string_get",
259+
arity: 2,
260+
inputs: &[
261+
InputRepr::Int, // index (popped second)
262+
InputRepr::HeapPtr(HeapInputKind::String), // text (popped first)
263+
],
264+
output: OutputKind::Tagged(ValueType::String),
265+
effect: BuiltinEffect::Pure,
266+
needs_failure_exit: false,
267+
};
268+
269+
/// `bytes.get(index)` — pure read, int result.
270+
pub(crate) const BYTES_GET_SPEC: BuiltinSpec = BuiltinSpec {
271+
name: "bytes_get",
272+
arity: 2,
273+
inputs: &[
274+
InputRepr::Int, // index (popped second)
275+
InputRepr::HeapPtr(HeapInputKind::Bytes), // bytes (popped first)
276+
],
277+
output: OutputKind::Int,
278+
effect: BuiltinEffect::Pure,
279+
needs_failure_exit: false,
280+
};
281+
282+
/// `bytes.has(index)` — pure read, bool result.
283+
pub(crate) const BYTES_HAS_SPEC: BuiltinSpec = BuiltinSpec {
284+
name: "bytes_has",
285+
arity: 2,
286+
inputs: &[
287+
InputRepr::Int, // index (popped second)
288+
InputRepr::HeapPtr(HeapInputKind::Bytes), // bytes (popped first)
289+
],
290+
output: OutputKind::Bool,
291+
effect: BuiltinEffect::Pure,
292+
needs_failure_exit: false,
293+
};
294+
295+
/// `string.replace_literal(needle, replacement)` — pure transformation.
296+
pub(crate) const STRING_REPLACE_LITERAL_SPEC: BuiltinSpec = BuiltinSpec {
297+
name: "string_replace_literal",
298+
arity: 3,
299+
inputs: &[
300+
InputRepr::HeapPtr(HeapInputKind::String), // replacement (popped third)
301+
InputRepr::HeapPtr(HeapInputKind::String), // needle (popped second)
302+
InputRepr::HeapPtr(HeapInputKind::String), // text (popped first)
303+
],
304+
output: OutputKind::Tagged(ValueType::String),
305+
effect: BuiltinEffect::Pure,
306+
needs_failure_exit: false,
307+
};
308+
309+
/// `string.lower_ascii()` — pure transformation.
310+
pub(crate) const STRING_LOWER_ASCII_SPEC: BuiltinSpec = BuiltinSpec {
311+
name: "string_lower_ascii",
312+
arity: 1,
313+
inputs: &[InputRepr::HeapPtr(HeapInputKind::String)],
314+
output: OutputKind::Tagged(ValueType::String),
315+
effect: BuiltinEffect::Pure,
316+
needs_failure_exit: false,
317+
};
318+
319+
/// `string.split_literal(delimiter)` — pure transformation, array result.
320+
pub(crate) const STRING_SPLIT_LITERAL_SPEC: BuiltinSpec = BuiltinSpec {
321+
name: "string_split_literal",
322+
arity: 2,
323+
inputs: &[
324+
InputRepr::HeapPtr(HeapInputKind::String), // delimiter (popped second)
325+
InputRepr::HeapPtr(HeapInputKind::String), // text (popped first)
326+
],
327+
output: OutputKind::Tagged(ValueType::Array),
328+
effect: BuiltinEffect::Pure,
329+
needs_failure_exit: false,
330+
};
331+
332+
/// `bytes.from_array_u8(array)` — pure transformation.
333+
pub(crate) const BYTES_FROM_ARRAY_U8_SPEC: BuiltinSpec = BuiltinSpec {
334+
name: "bytes_from_array_u8",
335+
arity: 1,
336+
inputs: &[InputRepr::HeapPtr(HeapInputKind::Array)],
337+
output: OutputKind::Tagged(ValueType::Bytes),
338+
effect: BuiltinEffect::Pure,
339+
needs_failure_exit: false,
340+
};
341+
342+
/// `bytes.to_utf8_ascii()` — pure transformation.
343+
pub(crate) const BYTES_TO_UTF8_ASCII_SPEC: BuiltinSpec = BuiltinSpec {
344+
name: "bytes_to_utf8_ascii",
345+
arity: 1,
346+
inputs: &[InputRepr::HeapPtr(HeapInputKind::Bytes)],
347+
output: OutputKind::Tagged(ValueType::String),
348+
effect: BuiltinEffect::Pure,
349+
needs_failure_exit: false,
350+
};
351+
352+
/// `bytes.to_array_u8()` — pure transformation.
353+
pub(crate) const BYTES_TO_ARRAY_U8_SPEC: BuiltinSpec = BuiltinSpec {
354+
name: "bytes_to_array_u8",
355+
arity: 1,
356+
inputs: &[InputRepr::HeapPtr(HeapInputKind::Bytes)],
357+
output: OutputKind::Tagged(ValueType::Array),
358+
effect: BuiltinEffect::Pure,
359+
needs_failure_exit: false,
360+
};
361+
362+
/// `to_string(value)` — pure transformation.
363+
pub(crate) const TO_STRING_SPEC: BuiltinSpec = BuiltinSpec {
364+
name: "to_string",
365+
arity: 1,
366+
inputs: &[InputRepr::Any],
367+
output: OutputKind::Tagged(ValueType::String),
368+
effect: BuiltinEffect::Pure,
369+
needs_failure_exit: false,
370+
};
371+
226372
/// Look up the spec for a specialized builtin kind, if one exists.
227373
///
228374
/// Returns `None` for builtins not yet covered by the spec-driven
@@ -241,6 +387,26 @@ pub(crate) fn spec_for(
241387
super::recorder::SpecializedBuiltinKind::TypeOf => Some(&TYPE_OF_SPEC),
242388
super::recorder::SpecializedBuiltinKind::StringContains => Some(&STRING_CONTAINS_SPEC),
243389
super::recorder::SpecializedBuiltinKind::ArrayHas => Some(&ARRAY_HAS_SPEC),
390+
super::recorder::SpecializedBuiltinKind::StringSlice => Some(&STRING_SLICE_SPEC),
391+
super::recorder::SpecializedBuiltinKind::BytesSlice => Some(&BYTES_SLICE_SPEC),
392+
super::recorder::SpecializedBuiltinKind::StringGet => Some(&STRING_GET_SPEC),
393+
super::recorder::SpecializedBuiltinKind::BytesGet => Some(&BYTES_GET_SPEC),
394+
super::recorder::SpecializedBuiltinKind::BytesHas => Some(&BYTES_HAS_SPEC),
395+
super::recorder::SpecializedBuiltinKind::StringReplaceLiteral => {
396+
Some(&STRING_REPLACE_LITERAL_SPEC)
397+
}
398+
super::recorder::SpecializedBuiltinKind::StringLowerAscii => Some(&STRING_LOWER_ASCII_SPEC),
399+
super::recorder::SpecializedBuiltinKind::StringSplitLiteral => {
400+
Some(&STRING_SPLIT_LITERAL_SPEC)
401+
}
402+
super::recorder::SpecializedBuiltinKind::BytesFromArrayU8 => {
403+
Some(&BYTES_FROM_ARRAY_U8_SPEC)
404+
}
405+
super::recorder::SpecializedBuiltinKind::BytesToUtf8Ascii => {
406+
Some(&BYTES_TO_UTF8_ASCII_SPEC)
407+
}
408+
super::recorder::SpecializedBuiltinKind::BytesToArrayU8 => Some(&BYTES_TO_ARRAY_U8_SPEC),
409+
super::recorder::SpecializedBuiltinKind::ToString => Some(&TO_STRING_SPEC),
244410
_ => None,
245411
}
246412
}

0 commit comments

Comments
 (0)