commit 2f7f40ec53b6c2a38abf4746f45cf3f1805c51f3
parent bd79703c2368280a4f1b12406f193a162f71e1c9
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 19 Dec 2020 09:27:17 -0500
Initial riggings for function check
Diffstat:
9 files changed, 154 insertions(+), 15 deletions(-)
diff --git a/include/ast.h b/include/ast.h
@@ -3,6 +3,7 @@
#include <stdbool.h>
#include <stdint.h>
#include "check.h"
+#include "expr.h"
#include "identifier.h"
#include "types.h"
@@ -83,10 +84,6 @@ struct ast_type {
};
};
-enum expression_type {
- EXPR_CONSTANT,
-};
-
struct ast_constant_expression {
enum type_storage storage;
union {
@@ -100,7 +97,7 @@ struct ast_constant_expression {
};
struct ast_expression {
- enum expression_type type;
+ enum expr_type type;
union {
struct ast_constant_expression constant;
};
diff --git a/include/check.h b/include/check.h
@@ -30,6 +30,9 @@ struct declaration {
enum declaration_type type;
struct identifier ident;
bool exported;
+ union {
+ struct function_decl func;
+ };
};
struct declarations {
diff --git a/include/expr.h b/include/expr.h
@@ -0,0 +1,52 @@
+#ifndef HAREC_EXPR_H
+#define HAREC_EXPR_H
+#include "types.h"
+
+enum expr_type {
+ EXPR_ACCESS,
+ EXPR_ASSERT,
+ EXPR_ASSIGN,
+ EXPR_BINARITHM,
+ EXPR_BINDING_LIST,
+ EXPR_CALL,
+ EXPR_CAST,
+ EXPR_CONSTANT,
+ EXPR_CONTROL,
+ EXPR_FOR,
+ EXPR_FREE,
+ EXPR_FUNC,
+ EXPR_IF,
+ EXPR_INDEX,
+ EXPR_LIST,
+ EXPR_MATCH,
+ EXPR_MEASURE,
+ EXPR_SLICE,
+ EXPR_STRUCT,
+ EXPR_SWITCH,
+ EXPR_UNARITHM,
+ EXPR_WHILE,
+};
+
+// TODO: Stretchy constants
+union expression_constant {
+ bool bval;
+ struct {
+ char *sval;
+ size_t ssz;
+ };
+ double fval;
+ intmax_t ival;
+ uintmax_t uval;
+ // TODO: Array, slice, struct constants
+};
+
+struct expression {
+ const struct type *result;
+ enum expr_type type;
+ bool terminates;
+ union {
+ union expression_constant constant;
+ };
+};
+
+#endif
diff --git a/include/trace.h b/include/trace.h
@@ -4,6 +4,8 @@
enum trace_sys {
TR_LEX,
TR_PARSE,
+ TR_SCAN,
+ TR_CHECK,
TR_MAX,
};
diff --git a/include/types.h b/include/types.h
@@ -126,7 +126,6 @@ extern const struct type
builtin_type_const_uintptr,
builtin_type_const_rune,
builtin_type_const_size,
- builtin_type_const_void,
// Aggregate
builtin_type_const_ptr_char;
diff --git a/src/check.c b/src/check.c
@@ -1,21 +1,80 @@
#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include "ast.h"
#include "check.h"
-#include "types.h"
+#include "expr.h"
+#include "trace.h"
#include "type_store.h"
+#include "types.h"
struct context {
struct type_store store;
};
static void
+expect(bool constraint, char *fmt, ...)
+{
+ // TODO: Bring along line numbers and such
+ if (!constraint) {
+ va_list ap;
+ va_start(ap, fmt);
+
+ fprintf(stderr, "Error: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ }
+}
+
+static void
+check_expression(struct context *ctx,
+ const struct ast_expression *aexpr,
+ struct expression *expr)
+{
+ trenter(TR_CHECK, "expression");
+ assert(0); // TODO
+ trleave(TR_CHECK, NULL);
+}
+
+static void
check_function(struct context *ctx,
const struct ast_function_decl *adecl,
struct declaration *decl)
{
+ assert(!adecl->prototype.params); // TODO
+ trenter(TR_CHECK, "function");
+
+ const struct ast_type fn_atype = {
+ .storage = TYPE_STORAGE_FUNCTION,
+ .flags = TYPE_CONST,
+ .func = adecl->prototype,
+ };
+ const struct type *fntype = type_store_lookup_atype(
+ &ctx->store, &fn_atype);
+ assert(fntype); // Invariant
decl->type = DECL_FUNC;
- assert(0); // TODO
+ decl->func.type = fntype;
+ decl->func.flags = adecl->flags;
+
+ struct expression *body = calloc(1, sizeof(struct expression));
+ check_expression(ctx, &adecl->body, body);
+ // TODO: Check assignability of expression result to function type
+
+ // TODO: Add function name to errors
+ if ((decl->func.flags & FN_INIT)
+ || (decl->func.flags & FN_FINI)
+ || (decl->func.flags & FN_TEST)) {
+ const char *flags = "@flags"; // TODO: Unparse flags
+ expect(fntype->func.result == &builtin_type_void,
+ "%s function must return void", flags);
+ }
+ if ((fntype->func.flags & FN_NORETURN)) {
+ expect(!body->terminates, "@noreturn function must not terminate.");
+ } else {
+ expect(body->terminates, "This function never terminates. Add a return statement or @noreturn.");
+ }
+ trleave(TR_CHECK, NULL);
}
static void
@@ -23,6 +82,7 @@ check_declarations(struct context *ctx,
const struct ast_decls *adecls,
struct declarations **next)
{
+ trenter(TR_CHECK, "declarations");
while (adecls) {
struct declarations *decls = *next =
calloc(1, sizeof(struct declarations));
@@ -43,11 +103,13 @@ check_declarations(struct context *ctx,
adecls = adecls->next;
next = &decls->next;
}
+ trleave(TR_CHECK, NULL);
}
static void
scan_function(struct context *ctx, const struct ast_function_decl *decl)
{
+ trenter(TR_SCAN, "function");
const struct ast_type fn_atype = {
.storage = TYPE_STORAGE_FUNCTION,
.flags = TYPE_CONST,
@@ -56,11 +118,16 @@ scan_function(struct context *ctx, const struct ast_function_decl *decl)
const struct type *fntype = type_store_lookup_atype(
&ctx->store, &fn_atype);
assert(fntype); // TODO: Forward references
+
+ char buf[1024];
+ identifier_unparse_static(&decl->ident, buf, sizeof(buf));
+ trleave(TR_SCAN, "func %s", buf);
}
static void
scan_declarations(struct context *ctx, const struct ast_decls *decls)
{
+ trenter(TR_SCAN, "declarations");
while (decls) {
const struct ast_decl *decl = &decls->decl;
switch (decl->decl_type) {
@@ -76,6 +143,7 @@ scan_declarations(struct context *ctx, const struct ast_decls *decls)
}
decls = decls->next;
}
+ trleave(TR_SCAN, NULL);
}
void
diff --git a/src/trace.c b/src/trace.c
@@ -8,11 +8,15 @@
static const char *sysname[] = {
[TR_LEX] = "lex",
[TR_PARSE] = "parse",
+ [TR_SCAN] = "scan",
+ [TR_CHECK] = "check",
};
static int depth[] = {
[TR_LEX] = 0,
[TR_PARSE] = 0,
+ [TR_SCAN] = 0,
+ [TR_CHECK] = 0,
};
static void
diff --git a/src/type_store.c b/src/type_store.c
@@ -139,7 +139,8 @@ builtin_for_atype(const struct ast_type *atype)
case TYPE_STORAGE_UINTPTR:
return is_const ? &builtin_type_uintptr : &builtin_type_const_uintptr;
case TYPE_STORAGE_VOID:
- return is_const ? &builtin_type_void : &builtin_type_const_void;
+ // const void and void are the same type
+ return is_const ? &builtin_type_void : &builtin_type_void;
case TYPE_STORAGE_POINTER:
if (atype->pointer.referent->storage == TYPE_STORAGE_CHAR
&& atype->pointer.referent->flags == TYPE_CONST) {
@@ -191,7 +192,26 @@ type_eq_atype(struct type_store *store,
return true;
case TYPE_STORAGE_ALIAS:
case TYPE_STORAGE_ARRAY:
+ assert(0); // TODO
case TYPE_STORAGE_FUNCTION:
+ if (!type_eq_atype(store, type->func.result, atype->func.result)
+ || type->func.variadism != atype->func.variadism
+ || type->func.flags != atype->func.flags) {
+ return false;
+ }
+ struct ast_function_parameters *aparam;
+ struct type_func_param *param;
+ for (aparam = atype->func.params, param = type->func.params;
+ aparam && param;
+ aparam = aparam->next, param = param->next) {
+ if (!!aparam->next != !!param->next) {
+ return false;
+ }
+ if (!type_eq_atype(store, param->type, aparam->type)) {
+ return false;
+ }
+ }
+ return true;
case TYPE_STORAGE_POINTER:
case TYPE_STORAGE_SLICE:
case TYPE_STORAGE_STRING:
diff --git a/src/types.c b/src/types.c
@@ -256,12 +256,6 @@ builtin_type_const_size = {
.flags = TYPE_CONST,
.size = 8, // XXX: ARCH
.align = 8,
-},
-builtin_type_const_void = {
- .storage = TYPE_STORAGE_VOID,
- .flags = TYPE_CONST,
- .size = 0,
- .align = 0,
};
// Selected aggregate type singletons