360 lines
9.5 KiB
C
360 lines
9.5 KiB
C
////////////////////////////////
|
|
// Functions: Arity Node
|
|
|
|
// construction
|
|
|
|
MR4TH_SYMBOL DS_ArityNode*
|
|
ds_aritynode_empty(Arena *arena){
|
|
DS_ArityNode *node = push_array(arena, DS_ArityNode, 1);
|
|
node->kind = DS_ArityKind_Empty;
|
|
return(node);
|
|
}
|
|
|
|
MR4TH_SYMBOL DS_ArityNode*
|
|
ds_aritynode_singleton(Arena *arena){
|
|
DS_ArityNode *node = push_array(arena, DS_ArityNode, 1);
|
|
node->kind = DS_ArityKind_Singleton;
|
|
node->coefficient = 1;
|
|
return(node);
|
|
}
|
|
|
|
MR4TH_SYMBOL DS_ArityNode*
|
|
ds_aritynode_arrow(Arena *arena, DS_ArityNode *domain, DS_ArityNode *codomain){
|
|
DS_ArityNode *node = 0;
|
|
if (domain->kind == DS_ArityKind_Empty ||
|
|
codomain->kind == DS_ArityKind_Empty){
|
|
node = codomain;
|
|
}
|
|
else{
|
|
node = push_array(arena, DS_ArityNode, 1);
|
|
node->kind = DS_ArityKind_Arrow;
|
|
node->coefficient = 1;
|
|
node->arrow.domain = domain;
|
|
node->arrow.codomain = codomain;
|
|
}
|
|
return(node);
|
|
}
|
|
|
|
MR4TH_SYMBOL DS_ArityNode*
|
|
ds_aritynode_paste(Arena *arena, DS_ArityNode *a, DS_ArityNode *b){
|
|
ArenaTemp scratch = arena_get_scratch(&arena, 1);
|
|
DS_ArityNode *node = 0;
|
|
|
|
if (a->kind == DS_ArityKind_Empty){
|
|
node = b;
|
|
}
|
|
else if (b->kind == DS_ArityKind_Empty){
|
|
node = a;
|
|
}
|
|
else{
|
|
// count parts
|
|
U64 max_part_count = 0;
|
|
if (a->kind != DS_ArityKind_Tuple){
|
|
max_part_count += 1;
|
|
}
|
|
else{
|
|
max_part_count += a->tuple.part_count;
|
|
}
|
|
if (b->kind != DS_ArityKind_Tuple){
|
|
max_part_count += 1;
|
|
}
|
|
else{
|
|
max_part_count += b->tuple.part_count;
|
|
}
|
|
|
|
// fill parts
|
|
DS_ArityNode **parts = push_array(scratch.arena, DS_ArityNode*, max_part_count);
|
|
DS_ArityNode **part_ptr = parts;
|
|
|
|
if (a->kind != DS_ArityKind_Tuple){
|
|
*part_ptr = ds_aritynode__part_copy(arena, a);
|
|
(*part_ptr)->coefficient = 1;
|
|
part_ptr += 1;
|
|
}
|
|
else{
|
|
for (U64 i = 0; i < a->tuple.part_count; i += 1){
|
|
DS_ArityNode *a_part = a->tuple.parts[i];
|
|
*part_ptr = ds_aritynode__part_copy(arena, a_part);
|
|
(*part_ptr)->coefficient = a_part->coefficient;
|
|
part_ptr += 1;
|
|
}
|
|
}
|
|
|
|
if (b->kind != DS_ArityKind_Tuple){
|
|
DS_ArityNode *match_pos = ds_aritynode__part_find_match(parts, part_ptr, b);
|
|
if (match_pos != 0){
|
|
match_pos->coefficient += 1;
|
|
}
|
|
else{
|
|
*part_ptr = ds_aritynode__part_copy(arena, b);
|
|
(*part_ptr)->coefficient = 1;
|
|
part_ptr += 1;
|
|
}
|
|
}
|
|
else{
|
|
for (U64 j = 0; j < b->tuple.part_count; j += 1){
|
|
DS_ArityNode *b_part = b->tuple.parts[j];
|
|
DS_ArityNode *match_pos = ds_aritynode__part_find_match(parts, part_ptr, b_part);
|
|
if (match_pos != 0){
|
|
match_pos->coefficient += b_part->coefficient;
|
|
}
|
|
else{
|
|
*part_ptr = ds_aritynode__part_copy(arena, b_part);
|
|
(*part_ptr)->coefficient = b_part->coefficient;
|
|
part_ptr += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// final part count
|
|
U64 part_count = (U64)(part_ptr - parts);
|
|
|
|
// fill result node
|
|
Assert(part_count > 1 ||
|
|
part_count == 1 && parts[0]->coefficient > 1);
|
|
|
|
DS_ArityNode **parts_final = push_array(arena, DS_ArityNode*, part_count);
|
|
MemoryCopy(parts_final, parts, sizeof(*parts)*part_count);
|
|
|
|
node = push_array(arena, DS_ArityNode, 1);
|
|
node->kind = DS_ArityKind_Tuple;
|
|
node->coefficient = 1;
|
|
node->tuple.parts = parts_final;
|
|
node->tuple.part_count = part_count;
|
|
}
|
|
|
|
arena_release_scratch(&scratch);
|
|
|
|
return(node);
|
|
}
|
|
|
|
MR4TH_SYMBOL DS_ArityNode*
|
|
ds_aritynode_sum(Arena *arena, ...){
|
|
va_list args;
|
|
va_start(args, arena);
|
|
|
|
va_list args2;
|
|
va_copy(args2, args);
|
|
|
|
ArenaTemp scratch = arena_get_scratch(&arena, 1);
|
|
|
|
// count parts
|
|
U64 max_part_count = 0;
|
|
for (;;){
|
|
U32 multiplier = va_arg(args, U32);
|
|
if (multiplier == 0){
|
|
break;
|
|
}
|
|
DS_ArityNode *arity = va_arg(args, DS_ArityNode*);
|
|
if (arity->kind == DS_ArityKind_Empty){
|
|
// do nothing
|
|
}
|
|
else if (arity->kind != DS_ArityKind_Tuple){
|
|
max_part_count += 1;
|
|
}
|
|
else{
|
|
max_part_count += arity->tuple.part_count;
|
|
}
|
|
}
|
|
|
|
// fill parts
|
|
DS_ArityNode **parts = push_array(scratch.arena, DS_ArityNode*, max_part_count);
|
|
DS_ArityNode **part_ptr = parts;
|
|
|
|
for (;;){
|
|
U32 multiplier = va_arg(args2, U32);
|
|
if (multiplier == 0){
|
|
break;
|
|
}
|
|
DS_ArityNode *arity = va_arg(args2, DS_ArityNode*);
|
|
|
|
if (arity->kind == DS_ArityKind_Empty){
|
|
// do nothing
|
|
}
|
|
else if (arity->kind != DS_ArityKind_Tuple){
|
|
DS_ArityNode *match_pos = ds_aritynode__part_find_match(parts, part_ptr, arity);
|
|
if (match_pos != 0){
|
|
match_pos->coefficient += multiplier;
|
|
}
|
|
else{
|
|
*part_ptr = ds_aritynode__part_copy(arena, arity);
|
|
(*part_ptr)->coefficient = multiplier;
|
|
part_ptr += 1;
|
|
}
|
|
}
|
|
else{
|
|
for (U64 j = 0; j < arity->tuple.part_count; j += 1){
|
|
DS_ArityNode *b_part = arity->tuple.parts[j];
|
|
DS_ArityNode *match_pos = ds_aritynode__part_find_match(parts, part_ptr, b_part);
|
|
if (match_pos != 0){
|
|
match_pos->coefficient += multiplier*b_part->coefficient;
|
|
}
|
|
else{
|
|
*part_ptr = ds_aritynode__part_copy(arena, b_part);
|
|
(*part_ptr)->coefficient = multiplier*b_part->coefficient;
|
|
part_ptr += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// final part count
|
|
U64 part_count = (U64)(part_ptr - parts);
|
|
|
|
// fill result node
|
|
DS_ArityNode *node = 0;
|
|
if (part_count == 0){
|
|
node = ds_aritynode_empty(arena);
|
|
}
|
|
else if (part_count == 1 &&
|
|
parts[0]->coefficient == 1){
|
|
node = parts[0];
|
|
}
|
|
else{
|
|
DS_ArityNode **parts_final = push_array(arena, DS_ArityNode*, part_count);
|
|
MemoryCopy(parts_final, parts, sizeof(*parts)*part_count);
|
|
|
|
node = push_array(arena, DS_ArityNode, 1);
|
|
node->kind = DS_ArityKind_Tuple;
|
|
node->coefficient = 1;
|
|
node->tuple.parts = parts_final;
|
|
node->tuple.part_count = part_count;
|
|
}
|
|
|
|
arena_release_scratch(&scratch);
|
|
|
|
va_end(args2);
|
|
va_end(args);
|
|
|
|
return(node);
|
|
}
|
|
|
|
MR4TH_SYMBOL DS_ArityNode*
|
|
ds_aritynode_ktuple(Arena *arena, U32 coefficient){
|
|
DS_ArityNode *result = 0;
|
|
|
|
if (coefficient > 1){
|
|
result = push_array(arena, DS_ArityNode, 1);
|
|
DS_ArityNode **parts = push_array(arena, DS_ArityNode*, 1);
|
|
DS_ArityNode *singleton = push_array(arena, DS_ArityNode, 1);
|
|
|
|
result->kind = DS_ArityKind_Tuple;
|
|
result->coefficient = 1;
|
|
result->tuple.parts = parts;
|
|
result->tuple.part_count = 1;
|
|
|
|
parts[0] = singleton;
|
|
|
|
singleton->kind = DS_ArityKind_Singleton;
|
|
singleton->coefficient = coefficient;
|
|
}
|
|
else if (coefficient == 1){
|
|
result = ds_aritynode_singleton(arena);
|
|
}
|
|
else{
|
|
result = ds_aritynode_empty(arena);
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
// operations
|
|
|
|
MR4TH_SYMBOL DS_ArityNode*
|
|
ds_aritynode_copy(Arena *arena, DS_ArityNode *arity){
|
|
DS_ArityNode *result = push_array(arena, DS_ArityNode, 1);
|
|
result->kind = arity->kind;
|
|
result->coefficient = arity->coefficient;
|
|
switch (result->kind){
|
|
case DS_ArityKind_Arrow:
|
|
{
|
|
result->arrow.domain = ds_aritynode_copy(arena, arity->arrow.domain);
|
|
result->arrow.codomain = ds_aritynode_copy(arena, arity->arrow.codomain);
|
|
}break;
|
|
|
|
case DS_ArityKind_Tuple:
|
|
{
|
|
U64 part_count = arity->tuple.part_count;
|
|
DS_ArityNode **parts = push_array(arena, DS_ArityNode*, part_count);
|
|
for (U64 i = 0; i < part_count; i += 1){
|
|
parts[i] = ds_aritynode_copy(arena, arity->tuple.parts[i]);
|
|
}
|
|
result->tuple.parts = parts;
|
|
result->tuple.part_count = part_count;
|
|
}break;
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
MR4TH_SYMBOL B32
|
|
ds_aritynode_equal(DS_ArityNode *a, DS_ArityNode *b){
|
|
B32 result = 0;
|
|
|
|
if (a->kind == b->kind){
|
|
switch (a->kind){
|
|
case DS_ArityKind_Empty:
|
|
case DS_ArityKind_Singleton: result = 1; break;
|
|
|
|
case DS_ArityKind_Arrow:
|
|
{
|
|
if (ds_aritynode_equal(a->arrow.domain, b->arrow.domain) &&
|
|
ds_aritynode_equal(a->arrow.codomain, b->arrow.codomain)){
|
|
result = 1;
|
|
}
|
|
}break;
|
|
|
|
case DS_ArityKind_Tuple:
|
|
{
|
|
if (a->tuple.part_count == b->tuple.part_count){
|
|
result = 1;
|
|
for (U64 i = 0; i < a->tuple.part_count; i += 1){
|
|
DS_ArityNode *a_part = a->tuple.parts[i];
|
|
B32 found_match = 0;
|
|
for (U64 j = 0; j < b->tuple.part_count; j += 1){
|
|
DS_ArityNode *b_part = b->tuple.parts[j];
|
|
if (b_part->coefficient == a_part->coefficient &&
|
|
ds_aritynode_equal(a_part, b_part)){
|
|
found_match = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!found_match){
|
|
result = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}break;
|
|
}
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
// helpers
|
|
|
|
MR4TH_SYMBOL DS_ArityNode*
|
|
ds_aritynode__part_copy(Arena *arena, DS_ArityNode *node){
|
|
Assert(node->kind != DS_ArityKind_Tuple);
|
|
DS_ArityNode *result = push_array(arena, DS_ArityNode, 1);
|
|
result->kind = node->kind;
|
|
if (result->kind == DS_ArityKind_Arrow){
|
|
result->arrow.domain = node->arrow.domain;
|
|
result->arrow.codomain = node->arrow.codomain;
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
MR4TH_SYMBOL DS_ArityNode*
|
|
ds_aritynode__part_find_match(DS_ArityNode **parts_first, DS_ArityNode **parts_opl, DS_ArityNode *key){
|
|
DS_ArityNode **part = parts_first;
|
|
DS_ArityNode *match = 0;
|
|
for (; part < parts_opl; part += 1){
|
|
if (ds_aritynode_equal(*part, key)){
|
|
match = *part;
|
|
break;
|
|
}
|
|
}
|
|
return(match);
|
|
}
|