93 lines
3.0 KiB
C
93 lines
3.0 KiB
C
#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
|