hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 5d22b63c9cb0325eeadeddb957f6369439803d43
parent bae714096f1a0571b82261d33644223fb2957cc2
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sun,  7 Mar 2021 09:25:06 -0500

path: add path::extension

Diffstat:
Mhare/module/scan.ha | 12+++++++-----
Mpath/names.ha | 44+++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/hare/module/scan.ha b/hare/module/scan.ha @@ -79,19 +79,21 @@ export fn lookup(ctx: *context, name: ast::ident) (version | error) = { return module_not_found; }; -// TODO: Filter inputs by build tags fn eligible(ctx: *context, name: path::path) bool = { if (!(name is str)) { return false; }; - let name = name as str; + let eligible = false; + const ext = path::extension(name); static const exts = [".ha", ".s"]; for (let i = 0z; i < len(exts); i += 1) { - if (strings::has_suffix(name, exts[i])) { - return true; + if (exts[i] == ext) { + eligible = true; + break; }; }; - return false; + // TODO: Check build tags as well + return eligible; }; fn scan_file( diff --git a/path/names.ha b/path/names.ha @@ -1,4 +1,5 @@ use bytes; +use encoding::utf8; use strings; // Returns the directory name for a given path. For a path to a file name, this @@ -61,4 +62,45 @@ export fn basename(path: path::path) path::path = { }; // Returns true if the given path is a root directory. -export fn is_root(path: path::path) bool = len(pathbytes(path)) == 1; +export fn is_root(path: path::path) bool = { + let b = pathbytes(path); + if (len(b) == 0) { + return false; + }; + return b[0] == PATHSEP; +}; + +// Returns the file extension for a path. This presumes that the file extension +// is a valid UTF-8 string, if not, it will return an empty string. The return +// value is borrowed from the input, see [strings::dup] to extend its lifetime. +// +// The return value includes the '.' character. +// +// extension("foo/example") => "" +// extension("foo/example.txt") => ".txt" +// extension("foo/example.tar.gz") => ".tar.gz" +export fn extension(p: path::path) str = { + let b = pathbytes(p); + if (len(b) == 0 || b[len(b) - 1] == PATHSEP) { + return ""; + }; + let b = pathbytes(basename(p)); + let i = match (bytes::index(b, '.': u32: u8)) { + void => return "", + z: size => z, + }; + let e = b[i..]; + return match (strings::try_from_utf8(e)) { + utf8::invalid => "", + s: str => s, + }; +}; + +@test fn extension() void = { + assert(extension("") == ""); + assert(extension("foo/") == ""); + assert(extension("foo/bar") == ""); + assert(extension("foo/bar.txt") == ".txt"); + assert(extension("foo/bar.tar.gz") == ".tar.gz"); + assert(extension("foo.bar/baz.ha") == ".ha"); +};