use crate::demangle::identifier;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ModulePath {
pub path: String,
pub prefix: Option<PathPrefix>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PathPrefix {
Module,
Package,
Directory,
Higher,
}
pub fn decode(mangled_module: &str) -> ModulePath {
let demangled = identifier::demangle(mangled_module);
parse_tokens(&demangled)
}
fn parse_tokens(s: &str) -> ModulePath {
let (prefix, body) = strip_prefix(s);
let body = body.replace("@c", ":");
let path = body
.split("@s")
.filter(|seg| !seg.is_empty())
.collect::<Vec<_>>()
.join("/");
ModulePath { path, prefix }
}
fn strip_prefix(s: &str) -> (Option<PathPrefix>, &str) {
if let Some(rest) = s.strip_prefix("@m") {
if let Some(rest2) = rest.strip_prefix("@d") {
return (Some(PathPrefix::Directory), rest2);
}
(Some(PathPrefix::Module), rest)
} else if let Some(rest) = s.strip_prefix("@p") {
(Some(PathPrefix::Package), rest)
} else if let Some(rest) = s.strip_prefix("@h") {
(Some(PathPrefix::Higher), rest)
} else if let Some(rest) = s.strip_prefix("@d") {
(Some(PathPrefix::Directory), rest)
} else {
(None, s)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn stdlib_system() {
let m = decode("atpsystemdotnim_");
assert_eq!(m.path, "system.nim");
assert_eq!(m.prefix, Some(PathPrefix::Package));
}
#[test]
fn stdlib_submodule() {
let m = decode("atpsystematsexceptionsdotnim_");
assert_eq!(m.path, "system/exceptions.nim");
assert_eq!(m.prefix, Some(PathPrefix::Package));
}
#[test]
fn module_direct() {
let m = decode("atmast2nifdotnim_");
assert_eq!(m.path, "ast2nif.nim");
assert_eq!(m.prefix, Some(PathPrefix::Module));
}
#[test]
fn deep_path() {
let m = decode("atmatdatsdistatsnimonyatssrcatslibatsnifstreamsdotnim_");
assert_eq!(m.path, "dist/nimony/src/lib/nifstreams.nim");
assert_eq!(m.prefix, Some(PathPrefix::Directory));
}
#[test]
fn welive_security_example() {
let m = decode("atmCatcatstoolsatsNimatsnimminus2dot0dot0atslibatssystemdotnim_");
assert_eq!(m.path, "C:/tools/Nim/nim-2.0.0/lib/system.nim");
assert_eq!(m.prefix, Some(PathPrefix::Module));
}
#[test]
fn no_prefix() {
let m = decode("systemdotnim_");
assert_eq!(m.path, "system.nim");
assert_eq!(m.prefix, None);
}
#[test]
fn no_trailing_underscore() {
let m = decode("system");
assert_eq!(m.path, "system");
assert_eq!(m.prefix, None);
}
}