Skip to main content

mir_php/
util.rs

1/// Utilities shared across mir-php modules.
2use php_ast::{TypeHint, TypeHintKind};
3
4/// Convert a byte offset into a `(line, character)` position.
5pub fn offset_to_position(source: &str, offset: u32) -> (u32, u32) {
6    let offset = (offset as usize).min(source.len());
7    let prefix = &source[..offset];
8    let line = prefix.bytes().filter(|&b| b == b'\n').count() as u32;
9    let last_nl = prefix.rfind('\n').map(|i| i + 1).unwrap_or(0);
10    let character = (offset - last_nl) as u32;
11    (line, character)
12}
13
14/// Format a `TypeHint` as a PHP type string, e.g. `?int`, `string|null`.
15pub fn format_type_hint(hint: &TypeHint<'_, '_>) -> String {
16    fmt_kind(&hint.kind)
17}
18
19fn fmt_kind(kind: &TypeHintKind<'_, '_>) -> String {
20    match kind {
21        TypeHintKind::Named(name) => name.to_string_repr().to_string(),
22        TypeHintKind::Keyword(builtin, _) => builtin.as_str().to_string(),
23        TypeHintKind::Nullable(inner) => format!("?{}", format_type_hint(inner)),
24        TypeHintKind::Union(types) => types
25            .iter()
26            .map(format_type_hint)
27            .collect::<Vec<_>>()
28            .join("|"),
29        TypeHintKind::Intersection(types) => types
30            .iter()
31            .map(format_type_hint)
32            .collect::<Vec<_>>()
33            .join("&"),
34    }
35}