use crate::region::wrap_anonymous;
use vyre_foundation::ir::{BufferAccess, BufferDecl, DataType, Expr, Node, Program};
pub const TOK_NONE: u32 = 0;
pub const TOK_IDENTIFIER: u32 = 1;
pub const TOK_STRING: u32 = 2;
pub const TOK_LPAREN: u32 = 10;
pub const TOK_RPAREN: u32 = 11;
pub const TOK_LBRACE: u32 = 12;
pub const TOK_RBRACE: u32 = 13;
pub const TOK_LBRACKET: u32 = 14;
pub const TOK_RBRACKET: u32 = 15;
pub const TOK_COMMA: u32 = 16;
pub const TOK_DOT: u32 = 17;
pub const TOK_SEMICOLON: u32 = 18;
pub const TOK_COLON: u32 = 19;
pub const TOK_ASSIGN: u32 = 20;
pub const TOK_STAR: u32 = 21;
pub const TOK_ARROW: u32 = 22;
pub const TOK_NEWLINE: u32 = 23;
fn byte_load(buffer: &str, index: Expr) -> Expr {
Expr::bitand(Expr::load(buffer, index), Expr::u32(0xFF))
}
fn byte_eq(expr: Expr, byte: u8) -> Expr {
Expr::eq(expr, Expr::u32(u32::from(byte)))
}
fn byte_between(expr: Expr, low: u8, high: u8) -> Expr {
Expr::and(
Expr::ge(expr.clone(), Expr::u32(u32::from(low))),
Expr::le(expr, Expr::u32(u32::from(high))),
)
}
fn ident_start(expr: Expr) -> Expr {
Expr::or(
Expr::or(
byte_between(expr.clone(), b'a', b'z'),
byte_between(expr.clone(), b'A', b'Z'),
),
byte_eq(expr, b'_'),
)
}
fn ident_continue(expr: Expr) -> Expr {
Expr::or(ident_start(expr.clone()), byte_between(expr, b'0', b'9'))
}
fn punctuation_token(byte: Expr, token: u32, chr: u8) -> Vec<Node> {
vec![Node::if_then(
byte_eq(byte, chr),
vec![
Node::assign("emit", Expr::u32(1)),
Node::assign("tok_type", Expr::u32(token)),
Node::assign("tok_len", Expr::u32(1)),
],
)]
}
#[must_use]
#[allow(clippy::too_many_arguments)]
pub fn go_lexer(
haystack: &str,
quote_ranks: &str,
out_tok_types: &str,
out_tok_starts: &str,
out_tok_lens: &str,
out_emit_flags: &str,
haystack_len: u32,
) -> Program {
let t = Expr::gid_x();
let mut body = vec![
Node::let_bind("byte", byte_load(haystack, t.clone())),
Node::let_bind(
"prev_byte",
Expr::select(
Expr::gt(t.clone(), Expr::u32(0)),
byte_load(haystack, Expr::sub(t.clone(), Expr::u32(1))),
Expr::u32(0),
),
),
Node::let_bind(
"next_byte",
Expr::select(
Expr::lt(Expr::add(t.clone(), Expr::u32(1)), Expr::u32(haystack_len)),
byte_load(haystack, Expr::add(t.clone(), Expr::u32(1))),
Expr::u32(0),
),
),
Node::let_bind("emit", Expr::u32(0)),
Node::let_bind("tok_type", Expr::u32(TOK_NONE)),
Node::let_bind("tok_len", Expr::u32(0)),
];
body.push(Node::if_then(
Expr::and(
ident_start(Expr::var("byte")),
Expr::not(ident_continue(Expr::var("prev_byte"))),
),
vec![
Node::assign("emit", Expr::u32(1)),
Node::assign("tok_type", Expr::u32(TOK_IDENTIFIER)),
Node::assign("tok_len", Expr::u32(1)),
Node::let_bind("still_ident", Expr::u32(1)),
Node::loop_for(
"scan",
Expr::add(t.clone(), Expr::u32(1)),
Expr::u32(haystack_len),
vec![Node::if_then(
Expr::eq(Expr::var("still_ident"), Expr::u32(1)),
vec![
Node::let_bind("scan_byte", byte_load(haystack, Expr::var("scan"))),
Node::if_then_else(
ident_continue(Expr::var("scan_byte")),
vec![Node::assign(
"tok_len",
Expr::add(Expr::var("tok_len"), Expr::u32(1)),
)],
vec![Node::assign("still_ident", Expr::u32(0))],
),
],
)],
),
],
));
body.push(Node::if_then(
Expr::and(
byte_eq(Expr::var("byte"), b'"'),
Expr::eq(
Expr::rem(Expr::load(quote_ranks, t.clone()), Expr::u32(2)),
Expr::u32(0),
),
),
vec![
Node::assign("emit", Expr::u32(1)),
Node::assign("tok_type", Expr::u32(TOK_STRING)),
Node::assign("tok_len", Expr::u32(1)),
Node::let_bind("string_done", Expr::u32(0)),
Node::loop_for(
"scan",
Expr::add(t.clone(), Expr::u32(1)),
Expr::u32(haystack_len),
vec![Node::if_then(
Expr::eq(Expr::var("string_done"), Expr::u32(0)),
vec![
Node::assign("tok_len", Expr::add(Expr::var("tok_len"), Expr::u32(1))),
Node::if_then(
Expr::and(
Expr::lt(
Expr::add(Expr::var("scan"), Expr::u32(1)),
Expr::u32(haystack_len),
),
Expr::gt(
Expr::load(
quote_ranks,
Expr::add(Expr::var("scan"), Expr::u32(1)),
),
Expr::load(quote_ranks, Expr::var("scan")),
),
),
vec![Node::assign("string_done", Expr::u32(1))],
),
],
)],
),
],
));
body.push(Node::if_then(
Expr::and(
byte_eq(Expr::var("byte"), b'<'),
byte_eq(Expr::var("next_byte"), b'-'),
),
vec![
Node::assign("emit", Expr::u32(1)),
Node::assign("tok_type", Expr::u32(TOK_ARROW)),
Node::assign("tok_len", Expr::u32(2)),
],
));
body.extend(punctuation_token(Expr::var("byte"), TOK_LPAREN, b'('));
body.extend(punctuation_token(Expr::var("byte"), TOK_RPAREN, b')'));
body.extend(punctuation_token(Expr::var("byte"), TOK_LBRACE, b'{'));
body.extend(punctuation_token(Expr::var("byte"), TOK_RBRACE, b'}'));
body.extend(punctuation_token(Expr::var("byte"), TOK_LBRACKET, b'['));
body.extend(punctuation_token(Expr::var("byte"), TOK_RBRACKET, b']'));
body.extend(punctuation_token(Expr::var("byte"), TOK_COMMA, b','));
body.extend(punctuation_token(Expr::var("byte"), TOK_DOT, b'.'));
body.extend(punctuation_token(Expr::var("byte"), TOK_SEMICOLON, b';'));
body.extend(punctuation_token(Expr::var("byte"), TOK_COLON, b':'));
body.extend(punctuation_token(Expr::var("byte"), TOK_ASSIGN, b'='));
body.extend(punctuation_token(Expr::var("byte"), TOK_STAR, b'*'));
body.extend(punctuation_token(Expr::var("byte"), TOK_NEWLINE, b'\n'));
body.push(Node::if_then(
Expr::eq(
Expr::rem(Expr::load(quote_ranks, t.clone()), Expr::u32(2)),
Expr::u32(1),
),
vec![
Node::assign("emit", Expr::u32(0)),
Node::assign("tok_type", Expr::u32(TOK_NONE)),
Node::assign("tok_len", Expr::u32(0)),
],
));
body.push(Node::store(out_emit_flags, t.clone(), Expr::var("emit")));
body.push(Node::store(out_tok_types, t.clone(), Expr::var("tok_type")));
body.push(Node::store(
out_tok_starts,
t.clone(),
Expr::select(
Expr::eq(Expr::var("emit"), Expr::u32(1)),
t.clone(),
Expr::u32(0),
),
));
body.push(Node::store(out_tok_lens, t.clone(), Expr::var("tok_len")));
Program::wrapped(
vec![
BufferDecl::storage(haystack, 0, BufferAccess::ReadOnly, DataType::U32)
.with_count(haystack_len),
BufferDecl::storage(quote_ranks, 1, BufferAccess::ReadOnly, DataType::U32)
.with_count(haystack_len),
BufferDecl::storage(out_tok_types, 2, BufferAccess::ReadWrite, DataType::U32)
.with_count(haystack_len),
BufferDecl::storage(out_tok_starts, 3, BufferAccess::ReadWrite, DataType::U32)
.with_count(haystack_len),
BufferDecl::storage(out_tok_lens, 4, BufferAccess::ReadWrite, DataType::U32)
.with_count(haystack_len),
BufferDecl::storage(out_emit_flags, 5, BufferAccess::ReadWrite, DataType::U32)
.with_count(haystack_len),
],
[256, 1, 1],
vec![wrap_anonymous(
"vyre-libs::parsing::go_lexer",
vec![Node::if_then(Expr::lt(t, Expr::u32(haystack_len)), body)],
)],
)
.with_entry_op_id("vyre-libs::parsing::go_lexer")
.with_non_composable_with_self(true)
}
#[must_use]
pub fn go_quote_flags(haystack: &str, out_quote_flags: &str, haystack_len: u32) -> Program {
let t = Expr::gid_x();
let backslash_run = vec![
Node::let_bind("run", Expr::u32(0)),
Node::loop_for(
"back",
Expr::u32(0),
t.clone(),
vec![Node::if_then_else(
byte_eq(byte_load(haystack, Expr::var("back")), b'\\'),
vec![Node::assign(
"run",
Expr::add(Expr::var("run"), Expr::u32(1)),
)],
vec![Node::assign("run", Expr::u32(0))],
)],
),
];
let mut body = backslash_run;
body.push(Node::store(
out_quote_flags,
t.clone(),
Expr::select(
Expr::and(
byte_eq(byte_load(haystack, t.clone()), b'"'),
Expr::eq(Expr::rem(Expr::var("run"), Expr::u32(2)), Expr::u32(0)),
),
Expr::u32(1),
Expr::u32(0),
),
));
Program::wrapped(
vec![
BufferDecl::storage(haystack, 0, BufferAccess::ReadOnly, DataType::U32)
.with_count(haystack_len),
BufferDecl::storage(out_quote_flags, 1, BufferAccess::ReadWrite, DataType::U32)
.with_count(haystack_len),
],
[256, 1, 1],
vec![wrap_anonymous(
"vyre-libs::parsing::go_quote_flags",
vec![Node::if_then(
Expr::lt(t.clone(), Expr::u32(haystack_len)),
body,
)],
)],
)
.with_entry_op_id("vyre-libs::parsing::go_quote_flags")
.with_non_composable_with_self(true)
}
#[must_use]
pub fn go_scan_quote_flags(quote_flags: &str, quote_ranks: &str, haystack_len: u32) -> Program {
vyre_primitives::reduce::multi_block_prefix_scan::multi_block_prefix_scan_sum_exclusive_u32(
quote_flags,
quote_ranks,
haystack_len,
)
}
#[must_use]
pub fn go_scan_emit_flags(emit_flags: &str, emit_offsets: &str, haystack_len: u32) -> Program {
vyre_primitives::reduce::multi_block_prefix_scan::multi_block_prefix_scan_sum_exclusive_u32(
emit_flags,
emit_offsets,
haystack_len,
)
}
#[must_use]
#[allow(clippy::too_many_arguments)]
pub fn go_compact_tokens(
sparse_types: &str,
sparse_starts: &str,
sparse_lens: &str,
emit_flags: &str,
emit_offsets: &str,
out_tok_types: &str,
out_tok_starts: &str,
out_tok_lens: &str,
out_counts: &str,
haystack_len: u32,
) -> Program {
let t = Expr::gid_x();
let last = haystack_len.saturating_sub(1);
let body = vec![
Node::let_bind("flag", Expr::load(emit_flags, t.clone())),
Node::let_bind("slot", Expr::load(emit_offsets, t.clone())),
Node::if_then(
Expr::eq(Expr::var("flag"), Expr::u32(1)),
vec![
Node::store(
out_tok_types,
Expr::var("slot"),
Expr::load(sparse_types, t.clone()),
),
Node::store(
out_tok_starts,
Expr::var("slot"),
Expr::load(sparse_starts, t.clone()),
),
Node::store(
out_tok_lens,
Expr::var("slot"),
Expr::load(sparse_lens, t.clone()),
),
],
),
Node::if_then(
Expr::eq(t.clone(), Expr::u32(last)),
vec![Node::store(
out_counts,
Expr::u32(0),
Expr::add(Expr::var("slot"), Expr::var("flag")),
)],
),
];
Program::wrapped(
vec![
BufferDecl::storage(sparse_types, 0, BufferAccess::ReadOnly, DataType::U32)
.with_count(haystack_len),
BufferDecl::storage(sparse_starts, 1, BufferAccess::ReadOnly, DataType::U32)
.with_count(haystack_len),
BufferDecl::storage(sparse_lens, 2, BufferAccess::ReadOnly, DataType::U32)
.with_count(haystack_len),
BufferDecl::storage(emit_flags, 3, BufferAccess::ReadOnly, DataType::U32)
.with_count(haystack_len),
BufferDecl::storage(emit_offsets, 4, BufferAccess::ReadOnly, DataType::U32)
.with_count(haystack_len),
BufferDecl::storage(out_tok_types, 5, BufferAccess::ReadWrite, DataType::U32)
.with_count(haystack_len),
BufferDecl::storage(out_tok_starts, 6, BufferAccess::ReadWrite, DataType::U32)
.with_count(haystack_len),
BufferDecl::storage(out_tok_lens, 7, BufferAccess::ReadWrite, DataType::U32)
.with_count(haystack_len),
BufferDecl::storage(out_counts, 8, BufferAccess::ReadWrite, DataType::U32)
.with_count(1),
],
[256, 1, 1],
vec![wrap_anonymous(
"vyre-libs::parsing::go_compact_tokens",
vec![Node::if_then(Expr::lt(t, Expr::u32(haystack_len)), body)],
)],
)
.with_entry_op_id("vyre-libs::parsing::go_compact_tokens")
.with_non_composable_with_self(true)
}