use super::{load_u32, search_next_token_into};
use crate::parsing::composition::child_phase;
use crate::parsing::python::lex::{TOK_DOT, TOK_IDENTIFIER};
use crate::parsing::python::{INVALID_POS, MAX_DOTTED_SEGMENTS};
use crate::region::wrap_anonymous;
use vyre_foundation::ir::{BufferAccess, BufferDecl, DataType, Expr, Node, Program};
pub(crate) struct DottedName<'a> {
pub tok_types: &'a str,
pub haystack_len: u32,
pub head: Expr,
pub accumulator: &'a str,
}
impl DottedName<'_> {
pub(crate) fn carriers(&self) -> Vec<Node> {
vec![
Node::let_bind(self.accumulator, self.head.clone()),
Node::let_bind("cursor", self.head.clone()),
Node::let_bind("dot_pos", Expr::u32(INVALID_POS)),
Node::let_bind("after_dot", Expr::u32(INVALID_POS)),
]
}
pub(crate) fn walk(&self) -> Node {
Node::loop_for(
"seg",
Expr::u32(0),
Expr::u32(MAX_DOTTED_SEGMENTS),
vec![
Node::assign("dot_pos", Expr::u32(INVALID_POS)),
Node::assign("after_dot", Expr::u32(INVALID_POS)),
Node::if_then(
Expr::ne(Expr::var("cursor"), Expr::u32(INVALID_POS)),
search_next_token_into(
"dot_pos",
Expr::add(Expr::var("cursor"), Expr::u32(1)),
self.tok_types,
self.haystack_len,
),
),
Node::if_then(
Expr::eq(
load_u32(self.tok_types, Expr::var("dot_pos")),
Expr::u32(TOK_DOT),
),
search_next_token_into(
"after_dot",
Expr::add(Expr::var("dot_pos"), Expr::u32(1)),
self.tok_types,
self.haystack_len,
),
),
Node::if_then(
Expr::eq(
load_u32(self.tok_types, Expr::var("after_dot")),
Expr::u32(TOK_IDENTIFIER),
),
vec![
Node::assign(self.accumulator, Expr::var("after_dot")),
Node::assign("cursor", Expr::var("after_dot")),
],
),
Node::if_then(
Expr::ne(
load_u32(self.tok_types, Expr::var("after_dot")),
Expr::u32(TOK_IDENTIFIER),
),
vec![Node::assign("cursor", Expr::u32(INVALID_POS))],
),
],
)
}
pub(crate) fn span(&self, tok_starts: &str, tok_lens: &str) -> [Expr; 2] {
[
load_u32(tok_starts, self.head.clone()),
Expr::add(
Expr::sub(
load_u32(tok_starts, Expr::var(self.accumulator)),
load_u32(tok_starts, self.head.clone()),
),
load_u32(tok_lens, Expr::var(self.accumulator)),
),
]
}
}
pub(crate) struct TokenPass<'a> {
pub op_id: &'a str,
pub child_op_id: &'a str,
pub tok_types: &'a str,
pub tok_starts: &'a str,
pub tok_lens: &'a str,
pub haystack_len: u32,
}
impl TokenPass<'_> {
pub(crate) fn token_buffers(&self) -> Vec<BufferDecl> {
[self.tok_types, self.tok_starts, self.tok_lens]
.into_iter()
.enumerate()
.map(|(binding, name)| {
BufferDecl::storage(
name,
binding as u32,
BufferAccess::ReadOnly,
DataType::U32,
)
.with_count(self.haystack_len)
})
.collect()
}
pub(crate) fn record_buffers(
&self,
records: &str,
counts: &str,
binding: u32,
record_words: u32,
) -> Vec<BufferDecl> {
vec![
BufferDecl::storage(records, binding, BufferAccess::ReadWrite, DataType::U32)
.with_count(self.haystack_len.saturating_mul(record_words)),
BufferDecl::storage(counts, binding + 1, BufferAccess::ReadWrite, DataType::U32)
.with_count(1),
]
}
pub(crate) fn program(&self, buffers: Vec<BufferDecl>, body: Vec<Node>) -> Program {
Program::wrapped(
buffers,
[256, 1, 1],
vec![wrap_anonymous(
self.op_id,
vec![child_phase(
self.op_id,
self.child_op_id,
vec![Node::if_then(
Expr::lt(
Expr::InvocationId { axis: 0 },
Expr::u32(self.haystack_len),
),
body,
)],
)],
)],
)
.with_entry_op_id(self.op_id)
.with_non_composable_with_self(true)
}
}
pub(crate) fn pack_sparse_tokens(
tokens: &[(usize, u32, u32)],
slots: usize,
) -> (Vec<u8>, Vec<u8>, Vec<u8>) {
let mut tok_types = vec![0u8; slots * 4];
let mut tok_starts = vec![0u8; slots * 4];
let mut tok_lens = vec![0u8; slots * 4];
for &(pos, tok, len) in tokens {
let base = pos * 4;
tok_types[base..base + 4].copy_from_slice(&tok.to_le_bytes());
tok_starts[base..base + 4].copy_from_slice(&(pos as u32).to_le_bytes());
tok_lens[base..base + 4].copy_from_slice(&len.to_le_bytes());
}
(tok_types, tok_starts, tok_lens)
}