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