1use super::atom::parse_int;
2use super::util::named_children;
3use crate::diagnostics::diagnostics_api::SymbolKind;
4use crate::diagnostics::source_map::{HoverInfo, span_with_hover};
5use crate::errors::FatalParseError;
6use crate::expression::parse_expression;
7use crate::parser::ParseContext;
8use crate::util::TypecheckingContext;
9use crate::{RecoverableParseError, child};
10use conjure_cp_core::ast::{
11 Atom, BinaryAttr, DeclarationPtr, Domain, DomainPtr, Expression, Field, FuncAttr, IntVal,
12 JectivityAttr, Literal, MSetAttr, Moo, Name, PartialityAttr, PartitionAttr, PermutationAttr,
13 Range, Reference, RelAttr, SequenceAttr, SetAttr,
14};
15use tree_sitter::Node;
16
17use crate::field;
18
19pub fn parse_domain(
21 ctx: &mut ParseContext,
22 domain: Node,
23) -> Result<Option<DomainPtr>, FatalParseError> {
24 match domain.kind() {
25 "domain" | "annotation_domain" => {
26 let inner = match domain.child(0) {
27 Some(node) => node,
28 None => {
29 ctx.record_error(RecoverableParseError::new(
30 format!("{} in expression of kind '{}'", "domain", domain.kind()),
31 Some(domain.range()),
32 ));
33 return Ok(None);
34 }
35 };
36 parse_domain(ctx, inner)
37 }
38 "bool_domain" => {
39 ctx.add_span_and_doc_hover(&domain, "L_bool", SymbolKind::Domain, None, None);
40 Ok(Some(Domain::bool()))
41 }
42 "int_domain" | "annotation_int_domain" => parse_int_domain(ctx, domain),
43 "identifier" => {
44 let Some(decl) = get_declaration_ptr_from_identifier(ctx, domain)? else {
45 return Ok(None);
46 };
47 let Some(dom) = Domain::reference(decl) else {
48 ctx.record_error(crate::errors::RecoverableParseError::new(
49 format!(
50 "The identifier '{}' is not a valid domain",
51 &ctx.source_code[domain.start_byte()..domain.end_byte()]
52 ),
53 Some(domain.range()),
54 ));
55 return Ok(None);
56 };
57 let name = &ctx.source_code[domain.start_byte()..domain.end_byte()];
58
59 span_with_hover(
61 &domain,
62 ctx.source_code,
63 ctx.source_map,
64 HoverInfo {
65 description: format!("Domain reference: {name}"),
66 doc_key: None,
67 kind: Some(SymbolKind::Variable),
68 ty: None,
69 decl_span: None, },
71 );
72 Ok(Some(dom))
73 }
74 "tuple_domain" | "annotation_tuple_domain" => parse_tuple_domain(ctx, domain),
75 "matrix_domain" | "annotation_matrix_domain" => parse_matrix_domain(ctx, domain),
76 "record_domain" | "annotation_record_domain" => parse_record_domain(ctx, domain),
77 "variant_domain" | "annotation_variant_domain" => parse_variant_domain(ctx, domain),
78 "set_domain" | "annotation_set_domain" => parse_set_domain(ctx, domain),
79 "mset_domain" | "annotation_mset_domain" => parse_mset_domain(ctx, domain),
80 "sequence_domain" | "annotation_sequence_domain" => parse_sequence_domain(ctx, domain),
81 "function_domain" | "annotation_function_domain" => parse_function_domain(ctx, domain),
82 "relation_domain" => parse_relation_domain(ctx, domain),
83 "partition_domain" => parse_partition_domain(ctx, domain),
84 "permutation_domain" => parse_permutation_domain(ctx, domain),
85 _ => {
86 ctx.record_error(RecoverableParseError::new(
87 format!("{} is not a supported domain type", domain.kind()),
88 Some(domain.range()),
89 ));
90 Ok(None)
91 }
92 }
93}
94
95fn parse_mset_domain(
96 ctx: &mut ParseContext,
97 mset_domain: Node,
98) -> Result<Option<DomainPtr>, FatalParseError> {
99 let mut representation = None;
100 let mut size = Range::Unbounded;
101 let mut occurrence = Range::Unbounded;
102 let mut min_size = None;
103 let mut max_size = None;
104 let mut min_occurrence = None;
105 let mut max_occurrence = None;
106 let mut value_domain = None;
107
108 for child in named_children(&mset_domain) {
109 match child.kind() {
110 "identifier" => {}
111 "mset_attributes" => {
112 for attribute in named_children(&child) {
113 let Some(value_node) = attribute.child_by_field_name("value") else {
114 return Ok(None);
115 };
116 let name = attribute
117 .child_by_field_name("attribute")
118 .map(|node| &ctx.source_code[node.start_byte()..node.end_byte()])
119 .unwrap_or_default();
120 if name == "representation" {
121 representation = Some(
122 ctx.source_code[value_node.start_byte()..value_node.end_byte()]
123 .to_string(),
124 );
125 continue;
126 }
127 let Some(value) = parse_int_val(ctx, value_node)? else {
130 return Ok(None);
131 };
132 match name {
133 "size" => size = Range::Single(value),
134 "minSize" => min_size = Some(value),
135 "maxSize" => max_size = Some(value),
136 "minOccur" => min_occurrence = Some(value),
137 "maxOccur" => max_occurrence = Some(value),
138 _ => return Ok(None),
139 }
140 }
141 }
142 "domain" | "annotation_domain" => value_domain = parse_domain(ctx, child)?,
143 _ => {}
144 }
145 }
146
147 if !matches!(size, Range::Single(_)) {
148 size = match (min_size, max_size) {
149 (Some(min), Some(max)) => Range::Bounded(min, max),
150 (Some(min), None) => Range::UnboundedR(min),
151 (None, Some(max)) => Range::UnboundedL(max),
152 (None, None) => Range::Unbounded,
153 };
154 }
155 occurrence = match (min_occurrence, max_occurrence) {
156 (Some(min), Some(max)) => Range::Bounded(min, max),
157 (Some(min), None) => Range::UnboundedR(min),
158 (None, Some(max)) => Range::UnboundedL(max),
159 (None, None) => occurrence,
160 };
161
162 let Some(value_domain) = value_domain else {
163 ctx.record_error(RecoverableParseError::new(
164 "Multiset domain must have a value domain".to_string(),
165 Some(mset_domain.range()),
166 ));
167 return Ok(None);
168 };
169 let mut attrs = MSetAttr::new(size, occurrence);
170 if let Some(representation) = representation {
171 attrs = attrs.with_representation(representation);
172 }
173 Ok(Some(Domain::mset(attrs, value_domain)))
174}
175
176fn get_declaration_ptr_from_identifier(
177 ctx: &mut ParseContext,
178 identifier: Node,
179) -> Result<Option<DeclarationPtr>, FatalParseError> {
180 let name = Name::user(&ctx.source_code[identifier.start_byte()..identifier.end_byte()]);
181 let decl = ctx.symbols.as_ref().unwrap().read().lookup(&name);
182
183 if decl.is_none() {
184 ctx.record_error(crate::errors::RecoverableParseError::new(
185 format!("The identifier '{}' is not defined", name),
186 Some(identifier.range()),
187 ));
188 return Ok(None);
189 }
190 match decl {
191 Some(decl) => Ok(Some(decl)),
192 None => {
193 ctx.record_error(crate::errors::RecoverableParseError::new(
194 format!("The identifier '{}' is not defined", name),
195 Some(identifier.range()),
196 ));
197 Ok(None)
198 }
199 }
200}
201
202fn parse_int_domain(
204 ctx: &mut ParseContext,
205 int_domain: Node,
206) -> Result<Option<DomainPtr>, FatalParseError> {
207 let int_keyword_node = child!(int_domain, 0, "int");
208
209 let Some(range_list) = int_domain.child_by_field_name("ranges") else {
210 ctx.add_span_and_doc_hover(&int_keyword_node, "L_int", SymbolKind::Domain, None, None);
211 let int_text = ctx.source_code[int_domain.start_byte()..int_domain.end_byte()].trim();
212 return if int_text == "int" {
213 Ok(Some(Domain::int(vec![Range::Bounded(
214 conjure_cp_core::ast::OXIDE_INT_MIN,
215 conjure_cp_core::ast::OXIDE_INT_MAX,
216 )])))
217 } else {
218 Ok(Some(Domain::int_ground(vec![])))
219 };
220 };
221 let components: Vec<_> = named_children(&range_list).collect();
224 if let [only] = components.as_slice()
225 && matches!(only.kind(), "atom" | "arithmetic_expr")
226 && let Some(expr) = parse_collection_valued_expression(ctx, *only)?
227 {
228 ctx.add_span_and_doc_hover(&int_keyword_node, "int", SymbolKind::Domain, None, None);
229 return Ok(Some(Domain::int_from_values(expr)));
230 }
231
232 let mut ranges_unresolved: Vec<Range<IntVal>> = Vec::new();
233 let mut all_resolved = true;
234
235 for domain_component in named_children(&range_list) {
236 match domain_component.kind() {
237 "atom" | "arithmetic_expr" | "integer" | "identifier" => {
238 let Some(int_val) = parse_int_val(ctx, domain_component)? else {
239 return Ok(None);
240 };
241
242 if !matches!(int_val, IntVal::Const(_)) {
243 all_resolved = false;
244 }
245 ranges_unresolved.push(Range::Single(int_val));
246 }
247 "int_range" | "annotation_int_range" => {
248 let lower_bound = match domain_component.child_by_field_name("lower") {
249 Some(node) => {
250 match parse_int_val(ctx, node)? {
251 Some(val) => Some(val),
252 None => return Ok(None), }
254 }
255 None => None,
256 };
257 let upper_bound = match domain_component.child_by_field_name("upper") {
258 Some(node) => {
259 match parse_int_val(ctx, node)? {
260 Some(val) => Some(val),
261 None => return Ok(None), }
263 }
264 None => None,
265 };
266
267 match (lower_bound, upper_bound) {
268 (Some(lower), Some(upper)) => {
269 if !matches!((&lower, &upper), (IntVal::Const(_), IntVal::Const(_))) {
270 all_resolved = false;
271 }
272 ranges_unresolved.push(Range::Bounded(lower, upper));
273 }
274 (Some(lower), None) => {
275 if !matches!(lower, IntVal::Const(_)) {
276 all_resolved = false;
277 }
278 ranges_unresolved.push(Range::UnboundedR(lower));
279 }
280 (None, Some(upper)) => {
281 if !matches!(upper, IntVal::Const(_)) {
282 all_resolved = false;
283 }
284 ranges_unresolved.push(Range::UnboundedL(upper));
285 }
286 _ => {
287 ctx.record_error(RecoverableParseError::new(
288 "Invalid int range: must have at least a lower or upper bound"
289 .to_string(),
290 Some(domain_component.range()),
291 ));
292 return Ok(None);
293 }
294 }
295 }
296 _ => {
297 ctx.record_error(RecoverableParseError::new(
298 format!(
299 "Unexpected int domain component: {}",
300 domain_component.kind()
301 ),
302 Some(domain_component.range()),
303 ));
304 return Ok(None);
305 }
306 }
307 }
308
309 if all_resolved {
311 let ranges: Vec<Range<i32>> = ranges_unresolved
312 .into_iter()
313 .map(|r| r.resolve())
314 .collect::<Result<Vec<_>, _>>()
315 .map_err(|e| {
316 FatalParseError::internal_error(
317 format!("could not resolve range: {e}"),
318 Some(int_domain.range()),
319 )
320 })?
321 .into_iter()
322 .filter(|range| !matches!(range, Range::Bounded(lower, upper) if lower > upper))
323 .collect();
324
325 ctx.add_span_and_doc_hover(&int_keyword_node, "L_int", SymbolKind::Domain, None, None);
326 Ok(Some(Domain::int(ranges)))
327 } else {
328 ctx.add_span_and_doc_hover(&int_keyword_node, "L_int", SymbolKind::Domain, None, None);
332 Ok(Some(Domain::int(ranges_unresolved)))
333 }
334}
335
336fn parse_int_val(ctx: &mut ParseContext, node: Node) -> Result<Option<IntVal>, FatalParseError> {
339 if matches!(node.kind(), "atom" | "integer") {
340 let text = &ctx.source_code[node.start_byte()..node.end_byte()];
341 if let Ok(integer) = text.parse::<i32>() {
342 return Ok(Some(IntVal::new_const(integer)));
343 }
344 }
345
346 if node.kind() == "identifier" {
347 let Some(decl) = get_declaration_ptr_from_identifier(ctx, node)? else {
348 return Ok(None);
350 };
351 return Ok(Some(IntVal::Reference(Reference::new(decl))));
352 }
353
354 let saved_context = ctx.typechecking_context;
355 let saved_inner_context = ctx.inner_typechecking_context;
356 ctx.typechecking_context = TypecheckingContext::Arithmetic;
357 ctx.inner_typechecking_context = TypecheckingContext::Arithmetic;
358 let expr = parse_expression(ctx, node)?;
359 ctx.typechecking_context = saved_context;
360 ctx.inner_typechecking_context = saved_inner_context;
361
362 let Some(expr) = expr else {
363 return Ok(None);
364 };
365
366 if let Expression::Atomic(_, Atom::Reference(reference)) = &expr
367 && let Ok(reference_val) = IntVal::new_ref(reference)
368 {
369 return Ok(Some(reference_val));
370 }
371
372 if let Expression::Atomic(_, Atom::Literal(Literal::Int(value))) = expr {
373 return Ok(Some(IntVal::new_const(value)));
374 }
375
376 Ok(IntVal::new_expr(Moo::new(expr)).ok())
377}
378
379fn parse_tuple_domain(
380 ctx: &mut ParseContext,
381 tuple_domain: Node,
382) -> Result<Option<DomainPtr>, FatalParseError> {
383 let mut domains: Vec<DomainPtr> = Vec::new();
384 for domain in named_children(&tuple_domain) {
385 let Some(parsed_domain) = parse_domain(ctx, domain)? else {
386 return Ok(None);
387 };
388 domains.push(parsed_domain);
389 }
390
391 if let Some(first) = tuple_domain.child(0)
393 && first.kind() == "tuple"
394 {
395 ctx.add_span_and_doc_hover(&first, "L_tuple", SymbolKind::Domain, None, None);
397 }
398
399 Ok(Some(Domain::tuple(domains)))
400}
401
402fn parse_matrix_domain(
403 ctx: &mut ParseContext,
404 matrix_domain: Node,
405) -> Result<Option<DomainPtr>, FatalParseError> {
406 let mut domains: Vec<DomainPtr> = Vec::new();
407 let Some(index_domain_list) = field!(recover, ctx, matrix_domain, "index_domain_list") else {
408 return Ok(None);
409 };
410 for domain in named_children(&index_domain_list) {
411 let Some(parsed_domain) = parse_domain(ctx, domain)? else {
412 return Ok(None);
413 };
414 domains.push(parsed_domain);
415 }
416 let Some(value_domain_node) = field!(recover, ctx, matrix_domain, "value_domain") else {
417 return Ok(None);
418 };
419 let Some(value_domain) = parse_domain(ctx, value_domain_node)? else {
420 return Ok(None);
421 };
422
423 let matrix_keyword_node = child!(matrix_domain, 0, "matrix");
425 ctx.add_span_and_doc_hover(
426 &matrix_keyword_node,
427 "matrix",
428 SymbolKind::Domain,
429 None,
430 None,
431 );
432 Ok(Some(Domain::matrix(value_domain, domains)))
433}
434
435fn parse_record_domain(
436 ctx: &mut ParseContext,
437 record_domain: Node,
438) -> Result<Option<DomainPtr>, FatalParseError> {
439 let mut record_entries: Vec<Field<DomainPtr>> = Vec::new();
440 for record_entry in named_children(&record_domain) {
441 let Some(name_node) = field!(recover, ctx, record_entry, "name") else {
442 return Ok(None);
443 };
444 let name = Name::user(&ctx.source_code[name_node.start_byte()..name_node.end_byte()]);
445 let Some(domain_node) = field!(recover, ctx, record_entry, "domain") else {
446 return Ok(None);
447 };
448 let Some(value) = parse_domain(ctx, domain_node)? else {
449 return Ok(None);
450 };
451 record_entries.push(Field { name, value });
452 }
453
454 let record_keyword_node = child!(record_domain, 0, "record");
456 ctx.add_span_and_doc_hover(
457 &record_keyword_node,
458 "L_record",
459 SymbolKind::Domain,
460 None,
461 None,
462 );
463 Ok(Some(Domain::record(record_entries)))
464}
465
466fn parse_variant_domain(
467 ctx: &mut ParseContext,
468 variant_domain: Node,
469) -> Result<Option<DomainPtr>, FatalParseError> {
470 let mut entries = Vec::new();
471 for entry in named_children(&variant_domain) {
472 let Some(name_node) = field!(recover, ctx, entry, "name") else {
473 return Ok(None);
474 };
475 let name = Name::user(&ctx.source_code[name_node.start_byte()..name_node.end_byte()]);
476 let Some(domain_node) = field!(recover, ctx, entry, "domain") else {
477 return Ok(None);
478 };
479 let Some(value) = parse_domain(ctx, domain_node)? else {
480 return Ok(None);
481 };
482 entries.push(Field { name, value });
483 }
484
485 let keyword = child!(variant_domain, 0, "variant");
486 ctx.add_span_and_doc_hover(&keyword, "variant", SymbolKind::Domain, None, None);
487 Ok(Some(Domain::variant(entries)))
488}
489
490fn parse_sequence_domain(
491 ctx: &mut ParseContext,
492 sequence_domain: Node,
493) -> Result<Option<DomainPtr>, FatalParseError> {
494 let mut size = Range::Unbounded;
495 let mut min_size = None;
496 let mut max_size = None;
497 let mut jectivity = JectivityAttr::None;
498 let mut value_domain: Option<DomainPtr> = None;
499
500 for child in named_children(&sequence_domain) {
501 match child.kind() {
502 "sequence_attributes" => {
503 for attribute in named_children(&child) {
504 let name = attribute
505 .child_by_field_name("attribute")
506 .map(|node| &ctx.source_code[node.start_byte()..node.end_byte()])
507 .unwrap_or_default();
508 match name {
509 "size" | "minSize" | "maxSize" => {
510 let Some(value_node) = attribute.child_by_field_name("value") else {
511 return Ok(None);
512 };
513 let Some(value) = parse_int_val(ctx, value_node)? else {
517 return Ok(None);
518 };
519 match name {
520 "size" => size = Range::Single(value),
521 "minSize" => min_size = Some(value),
522 "maxSize" => max_size = Some(value),
523 _ => unreachable!(),
524 }
525 }
526 "injective" => jectivity = JectivityAttr::Injective,
527 "surjective" => jectivity = JectivityAttr::Surjective,
528 "bijective" => jectivity = JectivityAttr::Bijective,
529 _ => return Ok(None),
530 }
531 }
532 }
533 "domain" | "annotation_domain" => value_domain = parse_domain(ctx, child)?,
534 _ => {}
535 }
536 }
537
538 if !matches!(size, Range::Single(_)) {
539 size = match (min_size, max_size) {
540 (Some(min), Some(max)) => Range::Bounded(min, max),
541 (Some(min), None) => Range::UnboundedR(min),
542 (None, Some(max)) => Range::UnboundedL(max),
543 (None, None) => Range::Unbounded,
544 };
545 }
546
547 let Some(value_domain) = value_domain else {
548 ctx.record_error(RecoverableParseError::new(
549 "Sequence domain must have a value domain".to_string(),
550 Some(sequence_domain.range()),
551 ));
552 return Ok(None);
553 };
554
555 let sequence_keyword_node = child!(sequence_domain, 0, "sequence");
557 ctx.add_span_and_doc_hover(
558 &sequence_keyword_node,
559 "sequence",
560 SymbolKind::Domain,
561 None,
562 None,
563 );
564
565 let attrs = SequenceAttr {
566 size,
567 jectivity,
568 representation: None,
569 };
570 Ok(Some(Domain::sequence(attrs, value_domain)))
571}
572
573fn parse_function_domain(
577 ctx: &mut ParseContext,
578 function_domain: Node,
579) -> Result<Option<DomainPtr>, FatalParseError> {
580 let mut size = Range::Unbounded;
581 let mut min_size = None;
582 let mut max_size = None;
583 let mut partiality = PartialityAttr::Partial;
584 let mut jectivity = JectivityAttr::None;
585
586 for child in named_children(&function_domain) {
587 if child.kind() == "function_attributes" {
588 for attribute in named_children(&child) {
589 let name = attribute
590 .child_by_field_name("attribute")
591 .map(|node| &ctx.source_code[node.start_byte()..node.end_byte()])
592 .unwrap_or_default();
593 match name {
594 "size" | "minSize" | "maxSize" => {
595 let Some(value_node) = attribute.child_by_field_name("value") else {
596 return Ok(None);
597 };
598 let Some(value) = parse_int(ctx, &value_node) else {
599 return Ok(None);
600 };
601 match name {
602 "size" => size = Range::Single(value),
603 "minSize" => min_size = Some(value),
604 "maxSize" => max_size = Some(value),
605 _ => unreachable!(),
606 }
607 }
608 "total" => partiality = PartialityAttr::Total,
609 "injective" => jectivity = JectivityAttr::Injective,
610 "surjective" => jectivity = JectivityAttr::Surjective,
611 "bijective" => jectivity = JectivityAttr::Bijective,
612 _ => return Ok(None),
613 }
614 }
615 }
616 }
617
618 if !matches!(size, Range::Single(_)) {
619 size = match (min_size, max_size) {
620 (Some(min), Some(max)) => Range::Bounded(min, max),
621 (Some(min), None) => Range::UnboundedR(min),
622 (None, Some(max)) => Range::UnboundedL(max),
623 (None, None) => Range::Unbounded,
624 };
625 }
626
627 let Some(domain_from_node) = function_domain.child_by_field_name("domain_from") else {
628 ctx.record_error(RecoverableParseError::new(
629 "Function domain must have a domain".to_string(),
630 Some(function_domain.range()),
631 ));
632 return Ok(None);
633 };
634 let Some(domain_from) = parse_domain(ctx, domain_from_node)? else {
635 return Ok(None);
636 };
637
638 let Some(domain_to_node) = function_domain.child_by_field_name("domain_to") else {
639 ctx.record_error(RecoverableParseError::new(
640 "Function domain must have a codomain".to_string(),
641 Some(function_domain.range()),
642 ));
643 return Ok(None);
644 };
645 let Some(domain_to) = parse_domain(ctx, domain_to_node)? else {
646 return Ok(None);
647 };
648
649 let function_keyword_node = child!(function_domain, 0, "function");
651 ctx.add_span_and_doc_hover(
652 &function_keyword_node,
653 "function",
654 SymbolKind::Domain,
655 None,
656 None,
657 );
658
659 let attrs = FuncAttr {
660 size,
661 partiality,
662 jectivity,
663 };
664 Ok(Some(Domain::function(attrs, domain_from, domain_to)))
665}
666
667fn parse_relation_domain(
671 ctx: &mut ParseContext,
672 relation_domain: Node,
673) -> Result<Option<DomainPtr>, FatalParseError> {
674 let mut size = Range::Unbounded;
675 let mut min_size = None;
676 let mut max_size = None;
677 let mut binary = Vec::new();
678
679 for child in named_children(&relation_domain) {
680 if child.kind() == "relation_attributes" {
681 for attribute in named_children(&child) {
682 let name = attribute
683 .child_by_field_name("attribute")
684 .map(|node| &ctx.source_code[node.start_byte()..node.end_byte()])
685 .unwrap_or_default();
686 match name {
687 "size" | "minSize" | "maxSize" => {
688 let Some(value_node) = attribute.child_by_field_name("value") else {
689 return Ok(None);
690 };
691 let Some(value) = parse_int(ctx, &value_node) else {
692 return Ok(None);
693 };
694 match name {
695 "size" => size = Range::Single(value),
696 "minSize" => min_size = Some(value),
697 "maxSize" => max_size = Some(value),
698 _ => unreachable!(),
699 }
700 }
701 _ => {
702 let Some(bin_attr) = BinaryAttr::from_keyword(name) else {
703 return Ok(None);
704 };
705 binary.push(bin_attr);
706 }
707 }
708 }
709 }
710 }
711
712 if !matches!(size, Range::Single(_)) {
713 size = match (min_size, max_size) {
714 (Some(min), Some(max)) => Range::Bounded(min, max),
715 (Some(min), None) => Range::UnboundedR(min),
716 (None, Some(max)) => Range::UnboundedL(max),
717 (None, None) => Range::Unbounded,
718 };
719 }
720
721 let Some(column_list) = field!(recover, ctx, relation_domain, "relation_domain_list") else {
722 return Ok(None);
723 };
724 let mut columns: Vec<DomainPtr> = Vec::new();
725 for column in named_children(&column_list) {
726 let Some(parsed) = parse_domain(ctx, column)? else {
727 return Ok(None);
728 };
729 columns.push(parsed);
730 }
731
732 let relation_keyword_node = child!(relation_domain, 0, "relation");
734 ctx.add_span_and_doc_hover(
735 &relation_keyword_node,
736 "relation",
737 SymbolKind::Domain,
738 None,
739 None,
740 );
741
742 let attrs = RelAttr { size, binary };
743 Ok(Some(Domain::relation(attrs, columns)))
744}
745
746fn parse_partition_domain(
747 ctx: &mut ParseContext,
748 partition_domain: Node,
749) -> Result<Option<DomainPtr>, FatalParseError> {
750 let mut num_parts = Range::Unbounded;
751 let mut min_num_parts = None;
752 let mut max_num_parts = None;
753 let mut part_len = Range::Unbounded;
754 let mut min_part_len = None;
755 let mut max_part_len = None;
756 let mut is_regular = false;
757
758 for child in named_children(&partition_domain) {
759 if child.kind() == "partition_attributes" {
760 for attribute in named_children(&child) {
761 let name = attribute
762 .child_by_field_name("attribute")
763 .map(|node| &ctx.source_code[node.start_byte()..node.end_byte()])
764 .unwrap_or_default();
765 match name {
766 "numParts" | "minNumParts" | "maxNumParts" | "partSize" | "minPartSize"
767 | "maxPartSize" => {
768 let Some(value_node) = attribute.child_by_field_name("value") else {
769 return Ok(None);
770 };
771 let Some(value) = parse_int(ctx, &value_node) else {
772 return Ok(None);
773 };
774 match name {
775 "numParts" => num_parts = Range::Single(value),
776 "minNumParts" => min_num_parts = Some(value),
777 "maxNumParts" => max_num_parts = Some(value),
778 "partSize" => part_len = Range::Single(value),
779 "minPartSize" => min_part_len = Some(value),
780 "maxPartSize" => max_part_len = Some(value),
781 _ => unreachable!(),
782 }
783 }
784 "regular" => is_regular = true,
785 _ => return Ok(None),
786 }
787 }
788 }
789 }
790
791 if !matches!(num_parts, Range::Single(_)) {
792 num_parts = match (min_num_parts, max_num_parts) {
793 (Some(min), Some(max)) => Range::Bounded(min, max),
794 (Some(min), None) => Range::UnboundedR(min),
795 (None, Some(max)) => Range::UnboundedL(max),
796 (None, None) => Range::Unbounded,
797 };
798 }
799 if !matches!(part_len, Range::Single(_)) {
800 part_len = match (min_part_len, max_part_len) {
801 (Some(min), Some(max)) => Range::Bounded(min, max),
802 (Some(min), None) => Range::UnboundedR(min),
803 (None, Some(max)) => Range::UnboundedL(max),
804 (None, None) => Range::Unbounded,
805 };
806 }
807
808 let Some(value_domain) = field!(recover, ctx, partition_domain, "value_domain") else {
809 return Ok(None);
810 };
811 let Some(inner) = parse_domain(ctx, value_domain)? else {
812 return Ok(None);
813 };
814
815 let partition_keyword_node = child!(partition_domain, 0, "partition");
816 ctx.add_span_and_doc_hover(
817 &partition_keyword_node,
818 "partition",
819 SymbolKind::Domain,
820 None,
821 None,
822 );
823
824 let attrs = PartitionAttr {
825 num_parts,
826 part_len,
827 is_regular,
828 };
829 Ok(Some(Domain::partition(attrs, inner)))
830}
831
832fn parse_permutation_domain(
833 ctx: &mut ParseContext,
834 permutation_domain: Node,
835) -> Result<Option<DomainPtr>, FatalParseError> {
836 let mut num_moved = Range::Unbounded;
837 let mut min_num_moved = None;
838 let mut max_num_moved = None;
839
840 for child in named_children(&permutation_domain) {
841 if child.kind() == "permutation_attributes" {
842 for attribute in named_children(&child) {
843 let name = attribute
844 .child_by_field_name("attribute")
845 .map(|node| &ctx.source_code[node.start_byte()..node.end_byte()])
846 .unwrap_or_default();
847 let Some(value_node) = attribute.child_by_field_name("value") else {
848 return Ok(None);
849 };
850 let Some(value) = parse_int(ctx, &value_node) else {
851 return Ok(None);
852 };
853 match name {
854 "numMoved" => num_moved = Range::Single(value),
855 "minNumMoved" => min_num_moved = Some(value),
856 "maxNumMoved" => max_num_moved = Some(value),
857 _ => return Ok(None),
858 }
859 }
860 }
861 }
862
863 if !matches!(num_moved, Range::Single(_)) {
864 num_moved = match (min_num_moved, max_num_moved) {
865 (Some(min), Some(max)) => Range::Bounded(min, max),
866 (Some(min), None) => Range::UnboundedR(min),
867 (None, Some(max)) => Range::UnboundedL(max),
868 (None, None) => Range::Unbounded,
869 };
870 }
871
872 let Some(value_domain) = field!(recover, ctx, permutation_domain, "value_domain") else {
873 return Ok(None);
874 };
875 let Some(inner) = parse_domain(ctx, value_domain)? else {
876 return Ok(None);
877 };
878
879 let permutation_keyword_node = child!(permutation_domain, 0, "permutation");
880 ctx.add_span_and_doc_hover(
881 &permutation_keyword_node,
882 "permutation",
883 SymbolKind::Domain,
884 None,
885 None,
886 );
887
888 let attrs = PermutationAttr { num_moved };
889 Ok(Some(Domain::permutation(attrs, inner)))
890}
891
892pub fn parse_set_domain(
893 ctx: &mut ParseContext,
894 set_domain: Node,
895) -> Result<Option<DomainPtr>, FatalParseError> {
896 let mut size = Range::Unbounded;
897 let mut min_size = None;
898 let mut max_size = None;
899 let mut representation = None;
900 let mut value_domain: Option<DomainPtr> = None;
901
902 for child in named_children(&set_domain) {
903 match child.kind() {
904 "set_attributes" => {
905 for attribute in named_children(&child) {
906 let Some(value_node) = attribute.child_by_field_name("value") else {
907 return Ok(None);
908 };
909 let name = attribute
910 .child_by_field_name("attribute")
911 .map(|node| &ctx.source_code[node.start_byte()..node.end_byte()])
912 .unwrap_or_default();
913 if name == "representation" {
914 representation = Some(
915 ctx.source_code[value_node.start_byte()..value_node.end_byte()]
916 .to_string(),
917 );
918 continue;
919 }
920 let Some(value) = parse_int_val(ctx, value_node)? else {
923 return Ok(None);
924 };
925 match name {
926 "size" => size = Range::Single(value),
927 "minSize" => min_size = Some(value),
928 "maxSize" => max_size = Some(value),
929 _ => return Ok(None),
930 }
931 }
932 }
933 "domain" | "annotation_domain" => {
934 let Some(parsed_domain) = parse_domain(ctx, child)? else {
935 return Ok(None);
936 };
937 value_domain = Some(parsed_domain);
938 }
939 _ => {
940 ctx.record_error(RecoverableParseError::new(
941 format!("Unrecognized set domain child kind: {}", child.kind()),
942 Some(child.range()),
943 ));
944 return Ok(None);
945 }
946 }
947 }
948
949 if let Some(domain) = value_domain {
950 let set_keyword_node = child!(set_domain, 0, "set");
952 ctx.add_span_and_doc_hover(&set_keyword_node, "set", SymbolKind::Domain, None, None);
954 if !matches!(size, Range::Single(_)) {
955 size = match (min_size, max_size) {
956 (Some(min), Some(max)) => Range::Bounded(min, max),
957 (Some(min), None) => Range::UnboundedR(min),
958 (None, Some(max)) => Range::UnboundedL(max),
959 (None, None) => Range::Unbounded,
960 };
961 }
962 let mut attr = SetAttr::new(size);
963 if let Some(repr) = representation {
964 attr = attr.with_representation(repr);
965 }
966 Ok(Some(Domain::set(attr, domain)))
967 } else {
968 ctx.record_error(RecoverableParseError::new(
969 "Set domain must have a value domain".to_string(),
970 Some(set_domain.range()),
971 ));
972 Ok(None)
973 }
974}
975
976fn parse_collection_valued_expression(
981 ctx: &mut ParseContext,
982 node: Node,
983) -> Result<Option<Expression>, FatalParseError> {
984 let saved_context = ctx.typechecking_context;
985 let saved_inner_context = ctx.inner_typechecking_context;
986 ctx.typechecking_context = TypecheckingContext::Unknown;
987 ctx.inner_typechecking_context = TypecheckingContext::Unknown;
988 let parsed = parse_expression(ctx, node);
989 ctx.typechecking_context = saved_context;
990 ctx.inner_typechecking_context = saved_inner_context;
991
992 let Some(expr) = parsed? else {
993 return Ok(None);
994 };
995 use conjure_cp_core::ast::Typeable;
996
997 if matches!(expr, Expression::Comprehension(_, _)) {
1000 return Ok(Some(expr));
1001 }
1002
1003 Ok(matches!(
1004 expr.return_type(),
1005 conjure_cp_core::ast::ReturnType::Set(_)
1006 | conjure_cp_core::ast::ReturnType::MSet(_)
1007 | conjure_cp_core::ast::ReturnType::Matrix(_)
1008 | conjure_cp_core::ast::ReturnType::Sequence(_)
1009 )
1010 .then_some(expr))
1011}