commit de0f374da023d1aade805bb0198bf45f76eba71b
parent f85f1f7cdcfccb683497172a70bfc687a0595680
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 20 Mar 2021 10:42:03 -0400
Implement -D (define) option
Diffstat:
9 files changed, 120 insertions(+), 30 deletions(-)
diff --git a/include/check.h b/include/check.h
@@ -17,8 +17,19 @@ struct modcache {
struct modcache *next;
};
+struct ast_expression;
+struct ast_unit;
+
+struct define {
+ struct identifier ident;
+ struct ast_type *type;
+ struct ast_expression *initializer;
+ struct define *next;
+};
+
struct context {
struct modcache **modcache;
+ struct define *defines;
struct type_store *store;
const struct type *fntype;
struct identifier *ns;
@@ -88,20 +99,19 @@ struct unit {
struct imports *imports;
};
-struct ast_expression;
-struct ast_unit;
-
struct scope *check(struct type_store *ts,
struct build_tags *tags,
+ struct define *defines,
const struct ast_unit *aunit,
struct unit *unit);
struct scope *check_internal(struct type_store *ts,
- struct modcache **cache,
- struct build_tags *tags,
- const struct ast_unit *aunit,
- struct unit *unit,
- bool scan_only);
+ struct modcache **cache,
+ struct build_tags *tags,
+ struct define *defines,
+ const struct ast_unit *aunit,
+ struct unit *unit,
+ bool scan_only);
struct errors {
struct location loc;
diff --git a/include/lex.h b/include/lex.h
@@ -163,6 +163,7 @@ struct lexer {
uint32_t c[2];
struct token un;
struct location loc;
+ bool disable_labels;
};
void lex_init(struct lexer *lexer, FILE *f, const char *filename);
diff --git a/include/mod.h b/include/mod.h
@@ -5,7 +5,10 @@
#include "type_store.h"
struct modcache;
+struct define;
struct scope *module_resolve(struct modcache *cache[],
- struct identifier *ident, struct type_store *store);
+ struct define *defines,
+ struct identifier *ident,
+ struct type_store *store);
#endif
diff --git a/include/parse.h b/include/parse.h
@@ -2,10 +2,14 @@
#define HAREC_PARSE_H
#include <stdio.h>
+struct ast_expression;
struct ast_subunit;
+struct ast_type;
struct lexer;
void parse(struct lexer *lexer, struct ast_subunit *unit);
bool parse_identifier(struct lexer *lexer, struct identifier *ident, bool trailing);
+struct ast_type *parse_type(struct lexer *lexer);
+struct ast_expression *parse_simple_expression(struct lexer *lexer);
#endif
diff --git a/src/check.c b/src/check.c
@@ -3295,7 +3295,8 @@ static void
load_import(struct context *ctx, struct ast_imports *import,
struct type_store *ts, struct scope *scope)
{
- struct scope *mod = module_resolve(ctx->modcache, &import->ident, ts);
+ struct scope *mod = module_resolve(ctx->modcache,
+ ctx->defines, &import->ident, ts);
switch (import->mode) {
case AST_IMPORT_IDENTIFIER:
@@ -3385,11 +3386,12 @@ load_import(struct context *ctx, struct ast_imports *import,
struct scope *
check_internal(struct type_store *ts,
- struct modcache **cache,
- struct build_tags *tags,
- const struct ast_unit *aunit,
- struct unit *unit,
- bool scan_only)
+ struct modcache **cache,
+ struct build_tags *tags,
+ struct define *defines,
+ const struct ast_unit *aunit,
+ struct unit *unit,
+ bool scan_only)
{
struct context ctx = {0};
ctx.ns = unit->ns;
@@ -3397,6 +3399,7 @@ check_internal(struct type_store *ts,
ctx.store = ts;
ctx.store->check_context = &ctx;
ctx.modcache = cache;
+ ctx.defines = defines;
// Top-level scope management involves:
//
@@ -3408,6 +3411,33 @@ check_internal(struct type_store *ts,
// sub-scopes for each declaration, expression-list, etc.
ctx.unit = scope_push(&ctx.scope, TR_MAX);
+ // Install defines (-D on the command line)
+ // XXX: This duplicates a lot of code with scan_const
+ for (struct define *def = defines; def; def = def->next) {
+ struct location loc = {
+ .path = "-D", .lineno = 1, .colno = 1,
+ };
+ const struct type *type = type_store_lookup_atype(
+ ctx.store, def->type);
+ expect(&loc, type != NULL, "Unable to resolve type");
+ struct expression *initializer =
+ xcalloc(1, sizeof(struct expression));
+ struct errors *errors = check_expression(&ctx,
+ def->initializer, initializer, type, NULL);
+ // TODO: This could be more detailed
+ expect(&loc, errors == NULL, "Invalid initializer");
+ expect(&loc, type_is_assignable(type, initializer->result),
+ "Constant type is not assignable from initializer type");
+ initializer = lower_implicit_cast(type, initializer);
+ struct expression *value =
+ xcalloc(1, sizeof(struct expression));
+ enum eval_result r = eval_expr(&ctx, initializer, value);
+ expect(&loc, r == EVAL_OK,
+ "Unable to evaluate constant initializer at compile time");
+ scope_insert(ctx.unit, O_CONST,
+ &def->ident, &def->ident, type, value);
+ }
+
struct scopes *subunit_scopes;
struct scopes **next = &subunit_scopes;
struct imports **inext = &unit->imports;
@@ -3526,11 +3556,12 @@ check_internal(struct type_store *ts,
struct scope *
check(struct type_store *ts,
- struct build_tags *tags,
- const struct ast_unit *aunit,
- struct unit *unit)
+ struct build_tags *tags,
+ struct define *defines,
+ const struct ast_unit *aunit,
+ struct unit *unit)
{
struct modcache *modcache[MODCACHE_BUCKETS];
memset(modcache, 0, sizeof(modcache));
- return check_internal(ts, modcache, tags, aunit, unit, false);
+ return check_internal(ts, modcache, tags, defines, aunit, unit, false);
}
diff --git a/src/lex.c b/src/lex.c
@@ -756,7 +756,8 @@ lex2(struct lexer *lexer, struct token *out, uint32_t c)
break;
default:
push(lexer, c, false);
- if (c <= 0x7F && (isalpha(c) || c == '_')) {
+ if (!lexer->disable_labels && c <= 0x7F
+ && (isalpha(c) || c == '_')) {
return lex_label(lexer, out);
}
out->token = T_COLON;
diff --git a/src/main.c b/src/main.c
@@ -53,6 +53,42 @@ parse_stage(const char *s)
}
}
+static struct define *
+parse_define(const char *argv_0, const char *in)
+{
+ struct define *def = xcalloc(1, sizeof(struct define));
+
+ struct token tok;
+ struct lexer lexer;
+ FILE *f = fmemopen((char *)in, strlen(in), "r");
+ lex_init(&lexer, f, "-D");
+
+ // The syntax for this parameter is:
+ //
+ // -D ident:type=value
+ //
+ // :type is lexed as a label unless we disable it here.
+ lexer.disable_labels = true;
+
+ parse_identifier(&lexer, &def->ident, false);
+ if (lex(&lexer, &tok) != T_COLON) {
+ lex_finish(&lexer);
+ usage(argv_0);
+ exit(1);
+ }
+ def->type = parse_type(&lexer);
+
+ if (lex(&lexer, &tok) != T_EQUAL) {
+ lex_finish(&lexer);
+ usage(argv_0);
+ exit(1);
+ }
+ def->initializer = parse_simple_expression(&lexer);
+
+ lex_finish(&lexer);
+ return def;
+}
+
int
main(int argc, char *argv[])
{
@@ -60,10 +96,16 @@ main(int argc, char *argv[])
struct build_tags *tags = NULL;
struct unit unit = {0};
struct lexer lexer;
+ struct define *defines, *def;
int c;
- while ((c = getopt(argc, argv, "o:T:t:N:")) != -1) {
+ while ((c = getopt(argc, argv, "D:o:T:t:N:")) != -1) {
switch (c) {
+ case 'D':
+ def = parse_define(argv[0], optarg);
+ def->next = defines;
+ defines = def;
+ break;
case 'o':
output = optarg;
break;
@@ -137,7 +179,7 @@ main(int argc, char *argv[])
struct type_store ts = {0};
builtin_types_init();
- check(&ts, tags, &aunit, &unit);
+ check(&ts, tags, defines, &aunit, &unit);
if (stage == STAGE_CHECK) {
return 0;
}
diff --git a/src/mod.c b/src/mod.c
@@ -64,8 +64,9 @@ open_typedefs(struct identifier *ident)
struct scope *
module_resolve(struct modcache *cache[],
- struct identifier *ident,
- struct type_store *store)
+ struct define *defines,
+ struct identifier *ident,
+ struct type_store *store)
{
uint32_t hash = identifier_hash(FNV1A_INIT, ident);
struct modcache **bucket = &cache[hash % MODCACHE_BUCKETS];
@@ -94,7 +95,7 @@ module_resolve(struct modcache *cache[],
// TODO: Free unused bits
struct unit u = {0};
struct scope *scope = check_internal(store,
- cache, NULL, &aunit, &u, true);
+ cache, NULL, defines, &aunit, &u, true);
bucket = &cache[hash % MODCACHE_BUCKETS];
struct modcache *item = xcalloc(1, sizeof(struct modcache));
diff --git a/src/parse.c b/src/parse.c
@@ -256,8 +256,6 @@ parse_imports(struct lexer *lexer, struct ast_subunit *subunit)
trleave(TR_PARSE, NULL);
}
-static struct ast_type *parse_type(struct lexer *lexer);
-
static void
parse_parameter_list(struct lexer *lexer, struct ast_function_type *type)
{
@@ -444,7 +442,6 @@ parse_primitive_type(struct lexer *lexer)
return type;
}
-static struct ast_expression *parse_simple_expression(struct lexer *lexer);
static struct ast_expression *parse_complex_expression(struct lexer *lexer);
static struct ast_expression *parse_compound_expression(struct lexer *lexer);
static struct ast_expression *parse_postfix_expression(struct lexer *lexer,
@@ -664,7 +661,7 @@ parse_tagged_or_tuple_type(struct lexer *lexer)
assert(0); // Unreachable
}
-static struct ast_type *
+struct ast_type *
parse_type(struct lexer *lexer)
{
trenter(TR_PARSE, "type");
@@ -1735,7 +1732,7 @@ parse_bin_expression(struct lexer *lexer, struct ast_expression *lvalue, int i)
return lvalue;
}
-static struct ast_expression *
+struct ast_expression *
parse_simple_expression(struct lexer *lexer)
{
return parse_bin_expression(lexer, NULL, 0);