vyre-libs 0.6.1

vyre Category A library ecosystem - pure-IR compositions over vyre-ops hardware primitives
Documentation
use super::*;

pub(crate) fn matched_macro_invocation<'a>(
    candidate_macros: &[&'a MacroDef],
    source: &[u8],
    after_name: usize,
) -> Option<(&'a MacroDef, usize)> {
    for mac in candidate_macros {
        if mac.is_function_like {
            let Some(invocation_end) = function_like_invocation_end(source, after_name) else {
                continue;
            };
            return Some((mac, invocation_end));
        }
        return Some((mac, after_name));
    }
    None
}

pub(crate) fn function_like_invocation_end(source: &[u8], after_name: usize) -> Option<usize> {
    let mut pos = after_name;
    while source
        .get(pos)
        .is_some_and(|byte| byte.is_ascii_whitespace())
    {
        pos += 1;
    }
    if source.get(pos).copied() != Some(b'(') {
        return None;
    }
    let mut depth = 1_u32;
    pos += 1;
    while let Some(byte) = source.get(pos).copied() {
        match byte {
            b'(' => depth = depth.saturating_add(1),
            b')' => {
                depth = depth.saturating_sub(1);
                if depth == 0 {
                    return pos.checked_add(1);
                }
            }
            _ => {}
        }
        pos += 1;
    }
    None
}

pub(crate) fn invocation_arg_spans(
    source: &[u8],
    after_name: usize,
) -> Option<SmallVec<[(usize, usize); 8]>> {
    let mut pos = after_name;
    while source
        .get(pos)
        .is_some_and(|byte| byte.is_ascii_whitespace())
    {
        pos += 1;
    }
    if source.get(pos).copied() != Some(b'(') {
        return None;
    }
    pos += 1;
    let mut args = SmallVec::new();
    let mut depth = 0_u32;
    let mut arg_start = pos;
    while let Some(byte) = source.get(pos).copied() {
        match byte {
            b'(' => depth = depth.saturating_add(1),
            b')' if depth == 0 => {
                push_trimmed_arg_span(source, arg_start, pos, &mut args);
                return Some(args);
            }
            b')' => depth = depth.saturating_sub(1),
            b',' if depth == 0 => {
                push_trimmed_arg_span(source, arg_start, pos, &mut args);
                arg_start = pos + 1;
            }
            _ => {}
        }
        pos += 1;
    }
    None
}

pub(crate) fn push_trimmed_arg_span(
    source: &[u8],
    start: usize,
    end: usize,
    args: &mut SmallVec<[(usize, usize); 8]>,
) {
    let mut trimmed_start = start;
    let mut trimmed_end = end;
    while trimmed_start < trimmed_end
        && source
            .get(trimmed_start)
            .is_some_and(|byte| byte.is_ascii_whitespace())
    {
        trimmed_start += 1;
    }
    while trimmed_end > trimmed_start
        && source
            .get(trimmed_end - 1)
            .is_some_and(|byte| byte.is_ascii_whitespace())
    {
        trimmed_end -= 1;
    }
    args.push((trimmed_start, trimmed_end.saturating_sub(trimmed_start)));
}