Actually just three programming languages in a trenchcoat

implement query and/or

+113 -28
+7
testsuite/query-and-or-prec/main.tri
···
··· 1 + module debug at "trilogy:debug" use dbg 2 + 3 + proc main!() { 4 + for a = 1 and b = 2 or b = 3 and a = 4 { 5 + dbg!(a : b) 6 + } 7 + }
+1
testsuite/query-and-or-prec/spec.toml
···
··· 1 + output = "1:2\n4:3\n"
+15
testsuite/query-conjunction/main.tri
···
··· 1 + module debug at "trilogy:debug" use dbg 2 + 3 + rule nums(1) 4 + rule nums(2) 5 + rule nums(3) 6 + 7 + proc main!() { 8 + for a = 5 and b = 10 { 9 + dbg!(a : b) 10 + } 11 + 12 + for nums(a) and nums(b) { 13 + dbg!(a : b) 14 + } 15 + }
+1
testsuite/query-conjunction/spec.toml
···
··· 1 + output = "5:10\n1:1\n1:2\n1:3\n2:1\n2:2\n2:3\n3:1\n3:2\n3:3\n"
+19
testsuite/query-disjunction/main.tri
···
··· 1 + module debug at "trilogy:debug" use dbg 2 + 3 + rule val_a(1) 4 + rule val_a(2) 5 + rule val_a(3) 6 + 7 + rule val_b(4) 8 + rule val_b(5) 9 + rule val_b(6) 10 + 11 + proc main!() { 12 + for a = 5 or a = 10 { 13 + dbg!(a) 14 + } 15 + 16 + for val_a(a) or val_b(a) { 17 + dbg!(a) 18 + } 19 + }
+1
testsuite/query-disjunction/spec.toml
···
··· 1 + output = "5\n10\n1\n2\n3\n4\n5\n6\n"
+2 -1
trilogy-llvm/src/expression/mod.rs
··· 144 self.bind_temporary(next_iteration); 145 if let Some(value) = self.compile_expression(&expr.value, name) { 146 let next_iteration = self.use_temporary(next_iteration).unwrap(); 147 - self.call_known_continuation(next_iteration, value); 148 } 149 150 self.become_continuation_point(done_continuation_point);
··· 144 self.bind_temporary(next_iteration); 145 if let Some(value) = self.compile_expression(&expr.value, name) { 146 let next_iteration = self.use_temporary(next_iteration).unwrap(); 147 + self.trilogy_value_destroy(value); 148 + self.void_call_continuation(next_iteration); 149 } 150 151 self.become_continuation_point(done_continuation_point);
+67 -27
trilogy-llvm/src/query.rs
··· 181 )?); 182 } 183 184 - // Wrap the next iteration with our own, as a lookup requires some cleanup 185 - // before starting its next internal iteration. 186 - let next_iteration_with_cleanup = self.add_continuation("rule_query_cleanup"); 187 - let (next_iteration_with_cleanup_continuation, next_iteration_with_cleanup_cp) = 188 - self.capture_current_continuation(next_iteration_with_cleanup, "pass_next"); 189 - self.call_known_continuation( 190 - self.use_temporary(next_to).unwrap(), 191 - next_iteration_with_cleanup_continuation, 192 ); 193 - // The cleanup: destroy all variables that were unbound on the way in. This uses 194 - // very similar detection as with patterns, noting that which variables are bound 195 - // at iteration time can be determined statically as we make the pass through the 196 - // query's IR. 197 - self.become_continuation_point(next_iteration_with_cleanup_cp); 198 - self.begin_next_function(next_iteration_with_cleanup); 199 - for id in bound_ids[bound_before_lookup..] 200 - .iter() 201 - .filter(|id| !bound_ids[0..bound_before_lookup].contains(id)) 202 - { 203 - let var = self.get_variable(id).unwrap().ptr(); 204 - self.trilogy_value_destroy(var); 205 - } 206 - let next_iteration = self.use_temporary(next_iteration_inner).unwrap(); 207 - self.call_known_continuation(next_iteration, self.get_continuation("")); 208 } 209 - ir::QueryValue::Disjunction(..) => todo!(), 210 - ir::QueryValue::Conjunction(..) => todo!(), 211 ir::QueryValue::Implication(..) => todo!(), 212 ir::QueryValue::Alternative(..) => todo!(), 213 ir::QueryValue::Direct(unification) => { 214 let rvalue = self.compile_expression(&unification.expression, "rvalue")?; 215 - self.compile_pattern_match(&unification.pattern, rvalue, done_to)?; 216 - self.next_deterministic(next_to, done_to, "assign_next"); 217 } 218 ir::QueryValue::Element(..) => todo!(), 219 ir::QueryValue::Not(..) => todo!(), ··· 237 self.begin_next_function(next_iteration); 238 let done_to = self.use_temporary(done_to).unwrap(); 239 self.void_call_continuation(done_to); 240 } 241 }
··· 181 )?); 182 } 183 184 + self.next_cleanup( 185 + next_iteration_inner, 186 + next_to, 187 + bound_ids, 188 + bound_before_lookup, 189 + "rule_query_cleanup", 190 ); 191 + } 192 + ir::QueryValue::Disjunction(disj) => { 193 + let disj_second_fn = self.add_continuation("disj.second"); 194 + let (disj_second, disj_second_cp) = 195 + self.capture_current_continuation(disj_second_fn, "disj.second"); 196 + let next_of_first = self.compile_iterator(&disj.0, disj_second)?; 197 + self.call_known_continuation(self.use_temporary(next_to).unwrap(), next_of_first); 198 + 199 + self.become_continuation_point(disj_second_cp); 200 + self.begin_next_function(disj_second_fn); 201 + let next_of_second = self.compile_iterator(&disj.1, done_to)?; 202 + self.call_known_continuation(self.use_temporary(next_to).unwrap(), next_of_second); 203 } 204 + ir::QueryValue::Conjunction(conj) => { 205 + let next_of_first = self.compile_iterator(&conj.0, done_to)?; 206 + self.bind_temporary(next_of_first); 207 + let next_of_second = self.compile_iterator(&conj.1, next_of_first)?; 208 + let next_to = self.use_temporary(next_to).unwrap(); 209 + self.call_known_continuation(next_to, next_of_second); 210 + } 211 ir::QueryValue::Implication(..) => todo!(), 212 ir::QueryValue::Alternative(..) => todo!(), 213 ir::QueryValue::Direct(unification) => { 214 let rvalue = self.compile_expression(&unification.expression, "rvalue")?; 215 + let pre_len = bound_ids.len(); 216 + bound_ids.extend(self.compile_pattern_match( 217 + &unification.pattern, 218 + rvalue, 219 + done_to, 220 + )?); 221 + self.next_cleanup(done_to, next_to, bound_ids, pre_len, "assign_next"); 222 } 223 ir::QueryValue::Element(..) => todo!(), 224 ir::QueryValue::Not(..) => todo!(), ··· 242 self.begin_next_function(next_iteration); 243 let done_to = self.use_temporary(done_to).unwrap(); 244 self.void_call_continuation(done_to); 245 + } 246 + 247 + fn next_cleanup( 248 + &self, 249 + next_iteration: PointerValue<'ctx>, 250 + next_to: PointerValue<'ctx>, 251 + bound_ids: &[Id], 252 + keep_ids: usize, 253 + name: &str, 254 + ) { 255 + // Wrap the next iteration with our own, as a lookup requires some cleanup 256 + // before starting its next internal iteration. 257 + let next_iteration_with_cleanup = self.add_continuation(name); 258 + let (next_iteration_with_cleanup_continuation, next_iteration_with_cleanup_cp) = 259 + self.capture_current_continuation(next_iteration_with_cleanup, name); 260 + self.call_known_continuation( 261 + self.use_temporary(next_to).unwrap(), 262 + next_iteration_with_cleanup_continuation, 263 + ); 264 + 265 + // The cleanup: destroy all variables that were unbound on the way in. This uses 266 + // very similar detection as with patterns, noting that which variables are bound 267 + // at iteration time can be determined statically as we make the pass through the 268 + // query's IR. 269 + self.become_continuation_point(next_iteration_with_cleanup_cp); 270 + self.begin_next_function(next_iteration_with_cleanup); 271 + for id in bound_ids[keep_ids..] 272 + .iter() 273 + .filter(|id| !bound_ids[0..keep_ids].contains(id)) 274 + { 275 + let var = self.get_variable(id).unwrap().ptr(); 276 + self.trilogy_value_destroy(var); 277 + } 278 + let next_iteration = self.use_temporary(next_iteration).unwrap(); 279 + self.void_call_continuation(next_iteration); 280 } 281 }