hare

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

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:
Mhare/module/scan.ha | 31++++++++++++++++++++++++++++---
Mhare/module/types.ha | 46++++++++++++++++++++++++++++++++++++++++++++++
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 {