Actually just three programming languages in a trenchcoat
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

implement base set functionality

+312 -13
+16
testsuite/set-comprehension/main.tri
··· 1 + rule keys(1) 2 + rule keys(4) 3 + 4 + rule values(1, 1) 5 + rule values(1, 2) 6 + rule values(2, 2) 7 + rule values(2, 3) 8 + rule values(3, 3) 9 + rule values(3, 4) 10 + rule values(4, 4) 11 + rule values(4, 5) 12 + 13 + proc main!() { 14 + let ins = [| value for keys(i) and values(i, value) |] 15 + assert ins == [| 1, 2, 4, 5 |] 16 + }
+4
testsuite/set-empty/main.tri
··· 1 + proc main!() { 2 + let set = [||] 3 + assert typeof set === 'set 4 + }
+5
testsuite/set-init/main.tri
··· 1 + proc main!() { 2 + let set = [|'a, 'b, 1, 2|] 3 + assert typeof set === 'set 4 + # assert is 'a in set 5 + }
+8 -3
trilogy-llvm/core/trilogy_record.c
··· 84 84 record->len = 0; 85 85 record->contents = calloc_safe(new_cap, sizeof(trilogy_tuple_value)); 86 86 for (size_t i = 0; i < old_cap; ++i) { 87 - trilogy_record_insert( 88 - record, &old_contents[i].fst, &old_contents[i].snd 89 - ); 87 + if (old_contents[i].fst.tag != TAG_UNDEFINED) { 88 + trilogy_record_insert( 89 + record, &old_contents[i].fst, &old_contents[i].snd 90 + ); 91 + } 90 92 } 91 93 free(old_contents); 92 94 } ··· 104 106 record->contents[empty].fst = *key; 105 107 record->contents[empty].snd = *value; 106 108 record->len++; 109 + *key = trilogy_undefined; 110 + *value = trilogy_undefined; 107 111 } else { 108 112 // If it is found, delete the new key, destroy the old value, and then 109 113 // insert the new value. 110 114 trilogy_value_destroy(key); 111 115 trilogy_value_destroy(&record->contents[found].snd); 112 116 record->contents[found].snd = *value; 117 + *value = trilogy_undefined; 113 118 } 114 119 } 115 120
+125
trilogy-llvm/core/trilogy_set.c
··· 6 6 #include <stdint.h> 7 7 #include <stdlib.h> 8 8 9 + // This is hash map with basic open-addressed linear probing, all values are 10 + // `unit` as it is a set. 11 + 9 12 trilogy_set_value* trilogy_set_init(trilogy_value* tv, trilogy_set_value* set) { 10 13 assert(tv->tag == TAG_UNDEFINED); 11 14 tv->tag = TAG_SET; ··· 22 25 return trilogy_set_init(tv, set); 23 26 } 24 27 28 + trilogy_set_value* trilogy_set_init_cap(trilogy_value* tv, size_t cap) { 29 + trilogy_set_value* set = malloc_safe(sizeof(trilogy_set_value)); 30 + set->rc = 1; 31 + set->len = 0; 32 + set->cap = cap; 33 + set->contents = 34 + cap == 0 ? NULL : calloc_safe(cap, sizeof(trilogy_tuple_value)); 35 + return trilogy_set_init(tv, set); 36 + } 37 + 25 38 trilogy_set_value* 26 39 trilogy_set_clone_into(trilogy_value* tv, trilogy_set_value* set) { 27 40 assert(set->rc != 0); ··· 29 42 return trilogy_set_init(tv, set); 30 43 } 31 44 45 + static size_t trilogy_set_find( 46 + trilogy_set_value* set, trilogy_value* key, size_t* insert_to 47 + ) { 48 + if (insert_to) *insert_to = set->cap; 49 + size_t h = ((size_t)trilogy_value_hash(key)) % set->cap; 50 + for (;; h = h == set->cap - 1 ? 0 : h + 1) { 51 + trilogy_tuple_value* entry = &set->contents[h]; 52 + if (entry->fst.tag == TAG_UNDEFINED && 53 + entry->snd.tag == TAG_UNDEFINED) { 54 + // Returning cap to indicate not found. Otherwise, return value is 55 + // in range. Insert here only if we haven't already found a better 56 + // spot. 57 + if (insert_to && *insert_to == set->cap) *insert_to = h; 58 + return set->cap; 59 + } 60 + if (entry->fst.tag == TAG_UNDEFINED) { 61 + // Key unset, but value not undefined: entry was deleted. Skip it as 62 + // if it were filled, since it might have been filled at time of 63 + // insert. We can insert here if the value is not found later, and 64 + // we haven't already found a better spot. 65 + if (insert_to && *insert_to == set->cap) *insert_to = h; 66 + continue; 67 + } 68 + if (trilogy_value_structural_eq(key, &entry->fst)) { 69 + if (insert_to) *insert_to = h; 70 + return h; 71 + } 72 + } 73 + } 74 + 75 + static void trilogy_set_maintainance(trilogy_set_value* set) { 76 + // Maximum load factor = 75% 77 + if (set->len >= set->cap - set->cap / 4) { 78 + size_t old_cap = set->cap; 79 + trilogy_tuple_value* old_contents = set->contents; 80 + size_t new_cap = old_cap <= SIZE_MAX / 2 ? old_cap * 2 : SIZE_MAX; 81 + if (new_cap == 0) new_cap = 8; 82 + set->cap = new_cap; 83 + set->len = 0; 84 + set->contents = calloc_safe(new_cap, sizeof(trilogy_tuple_value)); 85 + for (size_t i = 0; i < old_cap; ++i) { 86 + if (old_contents[i].fst.tag != TAG_UNDEFINED) { 87 + trilogy_set_insert(set, &old_contents[i].fst); 88 + } 89 + } 90 + free(old_contents); 91 + } 92 + } 93 + 94 + void trilogy_set_insert(trilogy_set_value* set, trilogy_value* value) { 95 + trilogy_set_maintainance(set); 96 + size_t empty = set->cap; 97 + size_t found = trilogy_set_find(set, value, &empty); 98 + if (found == set->cap) { 99 + // If it's not found, insert the new value and mark it with a `unit`. 100 + set->contents[empty].fst = *value; 101 + set->contents[empty].snd = trilogy_unit; 102 + set->len++; 103 + *value = trilogy_undefined; 104 + } else { 105 + // If it is found, delete the new value as if consumed, but we don't 106 + // have to change anything about the set's contents. 107 + trilogy_value_destroy(value); 108 + } 109 + } 110 + 111 + void trilogy_set_append(trilogy_set_value* set, trilogy_value* tv) { 112 + trilogy_set_value* tail = trilogy_set_untag(tv); 113 + uint64_t tail_len = tail->len; 114 + if (tail->rc == 1) { 115 + for (uint64_t i = 0; i < tail->cap; ++i) { 116 + trilogy_tuple_value* entry = &tail->contents[i]; 117 + if (entry->fst.tag != TAG_UNDEFINED) { 118 + trilogy_set_insert(set, &entry->fst); 119 + } 120 + } 121 + } else { 122 + for (uint64_t i = 0; i < tail_len; ++i) { 123 + trilogy_value clone = trilogy_undefined; 124 + trilogy_value_clone_into(&clone, &tail->contents[i]); 125 + trilogy_set_insert(set, &clone); 126 + } 127 + } 128 + trilogy_value_destroy(tv); 129 + } 130 + 131 + void trilogy_set_delete(trilogy_set_value* set, trilogy_value* value) { 132 + size_t found = trilogy_set_find(set, value, NULL); 133 + if (found != set->cap) { 134 + // Only if it's found does it need to be destroyed. Remove the value (to 135 + // mark as empty), and destroy the it. The marker `unit` does not need 136 + // to be adjusted. 137 + trilogy_value_destroy(&set->contents[found].fst); 138 + set->len--; 139 + } 140 + } 141 + 142 + bool trilogy_set_contains(trilogy_set_value* set, trilogy_value* value) { 143 + return trilogy_set_find(set, value, NULL) != set->cap; 144 + } 145 + 32 146 trilogy_set_value* trilogy_set_untag(trilogy_value* val) { 33 147 if (val->tag != TAG_SET) rte("set", val->tag); 34 148 return trilogy_set_assume(val); ··· 49 163 free(set); 50 164 } 51 165 } 166 + 167 + bool trilogy_set_structural_eq(trilogy_set_value* lhs, trilogy_set_value* rhs) { 168 + if (lhs->len != rhs->len) return false; 169 + for (uint64_t i = 0; i < lhs->cap; ++i) { 170 + trilogy_tuple_value* entry = &lhs->contents[i]; 171 + if (entry->fst.tag == TAG_UNDEFINED) continue; 172 + size_t rhs_index = trilogy_set_find(rhs, &entry->fst, NULL); 173 + if (rhs_index == rhs->cap) return false; 174 + } 175 + return true; 176 + }
+8
trilogy-llvm/core/trilogy_set.h
··· 3 3 4 4 trilogy_set_value* trilogy_set_init(trilogy_value* tv, trilogy_set_value* set); 5 5 trilogy_set_value* trilogy_set_init_empty(trilogy_value* tv); 6 + trilogy_set_value* trilogy_set_init_cap(trilogy_value* tv, size_t cap); 6 7 trilogy_set_value* 7 8 trilogy_set_clone_into(trilogy_value* tv, trilogy_set_value* arr); 9 + 10 + void trilogy_set_insert(trilogy_set_value* set, trilogy_value* value); 11 + void trilogy_set_append(trilogy_set_value* set, trilogy_value* value); 12 + void trilogy_set_delete(trilogy_set_value* set, trilogy_value* value); 13 + bool trilogy_set_contains(trilogy_set_value* set, trilogy_value* key); 14 + 15 + bool trilogy_set_structural_eq(trilogy_set_value* lhs, trilogy_set_value* rhs); 8 16 9 17 trilogy_set_value* trilogy_set_untag(trilogy_value* val); 10 18 trilogy_set_value* trilogy_set_assume(trilogy_value* val);
+8 -4
trilogy-llvm/core/trilogy_value.c
··· 231 231 } 232 232 return true; 233 233 } 234 - case TAG_RECORD: 234 + case TAG_RECORD: { 235 235 trilogy_record_value* lhs_rec = trilogy_record_assume(lhs); 236 236 trilogy_record_value* rhs_rec = trilogy_record_assume(rhs); 237 237 return trilogy_record_structural_eq(lhs_rec, rhs_rec); 238 - break; 239 - case TAG_SET: 238 + } 239 + case TAG_SET: { 240 + trilogy_set_value* lhs_set = trilogy_set_assume(lhs); 241 + trilogy_set_value* rhs_set = trilogy_set_assume(rhs); 242 + return trilogy_set_structural_eq(lhs_set, rhs_set); 243 + } 240 244 default: 241 - internal_panic("unimplemented\n"); 245 + internal_panic("unreachable\n"); 242 246 return false; 243 247 } 244 248 }
+4 -2
trilogy-llvm/core/types.h
··· 146 146 */ 147 147 size_t cap; 148 148 /** 149 - * An array of length `cap` containing the values of this set. 149 + * An array of length `cap` containing the values of this set. This is a 150 + * tuple, same as record as a set is just a record with `unit` for every 151 + * value. 150 152 */ 151 - trilogy_value* contents; 153 + trilogy_tuple_value* contents; 152 154 } trilogy_set_value; 153 155 154 156 typedef struct trilogy_record_value {
+83
trilogy-llvm/src/bare.rs
··· 531 531 .unwrap(); 532 532 } 533 533 534 + pub(crate) fn trilogy_set_init_cap( 535 + &self, 536 + value: PointerValue<'ctx>, 537 + cap: usize, 538 + name: &str, 539 + ) -> PointerValue<'ctx> { 540 + let f = self.declare_bare( 541 + "trilogy_set_init_cap", 542 + self.context.ptr_type(AddressSpace::default()).fn_type( 543 + &[ 544 + self.context.ptr_type(AddressSpace::default()).into(), 545 + self.usize_type().into(), 546 + ], 547 + false, 548 + ), 549 + ); 550 + self.builder 551 + .build_call( 552 + f, 553 + &[ 554 + value.into(), 555 + self.usize_type().const_int(cap as u64, false).into(), 556 + ], 557 + name, 558 + ) 559 + .unwrap() 560 + .try_as_basic_value() 561 + .unwrap_left() 562 + .into_pointer_value() 563 + } 564 + 565 + pub(crate) fn trilogy_set_assume( 566 + &self, 567 + t: PointerValue<'ctx>, 568 + name: &str, 569 + ) -> PointerValue<'ctx> { 570 + let f = self.declare_bare( 571 + "trilogy_set_assume", 572 + self.context.ptr_type(AddressSpace::default()).fn_type( 573 + &[self.context.ptr_type(AddressSpace::default()).into()], 574 + false, 575 + ), 576 + ); 577 + self.builder 578 + .build_call(f, &[t.into()], name) 579 + .unwrap() 580 + .try_as_basic_value() 581 + .unwrap_left() 582 + .into_pointer_value() 583 + } 584 + 585 + pub(crate) fn trilogy_set_insert(&self, set: PointerValue<'ctx>, value: PointerValue<'ctx>) { 586 + let f = self.declare_bare( 587 + "trilogy_set_insert", 588 + self.context.void_type().fn_type( 589 + &[ 590 + self.context.ptr_type(AddressSpace::default()).into(), 591 + self.context.ptr_type(AddressSpace::default()).into(), 592 + ], 593 + false, 594 + ), 595 + ); 596 + self.builder 597 + .build_call(f, &[set.into(), value.into()], "") 598 + .unwrap(); 599 + } 600 + 601 + pub(crate) fn trilogy_set_append(&self, set: PointerValue<'ctx>, value: PointerValue<'ctx>) { 602 + let f = self.declare_bare( 603 + "trilogy_set_append", 604 + self.context.void_type().fn_type( 605 + &[ 606 + self.context.ptr_type(AddressSpace::default()).into(), 607 + self.context.ptr_type(AddressSpace::default()).into(), 608 + ], 609 + false, 610 + ), 611 + ); 612 + self.builder 613 + .build_call(f, &[set.into(), value.into()], "") 614 + .unwrap(); 615 + } 616 + 534 617 pub(crate) fn trilogy_record_init_cap( 535 618 &self, 536 619 value: PointerValue<'ctx>,
+49 -2
trilogy-llvm/src/expression/mod.rs
··· 39 39 Some(val) 40 40 } 41 41 Value::Array(arr) => self.compile_array(arr, name), 42 - Value::Set(..) => todo!(), 42 + Value::Set(set) => self.compile_set(set, name), 43 43 Value::Record(record) => self.compile_record(record, name), 44 44 Value::ArrayComprehension(comp) => self.compile_array_comprehension(comp, name), 45 - Value::SetComprehension(..) => todo!(), 45 + Value::SetComprehension(comp) => self.compile_set_comprehension(comp, name), 46 46 Value::RecordComprehension(comp) => self.compile_record_comprehension(comp, name), 47 47 Value::Sequence(seq) => { 48 48 self.di.push_block_scope(expression.span); ··· 186 186 Some(output_clone) 187 187 } 188 188 189 + fn compile_set_comprehension( 190 + &self, 191 + expr: &ir::Iterator, 192 + name: &str, 193 + ) -> Option<PointerValue<'ctx>> { 194 + let output = self.allocate_value("acc"); 195 + self.trilogy_set_init_cap(output, 8, ""); 196 + self.bind_temporary(output); 197 + 198 + let done_function = self.add_continuation("done"); 199 + let (done_continuation, done_continuation_point) = 200 + self.capture_current_continuation_as_break(done_function, "for_break"); 201 + let next_iteration = self.compile_iterator(&expr.query, done_continuation)?; 202 + self.bind_temporary(next_iteration); 203 + if let Some(value) = self.compile_expression(&expr.value, "element") { 204 + let set_val = self.use_temporary(output).unwrap(); 205 + let set = self.trilogy_set_assume(set_val, ""); 206 + self.trilogy_set_insert(set, value); 207 + let next_iteration = self.use_temporary(next_iteration).unwrap(); 208 + self.void_call_continuation(next_iteration); 209 + } 210 + 211 + self.become_continuation_point(done_continuation_point); 212 + self.begin_next_function(done_function); 213 + let output_clone = self.allocate_value(name); 214 + self.trilogy_value_clone_into(output_clone, self.use_temporary(output).unwrap()); 215 + Some(output_clone) 216 + } 217 + 189 218 fn compile_record_comprehension( 190 219 &self, 191 220 expr: &ir::Iterator, ··· 357 386 self.trilogy_array_append(array_value, temporary); 358 387 } else { 359 388 self.trilogy_array_push(array_value, temporary); 389 + } 390 + } 391 + let target = self.use_temporary(target).unwrap(); 392 + Some(target) 393 + } 394 + 395 + fn compile_set(&self, pack: &ir::Pack, name: &str) -> Option<PointerValue<'ctx>> { 396 + let target = self.allocate_value(name); 397 + self.bind_temporary(target); 398 + self.trilogy_set_init_cap(target, pack.values.len(), "set"); 399 + for element in &pack.values { 400 + let temporary = self.compile_expression(&element.expression, "set.el")?; 401 + let target = self.use_temporary(target).unwrap(); 402 + let set_value = self.trilogy_set_assume(target, ""); 403 + if element.is_spread { 404 + self.trilogy_set_append(set_value, temporary); 405 + } else { 406 + self.trilogy_set_insert(set_value, temporary); 360 407 } 361 408 } 362 409 let target = self.use_temporary(target).unwrap();
+2 -2
trilogy-llvm/src/pattern_match.rs
··· 136 136 } 137 137 Value::Wildcard => { /* always passes with no action */ } 138 138 Value::Array(array) => self.match_array(array, value, on_fail, bound_ids)?, 139 - Value::Set(..) => {} 140 - Value::Record(..) => {} 139 + Value::Set(..) => todo!(), 140 + Value::Record(..) => todo!(), 141 141 // Not patterns: 142 142 Value::Pack(..) => unreachable!(), 143 143 Value::Sequence(..) => unreachable!(),