···55 dbg!(x)
66 }
7788+ let mut n = 0
89 for x in [|4, 4, 4, 5, 5|] {
99- dbg!(x)
1010+ n += 1
1011 }
1212+ assert n == 2
11131414+ let mut m = 0
1215 for x in {| 'a => 1, 'b => 2 |} {
1313- dbg!(x)
1616+ m += 1
1417 }
1818+ assert m == 2
1519}
···9393 if (insert_to && *insert_to == record->cap) *insert_to = h;
9494 continue;
9595 }
9696- if (trilogy_value_structural_eq(key, &entry->fst)) {
9696+ if (trilogy_value_referential_eq(key, &entry->fst)) {
9797 if (insert_to) *insert_to = h;
9898 return h;
9999 }
+1-1
trilogy-llvm/core/trilogy_set.c
···8989 if (insert_to && *insert_to == set->cap) *insert_to = h;
9090 continue;
9191 }
9292- if (trilogy_value_structural_eq(key, &entry->fst)) {
9292+ if (trilogy_value_referential_eq(key, &entry->fst)) {
9393 if (insert_to) *insert_to = h;
9494 return h;
9595 }
+141-116
trilogy-llvm/src/query.rs
···9090 // NOTE: at this time, the lookup expression is not an arbitrary expression, only a
9191 // reference/module path, so branching is not possible here.
9292 let rule = self.compile_expression(&lookup.path, "rule")?;
9393- self.perform_lookup(rule, &lookup.patterns, next_to, done_to, bound_ids)?;
9393+9494+ let arguments = lookup
9595+ .patterns
9696+ .iter()
9797+ .map(|pattern| self.compile_input_pattern(pattern))
9898+ .collect::<Option<Vec<_>>>()?;
9999+100100+ let (next_iteration_inner, output_arguments) = self.call_rule(
101101+ rule,
102102+ &arguments,
103103+ self.use_temporary(done_to).unwrap(),
104104+ "lookup_next",
105105+ );
106106+107107+ self.bind_temporary(next_iteration_inner);
108108+109109+ // Wrap the next iteration with our own, as a lookup requires some cleanup
110110+ // before starting its next internal iteration.
111111+ let next_iteration_with_cleanup = self.add_continuation("lookup.next");
112112+ let (next_iteration_with_cleanup_continuation, next_iteration_with_cleanup_cp) =
113113+ self.capture_current_continuation(next_iteration_with_cleanup, "lookup.next");
114114+115115+ let bound_before_lookup = bound_ids.len();
116116+ for (pattern, out_value) in lookup.patterns.iter().zip(output_arguments) {
117117+ let out_value = self.use_temporary(out_value).unwrap();
118118+ self.compile_pattern_match_with_bindings(
119119+ pattern,
120120+ out_value,
121121+ next_iteration_with_cleanup_continuation,
122122+ bound_ids,
123123+ )?;
124124+ }
125125+126126+ self.call_known_continuation(
127127+ self.use_temporary(next_to).unwrap(),
128128+ next_iteration_with_cleanup_continuation,
129129+ );
130130+131131+ self.become_continuation_point(next_iteration_with_cleanup_cp);
132132+ self.begin_next_function(next_iteration_with_cleanup);
133133+ self.cleanup_go_next(next_iteration_inner, bound_ids, bound_before_lookup);
94134 }
95135 ir::QueryValue::Disjunction(disj) => {
96136 let disj_second_fn = self.add_continuation("disj.second");
···176216 self.next_cleanup(done_to, next_to, bound_ids, pre_len, "assign_next");
177217 }
178218 ir::QueryValue::Element(unification) => {
219219+ let input = self.compile_input_pattern(&unification.pattern)?;
220220+ let collection =
221221+ self.compile_expression(&unification.expression, "in.collection")?;
179222 let elem = self.elem();
180180- self.perform_lookup(
223223+ let (next_iteration_inner, output_arguments) = self.call_rule(
181224 elem,
182182- [&unification.pattern, &unification.expression],
183183- next_to,
184184- done_to,
225225+ &[self.use_temporary(input).unwrap(), collection],
226226+ self.use_temporary(done_to).unwrap(),
227227+ "lookup_next",
228228+ );
229229+230230+ // The element unification is kind of implemented weird. The actual iteration
231231+ // is implemented as a rule in core.tri, but we call it in a way that would be
232232+ // syntactically invalid, though functionally possible; the difference being
233233+ // that the second argument is an expression (not a pattern) and does not get
234234+ // used as an output parameter.
235235+ self.bind_temporary(next_iteration_inner);
236236+237237+ // Wrap the next iteration with our own, as a lookup requires some cleanup
238238+ // before starting its next internal iteration.
239239+ let next_iteration_with_cleanup = self.add_continuation("in.next");
240240+ let (next_iteration_with_cleanup_continuation, next_iteration_with_cleanup_cp) =
241241+ self.capture_current_continuation(next_iteration_with_cleanup, "in.next");
242242+243243+ let bound_before_lookup = bound_ids.len();
244244+ self.compile_pattern_match_with_bindings(
245245+ &unification.pattern,
246246+ output_arguments[0],
247247+ next_iteration_with_cleanup_continuation,
185248 bound_ids,
186249 )?;
250250+251251+ self.call_known_continuation(
252252+ self.use_temporary(next_to).unwrap(),
253253+ next_iteration_with_cleanup_continuation,
254254+ );
255255+256256+ self.become_continuation_point(next_iteration_with_cleanup_cp);
257257+ self.begin_next_function(next_iteration_with_cleanup);
258258+ self.cleanup_go_next(next_iteration_inner, bound_ids, bound_before_lookup);
187259 }
188260 ir::QueryValue::Not(query) => {
189261 let go_next_fn = self.add_continuation("not.next");
···262334 self.void_call_continuation(next_iteration);
263335 }
264336265265- fn perform_lookup<'a>(
266266- &self,
267267- rule: PointerValue<'ctx>,
268268- patterns: impl IntoIterator<Item = &'a ir::Expression> + Copy,
269269- next_to: PointerValue<'ctx>,
270270- done_to: PointerValue<'ctx>,
271271- bound_ids: &mut Vec<Id>,
272272- ) -> Option<()> {
273273- // NOTE: similarly, the arguments of a query must be syntactically both patterns and
337337+ fn compile_input_pattern(&self, pattern: &ir::Expression) -> Option<PointerValue<'ctx>> {
338338+ // NOTE: the arguments of a query must be syntactically both patterns and
274339 // expressions, so we can again guarantee that branching is not possible.
275275- let arguments = patterns
276276- .into_iter()
277277- .map(|pattern| {
278278- if !pattern.can_evaluate() {
279279- // This pattern is not possibly an expression, e.g. due to containing a wildcard
280280- // or other pattern-only syntax element. It can only be used as an output parameter.
281281- let arg = self.allocate_undefined("out_arg");
282282- self.bind_temporary(arg);
283283- return Some(arg);
284284- }
285285- let variables = pattern
286286- .bindings()
287287- .iter()
288288- .map(|var| self.get_variable(var).unwrap())
289289- .collect::<Vec<_>>();
290290- if variables.is_empty() {
291291- let arg = self.compile_expression(pattern, "in_arg")?;
292292- self.bind_temporary(arg);
293293- return Some(arg);
294294- }
295295- // This pattern is (potentially) fully defined. We must confirm by checking all
296296- // the variables at runtime, and if they are all set, then we can construct
297297- // this pattern.
298298- let out_block = self.context.append_basic_block(self.get_function(), "out");
299299- let original_function = self.get_function();
300300- let snapshot = self.snapshot_function_context();
301301- for variable in variables {
302302- let next_arg = self.context.append_basic_block(self.get_function(), "next");
303303- self.branch_undefined(variable.ptr(), out_block, next_arg);
304304- self.builder.position_at_end(next_arg);
305305- }
306306- let in_arg = self.compile_expression(pattern, "in_arg")?;
307307- let final_function = self.get_function();
308308- if original_function == final_function {
309309- let merge_block = self.context.append_basic_block(final_function, "merge_arg");
340340+ if !pattern.can_evaluate() {
341341+ // This pattern is not possibly an expression, e.g. due to containing a wildcard
342342+ // or other pattern-only syntax element. It can only be used as an output parameter.
343343+ let arg = self.allocate_undefined("out_arg");
344344+ self.bind_temporary(arg);
345345+ return Some(arg);
346346+ }
347347+ let variables = pattern
348348+ .bindings()
349349+ .iter()
350350+ .map(|var| self.get_variable(var).unwrap())
351351+ .collect::<Vec<_>>();
352352+ if variables.is_empty() {
353353+ let arg = self.compile_expression(pattern, "in_arg")?;
354354+ self.bind_temporary(arg);
355355+ return Some(arg);
356356+ }
357357+ // This pattern is (potentially) fully defined. We must confirm by checking all
358358+ // the variables at runtime, and if they are all set, then we can construct
359359+ // this pattern.
360360+ let out_block = self.context.append_basic_block(self.get_function(), "out");
361361+ let original_function = self.get_function();
362362+ let snapshot = self.snapshot_function_context();
363363+ for variable in variables {
364364+ let next_arg = self.context.append_basic_block(self.get_function(), "next");
365365+ self.branch_undefined(variable.ptr(), out_block, next_arg);
366366+ self.builder.position_at_end(next_arg);
367367+ }
368368+ let in_arg = self.compile_expression(pattern, "in_arg")?;
369369+ let final_function = self.get_function();
370370+ if original_function == final_function {
371371+ let merge_block = self.context.append_basic_block(final_function, "merge_arg");
310372311311- let in_block = self.builder.get_insert_block().unwrap();
312312- self.builder
313313- .build_unconditional_branch(merge_block)
314314- .unwrap();
315315-316316- self.builder.position_at_end(out_block);
317317- let out_arg = self.allocate_undefined("out_arg");
318318- self.builder
319319- .build_unconditional_branch(merge_block)
320320- .unwrap();
321321-322322- self.builder.position_at_end(merge_block);
323323- let phi = self
324324- .builder
325325- .build_phi(self.context.ptr_type(AddressSpace::default()), "arg")
326326- .unwrap();
327327- phi.add_incoming(&[(&in_arg, in_block), (&out_arg, out_block)]);
328328- let arg = phi.as_basic_value().into_pointer_value();
329329- self.bind_temporary(arg);
330330- Some(arg)
331331- } else {
332332- let arg_continuation = self.add_continuation("arg");
333333- let end = self.continue_in_scope(arg_continuation, in_arg);
334334- self.end_continuation_point_as_close(end);
335335-336336- self.restore_function_context(snapshot);
337337- self.builder.position_at_end(out_block);
338338- let end = self.void_continue_in_scope(arg_continuation);
339339- self.end_continuation_point_as_close(end);
373373+ let in_block = self.builder.get_insert_block().unwrap();
374374+ self.builder
375375+ .build_unconditional_branch(merge_block)
376376+ .unwrap();
340377341341- self.begin_next_function(arg_continuation);
342342- let arg = self.get_continuation("arg");
343343- self.bind_temporary(arg);
344344- Some(arg)
345345- }
346346- })
347347- .collect::<Option<Vec<_>>>()?;
378378+ self.builder.position_at_end(out_block);
379379+ let out_arg = self.allocate_undefined("out_arg");
380380+ self.builder
381381+ .build_unconditional_branch(merge_block)
382382+ .unwrap();
348383349349- let (next_iteration_inner, output_arguments) = self.call_rule(
350350- rule,
351351- &arguments,
352352- self.use_temporary(done_to).unwrap(),
353353- "lookup_next",
354354- );
355355- self.bind_temporary(next_iteration_inner);
384384+ self.builder.position_at_end(merge_block);
385385+ let phi = self
386386+ .builder
387387+ .build_phi(self.context.ptr_type(AddressSpace::default()), "arg")
388388+ .unwrap();
389389+ phi.add_incoming(&[(&in_arg, in_block), (&out_arg, out_block)]);
390390+ let arg = phi.as_basic_value().into_pointer_value();
391391+ self.bind_temporary(arg);
392392+ Some(arg)
393393+ } else {
394394+ let arg_continuation = self.add_continuation("arg");
395395+ let end = self.continue_in_scope(arg_continuation, in_arg);
396396+ self.end_continuation_point_as_close(end);
356397357357- // Wrap the next iteration with our own, as a lookup requires some cleanup
358358- // before starting its next internal iteration.
359359- let next_iteration_with_cleanup = self.add_continuation("lookup.next");
360360- let (next_iteration_with_cleanup_continuation, next_iteration_with_cleanup_cp) =
361361- self.capture_current_continuation(next_iteration_with_cleanup, "lookup.next");
398398+ self.restore_function_context(snapshot);
399399+ self.builder.position_at_end(out_block);
400400+ let end = self.void_continue_in_scope(arg_continuation);
401401+ self.end_continuation_point_as_close(end);
362402363363- let bound_before_lookup = bound_ids.len();
364364- for (pattern, out_value) in patterns.into_iter().zip(output_arguments) {
365365- let out_value = self.use_temporary(out_value).unwrap();
366366- self.compile_pattern_match_with_bindings(
367367- pattern,
368368- out_value,
369369- next_iteration_with_cleanup_continuation,
370370- bound_ids,
371371- )?;
403403+ self.begin_next_function(arg_continuation);
404404+ let arg = self.get_continuation("arg");
405405+ self.bind_temporary(arg);
406406+ Some(arg)
372407 }
373373-374374- self.call_known_continuation(
375375- self.use_temporary(next_to).unwrap(),
376376- next_iteration_with_cleanup_continuation,
377377- );
378378-379379- self.become_continuation_point(next_iteration_with_cleanup_cp);
380380- self.begin_next_function(next_iteration_with_cleanup);
381381- self.cleanup_go_next(next_iteration_inner, bound_ids, bound_before_lookup);
382382- Some(())
383408 }
384409}
+5-4
trilogy/src/stdlib/core.tri
···243243export to_array
244244245245rule elem(element, [element, .._])
246246-rule elem(element, [_, ..rest]) <- elem(element, rest)
246246+rule elem(element, [_, ..rest]) <- elem(element, ^rest)
247247rule elem(_, []) <- end
248248rule elem(element, set and typeof 'set) <-
249249 array = c::set_to_array!(set)
250250- and elem(element, array)
251251-rule elem(element, record and typeof 'record) <- array = c::record_to_array!(record)
252252- and elem(element, array)
250250+ and elem(element, ^array)
251251+rule elem(element, record and typeof 'record) <-
252252+ array = c::record_to_array!(record)
253253+ and elem(element, ^array)
253254export elem