ref: vendor harec checker sources (#20)

ref/hare/ ships only ast/lex/parse/module/unparse — no checker. Every
bail-fix landing in A.6.2.1 (helper bail audit, N_IDENT bail audit,
enum fold) needs a `ref/harec/...` cite anchor so divergence rationale
isn't claimed against memory. PLAN.md L16, L35.

Snapshot of upstream commit ee640c6b2c17f57e8014d277a3028b262ffb7952
(`rt/+openbsd/start.ha: remove outdated comment about crt0`). 20 files:
5 src (check.c, eval.c, scope.c, types.c, type_store.c), 14 transitive
include/ headers (no parser/codegen surface), and COPYING.

License GPLv3 (COPYING included). Vendored as read-only reference per
CLAUDE.md rule 6 — no redistribution as binary, no edits.
This commit is contained in:
2026-05-21 23:03:11 +09:00
parent 6c70b46d5f
commit 8e3752f5ea
20 changed files with 11736 additions and 0 deletions

11
ref/harec/include/arch.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef HAREC_ARCH_H
#define HAREC_ARCH_H
enum arch {
AARCH64,
PPC64LE,
RISCV64,
X86_64,
};
#endif

444
ref/harec/include/ast.h Normal file
View File

@@ -0,0 +1,444 @@
#ifndef HARE_AST_H
#define HARE_AST_H
#include <stdbool.h>
#include <stdint.h>
#include "expr.h"
#include "identifier.h"
#include "lex.h"
#include "types.h"
struct ast_type;
enum ast_import_mode {
IMPORT_NORMAL, // use foo::bar;
IMPORT_ALIAS, // use foo = bar::baz;
IMPORT_MEMBERS, // use foo::{bar, baz};
IMPORT_WILDCARD, // use foo::bar::*;
};
struct ast_import_members {
struct location loc;
struct ident *name;
struct ast_import_members *next;
};
struct ast_imports {
enum ast_import_mode mode;
struct ident *ident;
union {
const char *alias;
struct ast_import_members *members;
};
struct ast_imports *next;
};
struct ast_array_type {
struct ast_expression *length; // NULL for unbounded arrays
struct ast_type *members;
bool contextual;
};
struct ast_slice_type {
struct ast_type *members;
};
struct ast_enum_field {
struct location loc;
struct ident *name;
struct ast_expression *value;
struct ast_enum_field *next;
};
struct ast_enum_type {
enum type_storage storage;
struct ast_enum_field *values;
};
struct ast_function_parameters {
struct location loc;
struct ident *name;
struct ast_type *type;
struct ast_expression *default_value;
struct ast_function_parameters *next;
};
struct ast_function_type {
struct ast_type *result;
struct ast_function_parameters *params;
enum variadism variadism;
};
struct ast_pointer_type {
struct ast_type *referent;
bool nullable;
};
struct ast_tagged_union_type {
struct ast_type *type;
bool unwrap;
struct ast_tagged_union_type *next;
};
struct ast_tuple_type {
struct ast_type *type;
struct ast_tuple_type *next;
};
struct ast_struct_union_field {
struct ast_struct_union_field *next;
const char *name; // null if embed, may be "_"
struct ast_type *type;
};
struct ast_struct_union_type {
struct ast_struct_union_field fields;
bool packed;
};
struct ast_type {
struct location loc;
enum type_storage storage;
union {
struct ast_array_type array;
struct ast_type *error;
struct ast_function_type func;
struct ast_pointer_type pointer;
struct ast_slice_type slice;
struct ast_struct_union_type struct_union;
struct ast_tagged_union_type tagged;
struct ast_tuple_type tuple;
struct {
struct ident *alias;
// Only valid for enums
struct ast_enum_type _enum;
};
};
};
struct ast_types {
const struct ast_type *type;
struct ast_types *next;
};
struct ast_expression_list {
struct ast_expression *expr;
struct ast_expression_list *next;
};
struct ast_expression_access {
enum access_type type;
union {
struct ident *ident;
struct {
struct ast_expression *array;
struct ast_expression *index;
};
struct {
struct ast_expression *_struct;
const char *field;
};
struct {
struct ast_expression *tuple;
struct ast_expression *value;
};
};
};
struct ast_expression_alloc {
enum alloc_kind kind;
struct ast_expression *init;
struct ast_expression *cap;
};
struct ast_expression_append {
struct ast_expression *object;
struct ast_expression *value;
struct ast_expression *length;
bool is_static, is_multi;
};
struct ast_expression_assert {
struct ast_expression *cond;
struct ast_expression *message;
bool is_static;
};
struct ast_expression_assign {
enum binarithm_operator op;
// object == NULL for discarding assignment (`_ = foo`)
struct ast_expression *object, *value;
};
struct ast_expression_binarithm {
enum binarithm_operator op;
struct ast_expression *lvalue, *rvalue;
};
struct ast_binding_names {
struct ident *name; // NULL for _
struct ast_binding_names *next;
};
struct ast_expression_binding {
// more than one name means tuple unpacking,
// otherwise it's a regular binding
struct ast_binding_names names;
struct ast_type *type;
bool is_static;
struct ast_expression *initializer;
struct ast_expression_binding *next;
};
struct ast_expression_call {
struct ast_expression *lvalue;
struct ast_expression_list *args;
bool variadic; // last argument is a variadic argument list
};
struct ast_expression_cast {
enum cast_kind kind;
struct ast_expression *value;
struct ast_type *type;
};
struct ast_expression_literal {
enum type_storage storage;
union {
int64_t ival;
uint64_t uval;
double fval;
uint32_t rune;
bool bval;
struct {
size_t len;
char *value;
} string;
struct {
struct ast_expression_list *exprs;
bool expand;
} array;
};
};
struct ast_expression_control {
const char *label; // Never set for return.
struct ast_expression *value; // Never set for continue
};
struct ast_expression_defer {
struct ast_expression *deferred;
};
struct ast_expression_delete {
struct ast_expression *expr;
bool is_static;
};
struct ast_expression_for {
enum for_kind kind;
const char *label;
struct ast_expression *bindings;
struct ast_expression *cond;
struct ast_expression *afterthought;
struct ast_expression *body;
struct ast_expression *else_branch;
};
struct ast_expression_free {
struct ast_expression *expr;
};
struct ast_expression_if {
struct ast_expression *cond;
struct ast_expression *true_branch, *false_branch;
};
struct ast_expression_compound {
const char *label;
struct location label_loc;
struct ast_expression_list list;
};
struct ast_match_case {
struct ident *name; // May be null
struct ast_type *type;
struct ast_expression_list exprs;
struct ast_match_case *next;
};
struct ast_expression_match {
const char *label;
struct ast_expression *value;
struct ast_match_case *cases;
};
enum measure_operator {
M_ALIGN,
M_LEN,
M_SIZE,
M_OFFSET,
};
struct ast_expression_measure {
enum measure_operator op;
union {
struct ast_expression *value;
struct ast_type *type;
// TODO: Field selection
};
};
struct ast_expression_propagate {
struct ast_expression *value;
bool abort;
};
struct ast_expression_slice {
struct ast_expression *object;
struct ast_expression *start, *end;
};
struct ast_case_option {
struct ast_expression *value;
struct ast_case_option *next;
};
struct ast_switch_case {
struct ast_case_option *options; // NULL for *
struct ast_expression_list exprs;
struct ast_switch_case *next;
};
struct ast_expression_switch {
const char *label;
struct ast_expression *value;
struct ast_switch_case *cases;
};
struct ast_field_value {
const char *name;
struct ast_type *type;
struct ast_expression *initializer;
struct ast_field_value *next;
};
struct ast_expression_struct {
bool autofill;
bool undefined;
struct ident *type;
struct ast_field_value *fields;
};
struct ast_expression_tuple {
struct ast_expression *expr;
struct ast_expression_tuple *next;
};
struct ast_expression_unarithm {
enum unarithm_operator op;
struct ast_expression *operand;
};
struct ast_expression_vaarg {
struct ast_expression *ap;
struct ast_type *type;
};
struct ast_expression {
struct location loc;
enum expr_type type;
union {
struct ast_expression_access access;
struct ast_expression_alloc alloc;
struct ast_expression_append append; // also insert
struct ast_expression_assert assert;
struct ast_expression_assign assign;
struct ast_expression_binarithm binarithm;
struct ast_expression_binding binding;
struct ast_expression_call call;
struct ast_expression_cast cast;
struct ast_expression_compound compound;
struct ast_expression_control control;
struct ast_expression_defer defer;
struct ast_expression_delete delete;
struct ast_expression_for _for;
struct ast_expression_free free;
struct ast_expression_if _if;
struct ast_expression_literal literal;
struct ast_expression_match match;
struct ast_expression_measure measure;
struct ast_expression_propagate propagate;
struct ast_expression_slice slice;
struct ast_expression_struct _struct;
struct ast_expression_switch _switch;
struct ast_expression_tuple tuple;
struct ast_expression_unarithm unarithm;
struct ast_expression_vaarg vaarg;
};
};
struct ast_global_decl {
const char *symbol;
bool threadlocal;
struct ident *ident;
struct ast_type *type;
struct ast_expression *init;
};
struct ast_type_decl {
struct ident *ident;
struct ast_type *type;
};
enum func_decl_flags {
FN_FINI = 1 << 0,
FN_INIT = 1 << 1,
FN_TEST = 1 << 2,
};
struct ast_function_decl {
const char *symbol;
struct ident *ident;
struct ast_function_type prototype;
struct ast_expression *body;
enum func_decl_flags flags;
};
enum ast_decl_type {
ADECL_FUNC,
ADECL_TYPE,
ADECL_GLOBAL,
ADECL_CONST,
ADECL_ASSERT,
};
struct ast_decl {
struct location loc;
enum ast_decl_type decl_type;
bool exported;
union {
struct ast_global_decl global;
struct ast_global_decl constant;
struct ast_type_decl type;
struct ast_function_decl function;
struct ast_expression_assert assert;
};
};
struct ast_decls {
struct ast_decl decl;
struct ast_decls *next;
};
struct ast_subunit {
struct ast_imports *imports;
struct ast_decls *decls;
struct ast_subunit *next;
};
struct ast_unit {
struct ident *ns;
struct ast_subunit subunits;
};
#endif

169
ref/harec/include/check.h Normal file
View File

@@ -0,0 +1,169 @@
#ifndef HARE_CHECK_H
#define HARE_CHECK_H
#include <stdbool.h>
#include <stdnoreturn.h>
#include "ast.h"
#include "identifier.h"
#include "scope.h"
#include "types.h"
#include "type_store.h"
#include "util.h"
struct expression;
#define MODCACHE_BUCKETS 256
struct modcache {
struct ident *ident;
struct scope *scope;
struct modcache *next;
};
struct errors {
struct location loc;
char *msg;
struct errors *next;
};
struct context {
type_store *store;
struct modcache **modcache;
const struct type *fntype;
struct ident *ns;
struct scope *unit;
struct scope *scope;
struct scope *defines;
const char *mainsym;
struct ident *mainident;
bool is_test;
int id;
struct errors *errors;
struct errors **next;
struct declarations *decls;
struct ast_types *unresolved;
struct intern_table *itbl;
};
struct constant_decl {
const struct type *type;
const struct expression *value;
};
struct function_decl {
const struct type *type;
struct expression *body;
struct scope *scope;
unsigned int flags; // enum func_decl_flags
};
struct global_decl {
const struct type *type;
struct expression *value; // EXPR_LITERAL
bool threadlocal;
};
enum decl_type {
DECL_FUNC,
DECL_TYPE,
DECL_GLOBAL,
DECL_CONST,
};
struct declaration {
enum decl_type decl_type;
int file;
struct ident *ident;
const char *symbol;
bool exported; // XXX: this bool takes up 8 bytes and i am in pain
union {
struct constant_decl constant;
struct function_decl func;
struct global_decl global;
const struct type *type;
};
};
struct declarations {
struct declaration decl;
struct declarations *next;
};
struct unit {
struct ident *ns;
struct declarations *declarations;
struct identifiers *imports;
};
enum idecl_type {
IDECL_DECL,
IDECL_ENUM_FLD,
};
// Keeps track of enum specific context required for enum field resolution
struct incomplete_enum_field {
struct ast_enum_field *field;
struct scope *enum_scope;
};
// Keeps track of context required to resolve a declaration or an enum field
// Extends the scope_object struct so it can be inserted into a scope
struct incomplete_decl {
struct scope *imports; // the scope of this declaration's subunit
enum idecl_type type;
bool in_progress;
bool dealias_in_progress;
union {
struct ast_decl decl;
struct incomplete_enum_field *field;
};
};
struct ident *mkident(struct context *ctx, struct ident *ident,
const char *symbol);
void append_decl(struct context *ctx, struct declaration *decl);
void mkstrliteral(struct expression *expr, const char *fmt, ...) FORMAT(2, 3);
char *gen_typename(const struct type *type);
struct expression *lower_implicit_cast(struct context *ctx,
const struct type *to, struct expression *expr);
typedef void (*resolvefn)(struct context *, struct scope_object *obj);
void resolve_dimensions(struct context *ctx, struct scope_object *obj);
void resolve_type(struct context *ctx, struct scope_object *obj);
void wrap_resolver(struct context *ctx,
struct scope_object *obj, resolvefn resolver);
struct scope *check(type_store *ts,
bool is_test,
const char *mainsym,
struct ident *mainident,
const struct ast_decls *defines,
const struct ast_unit *aunit,
struct unit *unit,
struct intern_table *itbl);
struct scope *check_internal(type_store *ts,
struct modcache **cache,
bool is_test,
const char *mainsym,
struct ident *mainident,
const struct ast_decls *defines,
const struct ast_unit *aunit,
struct unit *unit,
struct intern_table *itbl,
bool scan_only);
void check_expression(struct context *ctx,
const struct ast_expression *aexpr,
struct expression *expr,
const struct type *hint);
void error(struct context *ctx, struct location loc,
struct expression *expr, const char *fmt, ...) FORMAT(4, 5);
#endif

12
ref/harec/include/eval.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef HAREC_EVAL_H
#define HAREC_EVAL_H
#include <stdbool.h>
struct expression;
struct context;
// Evaluates an expression at compile time.
bool eval_expr(struct context *ctx, const struct expression *restrict in,
struct expression *restrict out);
#endif

402
ref/harec/include/expr.h Normal file
View File

@@ -0,0 +1,402 @@
#ifndef HAREC_EXPR_H
#define HAREC_EXPR_H
#include <stdint.h>
#include "lex.h"
#include "types.h"
struct scope;
struct scope_object;
enum expr_type {
EXPR_ACCESS,
EXPR_ALLOC,
EXPR_APPEND,
EXPR_ASSERT,
EXPR_ASSIGN,
EXPR_BINARITHM,
EXPR_BINDING,
EXPR_BREAK,
EXPR_CALL,
EXPR_CAST,
EXPR_COMPOUND,
EXPR_CONTINUE,
EXPR_DEFER,
EXPR_DEFINE,
EXPR_DELETE,
EXPR_FOR,
EXPR_FREE,
EXPR_IF,
EXPR_INSERT,
EXPR_LEN,
EXPR_MEASURE = EXPR_LEN, // for use in AST
EXPR_LITERAL,
EXPR_MATCH,
EXPR_PROPAGATE,
EXPR_RETURN,
EXPR_SLICE,
EXPR_STRUCT,
EXPR_SWITCH,
EXPR_TUPLE,
EXPR_UNARITHM,
EXPR_UNDEFINED,
EXPR_VAARG,
EXPR_VAEND,
EXPR_VASTART,
EXPR_YIELD,
};
struct expressions {
struct expression *expr;
struct expressions *next;
};
enum access_type {
ACCESS_IDENTIFIER,
ACCESS_INDEX,
ACCESS_FIELD,
ACCESS_TUPLE,
};
struct expression_access {
enum access_type type;
union {
struct scope_object *object;
struct {
struct expression *array;
struct expression *index;
bool bounds_checked;
};
struct {
struct expression *_struct;
const struct struct_field *field;
};
struct {
struct expression *tuple;
const struct type_tuple *tvalue;
size_t tindex;
};
};
};
enum alloc_kind {
ALLOC_OBJECT, // alloc(42)
ALLOC_CAP, // alloc([], 42)
ALLOC_LEN, // alloc([0...], 42)
ALLOC_COPY, // alloc(x...);
};
struct expression_alloc {
enum alloc_kind kind;
const struct type *allocation_result;
struct expression *init;
struct expression *cap;
};
struct expression_append {
struct expression *object;
struct expression *value;
struct expression *length;
bool is_static, is_multi;
};
enum fixed_aborts {
ABORT_OOB = 0,
ABORT_TYPE_ASSERTION = 1,
ABORT_UNREACHABLE = 2,
ABORT_CAP_TOO_SMALL = 3,
ABORT_ANON_ASSERTION_FAILED = 4,
ABORT_PROPAGATE_ERROR_OCCURRED = 5,
};
struct expression_assert {
struct expression *cond;
struct expression *message;
enum fixed_aborts fixed_reason;
};
enum binarithm_operator {
BIN_BAND, // &
BIN_BOR, // |
BIN_DIV, // /
BIN_GREATER, // >
BIN_GREATEREQ, // >=
BIN_LAND, // &&
BIN_LEQUAL, // ==
BIN_LESS, // <
BIN_LESSEQ, // <=
BIN_LOR, // ||
BIN_LSHIFT, // <<
BIN_LXOR, // ^^
BIN_MINUS, // -
BIN_MODULO, // %
BIN_NEQUAL, // !=
BIN_PLUS, // +
BIN_RSHIFT, // >>
BIN_TIMES, // *
BIN_BXOR, // ^
BIN_LAST = BIN_BXOR,
};
struct expression_assign {
enum binarithm_operator op;
struct expression *object, *value;
};
struct expression_binarithm {
enum binarithm_operator op;
struct expression *lvalue, *rvalue;
};
struct binding_unpack {
const struct scope_object *object;
size_t offset;
struct binding_unpack *next;
};
struct expression_binding {
const struct scope_object *object;
struct binding_unpack *unpack;
struct expression *initializer;
struct expression_binding *next;
};
enum cast_kind {
C_CAST,
C_ASSERTION,
C_TEST,
};
struct expression_cast {
enum cast_kind kind;
const struct type *secondary;
struct expression *value;
bool lowered;
};
struct call_argument {
struct expression *value;
struct call_argument *next;
};
struct expression_call {
struct expression *lvalue;
struct call_argument *args;
};
struct expression_compound {
const char *label;
struct scope *scope;
struct expressions exprs;
};
struct array_literal {
struct expression *value;
struct array_literal *next;
};
// Invariant: these are sorted by field offset
struct struct_literal {
const struct struct_field *field;
struct expression *value;
struct struct_literal *next;
};
struct tuple_literal {
const struct type_tuple *field;
struct expression *value;
struct tuple_literal *next;
};
struct tagged_literal {
const struct type *tag;
struct expression *value;
};
struct expression_literal {
// If non-null, ival is an offset from this object's address
const struct scope_object *object;
union {
bool bval;
double fval;
int64_t ival;
uint64_t uval;
uint32_t rune;
struct {
size_t len;
char *value;
} string;
struct {
union {
// if object is null
struct array_literal *array;
// if object is non-null
size_t offset;
};
size_t start;
size_t len;
size_t cap;
} slice;
struct array_literal *array;
struct struct_literal *_struct;
struct tuple_literal *tuple;
struct tagged_literal tagged;
};
};
struct expression_control {
const char *label;
const struct scope *scope;
struct expression *value; // Only set for yield and break
};
struct expression_defer {
struct scope *scope;
struct expression *deferred;
};
struct expression_delete {
struct expression *expr;
bool is_static;
};
enum for_kind {
FOR_ACCUMULATOR,
FOR_EACH_VALUE,
FOR_EACH_POINTER,
FOR_EACH_ITERATOR,
};
struct expression_for {
enum for_kind kind;
const char *label;
struct scope *scope;
struct expression *bindings;
struct expression *cond;
struct expression *afterthought;
struct expression *body;
struct expression *else_branch;
};
struct expression_free {
struct expression *expr;
};
struct expression_if {
struct expression *cond;
struct expression *true_branch, *false_branch;
};
struct match_case {
const struct scope_object *object; // NULL if not bound
const struct type *type; // NULL if default
struct expression *value;
struct match_case *next;
};
struct expression_len {
struct expression *value;
};
struct expression_match {
struct expression *value;
struct match_case *cases;
};
struct expression_return {
struct expression *value;
};
struct expression_slice {
struct expression *object;
struct expression *start, *end;
bool bounds_checked;
};
struct case_option {
struct expression *value;
struct case_option *next;
};
struct switch_case {
struct case_option *options; // NULL for default case
struct expression *value;
struct switch_case *next;
};
struct expression_switch {
struct expression *value;
struct switch_case *cases;
};
struct expr_struct_field {
const struct struct_field *field;
struct expression *value;
struct expr_struct_field *next;
};
struct expression_struct {
struct expr_struct_field *fields;
bool autofill, undefined;
};
struct expression_tuple {
struct expression *value;
struct expression_tuple *next;
};
enum unarithm_operator {
UN_ADDRESS, // &
UN_BNOT, // ~
UN_DEREF, // *
UN_LNOT, // !
UN_MINUS, // -
};
struct expression_unarithm {
enum unarithm_operator op;
struct expression *operand;
};
struct expression_vaarg {
struct expression *ap;
};
struct expression {
const struct type *result;
enum expr_type type;
struct location loc; // For fixed aborts
union {
struct expression_access access;
struct expression_alloc alloc;
struct expression_append append; // and insert
struct expression_assert assert;
struct expression_assign assign;
struct expression_binarithm binarithm;
struct expression_binding binding;
struct expression_call call;
struct expression_cast cast;
struct expression_compound compound;
struct expression_defer defer;
struct expression_delete delete;
struct expression_control control;
struct expression_for _for;
struct expression_free free;
struct expression_if _if;
struct expression_len len;
struct expression_literal literal;
struct expression_match match;
struct expression_return _return;
struct expression_switch _switch;
struct expression_struct _struct;
struct expression_slice slice;
struct expression_tuple tuple;
struct expression_unarithm unarithm;
struct expression_vaarg vaarg;
void *user;
};
};
uint32_t expr_hash(const struct expression *expr);
bool expr_equal(const struct expression *a, const struct expression *b);
#endif

View File

@@ -0,0 +1,53 @@
#ifndef HARE_IDENTIFIER_H
#define HARE_IDENTIFIER_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
// Maximum length of an identifier, as the sum of the lengths (excluding NUL
// terminators) of its parts plus one for each namespace deliniation.
//
// In other words, the length of "a::b::c" is 5.
#define IDENT_MAX 255
// Minimum buffer size needed to store an unparsed identifier, including the
// terminating NUL byte.
#define IDENT_BUFSIZ (IDENT_MAX / 2 + IDENT_MAX + 1)
struct ident {
const char *name;
struct ident *ns;
};
struct identifiers {
struct ident *ident;
struct identifiers *next;
};
struct bucket {
void **ids;
size_t sz;
size_t cap;
};
struct intern_table {
struct bucket *sbuckets;
struct bucket *ibuckets;
};
bool ident_equal(const struct ident *a, const struct ident *b);
uint32_t ident_hash(uint32_t init, const struct ident *ident);
char *ident_unparse(const struct ident *ident);
int ident_unparse_static(const struct ident *ident, char *buf);
const char *ident_to_sym(struct intern_table *itbl, const struct ident *ident);
void intern_init(struct intern_table *itbl);
const char *intern_copy(struct intern_table *itbl, const char *s);
const char *intern_owned(struct intern_table *itbl, char *s);
struct ident *intern_ident(struct intern_table *itbl,
const char *name, struct ident *ns);
struct ident *intern_name(struct intern_table *itbl, const char *name);
#endif

190
ref/harec/include/lex.h Normal file
View File

@@ -0,0 +1,190 @@
#ifndef HAREC_LEX_H
#define HAREC_LEX_H
#include <stdint.h>
#include <stdio.h>
#include "types.h"
#include "utf8.h"
#define C_EOF UTF8_INVALID
// Keep sorted
enum lexical_token {
T_ATTR_FINI,
T_ATTR_INIT,
T_ATTR_PACKED,
T_ATTR_SYMBOL,
T_ATTR_TEST,
T_ATTR_THREADLOCAL,
T_ATTR_UNDEFINED,
T_UNDERSCORE,
T_ABORT,
T_ALIGN,
T_ALLOC,
T_APPEND,
T_AS,
T_ASSERT,
T_BOOL,
T_BREAK,
T_CASE,
T_CONST,
T_CONTINUE,
T_DEF,
T_DEFER,
T_DELETE,
T_DONE,
T_ELSE,
T_ENUM,
T_EXPORT,
T_F32,
T_F64,
T_FALSE,
T_FN,
T_FOR,
T_FREE,
T_I16,
T_I32,
T_I64,
T_I8,
T_IF,
T_INSERT,
T_INT,
T_IS,
T_LEN,
T_LET,
T_MATCH,
T_NEVER,
T_NOMEM,
T_NULL,
T_NULLABLE,
T_OFFSET,
T_OPAQUE,
T_RETURN,
T_RUNE,
T_SIZE,
T_STATIC,
T_STR,
T_STRUCT,
T_SWITCH,
T_TRUE,
T_TYPE,
T_U16,
T_U32,
T_U64,
T_U8,
T_UINT,
T_UINTPTR,
T_UNION,
T_USE,
T_VAARG,
T_VAEND,
T_VALIST,
T_VASTART,
T_VOID,
T_YIELD,
T_LAST_KEYWORD = T_YIELD,
// Operators
T_ARROW,
T_BANDEQ,
T_BAND,
T_BNOT,
T_BOR,
T_COLON,
T_COMMA,
T_DIV,
T_DIVEQ,
T_DOT,
T_DOUBLE_COLON,
T_DOUBLE_DOT,
T_ELLIPSIS,
T_EQUAL,
T_GREATER,
T_GREATEREQ,
T_LAND,
T_LANDEQ,
T_LBRACE,
T_LBRACKET,
T_LEQUAL,
T_LESS,
T_LESSEQ,
T_LNOT,
T_LOR,
T_LOREQ,
T_LPAREN,
T_LSHIFT,
T_LSHIFTEQ,
T_LXOR,
T_LXOREQ,
T_MINUS,
T_MINUSEQ,
T_MODEQ,
T_MODULO,
T_NEQUAL,
T_BOREQ,
T_PLUS,
T_PLUSEQ,
T_QUESTION,
T_RBRACE,
T_RBRACKET,
T_RPAREN,
T_RSHIFT,
T_RSHIFTEQ,
T_SEMICOLON,
T_TIMES,
T_TIMESEQ,
T_BXOR,
T_BXOREQ,
T_LAST_OPERATOR = T_BXOREQ,
// Tokens with additional information
T_NAME,
T_LITERAL,
// Magic tokens
T_EOF,
T_NONE,
};
struct location {
int file;
int lineno, colno;
};
struct token {
struct location loc;
enum lexical_token token;
enum type_storage storage;
union {
const char *name;
uint32_t rune;
int64_t ival;
uint64_t uval;
double fval;
struct {
size_t len;
const char *value;
} string;
};
};
struct lexer {
FILE *in;
char *buf;
size_t bufsz, buflen;
uint32_t c[2];
struct token un;
struct location loc;
bool require_int;
bool in_annotation;
struct intern_table *itbl;
};
void lex_init(struct lexer *lexer, FILE *f, int fileid, struct intern_table *itbl);
void lex_finish(struct lexer *lexer);
enum lexical_token lex(struct lexer *lexer, struct token *out);
void unlex(struct lexer *lexer, const struct token *in);
const char *token_str(const struct token *tok);
const char *lexical_token_str(enum lexical_token tok);
#endif

11
ref/harec/include/mod.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef HARE_MOD_H
#define HARE_MOD_H
struct ast_decls;
struct context;
struct ident;
struct scope *module_resolve(struct context *ctx,
const struct ast_decls *defines, struct ident *ident);
#endif

96
ref/harec/include/scope.h Normal file
View File

@@ -0,0 +1,96 @@
#ifndef HAREC_SCOPE_H
#define HAREC_SCOPE_H
#include "expr.h"
#include "identifier.h"
#define SCOPE_BUCKETS 4096
enum object_type {
O_BIND,
O_CONST,
O_DECL,
O_SCAN,
O_TYPE,
};
enum scope_object_flags {
SO_THREADLOCAL = 1 << 0,
SO_FOR_EACH_SUBJECT = 1 << 1,
};
struct scope_object {
enum object_type otype;
// name is the name of the object within this scope (for lookups)
// ident is the global identifier (these may be different in some cases)
struct ident *name;
struct ident *ident;
enum scope_object_flags flags;
union {
const struct type *type;
struct expression *value; // For O_CONST
};
// Cannot be in union because type and idecl are needed at the same time
struct incomplete_decl *idecl;
struct scope_object *lnext; // Linked list
struct scope_object *mnext; // Hash map
};
enum scope_class {
SCOPE_COMPOUND,
SCOPE_DEFER,
SCOPE_ENUM,
SCOPE_FUNC,
SCOPE_LOOP,
SCOPE_MATCH,
SCOPE_SUBUNIT,
SCOPE_UNIT,
SCOPE_DEFINES,
};
struct yield { // and break
struct expression **expression;
struct yield *next;
};
struct scope {
enum scope_class class;
const char *label;
struct scope *parent;
const struct type *hint;
struct type_tagged_union results;
struct yield *yields;
// Linked list in insertion order
// Used for function parameters and enum values, where order matters
struct scope_object *objects;
struct scope_object **next;
// Hash map in reverse insertion order
// Used for lookups, and accounts for shadowing
struct scope_object *buckets[SCOPE_BUCKETS];
};
struct scopes {
struct scope *scope;
struct scopes *next;
};
struct scope *scope_push(struct scope **stack, enum scope_class class);
struct scope *scope_pop(struct scope **stack);
struct scope *scope_lookup_class(struct scope *scope, enum scope_class class);
struct scope *scope_lookup_label(struct scope *scope, const char *label);
void scope_free(struct scope *scope);
void scope_free_all(struct scopes *scopes);
struct scope_object *scope_insert(struct scope *scope,
enum object_type otype, struct ident *ident, struct ident *name,
const struct type *type, struct expression *value);
struct scope_object *scope_lookup(struct scope *scope, struct ident *ident);
#endif

View File

@@ -0,0 +1,60 @@
#ifndef HARE_TYPESTORE_H
#define HARE_TYPESTORE_H
#include "ast.h"
#include "lex.h"
#include "types.h"
#define TYPE_STORE_BUCKETS 65536
struct type_bucket {
struct type type;
struct type_bucket *next;
};
struct context;
struct dimensions {
size_t size;
size_t align;
};
typedef struct type_bucket *type_store[TYPE_STORE_BUCKETS];
// Applies the type reduction algorithm to the given tagged union.
const struct type *type_store_reduce_result(struct context *ctx,
struct location loc, struct type_tagged_union *in);
struct ast_type;
const struct type *type_store_lookup_atype(
struct context *ctx, const struct ast_type *atype);
struct dimensions type_store_lookup_dimensions(
struct context *ctx, const struct ast_type *atype);
const struct type *builtin_type_for_storage(enum type_storage storage);
const struct type *type_store_lookup_pointer(struct context *ctx,
struct location loc, const struct type *referent, bool nullable);
const struct type *type_store_lookup_array(struct context *ctx,
struct location loc, const struct type *members, size_t len,
bool expandable);
const struct type *type_store_lookup_slice(struct context *ctx,
struct location loc, const struct type *members);
const struct type *type_store_lookup_alias(struct context *ctx,
struct ident *ident, struct ident *name,
const struct type *secondary, bool exported);
const struct type *type_store_lookup_tagged(struct context *ctx,
struct location loc, struct type_tagged_union *tags);
const struct type *type_store_lookup_tuple(struct context *ctx,
struct location loc, struct type_tuple *values);
const struct type *type_store_lookup_enum(struct context *ctx,
const struct ast_type *atype, bool exported);
#endif

View File

@@ -0,0 +1,11 @@
#ifndef HARE_TYPEDEF_H
#define HARE_TYPEDEF_H
#include <stdio.h>
struct type;
struct unit;
void emit_type(const struct type *type, FILE *out);
void emit_typedefs(const struct unit *unit, FILE *out);
#endif

230
ref/harec/include/types.h Normal file
View File

@@ -0,0 +1,230 @@
#ifndef HARE_TYPES_H
#define HARE_TYPES_H
#include <stdbool.h>
#include <stdint.h>
#include "arch.h"
#include "identifier.h"
enum type_storage {
// Built-in types
// The order of these is important
STORAGE_BOOL,
STORAGE_DONE,
STORAGE_F32,
STORAGE_F64,
STORAGE_I16,
STORAGE_I32,
STORAGE_I64,
STORAGE_I8,
STORAGE_INT,
STORAGE_NEVER,
STORAGE_NOMEM,
STORAGE_NULL,
STORAGE_OPAQUE,
STORAGE_RUNE,
STORAGE_SIZE,
STORAGE_STRING,
STORAGE_U16,
STORAGE_U32,
STORAGE_U64,
STORAGE_U8,
STORAGE_UINT,
STORAGE_UINTPTR,
STORAGE_UNDEFINED,
STORAGE_VOID,
// Other types
STORAGE_ALIAS,
STORAGE_ARRAY,
STORAGE_ENUM,
STORAGE_FUNCTION,
STORAGE_POINTER,
STORAGE_SLICE,
STORAGE_STRUCT,
STORAGE_TAGGED,
STORAGE_TUPLE,
STORAGE_UNION,
STORAGE_VALIST,
STORAGE_FCONST,
STORAGE_ICONST,
STORAGE_RCONST,
STORAGE_ERROR,
// For internal use only
STORAGE_INVALID,
};
struct context;
struct type;
#define SIZE_UNDEFINED ((size_t)-1)
#define ALIGN_UNDEFINED ((size_t)-1)
struct type_alias {
struct ident *ident;
struct ident *name;
const struct type *type;
bool exported; // Used to make sure unexported aliases aren't emitted
};
struct type_array {
size_t length; // SIZE_UNDEFINED for [*] and slices
const struct type *members;
bool expandable;
};
struct type_enum {
struct scope *values;
};
enum variadism {
VARIADISM_NONE,
VARIADISM_C,
VARIADISM_HARE,
};
struct type_func_param {
const struct type *type;
struct expression *default_value;
struct type_func_param *next;
};
struct type_func {
const struct type *result;
enum variadism variadism;
struct type_func_param *params;
};
struct type_flexible {
int64_t min, max;
uint32_t id;
const struct type ***refs;
size_t nrefs;
size_t zrefs;
};
struct type_pointer {
const struct type *referent;
bool nullable;
};
struct struct_field {
const char *name;
const struct type *type;
size_t offset;
size_t size;
struct struct_field *next;
};
struct type_struct_union {
struct struct_field *fields;
bool packed;
};
struct type_tuple {
const struct type *type;
size_t offset;
struct type_tuple *next;
};
struct type_tagged_union {
const struct type **types;
size_t len;
size_t cap;
};
struct type {
enum type_storage storage;
uint32_t id;
size_t size, align;
union {
struct {
struct type_alias alias;
struct type_enum _enum;
};
struct type_array array;
const struct type *error;
struct type_flexible flexible;
struct type_func func;
struct type_pointer pointer;
struct type_struct_union struct_union;
struct type_tagged_union tagged;
struct type_tuple tuple;
};
};
const struct type *type_dereference(struct context *ctx, const struct type *type,
bool allow_nullable);
const struct type *type_dealias(struct context *ctx, const struct type *type);
bool type_is_done(struct context *ctx, const struct type *type);
const struct struct_field *type_get_field(struct context *ctx,
const struct type *type, const char *name);
const struct type_tuple *type_get_value(
const struct type *type, uint64_t index);
void tagged_append(struct type_tagged_union *tagged, const struct type *memb);
struct type_tagged_union tagged_dup_tags(const struct type_tagged_union *tags);
const struct type *tagged_select_subtype(struct context *ctx,
const struct type *tagged, const struct type *subtype, bool strip);
bool tagged_subset_compat(struct context *ctx,
const struct type *to, const struct type *from);
const char *type_storage_unparse(enum type_storage storage);
bool type_is_signed(struct context *ctx, const struct type *type);
bool type_is_integer(struct context *ctx, const struct type *type);
bool type_is_numeric(struct context *ctx, const struct type *type);
bool type_is_float(struct context *ctx, const struct type *type);
bool type_is_flexible(const struct type *type);
bool type_is_error(struct context *ctx, const struct type *type);
bool type_has_error(struct context *ctx, const struct type *type);
uint32_t type_hash(const struct type *type);
bool type_equal(const struct type *a, const struct type *b);
const struct type *promote_flexible(struct context *ctx,
const struct type *a, const struct type *b);
bool type_is_assignable(struct context *ctx,
const struct type *to, const struct type *from);
const struct type *type_is_castable(struct context *ctx,
const struct type *to, const struct type *from);
const struct type *type_create_flexible(enum type_storage storage,
int64_t min, int64_t max);
const struct type *lower_flexible(struct context *ctx,
const struct type *old, const struct type *new);
void flexible_refer(const struct type *type, const struct type **ref);
void flexible_reset_refs(const struct type *type);
void builtin_types_init(enum arch target);
// Built-in type singletons
extern struct type
// Primitive
builtin_type_bool,
builtin_type_done,
builtin_type_invalid,
builtin_type_f32,
builtin_type_f64,
builtin_type_i16,
builtin_type_i32,
builtin_type_i64,
builtin_type_i8,
builtin_type_int,
builtin_type_never,
builtin_type_nomem,
builtin_type_null,
builtin_type_opaque,
builtin_type_rune,
builtin_type_size,
builtin_type_u16,
builtin_type_u32,
builtin_type_u64,
builtin_type_u8,
builtin_type_uint,
builtin_type_uintptr,
builtin_type_void,
// etc
builtin_type_str,
builtin_type_valist,
builtin_type_undefined;
#endif

26
ref/harec/include/utf8.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef HAREC_UTF8_H
#define HAREC_UTF8_H
#include <stdint.h>
#include <limits.h>
#include <stdio.h>
#define UTF8_MAX_SIZE 4
#define UTF8_INVALID UINT32_MAX
/**
* Grabs the next UTF-8 codepoint and advances the string pointer
*/
uint32_t utf8_decode(const char **str);
/**
* Encodes a codepoint as UTF-8 and returns the length of that codepoint.
*/
size_t utf8_encode(char *str, uint32_t ch);
/**
* Reads and returns the next codepoint from the file.
*/
uint32_t utf8_get(FILE *f);
#endif

57
ref/harec/include/util.h Normal file
View File

@@ -0,0 +1,57 @@
#ifndef HARE_UTIL_H
#define HARE_UTIL_H
#include <assert.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "lex.h"
enum exit_status {
/* EXIT_SUCCESS = 0 (defined in stdlib.h) */
EXIT_USER = 1,
EXIT_LEX = 2,
EXIT_PARSE = 3,
EXIT_CHECK = 4,
EXIT_ABNORMAL = 255,
};
extern const char **sources;
// Sources unaffected by the -M option
extern const char **full_sources;
extern size_t nsources;
#define FNV1A_INIT 2166136261u
uint32_t fnv1a(uint32_t hash, unsigned char c);
uint32_t fnv1a_u32(uint32_t hash, uint32_t u32);
uint32_t fnv1a_u64(uint32_t hash, uint64_t u64);
uint32_t fnv1a_size(uint32_t hash, size_t sz);
uint32_t fnv1a_s(uint32_t hash, const char *str);
void *xcalloc(size_t n, size_t s);
void *xrealloc(void *p, size_t s);
char *xstrdup(const char *s);
#define FORMAT(FMT_PARAM, VA_PARAM)
#ifdef __has_attribute
#if __has_attribute(format)
#undef FORMAT
#define FORMAT(FMT_PARAM, VA_PARAM) __attribute__((format(printf, FMT_PARAM, VA_PARAM)))
#endif
#endif
int xfprintf(FILE *restrict f, const char *restrict fmt, ...) FORMAT(2, 3);
int xvfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) FORMAT(2, 0);
#define malloc(a) (void *)sizeof(struct { static_assert(0, "Use xcalloc instead"); int _; })
#define calloc(a, b) (void *)sizeof(struct { static_assert(0, "Use xcalloc instead"); int _; })
#define realloc(a, b) (void *)sizeof(struct { static_assert(0, "Use xrealloc instead"); int _; })
#define strdup(s) (char *)(sizeof(struct { static_assert(0, "Use xstrdup instead"); int _; })
char *gen_name(int *id, const char *fmt);
void append_buffer(char **buf, size_t *restrict ln, size_t *restrict cap,
const char *b, size_t sz);
void errline(struct location loc);
#endif