#ifndef ARITYNODE_H #define ARITYNODE_H //////////////////////////////// // Type: Arity Node typedef enum DS_ArityKind{ DS_ArityKind_Empty = 0, DS_ArityKind_Singleton = 1, DS_ArityKind_Arrow = 2, DS_ArityKind_Tuple = 3, } DS_ArityKind; typedef struct DS_ArityNode{ DS_ArityKind kind; U32 coefficient; union{ struct{ struct DS_ArityNode *domain; struct DS_ArityNode *codomain; } arrow; struct{ struct DS_ArityNode **parts; U64 part_count; } tuple; }; } DS_ArityNode; //////////////////////////////// // Functions: Arity Node // construction /* NOTE: ** Construction functions that take in arity node(s) require ** that the arena that allocated the input arity node(s) ** is the same arena that is used in the current call, and ** that the arena has not popped the nodes. ** ** Example of misuse: ** ** GIVEN Arena *a1; Arena *a2; ** WITH (a1 != a2): ** DS_ArityNode *n1 = ds_aritynode_singleton(a1); ** DS_ArityNode *n2 = ds_aritynode_arrow(a2, n1); @bad - changing arenas ** ** Why this matters: ** ** We don't want to have to deep copy every node we ever see as input, ** so construction functions just keep pointers to their inputs, or ** sometimes make shallow copies but still keep the original versions ** of the deeper nodes. Because of the way arenas work, if these ** all exist on one arena, later nodes always point towards earlier ** nodes, and so if a node is still on the arena, so are all of the nodes ** that it depends on. However, if we start crossing arenas, we would ** have to be much more careful not to start generating use-after-free ** issues. ** ** If you think it through and you *know what you're doing* you can ** break this rule, but as a rule of thumb, it usually works best if you ** can put all the nodes that work together into the same arena. */ MR4TH_SYMBOL DS_ArityNode* ds_aritynode_empty(Arena *arena); MR4TH_SYMBOL DS_ArityNode* ds_aritynode_singleton(Arena *arena); MR4TH_SYMBOL DS_ArityNode* ds_aritynode_arrow(Arena *arena, DS_ArityNode *domain, DS_ArityNode *codomain); MR4TH_SYMBOL DS_ArityNode* ds_aritynode_paste(Arena *arena, DS_ArityNode *a, DS_ArityNode *b); /* NOTE: ** ds_aritynode_sum takes the variadic layout: ** (coeff_1:U32, arity_1:DS_ArityNode*, ..., coeff_k:U32, arity_k:DS_ArityNode*, 0) */ MR4TH_SYMBOL DS_ArityNode* ds_aritynode_sum(Arena *arena, ...); MR4TH_SYMBOL DS_ArityNode* ds_aritynode_ktuple(Arena *arena, U32 coefficient); // operations /* NOTE: ** ds_aritynode_copy is not a "construction function" ** it can deep copy an arity node from one arena to another. */ MR4TH_SYMBOL DS_ArityNode* ds_aritynode_copy(Arena *arena, DS_ArityNode *arity); MR4TH_SYMBOL B32 ds_aritynode_equal(DS_ArityNode *a, DS_ArityNode *b); // helpers MR4TH_SYMBOL DS_ArityNode* ds_aritynode__part_copy(Arena *arena, DS_ArityNode *node); MR4TH_SYMBOL DS_ArityNode* ds_aritynode__part_find_match(DS_ArityNode **parts_first, DS_ArityNode **parts_opl, DS_ArityNode *key); #endif //ARITYNODE_H