hare

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

util.ha (1754B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use ascii;
      5 use fs;
      6 use os;
      7 use strings;
      8 use time;
      9 
     10 // insert a string into a sorted list of strings, deduplicated.
     11 fn insert_uniq(into: *[]str, s: str) void = {
     12 	let i = 0z;
     13 	// the `into` slice is generally small enough that a linear search is
     14 	// fine
     15 	for (i < len(into) && strings::compare(into[i], s) < 0) {
     16 		i += 1;
     17 	};
     18 	if (i == len(into) || into[i] != s) {
     19 		insert(into[i], strings::dup(s));
     20 	};
     21 };
     22 
     23 // Checks if the file at 'target' is out-of-date, given a list of dependency
     24 // files, and the last time the deps list changed. If "target" doesn't exist,
     25 // returns true. If any of the deps don't exist, they are skipped.
     26 export fn outdated(target: str, deps: []str, mtime: time::instant) bool = {
     27 	let current = match (os::stat(target)) {
     28 	case fs::error =>
     29 		return true;
     30 	case let stat: fs::filestat =>
     31 		yield stat.mtime;
     32 	};
     33 	if (time::compare(current, mtime) < 0) {
     34 		return true;
     35 	};
     36 	for (let dep .. deps) {
     37 		match (os::stat(dep)) {
     38 		case fs::error =>
     39 			continue;
     40 		case let stat: fs::filestat =>
     41 			if (time::compare(current, stat.mtime) < 0) {
     42 				return true;
     43 			};
     44 		};
     45 	};
     46 	return false;
     47 };
     48 
     49 // Wrapper for [[fs::next]] that only returns valid submodule directories.
     50 export fn next(it: *fs::iterator) (fs::dirent | done | fs::error) = {
     51 	for (let d => fs::next(it)?) {
     52 		if (!fs::isdir(d.ftype)) {
     53 			continue;
     54 		};
     55 		if (is_submodule(d.name)) {
     56 			return d;
     57 		};
     58 	};
     59 	return done;
     60 };
     61 
     62 fn is_submodule(path: str) bool = {
     63 	let it = strings::iter(path);
     64 
     65 	let first = true;
     66 	for (let r => strings::next(&it)) {
     67 		if (!ascii::isalpha(r) && r != '_'
     68 				&& (first || !ascii::isdigit(r))) {
     69 			return false;
     70 		};
     71 
     72 		first = false;
     73 	};
     74 	return true;
     75 };