commit 4216ecda9c9af2de3bee25aac828a5144c745846
parent 79770bae74563dc2b8f75602cf82bf5ce77aca1d
Author: Drew DeVault <sir@cmpwn.com>
Date: Wed, 3 Feb 2021 14:26:15 -0500
Initial riggings for build tags and @test support
Diffstat:
7 files changed, 112 insertions(+), 6 deletions(-)
diff --git a/configure b/configure
@@ -19,6 +19,7 @@ harec() {
src/qinstr.c \
src/qtype.c \
src/scope.c \
+ src/tags.c \
src/trace.c \
src/type_store.c \
src/typedef.c \
diff --git a/include/check.h b/include/check.h
@@ -5,6 +5,7 @@
#include "types.h"
#include "type_store.h"
+struct build_tags;
struct expression;
struct scope;
@@ -12,6 +13,7 @@ struct context {
struct type_store *store;
const struct type *fntype;
struct identifier *ns;
+ struct build_tags *tags;
struct scope *unit;
struct scope *scope;
bool deferring;
@@ -81,6 +83,7 @@ struct ast_expression;
struct ast_unit;
struct scope *check(struct type_store *ts,
+ struct build_tags *tags,
const struct ast_unit *aunit,
struct unit *unit);
diff --git a/include/tags.h b/include/tags.h
@@ -0,0 +1,21 @@
+#ifndef HARE_TAGS_H
+#define HARE_TAGS_H
+#include <stdbool.h>
+
+enum tag_mode {
+ TAG_INCLUDE,
+ TAG_EXCLUDE,
+};
+
+struct build_tags {
+ const char *tag;
+ enum tag_mode mode;
+ struct build_tags *next;
+};
+
+// Returns NULL on invalid syntax
+struct build_tags *parse_tags(char *input);
+
+bool tag_enabled(struct build_tags *tags, const char *tag);
+
+#endif
diff --git a/src/check.c b/src/check.c
@@ -9,6 +9,7 @@
#include "expr.h"
#include "mod.h"
#include "scope.h"
+#include "tags.h"
#include "trace.h"
#include "type_store.h"
#include "types.h"
@@ -1568,8 +1569,11 @@ check_function(struct context *ctx,
}
const struct ast_function_decl *afndecl = &adecl->function;
- trenter(TR_CHECK, "function");
+ if ((adecl->function.flags & FN_TEST) && !tag_enabled(ctx->tags, "test")) {
+ return NULL;
+ }
+ trenter(TR_CHECK, "function");
const struct ast_type fn_atype = {
.storage = TYPE_STORAGE_FUNCTION,
.flags = TYPE_CONST,
@@ -1788,6 +1792,9 @@ scan_const(struct context *ctx, const struct ast_global_decl *decl)
static void
scan_function(struct context *ctx, const struct ast_function_decl *decl)
{
+ if ((decl->flags & FN_TEST) && !tag_enabled(ctx->tags, "test")) {
+ return;
+ }
trenter(TR_SCAN, "function");
const struct ast_type fn_atype = {
.storage = TYPE_STORAGE_FUNCTION,
@@ -1947,10 +1954,12 @@ load_import(struct ast_imports *import,
}
struct scope *
-check(struct type_store *ts, const struct ast_unit *aunit, struct unit *unit)
+check(struct type_store *ts, struct build_tags *tags,
+ const struct ast_unit *aunit, struct unit *unit)
{
struct context ctx = {0};
ctx.ns = unit->ns;
+ ctx.tags = tags;
ctx.store = ts;
ctx.store->check_context = &ctx;
diff --git a/src/main.c b/src/main.c
@@ -12,8 +12,9 @@
#include "lex.h"
#include "parse.h"
#include "qbe.h"
-#include "typedef.h"
+#include "tags.h"
#include "type_store.h"
+#include "typedef.h"
#include "util.h"
static void
@@ -57,6 +58,7 @@ int
main(int argc, char *argv[])
{
char *output = NULL, *typedefs = NULL;
+ struct build_tags *tags = NULL;
struct unit unit = {0};
struct lexer lexer;
@@ -67,7 +69,12 @@ main(int argc, char *argv[])
output = optarg;
break;
case 'T':
- assert(0); // TODO: Build tags
+ tags = parse_tags(optarg);
+ if (!tags) {
+ fprintf(stderr, "Invalid tags\n");
+ return 1;
+ }
+ break;
case 't':
typedefs = optarg;
break;
@@ -131,7 +138,7 @@ main(int argc, char *argv[])
struct type_store ts = {0};
builtin_types_init();
- check(&ts, &aunit, &unit);
+ check(&ts, tags, &aunit, &unit);
if (stage == STAGE_CHECK) {
dump_unit(&unit);
return 0;
diff --git a/src/mod.c b/src/mod.c
@@ -64,5 +64,5 @@ module_resolve(struct identifier *ident, struct type_store *store)
// TODO: Free unused bits
struct unit u = {0};
- return check(store, &aunit, &u);
+ return check(store, NULL, &aunit, &u);
}
diff --git a/src/tags.c b/src/tags.c
@@ -0,0 +1,65 @@
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#include "tags.h"
+#include "util.h"
+
+struct build_tags *
+parse_tags(char *input)
+{
+ struct build_tags *tag, **next = &tag;
+ while (input[0]) {
+ enum tag_mode mode;
+ switch (input[0]) {
+ case '+':
+ mode = TAG_INCLUDE;
+ break;
+ case '-':
+ mode = TAG_EXCLUDE;
+ break;
+ default:
+ return NULL;
+ }
+ ++input;
+
+ char c;
+ char *tok = NULL;
+ char *p = strchr(input, '+'), *m = strchr(input, '-');
+ if (p && !m) {
+ tok = p;
+ } else if (m && !p) {
+ tok = m;
+ } else if (m && p) {
+ tok = m < p ? m : p;
+ }
+
+ if (tok) {
+ c = *tok;
+ *tok = '\0';
+ }
+
+ tag = *next = xcalloc(1, sizeof(struct build_tags));
+ tag->tag = strdup(input);
+ tag->mode = mode;
+ next = &tag->next;
+
+ if (tok) {
+ *tok = c;
+ }
+
+ input += strlen(tag->tag);
+ }
+ return tag;
+}
+
+bool
+tag_enabled(struct build_tags *tags, const char *tag)
+{
+ while (tags) {
+ if (strcmp(tags->tag, tag) == 0) {
+ return tags->mode == TAG_INCLUDE;
+ }
+ tags = tags->next;
+ }
+ return false;
+}