harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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:
Minclude/ast.h | 7++-----
Minclude/check.h | 3+++
Ainclude/expr.h | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/trace.h | 2++
Minclude/types.h | 1-
Msrc/check.c | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/trace.c | 4++++
Msrc/type_store.c | 22+++++++++++++++++++++-
Msrc/types.c | 6------
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