Actually just three programming languages in a trenchcoat
1
fork

Configure Feed

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

fixing some bugs, got `in` query working passably

+201 -128
+10
testsuite/query-in-expression/main.tri
··· 1 + import "trilogy:debug" use dbg 2 + 3 + func make_twice n = [n, n] 4 + 5 + proc main!() { 6 + for x in make_twice 3 { 7 + dbg!(x) 8 + } 9 + } 10 +
+1
testsuite/query-in-expression/spec.toml
··· 1 + output = "3\n3\n"
+6 -2
testsuite/query-in/main.tri
··· 5 5 dbg!(x) 6 6 } 7 7 8 + let mut n = 0 8 9 for x in [|4, 4, 4, 5, 5|] { 9 - dbg!(x) 10 + n += 1 10 11 } 12 + assert n == 2 11 13 14 + let mut m = 0 12 15 for x in {| 'a => 1, 'b => 2 |} { 13 - dbg!(x) 16 + m += 1 14 17 } 18 + assert m == 2 15 19 }
+1 -1
testsuite/query-in/spec.toml
··· 1 - output = "1\n2\n3\n4\n5\na:1\nb:2\n" 1 + output = "1\n2\n3\n"
+7
testsuite/record-elements-ref-eq/main.tri
··· 1 + proc main!() { 2 + let x = [] 3 + let y = [] 4 + let rec = {| x => 1 , y => 2 |} 5 + assert rec.x == 1 6 + assert rec.y == 2 7 + }
+1 -1
testsuite/rule-recursive/main.tri
··· 1 1 import "trilogy:debug" use dbg 2 2 3 3 rule array_iterate(element, [element, .._]) 4 - rule array_iterate(element, [_, ..rest]) <- array_iterate(element, rest) 4 + rule array_iterate(element, [_, ..rest]) <- array_iterate(element, ^rest) 5 5 rule array_iterate(_, []) <- end 6 6 7 7 proc main!() {
+7
testsuite/set-elements-ref-eq/main.tri
··· 1 + proc main!() { 2 + let x = [] 3 + let y = [] 4 + let set = [| x, y |] 5 + assert set == [| x, y |] 6 + assert set != [| x |] 7 + }
+20 -2
trilogy-ir/src/visitor/bindings.rs
··· 4 4 use std::collections::HashSet; 5 5 6 6 pub struct Bindings { 7 + is_bindable: bool, 7 8 bindings: HashSet<Id>, 8 9 } 9 10 10 11 impl Bindings { 11 12 pub fn of<N: IrVisitable>(node: &N) -> HashSet<Id> { 12 13 let mut bindings = Self { 14 + is_bindable: true, 13 15 bindings: HashSet::default(), 14 16 }; 15 17 node.visit(&mut bindings); ··· 29 31 Disjunction(pair) => self.visit_disjunction(pair), 30 32 Application(application) => self.visit_application(application), 31 33 Reference(ident) => { 32 - self.bindings.insert(ident.id.clone()); 34 + if self.is_bindable { 35 + self.bindings.insert(ident.id.clone()); 36 + } 33 37 } 34 38 Set(pack) => self.visit_set(pack), 35 39 Array(pack) => self.visit_array(pack), ··· 64 68 fn visit_application(&mut self, node: &Application) { 65 69 match &node.function.value { 66 70 Value::Builtin(Builtin::Pin) => {} 67 - _ => node.visit(self), 71 + Value::Builtin(Builtin::Glue) 72 + | Value::Builtin(Builtin::Negate) 73 + | Value::Builtin(Builtin::Cons) 74 + | Value::Builtin(Builtin::Typeof) 75 + | Value::Builtin(Builtin::Construct) => { 76 + self.is_bindable = true; 77 + node.argument.visit(self); 78 + } 79 + _ => { 80 + let was_bindable = self.is_bindable; 81 + self.is_bindable = false; 82 + node.function.visit(self); 83 + node.argument.visit(self); 84 + self.is_bindable = self.is_bindable || was_bindable; 85 + } 68 86 } 69 87 } 70 88
+1 -1
trilogy-llvm/core/trilogy_record.c
··· 93 93 if (insert_to && *insert_to == record->cap) *insert_to = h; 94 94 continue; 95 95 } 96 - if (trilogy_value_structural_eq(key, &entry->fst)) { 96 + if (trilogy_value_referential_eq(key, &entry->fst)) { 97 97 if (insert_to) *insert_to = h; 98 98 return h; 99 99 }
+1 -1
trilogy-llvm/core/trilogy_set.c
··· 89 89 if (insert_to && *insert_to == set->cap) *insert_to = h; 90 90 continue; 91 91 } 92 - if (trilogy_value_structural_eq(key, &entry->fst)) { 92 + if (trilogy_value_referential_eq(key, &entry->fst)) { 93 93 if (insert_to) *insert_to = h; 94 94 return h; 95 95 }
+141 -116
trilogy-llvm/src/query.rs
··· 90 90 // NOTE: at this time, the lookup expression is not an arbitrary expression, only a 91 91 // reference/module path, so branching is not possible here. 92 92 let rule = self.compile_expression(&lookup.path, "rule")?; 93 - self.perform_lookup(rule, &lookup.patterns, next_to, done_to, bound_ids)?; 93 + 94 + let arguments = lookup 95 + .patterns 96 + .iter() 97 + .map(|pattern| self.compile_input_pattern(pattern)) 98 + .collect::<Option<Vec<_>>>()?; 99 + 100 + let (next_iteration_inner, output_arguments) = self.call_rule( 101 + rule, 102 + &arguments, 103 + self.use_temporary(done_to).unwrap(), 104 + "lookup_next", 105 + ); 106 + 107 + self.bind_temporary(next_iteration_inner); 108 + 109 + // Wrap the next iteration with our own, as a lookup requires some cleanup 110 + // before starting its next internal iteration. 111 + let next_iteration_with_cleanup = self.add_continuation("lookup.next"); 112 + let (next_iteration_with_cleanup_continuation, next_iteration_with_cleanup_cp) = 113 + self.capture_current_continuation(next_iteration_with_cleanup, "lookup.next"); 114 + 115 + let bound_before_lookup = bound_ids.len(); 116 + for (pattern, out_value) in lookup.patterns.iter().zip(output_arguments) { 117 + let out_value = self.use_temporary(out_value).unwrap(); 118 + self.compile_pattern_match_with_bindings( 119 + pattern, 120 + out_value, 121 + next_iteration_with_cleanup_continuation, 122 + bound_ids, 123 + )?; 124 + } 125 + 126 + self.call_known_continuation( 127 + self.use_temporary(next_to).unwrap(), 128 + next_iteration_with_cleanup_continuation, 129 + ); 130 + 131 + self.become_continuation_point(next_iteration_with_cleanup_cp); 132 + self.begin_next_function(next_iteration_with_cleanup); 133 + self.cleanup_go_next(next_iteration_inner, bound_ids, bound_before_lookup); 94 134 } 95 135 ir::QueryValue::Disjunction(disj) => { 96 136 let disj_second_fn = self.add_continuation("disj.second"); ··· 176 216 self.next_cleanup(done_to, next_to, bound_ids, pre_len, "assign_next"); 177 217 } 178 218 ir::QueryValue::Element(unification) => { 219 + let input = self.compile_input_pattern(&unification.pattern)?; 220 + let collection = 221 + self.compile_expression(&unification.expression, "in.collection")?; 179 222 let elem = self.elem(); 180 - self.perform_lookup( 223 + let (next_iteration_inner, output_arguments) = self.call_rule( 181 224 elem, 182 - [&unification.pattern, &unification.expression], 183 - next_to, 184 - done_to, 225 + &[self.use_temporary(input).unwrap(), collection], 226 + self.use_temporary(done_to).unwrap(), 227 + "lookup_next", 228 + ); 229 + 230 + // The element unification is kind of implemented weird. The actual iteration 231 + // is implemented as a rule in core.tri, but we call it in a way that would be 232 + // syntactically invalid, though functionally possible; the difference being 233 + // that the second argument is an expression (not a pattern) and does not get 234 + // used as an output parameter. 235 + self.bind_temporary(next_iteration_inner); 236 + 237 + // Wrap the next iteration with our own, as a lookup requires some cleanup 238 + // before starting its next internal iteration. 239 + let next_iteration_with_cleanup = self.add_continuation("in.next"); 240 + let (next_iteration_with_cleanup_continuation, next_iteration_with_cleanup_cp) = 241 + self.capture_current_continuation(next_iteration_with_cleanup, "in.next"); 242 + 243 + let bound_before_lookup = bound_ids.len(); 244 + self.compile_pattern_match_with_bindings( 245 + &unification.pattern, 246 + output_arguments[0], 247 + next_iteration_with_cleanup_continuation, 185 248 bound_ids, 186 249 )?; 250 + 251 + self.call_known_continuation( 252 + self.use_temporary(next_to).unwrap(), 253 + next_iteration_with_cleanup_continuation, 254 + ); 255 + 256 + self.become_continuation_point(next_iteration_with_cleanup_cp); 257 + self.begin_next_function(next_iteration_with_cleanup); 258 + self.cleanup_go_next(next_iteration_inner, bound_ids, bound_before_lookup); 187 259 } 188 260 ir::QueryValue::Not(query) => { 189 261 let go_next_fn = self.add_continuation("not.next"); ··· 262 334 self.void_call_continuation(next_iteration); 263 335 } 264 336 265 - fn perform_lookup<'a>( 266 - &self, 267 - rule: PointerValue<'ctx>, 268 - patterns: impl IntoIterator<Item = &'a ir::Expression> + Copy, 269 - next_to: PointerValue<'ctx>, 270 - done_to: PointerValue<'ctx>, 271 - bound_ids: &mut Vec<Id>, 272 - ) -> Option<()> { 273 - // NOTE: similarly, the arguments of a query must be syntactically both patterns and 337 + fn compile_input_pattern(&self, pattern: &ir::Expression) -> Option<PointerValue<'ctx>> { 338 + // NOTE: the arguments of a query must be syntactically both patterns and 274 339 // expressions, so we can again guarantee that branching is not possible. 275 - let arguments = patterns 276 - .into_iter() 277 - .map(|pattern| { 278 - if !pattern.can_evaluate() { 279 - // This pattern is not possibly an expression, e.g. due to containing a wildcard 280 - // or other pattern-only syntax element. It can only be used as an output parameter. 281 - let arg = self.allocate_undefined("out_arg"); 282 - self.bind_temporary(arg); 283 - return Some(arg); 284 - } 285 - let variables = pattern 286 - .bindings() 287 - .iter() 288 - .map(|var| self.get_variable(var).unwrap()) 289 - .collect::<Vec<_>>(); 290 - if variables.is_empty() { 291 - let arg = self.compile_expression(pattern, "in_arg")?; 292 - self.bind_temporary(arg); 293 - return Some(arg); 294 - } 295 - // This pattern is (potentially) fully defined. We must confirm by checking all 296 - // the variables at runtime, and if they are all set, then we can construct 297 - // this pattern. 298 - let out_block = self.context.append_basic_block(self.get_function(), "out"); 299 - let original_function = self.get_function(); 300 - let snapshot = self.snapshot_function_context(); 301 - for variable in variables { 302 - let next_arg = self.context.append_basic_block(self.get_function(), "next"); 303 - self.branch_undefined(variable.ptr(), out_block, next_arg); 304 - self.builder.position_at_end(next_arg); 305 - } 306 - let in_arg = self.compile_expression(pattern, "in_arg")?; 307 - let final_function = self.get_function(); 308 - if original_function == final_function { 309 - let merge_block = self.context.append_basic_block(final_function, "merge_arg"); 340 + if !pattern.can_evaluate() { 341 + // This pattern is not possibly an expression, e.g. due to containing a wildcard 342 + // or other pattern-only syntax element. It can only be used as an output parameter. 343 + let arg = self.allocate_undefined("out_arg"); 344 + self.bind_temporary(arg); 345 + return Some(arg); 346 + } 347 + let variables = pattern 348 + .bindings() 349 + .iter() 350 + .map(|var| self.get_variable(var).unwrap()) 351 + .collect::<Vec<_>>(); 352 + if variables.is_empty() { 353 + let arg = self.compile_expression(pattern, "in_arg")?; 354 + self.bind_temporary(arg); 355 + return Some(arg); 356 + } 357 + // This pattern is (potentially) fully defined. We must confirm by checking all 358 + // the variables at runtime, and if they are all set, then we can construct 359 + // this pattern. 360 + let out_block = self.context.append_basic_block(self.get_function(), "out"); 361 + let original_function = self.get_function(); 362 + let snapshot = self.snapshot_function_context(); 363 + for variable in variables { 364 + let next_arg = self.context.append_basic_block(self.get_function(), "next"); 365 + self.branch_undefined(variable.ptr(), out_block, next_arg); 366 + self.builder.position_at_end(next_arg); 367 + } 368 + let in_arg = self.compile_expression(pattern, "in_arg")?; 369 + let final_function = self.get_function(); 370 + if original_function == final_function { 371 + let merge_block = self.context.append_basic_block(final_function, "merge_arg"); 310 372 311 - let in_block = self.builder.get_insert_block().unwrap(); 312 - self.builder 313 - .build_unconditional_branch(merge_block) 314 - .unwrap(); 315 - 316 - self.builder.position_at_end(out_block); 317 - let out_arg = self.allocate_undefined("out_arg"); 318 - self.builder 319 - .build_unconditional_branch(merge_block) 320 - .unwrap(); 321 - 322 - self.builder.position_at_end(merge_block); 323 - let phi = self 324 - .builder 325 - .build_phi(self.context.ptr_type(AddressSpace::default()), "arg") 326 - .unwrap(); 327 - phi.add_incoming(&[(&in_arg, in_block), (&out_arg, out_block)]); 328 - let arg = phi.as_basic_value().into_pointer_value(); 329 - self.bind_temporary(arg); 330 - Some(arg) 331 - } else { 332 - let arg_continuation = self.add_continuation("arg"); 333 - let end = self.continue_in_scope(arg_continuation, in_arg); 334 - self.end_continuation_point_as_close(end); 335 - 336 - self.restore_function_context(snapshot); 337 - self.builder.position_at_end(out_block); 338 - let end = self.void_continue_in_scope(arg_continuation); 339 - self.end_continuation_point_as_close(end); 373 + let in_block = self.builder.get_insert_block().unwrap(); 374 + self.builder 375 + .build_unconditional_branch(merge_block) 376 + .unwrap(); 340 377 341 - self.begin_next_function(arg_continuation); 342 - let arg = self.get_continuation("arg"); 343 - self.bind_temporary(arg); 344 - Some(arg) 345 - } 346 - }) 347 - .collect::<Option<Vec<_>>>()?; 378 + self.builder.position_at_end(out_block); 379 + let out_arg = self.allocate_undefined("out_arg"); 380 + self.builder 381 + .build_unconditional_branch(merge_block) 382 + .unwrap(); 348 383 349 - let (next_iteration_inner, output_arguments) = self.call_rule( 350 - rule, 351 - &arguments, 352 - self.use_temporary(done_to).unwrap(), 353 - "lookup_next", 354 - ); 355 - self.bind_temporary(next_iteration_inner); 384 + self.builder.position_at_end(merge_block); 385 + let phi = self 386 + .builder 387 + .build_phi(self.context.ptr_type(AddressSpace::default()), "arg") 388 + .unwrap(); 389 + phi.add_incoming(&[(&in_arg, in_block), (&out_arg, out_block)]); 390 + let arg = phi.as_basic_value().into_pointer_value(); 391 + self.bind_temporary(arg); 392 + Some(arg) 393 + } else { 394 + let arg_continuation = self.add_continuation("arg"); 395 + let end = self.continue_in_scope(arg_continuation, in_arg); 396 + self.end_continuation_point_as_close(end); 356 397 357 - // Wrap the next iteration with our own, as a lookup requires some cleanup 358 - // before starting its next internal iteration. 359 - let next_iteration_with_cleanup = self.add_continuation("lookup.next"); 360 - let (next_iteration_with_cleanup_continuation, next_iteration_with_cleanup_cp) = 361 - self.capture_current_continuation(next_iteration_with_cleanup, "lookup.next"); 398 + self.restore_function_context(snapshot); 399 + self.builder.position_at_end(out_block); 400 + let end = self.void_continue_in_scope(arg_continuation); 401 + self.end_continuation_point_as_close(end); 362 402 363 - let bound_before_lookup = bound_ids.len(); 364 - for (pattern, out_value) in patterns.into_iter().zip(output_arguments) { 365 - let out_value = self.use_temporary(out_value).unwrap(); 366 - self.compile_pattern_match_with_bindings( 367 - pattern, 368 - out_value, 369 - next_iteration_with_cleanup_continuation, 370 - bound_ids, 371 - )?; 403 + self.begin_next_function(arg_continuation); 404 + let arg = self.get_continuation("arg"); 405 + self.bind_temporary(arg); 406 + Some(arg) 372 407 } 373 - 374 - self.call_known_continuation( 375 - self.use_temporary(next_to).unwrap(), 376 - next_iteration_with_cleanup_continuation, 377 - ); 378 - 379 - self.become_continuation_point(next_iteration_with_cleanup_cp); 380 - self.begin_next_function(next_iteration_with_cleanup); 381 - self.cleanup_go_next(next_iteration_inner, bound_ids, bound_before_lookup); 382 - Some(()) 383 408 } 384 409 }
+5 -4
trilogy/src/stdlib/core.tri
··· 243 243 export to_array 244 244 245 245 rule elem(element, [element, .._]) 246 - rule elem(element, [_, ..rest]) <- elem(element, rest) 246 + rule elem(element, [_, ..rest]) <- elem(element, ^rest) 247 247 rule elem(_, []) <- end 248 248 rule elem(element, set and typeof 'set) <- 249 249 array = c::set_to_array!(set) 250 - and elem(element, array) 251 - rule elem(element, record and typeof 'record) <- array = c::record_to_array!(record) 252 - and elem(element, array) 250 + and elem(element, ^array) 251 + rule elem(element, record and typeof 'record) <- 252 + array = c::record_to_array!(record) 253 + and elem(element, ^array) 253 254 export elem