1use std::{collections::HashSet, str::FromStr};
9
10use indexmap::IndexMap;
11use nom_locate::LocatedSpan;
12use num_complex::Complex64;
13
14use crate::{
15 expression::format_complex,
16 hash::hash_f64,
17 parser::lex,
18 program::{disallow_leftover, MemoryAccesses, MemoryRegion, SyntaxError},
19 quil::Quil,
20 validation::identifier::{validate_user_identifier, IdentifierValidationError},
21};
22
23use super::{
24 Instruction, MemoryReference, Pragma, PragmaArgument, ScalarType, Vector,
25 RESERVED_PRAGMA_EXTERN,
26};
27
28#[derive(Clone, Debug, PartialEq, Hash, Eq)]
30pub enum ExternParameterType {
31 Scalar(ScalarType),
35 FixedLengthVector(Vector),
40 VariableLengthVector(ScalarType),
45}
46
47impl Quil for ExternParameterType {
48 fn write(
49 &self,
50 f: &mut impl std::fmt::Write,
51 fall_back_to_debug: bool,
52 ) -> crate::quil::ToQuilResult<()> {
53 match self {
54 ExternParameterType::Scalar(value) => value.write(f, fall_back_to_debug),
55 ExternParameterType::FixedLengthVector(value) => value.write(f, fall_back_to_debug),
56 ExternParameterType::VariableLengthVector(value) => {
57 value.write(f, fall_back_to_debug)?;
58 Ok(write!(f, "[]")?)
59 }
60 }
61 }
62}
63
64#[derive(Clone, Debug, PartialEq, Eq, Hash)]
66pub struct ExternParameter {
67 pub(crate) name: String,
69 pub(crate) mutable: bool,
71 pub(crate) data_type: ExternParameterType,
73}
74
75impl ExternParameter {
76 pub fn try_new(
79 name: String,
80 mutable: bool,
81 data_type: ExternParameterType,
82 ) -> Result<Self, ExternError> {
83 validate_user_identifier(name.as_str()).map_err(ExternError::from_boxed)?;
84 Ok(Self {
85 name,
86 mutable,
87 data_type,
88 })
89 }
90
91 pub fn name(&self) -> &str {
92 self.name.as_str()
93 }
94
95 pub fn mutable(&self) -> bool {
96 self.mutable
97 }
98
99 pub fn data_type(&self) -> &ExternParameterType {
100 &self.data_type
101 }
102}
103
104impl Quil for ExternParameter {
105 fn write(
106 &self,
107 writer: &mut impl std::fmt::Write,
108 fall_back_to_debug: bool,
109 ) -> Result<(), crate::quil::ToQuilError> {
110 write!(writer, "{} : ", self.name)?;
111 if self.mutable {
112 write!(writer, "mut ")?;
113 }
114 self.data_type.write(writer, fall_back_to_debug)
115 }
116}
117
118#[derive(Clone, Debug, PartialEq, Eq, Hash)]
120pub struct ExternSignature {
121 pub(crate) return_type: Option<ScalarType>,
123 pub(crate) parameters: Vec<ExternParameter>,
125}
126
127impl ExternSignature {
128 pub fn new(return_type: Option<ScalarType>, parameters: Vec<ExternParameter>) -> Self {
130 Self {
131 return_type,
132 parameters,
133 }
134 }
135
136 pub fn return_type(&self) -> Option<&ScalarType> {
137 self.return_type.as_ref()
138 }
139
140 pub fn parameters(&self) -> &[ExternParameter] {
141 self.parameters.as_slice()
142 }
143}
144
145const EXPECTED_PRAGMA_EXTERN_STRUCTURE: &str = "PRAGMA EXTERN {name} \"{scalar type}? (\\(({parameter name} : mut? {parameter type}) (, {parameter name} : mut? {parameter type})*\\))?\"";
146
147#[derive(Debug, thiserror::Error, PartialEq, Clone)]
149pub enum ExternError {
150 #[error(
152 "invalid extern signature syntax: {0:?} (expected `{EXPECTED_PRAGMA_EXTERN_STRUCTURE}`)"
153 )]
154 Syntax(Box<SyntaxError<ExternSignature>>),
155 #[error(
157 "failed to lex extern signature: {0:?} (expected `{EXPECTED_PRAGMA_EXTERN_STRUCTURE}`)"
158 )]
159 Lex(Box<crate::parser::LexError>),
160 #[error("`PRAGMA EXTERN` must have a single argument representing the extern name")]
162 InvalidPragmaArguments,
163 #[error("`PRAGMA EXTERN` instruction has no signature")]
165 NoSignature,
166 #[error("`PRAGMA EXTERN` instruction has no name")]
168 NoName,
169 #[error("ExternPragmaMap contained a pragma that was not EXTERN")]
171 PragmaIsNotExtern,
172 #[error("extern definition has a signature but it has neither a return nor parameters")]
174 NoReturnOrParameters,
175 #[error("invalid identifier: {0:?}")]
177 Name(#[from] Box<IdentifierValidationError>),
178}
179
180impl ExternError {
181 fn from_boxed<T>(value: T) -> Self
182 where
183 ExternError: From<Box<T>>,
184 {
185 ExternError::from(Box::new(value))
186 }
187}
188
189impl FromStr for ExternSignature {
190 type Err = ExternError;
191
192 fn from_str(s: &str) -> Result<Self, Self::Err> {
193 let signature_input = LocatedSpan::new(s);
194 let signature_tokens = lex(signature_input)
195 .map_err(Box::new)
196 .map_err(ExternError::Lex)?;
197 let signature = disallow_leftover(
198 crate::parser::pragma_extern::parse_extern_signature(signature_tokens.as_slice())
199 .map_err(crate::parser::ParseError::from_nom_internal_err),
200 )
201 .map_err(Box::new)
202 .map_err(ExternError::Syntax)?;
203 if signature.return_type.is_none() && signature.parameters.is_empty() {
204 return Err(ExternError::NoReturnOrParameters);
205 }
206 for parameter in &signature.parameters {
207 validate_user_identifier(parameter.name.as_str()).map_err(ExternError::from_boxed)?;
208 }
209 Ok(signature)
210 }
211}
212
213impl Quil for ExternSignature {
214 fn write(
215 &self,
216 writer: &mut impl std::fmt::Write,
217 fall_back_to_debug: bool,
218 ) -> Result<(), crate::quil::ToQuilError> {
219 if let Some(return_type) = &self.return_type {
220 return_type.write(writer, fall_back_to_debug)?;
221 if !self.parameters.is_empty() {
222 write!(writer, " ")?;
223 }
224 }
225 if self.parameters.is_empty() {
226 return Ok(());
227 }
228 write!(writer, "(")?;
229 for (i, parameter) in self.parameters.iter().enumerate() {
230 if i > 0 {
231 write!(writer, ", ")?;
232 }
233 parameter.write(writer, fall_back_to_debug)?;
234 }
235 write!(writer, ")").map_err(Into::into)
236 }
237}
238
239impl TryFrom<Pragma> for ExternSignature {
240 type Error = ExternError;
241
242 fn try_from(value: Pragma) -> Result<Self, ExternError> {
243 if value.name != RESERVED_PRAGMA_EXTERN {
244 return Err(ExternError::PragmaIsNotExtern);
245 }
246 if value.arguments.is_empty()
247 || !matches!(value.arguments[0], PragmaArgument::Identifier(_))
248 {
249 return Err(ExternError::NoName);
250 }
251 if value.arguments.len() > 1 {
252 return Err(ExternError::InvalidPragmaArguments);
253 }
254
255 match value.data {
256 Some(data) => ExternSignature::from_str(data.as_str()),
257 None => Err(ExternError::NoSignature),
258 }
259 }
260}
261
262#[derive(Clone, Debug, PartialEq, Default)]
266pub struct ExternPragmaMap(IndexMap<Option<String>, Pragma>);
267
268impl ExternPragmaMap {
269 pub(crate) fn len(&self) -> usize {
270 self.0.len()
271 }
272
273 pub(crate) fn into_instructions(self) -> Vec<Instruction> {
274 self.0.into_values().map(Instruction::Pragma).collect()
275 }
276
277 pub fn to_instructions(&self) -> Vec<Instruction> {
279 self.0.values().cloned().map(Instruction::Pragma).collect()
280 }
281
282 pub(crate) fn insert(&mut self, pragma: Pragma) -> Option<Pragma> {
290 self.0.insert(
291 match pragma.arguments.first() {
292 Some(PragmaArgument::Identifier(name)) => Some(name.clone()),
293 _ => None,
294 },
295 pragma,
296 )
297 }
298
299 pub fn extend(&mut self, other: Self) {
305 self.0.extend(other.0);
306 }
307
308 pub(crate) fn retain<F>(&mut self, f: F)
309 where
310 F: FnMut(&Option<String>, &mut Pragma) -> bool,
311 {
312 self.0.retain(f)
313 }
314}
315
316impl std::iter::IntoIterator for ExternPragmaMap {
317 type Item = (Option<String>, Pragma);
318 type IntoIter = indexmap::map::IntoIter<Option<String>, Pragma>;
319
320 fn into_iter(self) -> Self::IntoIter {
321 self.0.into_iter()
322 }
323}
324
325#[derive(Clone, Debug, PartialEq, Default)]
328pub struct ExternSignatureMap(IndexMap<String, ExternSignature>);
329
330impl TryFrom<ExternPragmaMap> for ExternSignatureMap {
331 type Error = (Pragma, ExternError);
334
335 fn try_from(value: ExternPragmaMap) -> Result<Self, Self::Error> {
336 Ok(ExternSignatureMap(
337 value
338 .0
339 .into_iter()
340 .map(|(key, value)| -> Result<_, Self::Error> {
341 match key {
342 Some(name) => {
343 validate_user_identifier(name.as_str())
344 .map_err(ExternError::from_boxed)
345 .map_err(|error| (value.clone(), error))?;
346 let signature = ExternSignature::try_from(value.clone())
347 .map_err(|error| (value, error))?;
348 Ok((name, signature))
349 }
350 _ => Err((value, ExternError::NoName)),
351 }
352 })
353 .collect::<Result<_, Self::Error>>()?,
354 ))
355 }
356}
357
358impl ExternSignatureMap {
359 #[inline]
360 pub fn len(&self) -> usize {
361 self.0.len()
362 }
363
364 #[inline]
365 pub fn is_empty(&self) -> bool {
366 self.0.is_empty()
367 }
368
369 #[inline]
370 pub fn iter(&self) -> impl Iterator<Item = (&String, &ExternSignature)> {
371 self.0.iter()
372 }
373}
374
375#[derive(Clone, Debug, thiserror::Error, PartialEq)]
377pub enum CallArgumentResolutionError {
378 #[error("undeclared memory reference {0}")]
380 UndeclaredMemoryReference(String),
381 #[error("mismatched vector: expected {expected:?}, found {found:?}")]
383 MismatchedVector { expected: Vector, found: Vector },
384 #[error("mismatched scalar: expected {expected:?}, found {found:?}")]
386 MismatchedScalar {
387 expected: ScalarType,
388 found: ScalarType,
389 },
390 #[error("vector parameters must be passed as an identifier, found {0:?}")]
392 InvalidVectorArgument(UnresolvedCallArgument),
393 #[error("return argument must be a memory reference or identifier, found {found:?}")]
395 ReturnArgument { found: UnresolvedCallArgument },
396 #[error("immediate arguments cannot be specified for mutable parameter {0}")]
398 ImmediateArgumentForMutable(String),
399}
400
401#[derive(Clone, Debug, PartialEq)]
405pub enum UnresolvedCallArgument {
406 Identifier(String),
409 MemoryReference(MemoryReference),
411 Immediate(Complex64),
413}
414
415impl Eq for UnresolvedCallArgument {}
416
417impl std::hash::Hash for UnresolvedCallArgument {
418 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
419 match self {
420 UnresolvedCallArgument::Identifier(value) => {
421 "Identifier".hash(state);
422 value.hash(state);
423 }
424 UnresolvedCallArgument::MemoryReference(value) => {
425 "MemoryReference".hash(state);
426 value.hash(state);
427 }
428 UnresolvedCallArgument::Immediate(value) => {
429 "Immediate".hash(state);
430 hash_complex_64(value, state);
431 }
432 }
433 }
434}
435
436impl UnresolvedCallArgument {
437 fn resolve(
440 &self,
441 memory_regions: &IndexMap<String, MemoryRegion>,
442 extern_parameter: &ExternParameter,
443 ) -> Result<ResolvedCallArgument, CallArgumentResolutionError> {
444 match self {
445 UnresolvedCallArgument::Identifier(value) => {
446 let expected_vector = match &extern_parameter.data_type {
447 ExternParameterType::Scalar(_) => {
448 return UnresolvedCallArgument::MemoryReference(MemoryReference::new(
449 value.clone(),
450 0,
451 ))
452 .resolve(memory_regions, extern_parameter);
453 }
454 ExternParameterType::FixedLengthVector(expected_vector) => {
455 let memory_region =
456 memory_regions.get(value.as_str()).ok_or_else(|| {
457 CallArgumentResolutionError::UndeclaredMemoryReference(
458 value.clone(),
459 )
460 })?;
461 if &memory_region.size != expected_vector {
462 return Err(CallArgumentResolutionError::MismatchedVector {
463 expected: expected_vector.clone(),
464 found: memory_region.size.clone(),
465 });
466 }
467
468 Ok(expected_vector.clone())
469 }
470 ExternParameterType::VariableLengthVector(scalar_type) => {
471 let memory_region =
472 memory_regions.get(value.as_str()).ok_or_else(|| {
473 CallArgumentResolutionError::UndeclaredMemoryReference(
474 value.clone(),
475 )
476 })?;
477 if &memory_region.size.data_type != scalar_type {
478 return Err(CallArgumentResolutionError::MismatchedScalar {
479 expected: *scalar_type,
480 found: memory_region.size.data_type,
481 });
482 }
483 Ok(memory_region.size.clone())
484 }
485 }?;
486 Ok(ResolvedCallArgument::Vector {
487 memory_region_name: value.clone(),
488 vector: expected_vector,
489 mutable: extern_parameter.mutable,
490 })
491 }
492 UnresolvedCallArgument::MemoryReference(value) => {
493 let expected_scalar = match extern_parameter.data_type {
494 ExternParameterType::Scalar(ref scalar) => Ok(scalar),
495 ExternParameterType::FixedLengthVector(_)
496 | ExternParameterType::VariableLengthVector(_) => {
497 Err(CallArgumentResolutionError::InvalidVectorArgument(
498 Self::MemoryReference(value.clone()),
499 ))
500 }
501 }?;
502 let memory_region = memory_regions.get(value.name.as_str()).ok_or_else(|| {
503 CallArgumentResolutionError::UndeclaredMemoryReference(value.name.clone())
504 })?;
505 if memory_region.size.data_type != *expected_scalar {
506 return Err(CallArgumentResolutionError::MismatchedScalar {
507 expected: *expected_scalar,
508 found: memory_region.size.data_type,
509 });
510 }
511 Ok(ResolvedCallArgument::MemoryReference {
512 memory_reference: value.clone(),
513 scalar_type: *expected_scalar,
514 mutable: extern_parameter.mutable,
515 })
516 }
517 UnresolvedCallArgument::Immediate(value) => {
518 if extern_parameter.mutable {
519 return Err(CallArgumentResolutionError::ImmediateArgumentForMutable(
520 extern_parameter.name.clone(),
521 ));
522 }
523 let expected_scalar = match extern_parameter.data_type {
524 ExternParameterType::Scalar(ref scalar) => Ok(scalar),
525 ExternParameterType::FixedLengthVector(_)
526 | ExternParameterType::VariableLengthVector(_) => Err(
527 CallArgumentResolutionError::InvalidVectorArgument(self.clone()),
528 ),
529 }?;
530 Ok(ResolvedCallArgument::Immediate {
531 value: *value,
532 scalar_type: *expected_scalar,
533 })
534 }
535 }
536 }
537
538 fn resolve_return(
541 &self,
542 memory_regions: &IndexMap<String, MemoryRegion>,
543 return_type: ScalarType,
544 ) -> Result<ResolvedCallArgument, CallArgumentResolutionError> {
545 let memory_reference = match self {
546 UnresolvedCallArgument::MemoryReference(memory_reference) => {
547 Ok(memory_reference.clone())
548 }
549 UnresolvedCallArgument::Identifier(identifier) => {
550 Ok(MemoryReference::new(identifier.clone(), 0))
551 }
552 _ => Err(CallArgumentResolutionError::ReturnArgument {
553 found: self.clone(),
554 }),
555 }?;
556 let memory_region = memory_regions
557 .get(memory_reference.name.as_str())
558 .ok_or_else(|| {
559 CallArgumentResolutionError::UndeclaredMemoryReference(
560 memory_reference.name.clone(),
561 )
562 })?;
563 if memory_region.size.data_type != return_type {
564 return Err(CallArgumentResolutionError::MismatchedScalar {
565 expected: return_type,
566 found: memory_region.size.data_type,
567 });
568 }
569 Ok(ResolvedCallArgument::MemoryReference {
570 memory_reference: memory_reference.clone(),
571 scalar_type: return_type,
572 mutable: true,
573 })
574 }
575}
576
577impl Quil for UnresolvedCallArgument {
578 fn write(
579 &self,
580 f: &mut impl std::fmt::Write,
581 fall_back_to_debug: bool,
582 ) -> crate::quil::ToQuilResult<()> {
583 match &self {
584 UnresolvedCallArgument::Identifier(value) => write!(f, "{value}",).map_err(Into::into),
585 UnresolvedCallArgument::MemoryReference(value) => value.write(f, fall_back_to_debug),
586 UnresolvedCallArgument::Immediate(value) => {
587 write!(f, "{}", format_complex(value)).map_err(Into::into)
588 }
589 }
590 }
591}
592
593#[derive(Clone, Debug, PartialEq)]
597pub enum ResolvedCallArgument {
598 Vector {
600 memory_region_name: String,
601 vector: Vector,
602 mutable: bool,
603 },
604 MemoryReference {
606 memory_reference: MemoryReference,
607 scalar_type: ScalarType,
608 mutable: bool,
609 },
610 Immediate {
612 value: Complex64,
613 scalar_type: ScalarType,
614 },
615}
616
617impl From<ResolvedCallArgument> for UnresolvedCallArgument {
618 fn from(value: ResolvedCallArgument) -> Self {
619 match value {
620 ResolvedCallArgument::Vector {
621 memory_region_name, ..
622 } => UnresolvedCallArgument::Identifier(memory_region_name),
623 ResolvedCallArgument::MemoryReference {
624 memory_reference, ..
625 } => UnresolvedCallArgument::MemoryReference(memory_reference),
626 ResolvedCallArgument::Immediate { value, .. } => {
627 UnresolvedCallArgument::Immediate(value)
628 }
629 }
630 }
631}
632
633impl Eq for ResolvedCallArgument {}
634
635impl std::hash::Hash for ResolvedCallArgument {
636 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
637 match self {
638 ResolvedCallArgument::Vector {
639 memory_region_name,
640 vector,
641 mutable,
642 } => {
643 "Vector".hash(state);
644 memory_region_name.hash(state);
645 vector.hash(state);
646 mutable.hash(state);
647 }
648 ResolvedCallArgument::MemoryReference {
649 memory_reference,
650 scalar_type,
651 mutable,
652 } => {
653 "MemoryReference".hash(state);
654 memory_reference.hash(state);
655 scalar_type.hash(state);
656 mutable.hash(state);
657 }
658 ResolvedCallArgument::Immediate { value, scalar_type } => {
659 "Immediate".hash(state);
660 hash_complex_64(value, state);
661 scalar_type.hash(state);
662 }
663 }
664 }
665}
666
667fn hash_complex_64<H: std::hash::Hasher>(value: &Complex64, state: &mut H) {
668 if value.re.abs() > 0f64 {
669 hash_f64(value.re, state);
670 }
671 if value.im.abs() > 0f64 {
672 hash_f64(value.im, state);
673 }
674}
675
676#[derive(Clone, Debug, PartialEq, thiserror::Error, Eq)]
678pub enum CallError {
679 #[error(transparent)]
681 Name(#[from] IdentifierValidationError),
682}
683
684#[derive(Clone, Debug, PartialEq, Hash, Eq)]
686pub struct Call {
687 pub name: String,
689 pub arguments: Vec<UnresolvedCallArgument>,
691}
692
693impl Call {
694 pub fn try_new(
697 name: String,
698 arguments: Vec<UnresolvedCallArgument>,
699 ) -> Result<Self, CallError> {
700 validate_user_identifier(name.as_str()).map_err(CallError::Name)?;
701
702 Ok(Self { name, arguments })
703 }
704
705 pub fn name(&self) -> &str {
706 self.name.as_str()
707 }
708
709 pub fn arguments(&self) -> &[UnresolvedCallArgument] {
710 self.arguments.as_slice()
711 }
712}
713
714#[derive(Clone, Debug, thiserror::Error, PartialEq)]
716pub enum CallArgumentError {
717 #[error("error resolving return argument: {0:?}")]
719 Return(CallArgumentResolutionError),
720 #[error("error resolving argument {index}: {error:?}")]
722 Argument {
723 index: usize,
724 error: CallArgumentResolutionError,
725 },
726}
727
728#[derive(Debug, thiserror::Error, PartialEq, Clone)]
731pub enum CallSignatureError {
732 #[error("expected {expected} arguments, found {found}")]
733 ParameterCount { expected: usize, found: usize },
734 #[error("error resolving arguments: {0:?}")]
735 Arguments(Vec<CallArgumentError>),
736}
737
738#[derive(Debug, thiserror::Error, PartialEq, Clone)]
741pub enum CallResolutionError {
742 #[error("call found matching extern instruction for {name}, but signature validation failed: {error:?}")]
744 Signature {
745 name: String,
746 error: CallSignatureError,
747 },
748 #[error("no extern instruction found with name {0}")]
750 NoMatchingExternInstruction(String),
751 #[error(transparent)]
753 ExternSignature(#[from] ExternError),
754}
755
756#[allow(clippy::manual_try_fold)]
757fn convert_unresolved_to_resolved_call_arguments(
758 arguments: &[UnresolvedCallArgument],
759 signature: &ExternSignature,
760 memory_regions: &IndexMap<String, MemoryRegion>,
761) -> Result<Vec<ResolvedCallArgument>, CallSignatureError> {
762 arguments
763 .iter()
764 .enumerate()
765 .map(|(i, argument)| {
766 if i == 0 {
767 if let Some(return_type) = signature.return_type {
768 return argument
769 .resolve_return(memory_regions, return_type)
770 .map_err(CallArgumentError::Return);
771 }
772 }
773 let parameter_index = if signature.return_type.is_some() {
774 i - 1
775 } else {
776 i
777 };
778 let parameter = &signature.parameters[parameter_index];
779 argument
780 .resolve(memory_regions, parameter)
781 .map_err(|error| CallArgumentError::Argument {
782 index: parameter_index,
783 error,
784 })
785 })
786 .fold(
787 Ok(Vec::new()),
788 |acc: Result<Vec<ResolvedCallArgument>, Vec<CallArgumentError>>,
789 result: Result<ResolvedCallArgument, CallArgumentError>| {
790 match (acc, result) {
791 (Ok(mut acc), Ok(resolved)) => {
792 acc.push(resolved);
793 Ok(acc)
794 }
795 (Ok(_), Err(error)) => Err(vec![error]),
796 (Err(errors), Ok(_)) => Err(errors),
797 (Err(mut errors), Err(error)) => {
798 errors.push(error);
799 Err(errors)
800 }
801 }
802 },
803 )
804 .map_err(CallSignatureError::Arguments)
805}
806
807impl Call {
808 fn resolve_to_signature(
810 &self,
811 signature: &ExternSignature,
812 memory_regions: &IndexMap<String, MemoryRegion>,
813 ) -> Result<Vec<ResolvedCallArgument>, CallSignatureError> {
814 let mut expected_parameter_count = signature.parameters.len();
815 if signature.return_type.is_some() {
816 expected_parameter_count += 1;
817 }
818
819 if self.arguments.len() != expected_parameter_count {
820 return Err(CallSignatureError::ParameterCount {
821 expected: expected_parameter_count,
822 found: self.arguments.len(),
823 });
824 }
825
826 let resolved_call_arguments = convert_unresolved_to_resolved_call_arguments(
827 &self.arguments,
828 signature,
829 memory_regions,
830 )?;
831
832 Ok(resolved_call_arguments)
833 }
834
835 pub fn resolve_arguments(
838 &self,
839 memory_regions: &IndexMap<String, MemoryRegion>,
840 extern_signature_map: &ExternSignatureMap,
841 ) -> Result<Vec<ResolvedCallArgument>, CallResolutionError> {
842 let extern_signature = extern_signature_map
843 .0
844 .get(self.name.as_str())
845 .ok_or_else(|| CallResolutionError::NoMatchingExternInstruction(self.name.clone()))?;
846
847 self.resolve_to_signature(extern_signature, memory_regions)
848 .map_err(|error| CallResolutionError::Signature {
849 name: self.name.clone(),
850 error,
851 })
852 }
853
854 pub(crate) fn get_memory_accesses(
857 &self,
858 extern_signatures: &ExternSignatureMap,
859 ) -> Result<MemoryAccesses, CallResolutionError> {
860 let extern_signature = extern_signatures
861 .0
862 .get(self.name.as_str())
863 .ok_or_else(|| CallResolutionError::NoMatchingExternInstruction(self.name.clone()))?;
864
865 let mut reads = HashSet::new();
866 let mut writes = HashSet::new();
867 let mut arguments = self.arguments.iter();
868 if extern_signature.return_type.is_some() {
869 if let Some(argument) = self.arguments.first() {
870 arguments.next();
871 match argument {
872 UnresolvedCallArgument::MemoryReference(memory_reference) => {
873 reads.insert(memory_reference.name.clone());
874 writes.insert(memory_reference.name.clone());
875 }
876 UnresolvedCallArgument::Identifier(identifier) => {
877 reads.insert(identifier.clone());
878 writes.insert(identifier.clone());
879 }
880 _ => {}
881 }
882 }
883 }
884 for (argument, parameter) in std::iter::zip(arguments, extern_signature.parameters.iter()) {
885 match argument {
886 UnresolvedCallArgument::MemoryReference(memory_reference) => {
887 reads.insert(memory_reference.name.clone());
888 if parameter.mutable {
889 writes.insert(memory_reference.name.clone());
890 }
891 }
892 UnresolvedCallArgument::Identifier(identifier) => {
893 reads.insert(identifier.clone());
894 if parameter.mutable {
895 writes.insert(identifier.clone());
896 }
897 }
898 _ => {}
899 }
900 }
901 Ok(MemoryAccesses {
902 reads,
903 writes,
904 captures: HashSet::new(),
905 })
906 }
907}
908
909impl Quil for Call {
910 fn write(
911 &self,
912 f: &mut impl std::fmt::Write,
913 fall_back_to_debug: bool,
914 ) -> crate::quil::ToQuilResult<()> {
915 write!(f, "CALL {}", self.name)?;
916 for argument in self.arguments.as_slice() {
917 write!(f, " ")?;
918 argument.write(f, fall_back_to_debug)?;
919 }
920 Ok(())
921 }
922}
923
924#[cfg(test)]
925mod tests {
926 use super::*;
927 use crate::instruction::PragmaArgument;
928 use rstest::*;
929
930 struct ExternSignatureQuilTestCase {
932 signature: ExternSignature,
934 expected: &'static str,
936 }
937
938 impl ExternSignatureQuilTestCase {
939 fn case_01() -> Self {
941 Self {
942 signature: ExternSignature {
943 return_type: Some(ScalarType::Integer),
944 parameters: vec![
945 ExternParameter {
946 name: "bar".to_string(),
947 mutable: false,
948 data_type: ExternParameterType::Scalar(ScalarType::Integer),
949 },
950 ExternParameter {
951 name: "baz".to_string(),
952 mutable: true,
953 data_type: ExternParameterType::FixedLengthVector(Vector {
954 data_type: ScalarType::Bit,
955 length: 2,
956 }),
957 },
958 ],
959 },
960 expected: "INTEGER (bar : INTEGER, baz : mut BIT[2])",
961 }
962 }
963
964 fn case_02() -> Self {
966 let signature = ExternSignature {
967 return_type: None,
968 parameters: vec![
969 ExternParameter {
970 name: "bar".to_string(),
971 mutable: false,
972 data_type: ExternParameterType::Scalar(ScalarType::Integer),
973 },
974 ExternParameter {
975 name: "baz".to_string(),
976 mutable: true,
977 data_type: ExternParameterType::FixedLengthVector(Vector {
978 data_type: ScalarType::Bit,
979 length: 2,
980 }),
981 },
982 ],
983 };
984 Self {
985 signature,
986 expected: "(bar : INTEGER, baz : mut BIT[2])",
987 }
988 }
989
990 fn case_03() -> Self {
992 let signature = ExternSignature {
993 return_type: Some(ScalarType::Integer),
994 parameters: vec![],
995 };
996 Self {
997 signature,
998 expected: "INTEGER",
999 }
1000 }
1001
1002 fn case_04() -> Self {
1004 let signature = ExternSignature {
1005 return_type: None,
1006 parameters: vec![],
1007 };
1008 Self {
1009 signature,
1010 expected: "",
1011 }
1012 }
1013
1014 fn case_05() -> Self {
1016 let signature = ExternSignature {
1017 return_type: None,
1018 parameters: vec![ExternParameter {
1019 name: "bar".to_string(),
1020 mutable: false,
1021 data_type: ExternParameterType::VariableLengthVector(ScalarType::Integer),
1022 }],
1023 };
1024 Self {
1025 signature,
1026 expected: "(bar : INTEGER[])",
1027 }
1028 }
1029 }
1030
1031 #[rstest]
1033 #[case(ExternSignatureQuilTestCase::case_01())]
1034 #[case(ExternSignatureQuilTestCase::case_02())]
1035 #[case(ExternSignatureQuilTestCase::case_03())]
1036 #[case(ExternSignatureQuilTestCase::case_04())]
1037 #[case(ExternSignatureQuilTestCase::case_05())]
1038 #[case(ExternSignatureQuilTestCase::case_05())]
1039 fn test_extern_signature_quil(#[case] test_case: ExternSignatureQuilTestCase) {
1040 assert_eq!(
1041 test_case
1042 .signature
1043 .to_quil()
1044 .expect("must be able to call to quil"),
1045 test_case.expected.to_string()
1046 );
1047 }
1048
1049 struct CallQuilTestCase {
1051 call: Call,
1053 expected: &'static str,
1055 }
1056
1057 impl CallQuilTestCase {
1058 fn case_01() -> Self {
1059 let call = Call {
1060 name: "foo".to_string(),
1061 arguments: vec![
1062 UnresolvedCallArgument::MemoryReference(MemoryReference {
1063 name: "bar".to_string(),
1064 index: 0,
1065 }),
1066 UnresolvedCallArgument::Immediate(Complex64::new(2.0, 0.0)),
1067 UnresolvedCallArgument::Identifier("baz".to_string()),
1068 ],
1069 };
1070 Self {
1071 call,
1072 expected: "CALL foo bar[0] 2 baz",
1073 }
1074 }
1075
1076 fn case_02() -> Self {
1077 let call = Call {
1078 name: "foo".to_string(),
1079 arguments: vec![
1080 UnresolvedCallArgument::MemoryReference(MemoryReference {
1081 name: "bar".to_string(),
1082 index: 0,
1083 }),
1084 UnresolvedCallArgument::Identifier("baz".to_string()),
1085 ],
1086 };
1087 Self {
1088 call,
1089 expected: "CALL foo bar[0] baz",
1090 }
1091 }
1092
1093 fn case_03() -> Self {
1094 let call = Call {
1095 name: "foo".to_string(),
1096 arguments: vec![UnresolvedCallArgument::MemoryReference(MemoryReference {
1097 name: "bar".to_string(),
1098 index: 0,
1099 })],
1100 };
1101 Self {
1102 call,
1103 expected: "CALL foo bar[0]",
1104 }
1105 }
1106
1107 fn case_04() -> Self {
1109 let call = Call {
1110 name: "foo".to_string(),
1111 arguments: vec![],
1112 };
1113
1114 Self {
1115 call,
1116 expected: "CALL foo",
1117 }
1118 }
1119 }
1120
1121 #[rstest]
1123 #[case(CallQuilTestCase::case_01())]
1124 #[case(CallQuilTestCase::case_02())]
1125 #[case(CallQuilTestCase::case_03())]
1126 #[case(CallQuilTestCase::case_04())]
1127 fn test_call_quil(#[case] test_case: CallQuilTestCase) {
1128 assert_eq!(
1129 test_case
1130 .call
1131 .to_quil()
1132 .expect("must be able to call to quil"),
1133 test_case.expected.to_string()
1134 );
1135 }
1136
1137 fn build_declarations() -> IndexMap<String, MemoryRegion> {
1139 [
1140 ("integer", Vector::new(ScalarType::Integer, 3)),
1141 ("real", Vector::new(ScalarType::Real, 3)),
1142 ("bit", Vector::new(ScalarType::Bit, 3)),
1143 ("octet", Vector::new(ScalarType::Octet, 3)),
1144 ]
1145 .into_iter()
1146 .map(|(name, vector)| (name.to_string(), MemoryRegion::new(vector, None)))
1147 .collect()
1148 }
1149
1150 struct ArgumentResolutionTestCase {
1152 call_argument: UnresolvedCallArgument,
1153 extern_parameter: ExternParameter,
1154 expected: Result<ResolvedCallArgument, CallArgumentResolutionError>,
1155 }
1156
1157 impl ArgumentResolutionTestCase {
1158 fn case_01() -> Self {
1160 ArgumentResolutionTestCase {
1161 call_argument: UnresolvedCallArgument::MemoryReference(MemoryReference {
1162 name: "integer".to_string(),
1163 index: 0,
1164 }),
1165 extern_parameter: ExternParameter {
1166 name: "bar".to_string(),
1167 mutable: false,
1168 data_type: ExternParameterType::Scalar(ScalarType::Integer),
1169 },
1170 expected: Ok(ResolvedCallArgument::MemoryReference {
1171 memory_reference: MemoryReference {
1172 name: "integer".to_string(),
1173 index: 0,
1174 },
1175 scalar_type: ScalarType::Integer,
1176 mutable: false,
1177 }),
1178 }
1179 }
1180
1181 fn case_02() -> Self {
1183 ArgumentResolutionTestCase {
1184 call_argument: UnresolvedCallArgument::Identifier("real".to_string()),
1185 extern_parameter: ExternParameter {
1186 name: "bar".to_string(),
1187 mutable: false,
1188 data_type: ExternParameterType::FixedLengthVector(Vector {
1189 data_type: ScalarType::Real,
1190 length: 3,
1191 }),
1192 },
1193 expected: Ok(ResolvedCallArgument::Vector {
1194 memory_region_name: "real".to_string(),
1195 vector: Vector {
1196 data_type: ScalarType::Real,
1197 length: 3,
1198 },
1199 mutable: false,
1200 }),
1201 }
1202 }
1203
1204 fn case_03() -> Self {
1206 ArgumentResolutionTestCase {
1207 call_argument: UnresolvedCallArgument::Immediate(Complex64::new(2.0, 0.0)),
1208 extern_parameter: ExternParameter {
1209 name: "bar".to_string(),
1210 mutable: false,
1211 data_type: ExternParameterType::Scalar(ScalarType::Integer),
1212 },
1213 expected: Ok(ResolvedCallArgument::Immediate {
1214 value: Complex64::new(2.0, 0.0),
1215 scalar_type: ScalarType::Integer,
1216 }),
1217 }
1218 }
1219
1220 fn case_04() -> Self {
1222 ArgumentResolutionTestCase {
1223 call_argument: UnresolvedCallArgument::Identifier("undeclared".to_string()),
1224 extern_parameter: ExternParameter {
1225 name: "bar".to_string(),
1226 mutable: false,
1227 data_type: ExternParameterType::FixedLengthVector(Vector {
1228 data_type: ScalarType::Real,
1229 length: 3,
1230 }),
1231 },
1232 expected: Err(CallArgumentResolutionError::UndeclaredMemoryReference(
1233 "undeclared".to_string(),
1234 )),
1235 }
1236 }
1237
1238 fn case_05() -> Self {
1240 ArgumentResolutionTestCase {
1241 call_argument: UnresolvedCallArgument::MemoryReference(MemoryReference {
1242 name: "undeclared".to_string(),
1243 index: 0,
1244 }),
1245 extern_parameter: ExternParameter {
1246 name: "bar".to_string(),
1247 mutable: false,
1248 data_type: ExternParameterType::Scalar(ScalarType::Integer),
1249 },
1250 expected: Err(CallArgumentResolutionError::UndeclaredMemoryReference(
1251 "undeclared".to_string(),
1252 )),
1253 }
1254 }
1255
1256 fn case_06() -> Self {
1258 ArgumentResolutionTestCase {
1259 call_argument: UnresolvedCallArgument::Identifier("integer".to_string()),
1260 extern_parameter: ExternParameter {
1261 name: "bar".to_string(),
1262 mutable: false,
1263 data_type: ExternParameterType::FixedLengthVector(Vector {
1264 data_type: ScalarType::Real,
1265 length: 3,
1266 }),
1267 },
1268 expected: Err(CallArgumentResolutionError::MismatchedVector {
1269 expected: Vector {
1270 data_type: ScalarType::Real,
1271 length: 3,
1272 },
1273 found: Vector {
1274 data_type: ScalarType::Integer,
1275 length: 3,
1276 },
1277 }),
1278 }
1279 }
1280
1281 fn case_07() -> Self {
1283 ArgumentResolutionTestCase {
1284 call_argument: UnresolvedCallArgument::Identifier("integer".to_string()),
1285 extern_parameter: ExternParameter {
1286 name: "bar".to_string(),
1287 mutable: false,
1288 data_type: ExternParameterType::FixedLengthVector(Vector {
1289 data_type: ScalarType::Integer,
1290 length: 4,
1291 }),
1292 },
1293 expected: Err(CallArgumentResolutionError::MismatchedVector {
1294 expected: Vector {
1295 data_type: ScalarType::Integer,
1296 length: 4,
1297 },
1298 found: Vector {
1299 data_type: ScalarType::Integer,
1300 length: 3,
1301 },
1302 }),
1303 }
1304 }
1305
1306 fn case_08() -> Self {
1308 ArgumentResolutionTestCase {
1309 call_argument: UnresolvedCallArgument::MemoryReference(MemoryReference {
1310 name: "octet".to_string(),
1311 index: 0,
1312 }),
1313 extern_parameter: ExternParameter {
1314 name: "bar".to_string(),
1315 mutable: false,
1316 data_type: ExternParameterType::Scalar(ScalarType::Integer),
1317 },
1318 expected: Err(CallArgumentResolutionError::MismatchedScalar {
1319 expected: ScalarType::Integer,
1320 found: ScalarType::Octet,
1321 }),
1322 }
1323 }
1324
1325 fn case_09() -> Self {
1328 let call_argument = UnresolvedCallArgument::Identifier("integer".to_string());
1329 ArgumentResolutionTestCase {
1330 call_argument: call_argument.clone(),
1331 extern_parameter: ExternParameter {
1332 name: "bar".to_string(),
1333 mutable: false,
1334 data_type: ExternParameterType::Scalar(ScalarType::Integer),
1335 },
1336 expected: Ok(ResolvedCallArgument::MemoryReference {
1337 memory_reference: MemoryReference::new("integer".to_string(), 0),
1338 scalar_type: ScalarType::Integer,
1339 mutable: false,
1340 }),
1341 }
1342 }
1343
1344 fn case_10() -> Self {
1346 let call_argument = UnresolvedCallArgument::MemoryReference(MemoryReference {
1347 name: "integer".to_string(),
1348 index: 0,
1349 });
1350 ArgumentResolutionTestCase {
1351 call_argument: call_argument.clone(),
1352 extern_parameter: ExternParameter {
1353 name: "bar".to_string(),
1354 mutable: false,
1355 data_type: ExternParameterType::FixedLengthVector(Vector {
1356 data_type: ScalarType::Integer,
1357 length: 3,
1358 }),
1359 },
1360 expected: Err(CallArgumentResolutionError::InvalidVectorArgument(
1361 call_argument,
1362 )),
1363 }
1364 }
1365
1366 fn case_11() -> Self {
1368 let call_argument = UnresolvedCallArgument::Immediate(Complex64::new(2.0, 0.0));
1369 ArgumentResolutionTestCase {
1370 call_argument: call_argument.clone(),
1371 extern_parameter: ExternParameter {
1372 name: "bar".to_string(),
1373 mutable: false,
1374 data_type: ExternParameterType::FixedLengthVector(Vector {
1375 data_type: ScalarType::Integer,
1376 length: 3,
1377 }),
1378 },
1379 expected: Err(CallArgumentResolutionError::InvalidVectorArgument(
1380 call_argument,
1381 )),
1382 }
1383 }
1384
1385 fn case_12() -> Self {
1388 let call_argument = UnresolvedCallArgument::Identifier("integer".to_string());
1389 ArgumentResolutionTestCase {
1390 call_argument: call_argument.clone(),
1391 extern_parameter: ExternParameter {
1392 name: "bar".to_string(),
1393 mutable: false,
1394 data_type: ExternParameterType::VariableLengthVector(ScalarType::Integer),
1395 },
1396 expected: Ok(ResolvedCallArgument::Vector {
1397 memory_region_name: "integer".to_string(),
1398 mutable: false,
1399 vector: Vector {
1400 data_type: ScalarType::Integer,
1401 length: 3,
1402 },
1403 }),
1404 }
1405 }
1406
1407 fn case_13() -> Self {
1409 let call_argument = UnresolvedCallArgument::Immediate(Complex64::new(2.0, 0.0));
1410 ArgumentResolutionTestCase {
1411 call_argument: call_argument.clone(),
1412 extern_parameter: ExternParameter {
1413 name: "bar".to_string(),
1414 mutable: true,
1415 data_type: ExternParameterType::Scalar(ScalarType::Integer),
1416 },
1417 expected: Err(CallArgumentResolutionError::ImmediateArgumentForMutable(
1418 "bar".to_string(),
1419 )),
1420 }
1421 }
1422 }
1423
1424 #[rstest]
1426 #[case(ArgumentResolutionTestCase::case_01())]
1427 #[case(ArgumentResolutionTestCase::case_02())]
1428 #[case(ArgumentResolutionTestCase::case_03())]
1429 #[case(ArgumentResolutionTestCase::case_04())]
1430 #[case(ArgumentResolutionTestCase::case_05())]
1431 #[case(ArgumentResolutionTestCase::case_06())]
1432 #[case(ArgumentResolutionTestCase::case_07())]
1433 #[case(ArgumentResolutionTestCase::case_08())]
1434 #[case(ArgumentResolutionTestCase::case_09())]
1435 #[case(ArgumentResolutionTestCase::case_10())]
1436 #[case(ArgumentResolutionTestCase::case_11())]
1437 #[case(ArgumentResolutionTestCase::case_12())]
1438 #[case(ArgumentResolutionTestCase::case_13())]
1439 fn test_argument_resolution(#[case] test_case: ArgumentResolutionTestCase) {
1440 let memory_regions = build_declarations();
1441 let found = test_case
1442 .call_argument
1443 .resolve(&memory_regions, &test_case.extern_parameter);
1444 match (test_case.expected, found) {
1445 (Ok(expected), Ok(found)) => assert_eq!(expected, found),
1446 (Ok(expected), Err(found)) => {
1447 panic!("expected resolution {:?}, found err {:?}", expected, found)
1448 }
1449 (Err(expected), Ok(found)) => {
1450 panic!("expected err {:?}, found resolution {:?}", expected, found)
1451 }
1452 (Err(expected), Err(found)) => assert_eq!(expected, found),
1453 }
1454 }
1455
1456 struct ReturnArgumentResolutionTestCase {
1458 call_argument: UnresolvedCallArgument,
1460 return_type: ScalarType,
1462 expected: Result<ResolvedCallArgument, CallArgumentResolutionError>,
1464 }
1465
1466 impl ReturnArgumentResolutionTestCase {
1467 fn case_01() -> Self {
1469 let call_argument = UnresolvedCallArgument::MemoryReference(MemoryReference {
1470 name: "integer".to_string(),
1471 index: 0,
1472 });
1473 let expected = Ok(ResolvedCallArgument::MemoryReference {
1474 memory_reference: MemoryReference {
1475 name: "integer".to_string(),
1476 index: 0,
1477 },
1478 scalar_type: ScalarType::Integer,
1479 mutable: true,
1480 });
1481 Self {
1482 call_argument,
1483 return_type: ScalarType::Integer,
1484 expected,
1485 }
1486 }
1487
1488 fn case_02() -> Self {
1490 let call_argument = UnresolvedCallArgument::Immediate(Complex64::new(2.0, 0.0));
1491 let expected = Err(CallArgumentResolutionError::ReturnArgument {
1492 found: call_argument.clone(),
1493 });
1494 Self {
1495 call_argument,
1496 return_type: ScalarType::Integer,
1497 expected,
1498 }
1499 }
1500
1501 fn case_03() -> Self {
1503 let call_argument = UnresolvedCallArgument::Identifier("integer".to_string());
1504 let expected = Ok(ResolvedCallArgument::MemoryReference {
1505 memory_reference: MemoryReference::new("integer".to_string(), 0),
1506 scalar_type: ScalarType::Integer,
1507 mutable: true,
1508 });
1509 Self {
1510 call_argument,
1511 return_type: ScalarType::Integer,
1512 expected,
1513 }
1514 }
1515 }
1516
1517 #[rstest]
1519 #[case(ReturnArgumentResolutionTestCase::case_01())]
1520 #[case(ReturnArgumentResolutionTestCase::case_02())]
1521 #[case(ReturnArgumentResolutionTestCase::case_03())]
1522 fn test_return_argument_resolution(#[case] test_case: ReturnArgumentResolutionTestCase) {
1523 let memory_regions = build_declarations();
1524
1525 let found = test_case
1526 .call_argument
1527 .resolve_return(&memory_regions, test_case.return_type);
1528 match (test_case.expected, found) {
1529 (Ok(expected), Ok(found)) => assert_eq!(expected, found),
1530 (Ok(expected), Err(found)) => {
1531 panic!("expected resolution {:?}, found err {:?}", expected, found)
1532 }
1533 (Err(expected), Ok(found)) => {
1534 panic!("expected err {:?}, found resolution {:?}", expected, found)
1535 }
1536 (Err(expected), Err(found)) => assert_eq!(expected, found),
1537 }
1538 }
1539
1540 struct ResolveToSignatureTestCase {
1542 call: Call,
1544 signature: ExternSignature,
1546 expected: Result<Vec<ResolvedCallArgument>, CallSignatureError>,
1548 }
1549
1550 impl ResolveToSignatureTestCase {
1551 fn case_01() -> Self {
1553 let call = Call {
1554 name: "foo".to_string(),
1555 arguments: vec![
1556 UnresolvedCallArgument::MemoryReference(MemoryReference {
1557 name: "integer".to_string(),
1558 index: 0,
1559 }),
1560 UnresolvedCallArgument::Immediate(Complex64::new(2.0, 0.0)),
1561 UnresolvedCallArgument::Identifier("bit".to_string()),
1562 ],
1563 };
1564 let signature = ExternSignature {
1565 return_type: Some(ScalarType::Integer),
1566 parameters: vec![
1567 ExternParameter {
1568 name: "bar".to_string(),
1569 mutable: false,
1570 data_type: ExternParameterType::Scalar(ScalarType::Integer),
1571 },
1572 ExternParameter {
1573 name: "baz".to_string(),
1574 mutable: true,
1575 data_type: ExternParameterType::FixedLengthVector(Vector {
1576 data_type: ScalarType::Bit,
1577 length: 3,
1578 }),
1579 },
1580 ],
1581 };
1582 let resolved = vec![
1583 ResolvedCallArgument::MemoryReference {
1584 memory_reference: MemoryReference {
1585 name: "integer".to_string(),
1586 index: 0,
1587 },
1588 scalar_type: ScalarType::Integer,
1589 mutable: true,
1590 },
1591 ResolvedCallArgument::Immediate {
1592 value: Complex64::new(2.0, 0.0),
1593 scalar_type: ScalarType::Integer,
1594 },
1595 ResolvedCallArgument::Vector {
1596 memory_region_name: "bit".to_string(),
1597 vector: Vector {
1598 data_type: ScalarType::Bit,
1599 length: 3,
1600 },
1601 mutable: true,
1602 },
1603 ];
1604 Self {
1605 call,
1606 signature,
1607 expected: Ok(resolved),
1608 }
1609 }
1610
1611 fn case_02() -> Self {
1613 let call = Call {
1614 name: "foo".to_string(),
1615 arguments: vec![
1616 UnresolvedCallArgument::Immediate(Complex64::new(2.0, 0.0)),
1617 UnresolvedCallArgument::Identifier("bit".to_string()),
1618 ],
1619 };
1620 let signature = ExternSignature {
1621 return_type: None,
1622 parameters: vec![
1623 ExternParameter {
1624 name: "bar".to_string(),
1625 mutable: false,
1626 data_type: ExternParameterType::Scalar(ScalarType::Integer),
1627 },
1628 ExternParameter {
1629 name: "baz".to_string(),
1630 mutable: true,
1631 data_type: ExternParameterType::FixedLengthVector(Vector {
1632 data_type: ScalarType::Bit,
1633 length: 3,
1634 }),
1635 },
1636 ],
1637 };
1638 let resolved = vec![
1639 ResolvedCallArgument::Immediate {
1640 value: Complex64::new(2.0, 0.0),
1641 scalar_type: ScalarType::Integer,
1642 },
1643 ResolvedCallArgument::Vector {
1644 memory_region_name: "bit".to_string(),
1645 vector: Vector {
1646 data_type: ScalarType::Bit,
1647 length: 3,
1648 },
1649 mutable: true,
1650 },
1651 ];
1652 Self {
1653 call,
1654 signature,
1655 expected: Ok(resolved),
1656 }
1657 }
1658
1659 fn case_03() -> Self {
1661 let call = Call {
1662 name: "foo".to_string(),
1663 arguments: vec![UnresolvedCallArgument::MemoryReference(MemoryReference {
1664 name: "integer".to_string(),
1665 index: 0,
1666 })],
1667 };
1668 let signature = ExternSignature {
1669 return_type: Some(ScalarType::Integer),
1670 parameters: vec![],
1671 };
1672 let resolved = vec![ResolvedCallArgument::MemoryReference {
1673 memory_reference: MemoryReference {
1674 name: "integer".to_string(),
1675 index: 0,
1676 },
1677 scalar_type: ScalarType::Integer,
1678 mutable: true,
1679 }];
1680 Self {
1681 call,
1682 signature,
1683 expected: Ok(resolved),
1684 }
1685 }
1686
1687 fn case_04() -> Self {
1689 let call = Call {
1690 name: "foo".to_string(),
1691 arguments: vec![
1692 UnresolvedCallArgument::MemoryReference(MemoryReference {
1693 name: "integer".to_string(),
1694 index: 0,
1695 }),
1696 UnresolvedCallArgument::Immediate(Complex64::new(2.0, 0.0)),
1697 UnresolvedCallArgument::Identifier("bit".to_string()),
1698 ],
1699 };
1700 let signature = ExternSignature {
1701 return_type: Some(ScalarType::Integer),
1702 parameters: vec![ExternParameter {
1703 name: "bar".to_string(),
1704 mutable: false,
1705 data_type: ExternParameterType::Scalar(ScalarType::Integer),
1706 }],
1707 };
1708
1709 Self {
1710 call,
1711 signature,
1712 expected: Err(CallSignatureError::ParameterCount {
1713 expected: 2,
1714 found: 3,
1715 }),
1716 }
1717 }
1718
1719 fn case_05() -> Self {
1721 let call = Call {
1722 name: "foo".to_string(),
1723 arguments: vec![
1724 UnresolvedCallArgument::MemoryReference(MemoryReference {
1725 name: "integer".to_string(),
1726 index: 0,
1727 }),
1728 UnresolvedCallArgument::Immediate(Complex64::new(2.0, 0.0)),
1729 ],
1730 };
1731 let signature = ExternSignature {
1732 return_type: Some(ScalarType::Integer),
1733 parameters: vec![],
1734 };
1735
1736 Self {
1737 call,
1738 signature,
1739 expected: Err(CallSignatureError::ParameterCount {
1740 expected: 1,
1741 found: 2,
1742 }),
1743 }
1744 }
1745
1746 fn case_06() -> Self {
1748 let call = Call {
1749 name: "foo".to_string(),
1750 arguments: vec![
1751 UnresolvedCallArgument::MemoryReference(MemoryReference {
1752 name: "integer".to_string(),
1753 index: 0,
1754 }),
1755 UnresolvedCallArgument::Immediate(Complex64::new(2.0, 0.0)),
1756 UnresolvedCallArgument::Identifier("bit".to_string()),
1757 ],
1758 };
1759 let signature = ExternSignature {
1760 return_type: None,
1761 parameters: vec![ExternParameter {
1762 name: "bar".to_string(),
1763 mutable: false,
1764 data_type: ExternParameterType::Scalar(ScalarType::Integer),
1765 }],
1766 };
1767
1768 Self {
1769 call,
1770 signature,
1771 expected: Err(CallSignatureError::ParameterCount {
1772 expected: 1,
1773 found: 3,
1774 }),
1775 }
1776 }
1777
1778 fn case_07() -> Self {
1780 let call = Call {
1781 name: "foo".to_string(),
1782 arguments: vec![
1783 UnresolvedCallArgument::Immediate(Complex64::new(2.0, 0.0)),
1784 UnresolvedCallArgument::Identifier("bit".to_string()),
1785 ],
1786 };
1787 let signature = ExternSignature {
1788 return_type: Some(ScalarType::Integer),
1789 parameters: vec![ExternParameter {
1790 name: "bar".to_string(),
1791 mutable: false,
1792 data_type: ExternParameterType::Scalar(ScalarType::Real),
1793 }],
1794 };
1795
1796 Self {
1797 call,
1798 signature,
1799 expected: Err(CallSignatureError::Arguments(vec![
1800 CallArgumentError::Return(CallArgumentResolutionError::ReturnArgument {
1801 found: UnresolvedCallArgument::Immediate(Complex64::new(2.0, 0.0)),
1802 }),
1803 CallArgumentError::Argument {
1804 index: 0,
1805 error: CallArgumentResolutionError::MismatchedScalar {
1806 expected: ScalarType::Real,
1807 found: ScalarType::Bit,
1808 },
1809 },
1810 ])),
1811 }
1812 }
1813 }
1814
1815 #[rstest]
1817 #[case(ResolveToSignatureTestCase::case_01())]
1818 #[case(ResolveToSignatureTestCase::case_02())]
1819 #[case(ResolveToSignatureTestCase::case_03())]
1820 #[case(ResolveToSignatureTestCase::case_04())]
1821 #[case(ResolveToSignatureTestCase::case_05())]
1822 #[case(ResolveToSignatureTestCase::case_06())]
1823 #[case(ResolveToSignatureTestCase::case_07())]
1824 fn test_assert_matching_signature(#[case] test_case: ResolveToSignatureTestCase) {
1825 let memory_regions = build_declarations();
1826 let found = test_case
1827 .call
1828 .resolve_to_signature(&test_case.signature, &memory_regions);
1829 match (test_case.expected, found) {
1830 (Ok(_), Ok(_)) => {}
1831 (Ok(expected), Err(found)) => {
1832 panic!("expected resolution {:?}, found err {:?}", expected, found)
1833 }
1834 (Err(expected), Ok(found)) => {
1835 panic!("expected err {:?}, found resolution {:?}", expected, found)
1836 }
1837 (Err(expected), Err(found)) => assert_eq!(expected, found),
1838 }
1839 }
1840
1841 struct CallResolutionTestCase {
1843 call: Call,
1845 extern_signature_map: ExternSignatureMap,
1847 expected: Result<Vec<ResolvedCallArgument>, CallResolutionError>,
1849 }
1850
1851 impl CallResolutionTestCase {
1852 fn case_01() -> Self {
1854 let call = Call {
1855 name: "foo".to_string(),
1856 arguments: vec![UnresolvedCallArgument::MemoryReference(MemoryReference {
1857 name: "integer".to_string(),
1858 index: 0,
1859 })],
1860 };
1861 let signature = ExternSignature {
1862 return_type: Some(ScalarType::Integer),
1863 parameters: vec![],
1864 };
1865 let resolved = vec![ResolvedCallArgument::MemoryReference {
1866 memory_reference: MemoryReference {
1867 name: "integer".to_string(),
1868 index: 0,
1869 },
1870 scalar_type: ScalarType::Integer,
1871 mutable: true,
1872 }];
1873 Self {
1874 call,
1875 extern_signature_map: ExternSignatureMap(
1876 [("foo".to_string(), signature)].iter().cloned().collect(),
1877 ),
1878 expected: Ok(resolved),
1879 }
1880 }
1881
1882 fn case_02() -> Self {
1884 let call = Call {
1885 name: "foo".to_string(),
1886 arguments: vec![UnresolvedCallArgument::MemoryReference(MemoryReference {
1887 name: "integer".to_string(),
1888 index: 0,
1889 })],
1890 };
1891 let signature = ExternSignature {
1892 return_type: Some(ScalarType::Real),
1893 parameters: vec![],
1894 };
1895 Self {
1896 call,
1897 extern_signature_map: ExternSignatureMap(
1898 [("foo".to_string(), signature)].iter().cloned().collect(),
1899 ),
1900 expected: Err(CallResolutionError::Signature {
1901 name: "foo".to_string(),
1902 error: CallSignatureError::Arguments(vec![CallArgumentError::Return(
1903 CallArgumentResolutionError::MismatchedScalar {
1904 expected: ScalarType::Real,
1905 found: ScalarType::Integer,
1906 },
1907 )]),
1908 }),
1909 }
1910 }
1911
1912 fn case_03() -> Self {
1914 let call = Call {
1915 name: "undeclared".to_string(),
1916 arguments: vec![UnresolvedCallArgument::MemoryReference(MemoryReference {
1917 name: "integer".to_string(),
1918 index: 0,
1919 })],
1920 };
1921 let signature = ExternSignature {
1922 return_type: Some(ScalarType::Real),
1923 parameters: vec![],
1924 };
1925 Self {
1926 call,
1927 extern_signature_map: ExternSignatureMap(
1928 [("foo".to_string(), signature)].iter().cloned().collect(),
1929 ),
1930 expected: Err(CallResolutionError::NoMatchingExternInstruction(
1931 "undeclared".to_string(),
1932 )),
1933 }
1934 }
1935 }
1936
1937 #[rstest]
1939 #[case(CallResolutionTestCase::case_01())]
1940 #[case(CallResolutionTestCase::case_02())]
1941 #[case(CallResolutionTestCase::case_03())]
1942 fn test_call_resolution(#[case] test_case: CallResolutionTestCase) {
1943 let memory_regions = build_declarations();
1944 let found = test_case
1945 .call
1946 .resolve_arguments(&memory_regions, &test_case.extern_signature_map);
1947 match (test_case.expected, found) {
1948 (Ok(expected), Ok(found)) => {
1949 assert_eq!(expected, found);
1950 }
1951 (Ok(expected), Err(found)) => {
1952 panic!("expected resolution {:?}, found err {:?}", expected, found)
1953 }
1954 (Err(expected), Ok(_)) => {
1955 panic!(
1956 "expected err {:?}, found resolution {:?}",
1957 expected, test_case.call.arguments
1958 )
1959 }
1960 (Err(expected), Err(found)) => assert_eq!(expected, found),
1961 }
1962 }
1963
1964 struct ExternPragmaMapConverstionTestCase {
1966 extern_pragma_map: ExternPragmaMap,
1968 expected: Result<ExternSignatureMap, ExternError>,
1970 }
1971
1972 impl ExternPragmaMapConverstionTestCase {
1973 fn case_01() -> Self {
1975 let pragma1 = Pragma {
1976 name: RESERVED_PRAGMA_EXTERN.to_string(),
1977 arguments: vec![PragmaArgument::Identifier("foo".to_string())],
1978 data: Some("(bar : INTEGER)".to_string()),
1979 };
1980 let signature1 = ExternSignature {
1981 return_type: None,
1982 parameters: vec![ExternParameter {
1983 name: "bar".to_string(),
1984 mutable: false,
1985 data_type: ExternParameterType::Scalar(ScalarType::Integer),
1986 }],
1987 };
1988 let pragma2 = Pragma {
1989 name: RESERVED_PRAGMA_EXTERN.to_string(),
1990 arguments: vec![PragmaArgument::Identifier("baz".to_string())],
1991 data: Some("REAL (biz : REAL)".to_string()),
1992 };
1993 let signature2 = ExternSignature {
1994 return_type: Some(ScalarType::Real),
1995 parameters: vec![ExternParameter {
1996 name: "biz".to_string(),
1997 mutable: false,
1998 data_type: ExternParameterType::Scalar(ScalarType::Real),
1999 }],
2000 };
2001 let pragma3 = Pragma {
2002 name: RESERVED_PRAGMA_EXTERN.to_string(),
2003 arguments: vec![PragmaArgument::Identifier("buzz".to_string())],
2004 data: Some("OCTET".to_string()),
2005 };
2006 let signature3 = ExternSignature {
2007 return_type: Some(ScalarType::Octet),
2008 parameters: vec![],
2009 };
2010 Self {
2011 extern_pragma_map: ExternPragmaMap(
2012 [("foo", pragma1), ("baz", pragma2), ("buzz", pragma3)]
2013 .into_iter()
2014 .map(|(name, pragma)| (Some(name.to_string()), pragma))
2015 .collect(),
2016 ),
2017 expected: Ok(ExternSignatureMap(
2018 [
2019 ("foo", signature1),
2020 ("baz", signature2),
2021 ("buzz", signature3),
2022 ]
2023 .into_iter()
2024 .map(|(name, signature)| (name.to_string(), signature))
2025 .collect(),
2026 )),
2027 }
2028 }
2029
2030 fn case_02() -> Self {
2032 let pragma = Pragma {
2033 name: RESERVED_PRAGMA_EXTERN.to_string(),
2034 arguments: vec![PragmaArgument::Identifier("foo".to_string())],
2035 data: None,
2036 };
2037 let expected = Err(ExternError::NoSignature);
2038 Self {
2039 extern_pragma_map: ExternPragmaMap(
2040 [(Some("foo".to_string()), pragma)].into_iter().collect(),
2041 ),
2042 expected,
2043 }
2044 }
2045
2046 fn case_03() -> Self {
2048 let pragma = Pragma {
2049 name: RESERVED_PRAGMA_EXTERN.to_string(),
2050 arguments: vec![PragmaArgument::Identifier("foo".to_string())],
2051 data: Some("()".to_string()),
2052 };
2053 let expected = Err(ExternError::NoReturnOrParameters);
2054 Self {
2055 extern_pragma_map: ExternPragmaMap(
2056 [(Some("foo".to_string()), pragma)].into_iter().collect(),
2057 ),
2058 expected,
2059 }
2060 }
2061
2062 fn case_04() -> Self {
2064 let pragma = Pragma {
2065 name: RESERVED_PRAGMA_EXTERN.to_string(),
2066 arguments: vec![],
2067 data: Some("(bar : REAL)".to_string()),
2068 };
2069 let expected = Err(ExternError::NoName);
2070 Self {
2071 extern_pragma_map: ExternPragmaMap([(None, pragma)].into_iter().collect()),
2072 expected,
2073 }
2074 }
2075
2076 fn case_05() -> Self {
2078 let pragma = Pragma {
2079 name: "NOTEXTERN".to_string(),
2080 arguments: vec![PragmaArgument::Identifier("foo".to_string())],
2081 data: Some("(bar : REAL)".to_string()),
2082 };
2083 let expected = Err(ExternError::NoName);
2084 Self {
2085 extern_pragma_map: ExternPragmaMap([(None, pragma)].into_iter().collect()),
2086 expected,
2087 }
2088 }
2089
2090 fn case_06() -> Self {
2092 let pragma = Pragma {
2093 name: RESERVED_PRAGMA_EXTERN.to_string(),
2094 arguments: vec![
2095 PragmaArgument::Identifier("foo".to_string()),
2096 PragmaArgument::Identifier("bar".to_string()),
2097 ],
2098 data: Some("OCTET".to_string()),
2099 };
2100 let expected = Err(ExternError::NoName);
2101 Self {
2102 extern_pragma_map: ExternPragmaMap([(None, pragma)].into_iter().collect()),
2103 expected,
2104 }
2105 }
2106
2107 fn case_07() -> Self {
2109 let pragma = Pragma {
2110 name: RESERVED_PRAGMA_EXTERN.to_string(),
2111 arguments: vec![PragmaArgument::Integer(0)],
2112 data: Some("OCTET".to_string()),
2113 };
2114 let expected = Err(ExternError::NoName);
2115 Self {
2116 extern_pragma_map: ExternPragmaMap([(None, pragma)].into_iter().collect()),
2117 expected,
2118 }
2119 }
2120
2121 fn case_08() -> Self {
2123 let pragma = Pragma {
2124 name: RESERVED_PRAGMA_EXTERN.to_string(),
2125 arguments: vec![PragmaArgument::Identifier("foo".to_string())],
2126 data: Some("OCTET (ㆆ _ ㆆ)".to_string()),
2127 };
2128 let expected = Err(ExternSignature::from_str("OCTET (ㆆ _ ㆆ)").unwrap_err());
2129 Self {
2130 extern_pragma_map: ExternPragmaMap(
2131 [(Some("foo".to_string()), pragma)].into_iter().collect(),
2132 ),
2133 expected,
2134 }
2135 }
2136
2137 fn case_09() -> Self {
2139 let pragma = Pragma {
2140 name: RESERVED_PRAGMA_EXTERN.to_string(),
2141 arguments: vec![PragmaArgument::Identifier("foo".to_string())],
2142 data: Some("OCTET (bar : INTEGER".to_string()),
2143 };
2144 let expected = Err(ExternSignature::from_str("OCTET (bar : INTEGER").unwrap_err());
2145 Self {
2146 extern_pragma_map: ExternPragmaMap(
2147 [(Some("foo".to_string()), pragma)].into_iter().collect(),
2148 ),
2149 expected,
2150 }
2151 }
2152 }
2153
2154 #[rstest]
2156 #[case(ExternPragmaMapConverstionTestCase::case_01())]
2157 #[case(ExternPragmaMapConverstionTestCase::case_02())]
2158 #[case(ExternPragmaMapConverstionTestCase::case_03())]
2159 #[case(ExternPragmaMapConverstionTestCase::case_04())]
2160 #[case(ExternPragmaMapConverstionTestCase::case_05())]
2161 #[case(ExternPragmaMapConverstionTestCase::case_06())]
2162 #[case(ExternPragmaMapConverstionTestCase::case_07())]
2163 #[case(ExternPragmaMapConverstionTestCase::case_08())]
2164 #[case(ExternPragmaMapConverstionTestCase::case_09())]
2165 fn test_extern_signature_map_validation(#[case] test_case: ExternPragmaMapConverstionTestCase) {
2166 let found = ExternSignatureMap::try_from(test_case.extern_pragma_map);
2167 match (test_case.expected, found) {
2168 (Ok(expected), Ok(found)) => {
2169 assert_eq!(expected, found);
2170 }
2171 (Ok(_), Err(found)) => {
2172 panic!("expected valid, found err {:?}", found)
2173 }
2174 (Err(expected), Ok(_)) => {
2175 panic!("expected err {:?}, found valid", expected)
2176 }
2177 (Err(expected), Err((_, found))) => assert_eq!(expected, found),
2178 }
2179 }
2180
2181 struct ExternSignatureFromStrTestCase {
2183 input: &'static str,
2185 expected: Result<ExternSignature, ExternError>,
2187 }
2188
2189 impl ExternSignatureFromStrTestCase {
2190 fn case_01() -> Self {
2192 Self {
2193 input: "",
2194 expected: Err(ExternError::NoReturnOrParameters),
2195 }
2196 }
2197
2198 fn case_02() -> Self {
2200 Self {
2201 input: "()",
2202 expected: Err(ExternError::NoReturnOrParameters),
2203 }
2204 }
2205
2206 fn case_03() -> Self {
2208 Self {
2209 input: "INTEGER",
2210 expected: Ok(crate::instruction::ExternSignature {
2211 return_type: Some(ScalarType::Integer),
2212 parameters: vec![],
2213 }),
2214 }
2215 }
2216
2217 fn case_04() -> Self {
2219 Self {
2220 input: "INTEGER ()",
2221 expected: Ok(crate::instruction::ExternSignature {
2222 return_type: Some(ScalarType::Integer),
2223 parameters: vec![],
2224 }),
2225 }
2226 }
2227
2228 fn case_05() -> Self {
2230 Self {
2231 input: "INTEGER (bar: REAL, baz: BIT[10], biz: mut OCTET)",
2232 expected: Ok(crate::instruction::ExternSignature {
2233 return_type: Some(ScalarType::Integer),
2234 parameters: vec![
2235 ExternParameter {
2236 name: "bar".to_string(),
2237 mutable: false,
2238 data_type: ExternParameterType::Scalar(ScalarType::Real),
2239 },
2240 ExternParameter {
2241 name: "baz".to_string(),
2242 mutable: false,
2243 data_type: ExternParameterType::FixedLengthVector(Vector {
2244 data_type: ScalarType::Bit,
2245 length: 10,
2246 }),
2247 },
2248 ExternParameter {
2249 name: "biz".to_string(),
2250 mutable: true,
2251 data_type: ExternParameterType::Scalar(ScalarType::Octet),
2252 },
2253 ],
2254 }),
2255 }
2256 }
2257
2258 fn case_06() -> Self {
2260 Self {
2261 input: "(bar: REAL, baz: BIT[10], biz : mut OCTET)",
2262 expected: Ok(crate::instruction::ExternSignature {
2263 return_type: None,
2264 parameters: vec![
2265 ExternParameter {
2266 name: "bar".to_string(),
2267 mutable: false,
2268 data_type: ExternParameterType::Scalar(ScalarType::Real),
2269 },
2270 ExternParameter {
2271 name: "baz".to_string(),
2272 mutable: false,
2273 data_type: ExternParameterType::FixedLengthVector(Vector {
2274 data_type: ScalarType::Bit,
2275 length: 10,
2276 }),
2277 },
2278 ExternParameter {
2279 name: "biz".to_string(),
2280 mutable: true,
2281 data_type: ExternParameterType::Scalar(ScalarType::Octet),
2282 },
2283 ],
2284 }),
2285 }
2286 }
2287
2288 fn case_07() -> Self {
2290 Self {
2291 input: "(bar : mut REAL[])",
2292 expected: Ok(crate::instruction::ExternSignature {
2293 return_type: None,
2294 parameters: vec![ExternParameter {
2295 name: "bar".to_string(),
2296 mutable: true,
2297 data_type: ExternParameterType::VariableLengthVector(ScalarType::Real),
2298 }],
2299 }),
2300 }
2301 }
2302 }
2303
2304 #[rstest]
2306 #[case(ExternSignatureFromStrTestCase::case_01())]
2307 #[case(ExternSignatureFromStrTestCase::case_02())]
2308 #[case(ExternSignatureFromStrTestCase::case_03())]
2309 #[case(ExternSignatureFromStrTestCase::case_04())]
2310 #[case(ExternSignatureFromStrTestCase::case_05())]
2311 #[case(ExternSignatureFromStrTestCase::case_06())]
2312 #[case(ExternSignatureFromStrTestCase::case_07())]
2313 fn test_parse_reserved_pragma_extern(#[case] test_case: ExternSignatureFromStrTestCase) {
2314 match (
2315 test_case.expected,
2316 ExternSignature::from_str(test_case.input),
2317 ) {
2318 (Ok(expected), Ok(parsed)) => {
2319 assert_eq!(expected, parsed);
2320 }
2321 (Ok(expected), Err(e)) => {
2322 panic!("Expected {:?}, got error: {:?}", expected, e);
2323 }
2324 (Err(expected), Ok(parsed)) => {
2325 panic!("Expected error: {:?}, got {:?}", expected, parsed);
2326 }
2327 (Err(expected), Err(found)) => {
2328 let expected = format!("{expected:?}");
2329 let found = format!("{found:?}");
2330 assert!(
2331 found.contains(&expected),
2332 "`{}` not in `{}`",
2333 expected,
2334 found
2335 );
2336 }
2337 }
2338 }
2339}