commit 245815c694a4fde576c62367e22c3a5ae18374b0
parent 2a2795b6c27b35408ae5d5a4357ad96ecca5c7b8
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 7 Mar 2021 11:14:37 -0500
hare::module: parse tags for file eligibility
Diffstat:
2 files changed, 74 insertions(+), 3 deletions(-)
diff --git a/hare/module/scan.ha b/hare/module/scan.ha
@@ -1,4 +1,6 @@
+use bytes;
use crypto::sha256;
+use encoding::utf8;
use fs;
use hare::ast;
use hare::lex;
@@ -86,7 +88,7 @@ export fn lookup(ctx: *context, name: ast::ident) (version | error) = {
};
fn eligible(ctx: *context, name: path::path) bool = {
- if (!(name is str)) {
+ if (!utf8::valid(name: []u8)) {
return false;
};
let eligible = false;
@@ -98,8 +100,31 @@ fn eligible(ctx: *context, name: path::path) bool = {
break;
};
};
- // TODO: Check build tags as well
- return eligible;
+ if (!eligible) {
+ return false;
+ };
+
+ // XXX: It might be nice if the stdlib offered search functions which
+ // support multiple needles
+ let b = name: []u8;
+ let p = bytes::index(b, '+': u32: u8);
+ let m = bytes::index(b, '-': u32: u8);
+ if (p is void && m is void) {
+ return true;
+ };
+ let i: size =
+ if (p is void && m is size) m: size
+ else if (m is void && p is size) p: size
+ else if (m: size < p: size) m: size
+ else p: size;
+ let tags = b[i..(bytes::index(b, '.': u32: u8) as size)];
+ let tags = match (parse_tags(strings::from_utf8_unsafe(tags))) {
+ void => return false,
+ t: []tag => t,
+ };
+ defer tags_free(tags);
+ // TODO: Check tag compatibility
+ return true;
};
fn type_for_ext(name: path::path) (filetype | void) = {
diff --git a/hare/module/types.ha b/hare/module/types.ha
@@ -1,8 +1,11 @@
+use ascii;
use fs;
use hare::ast;
use hare::parse;
use io;
use path;
+use strings;
+use strio;
// The inclusive/exclusive state for a build tag.
export type tag_mode = enum {
@@ -16,6 +19,49 @@ export type tag = struct {
mode: tag_mode,
};
+// Parses a set of build tags, returning void if the string is an invalid tag
+// set. The caller must free the return value with [tags_free].
+export fn parse_tags(in: str) ([]tag | void) = {
+ let tags: []tag = [];
+ // defer! tags_free(tags);
+ let iter = strings::iter(in);
+ for (true) {
+ let t = tag { ... };
+ let m = match (strings::next(&iter)) {
+ void => break,
+ r: rune => r,
+ };
+ t.mode = switch (m) {
+ * => return,
+ '+' => tag_mode::INCLUSIVE,
+ '-' => tag_mode::EXCLUSIVE,
+ };
+ let buf = strio::dynamic();
+ for (true) match (strings::next(&iter)) {
+ void => break,
+ r: rune => {
+ if (ascii::isalnum(r) || r == '_') {
+ strio::append_rune(buf, r);
+ } else {
+ strings::push(&iter, r);
+ break;
+ };
+ },
+ };
+ t.name = strio::finish(buf);
+ append(tags, t);
+ };
+ return tags;
+};
+
+// Frees a set of tags.
+export fn tags_free(tags: []tag) void = {
+ for (let i = 0z; i < len(tags); i += 1) {
+ free(tags[i].name);
+ };
+ free(tags);
+};
+
// The manifest for a particular module, with some number of inputs, and
// versions.
export type manifest = struct {