1use combine::stream::position::Stream;
2use combine::{eof, EasyParser, Parser};
3
4use serde::{Deserialize, Serialize};
5use std::fmt::Display;
6
7#[derive(PartialEq, Hash, Eq, Clone, Ord, PartialOrd)]
8pub struct SemVer(pub semver::Version);
9
10impl SemVer {
11 pub fn parse(version: &str) -> Result<Self, String> {
12 semver::Version::parse(version)
13 .map(SemVer)
14 .map_err(|e| format!("Invalid semver string: {e}"))
15 }
16}
17
18impl std::fmt::Debug for SemVer {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 write!(f, "{}", self.0)
21 }
22}
23
24#[derive(Debug, Hash, PartialEq, Eq, Clone, Ord, PartialOrd)]
25pub enum ParsedFunctionSite {
26 Global,
27 Interface {
28 name: String,
29 },
30 PackagedInterface {
31 namespace: String,
32 package: String,
33 interface: String,
34 version: Option<SemVer>,
35 },
36}
37
38impl ParsedFunctionSite {
39 pub fn parse(name: impl AsRef<str>) -> Result<Self, String> {
40 ParsedFunctionName::parse(format!("{}.{{x}}", name.as_ref()))
41 .map(|ParsedFunctionName { site, .. }| site)
42 }
43
44 pub fn interface_name(&self) -> Option<String> {
45 match self {
46 Self::Global => None,
47 Self::Interface { name } => Some(name.clone()),
48 Self::PackagedInterface {
49 namespace,
50 package,
51 interface,
52 version: None,
53 } => Some(format!("{namespace}:{package}/{interface}")),
54 Self::PackagedInterface {
55 namespace,
56 package,
57 interface,
58 version: Some(version),
59 } => Some(format!("{namespace}:{package}/{interface}@{}", version.0)),
60 }
61 }
62
63 pub fn unversioned(&self) -> ParsedFunctionSite {
64 match self {
65 ParsedFunctionSite::Global => ParsedFunctionSite::Global,
66 ParsedFunctionSite::Interface { name } => {
67 ParsedFunctionSite::Interface { name: name.clone() }
68 }
69 ParsedFunctionSite::PackagedInterface {
70 namespace,
71 package,
72 interface,
73 version: _,
74 } => ParsedFunctionSite::PackagedInterface {
75 namespace: namespace.clone(),
76 package: package.clone(),
77 interface: interface.clone(),
78 version: None,
79 },
80 }
81 }
82}
83
84#[derive(Debug, Hash, PartialEq, Eq, Clone, Ord, PartialOrd)]
85pub enum DynamicParsedFunctionReference {
86 Function { function: String },
87 RawResourceConstructor { resource: String },
88 RawResourceDrop { resource: String },
89 RawResourceMethod { resource: String, method: String },
90 RawResourceStaticMethod { resource: String, method: String },
91}
92
93impl DynamicParsedFunctionReference {
94 pub fn name_pretty(&self) -> String {
95 match self {
96 DynamicParsedFunctionReference::Function { function, .. } => function.clone(),
97 DynamicParsedFunctionReference::RawResourceConstructor { resource, .. } => {
98 resource.to_string()
99 }
100 DynamicParsedFunctionReference::RawResourceDrop { .. } => "drop".to_string(),
101 DynamicParsedFunctionReference::RawResourceMethod { method, .. } => method.to_string(),
102 DynamicParsedFunctionReference::RawResourceStaticMethod { method, .. } => {
103 method.to_string()
104 }
105 }
106 }
107
108 fn to_static(&self) -> ParsedFunctionReference {
109 match self {
110 Self::Function { function } => ParsedFunctionReference::Function {
111 function: function.clone(),
112 },
113 Self::RawResourceConstructor { resource } => {
114 ParsedFunctionReference::RawResourceConstructor {
115 resource: resource.clone(),
116 }
117 }
118 Self::RawResourceDrop { resource } => ParsedFunctionReference::RawResourceDrop {
119 resource: resource.clone(),
120 },
121 Self::RawResourceMethod { resource, method } => {
122 ParsedFunctionReference::RawResourceMethod {
123 resource: resource.clone(),
124 method: method.clone(),
125 }
126 }
127 Self::RawResourceStaticMethod { resource, method } => {
128 ParsedFunctionReference::RawResourceStaticMethod {
129 resource: resource.clone(),
130 method: method.clone(),
131 }
132 }
133 }
134 }
135}
136
137#[derive(Debug, PartialEq, Eq, Clone, Hash)]
138pub enum ParsedFunctionReference {
139 Function { function: String },
140 RawResourceConstructor { resource: String },
141 RawResourceDrop { resource: String },
142 RawResourceMethod { resource: String, method: String },
143 RawResourceStaticMethod { resource: String, method: String },
144}
145
146impl Display for ParsedFunctionReference {
147 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148 let function_name = match self {
149 Self::Function { function } => function.clone(),
150 Self::RawResourceConstructor { resource } => format!("{resource}.new"),
151 Self::RawResourceMethod { resource, method } => format!("{resource}.{method}"),
152 Self::RawResourceStaticMethod { resource, method } => {
153 format!("[static]{resource}.{method}")
154 }
155 Self::RawResourceDrop { resource } => format!("{resource}.drop"),
156 };
157
158 write!(f, "{function_name}")
159 }
160}
161
162impl ParsedFunctionReference {
163 pub fn function_name(&self) -> String {
164 match self {
165 Self::Function { function, .. } => function.clone(),
166 Self::RawResourceConstructor { resource, .. } => format!("[constructor]{resource}"),
167 Self::RawResourceDrop { resource, .. } => format!("[drop]{resource}"),
168 Self::RawResourceMethod {
169 resource, method, ..
170 } => format!("[method]{resource}.{method}"),
171 Self::RawResourceStaticMethod {
172 resource, method, ..
173 } => format!("[static]{resource}.{method}"),
174 }
175 }
176
177 pub fn resource_method_name(&self) -> Option<String> {
178 match self {
179 Self::RawResourceMethod { method, .. }
180 | Self::RawResourceStaticMethod { method, .. } => Some(method.clone()),
181 _ => None,
182 }
183 }
184
185 pub fn method_as_static(&self) -> Option<ParsedFunctionReference> {
186 match self {
187 Self::RawResourceMethod { resource, method } => Some(Self::RawResourceStaticMethod {
188 resource: resource.clone(),
189 method: method.clone(),
190 }),
191
192 _ => None,
193 }
194 }
195
196 pub fn resource_name(&self) -> Option<&String> {
197 match self {
198 Self::RawResourceConstructor { resource }
199 | Self::RawResourceDrop { resource }
200 | Self::RawResourceMethod { resource, .. }
201 | Self::RawResourceStaticMethod { resource, .. } => Some(resource),
202 _ => None,
203 }
204 }
205}
206
207#[derive(Debug, Hash, PartialEq, Eq, Clone, Ord, PartialOrd)]
216pub struct DynamicParsedFunctionName {
217 pub site: ParsedFunctionSite,
218 pub function: DynamicParsedFunctionReference,
219}
220
221impl DynamicParsedFunctionName {
222 pub fn parse(name: impl AsRef<str>) -> Result<Self, String> {
223 let name = name.as_ref();
224
225 let mut parser = crate::parser::call::function_name();
226
227 let result = parser.easy_parse(Stream::new(name));
228
229 match result {
230 Ok((parsed, _)) => Ok(parsed),
231 Err(error) => {
232 let error_message = error.map_position(|p| p.to_string()).to_string();
233 Err(error_message)
234 }
235 }
236 }
237
238 pub fn function_name_with_prefix_identifiers(&self) -> String {
239 self.to_parsed_function_name().function.function_name()
240 }
241
242 pub fn resource_name_simplified(&self) -> Option<String> {
245 self.to_parsed_function_name()
246 .function
247 .resource_name()
248 .cloned()
249 }
250
251 pub fn resource_method_name_simplified(&self) -> Option<String> {
253 self.to_parsed_function_name()
254 .function
255 .resource_method_name()
256 }
257
258 pub fn to_parsed_function_name(&self) -> ParsedFunctionName {
260 ParsedFunctionName {
261 site: self.site.clone(),
262 function: self.function.to_static(),
263 }
264 }
265}
266
267impl Display for DynamicParsedFunctionName {
268 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269 let function_name = self.to_parsed_function_name().to_string();
270 write!(f, "{function_name}")
271 }
272}
273
274#[derive(Debug, PartialEq, Eq, Clone, Hash)]
275pub struct ParsedFunctionName {
276 pub site: ParsedFunctionSite,
277 pub function: ParsedFunctionReference,
278}
279
280impl Serialize for ParsedFunctionName {
281 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
282 let function_name = self.to_string();
283 serializer.serialize_str(&function_name)
284 }
285}
286
287impl<'de> Deserialize<'de> for ParsedFunctionName {
288 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
289 where
290 D: serde::Deserializer<'de>,
291 {
292 let function_name = <String as Deserialize>::deserialize(deserializer)?;
293 ParsedFunctionName::parse(function_name).map_err(serde::de::Error::custom)
294 }
295}
296
297impl Display for ParsedFunctionName {
298 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
299 let function_name = self
300 .site
301 .interface_name()
302 .map_or(self.function.function_name(), |interface| {
303 format!("{}.{{{}}}", interface, self.function)
304 });
305 write!(f, "{function_name}")
306 }
307}
308
309impl ParsedFunctionName {
310 pub fn new(site: ParsedFunctionSite, function: ParsedFunctionReference) -> Self {
311 Self { site, function }
312 }
313
314 pub fn global(name: String) -> Self {
315 Self {
316 site: ParsedFunctionSite::Global,
317 function: ParsedFunctionReference::Function { function: name },
318 }
319 }
320
321 pub fn on_interface(interface: String, function: String) -> Self {
322 Self {
323 site: ParsedFunctionSite::Interface { name: interface },
324 function: ParsedFunctionReference::Function { function },
325 }
326 }
327
328 pub fn parse(name: impl AsRef<str>) -> Result<Self, String> {
329 let name = name.as_ref();
330
331 let mut parser = crate::parser::call::function_name().skip(eof());
332
333 let result = parser.easy_parse(Stream::new(name));
334
335 match result {
336 Ok((parsed, _)) => Ok(parsed.to_parsed_function_name()),
337 Err(error) => {
338 let error_message = error.map_position(|p| p.to_string()).to_string();
339 Err(error_message)
340 }
341 }
342 }
343
344 pub fn site(&self) -> &ParsedFunctionSite {
345 &self.site
346 }
347
348 pub fn function(&self) -> &ParsedFunctionReference {
349 &self.function
350 }
351
352 pub fn method_as_static(&self) -> Option<Self> {
353 self.function.method_as_static().map(|function| Self {
354 site: self.site.clone(),
355 function,
356 })
357 }
358
359 pub fn is_constructor(&self) -> Option<&str> {
360 match &self.function {
361 ParsedFunctionReference::RawResourceConstructor { resource, .. } => Some(resource),
362 _ => None,
363 }
364 }
365
366 pub fn is_method(&self) -> Option<&str> {
367 match &self.function {
368 ParsedFunctionReference::RawResourceMethod { resource, .. }
369 | ParsedFunctionReference::RawResourceStaticMethod { resource, .. } => Some(resource),
370 _ => None,
371 }
372 }
373
374 pub fn is_static_method(&self) -> Option<&str> {
375 match &self.function {
376 ParsedFunctionReference::RawResourceStaticMethod { resource, .. } => Some(resource),
377 _ => None,
378 }
379 }
380
381 pub fn with_site(&self, site: ParsedFunctionSite) -> Self {
382 Self {
383 site,
384 function: self.function.clone(),
385 }
386 }
387
388 pub fn wasm_component_export_path(&self) -> Vec<String> {
397 let mut segments: Vec<String> = match &self.site {
398 ParsedFunctionSite::Global => Vec::new(),
399 ParsedFunctionSite::Interface { name } => name
400 .split('/')
401 .filter(|s| !s.is_empty())
402 .map(str::to_string)
403 .collect(),
404 ParsedFunctionSite::PackagedInterface { interface, .. } => vec![interface.clone()],
405 };
406 let leaf = match &self.function {
407 ParsedFunctionReference::Function { function } => function.clone(),
408 _ => self.function.function_name(),
409 };
410 segments.push(leaf);
411 segments
412 }
413
414 pub fn wasm_component_export_path_candidates(&self) -> Vec<Vec<String>> {
417 let primary = self.wasm_component_export_path();
418 let mut out: Vec<Vec<String>> = Vec::new();
419 let mut push = |p: Vec<String>| {
420 if !out.iter().any(|e| e == &p) {
421 out.push(p);
422 }
423 };
424 push(primary.clone());
425 if let Some(last) = primary.last() {
426 let snake = last.replace('-', "_");
427 if snake != *last {
428 let mut alt = primary.clone();
429 alt.pop();
430 alt.push(snake);
431 push(alt);
432 }
433 }
434 out
435 }
436}
437
438#[cfg(test)]
439mod function_name_tests {
440 use super::{ParsedFunctionName, ParsedFunctionReference, ParsedFunctionSite, SemVer};
441 use test_r::test;
442
443 #[test]
444 fn parse_function_name_does_not_accept_partial_matches() {
445 let result = ParsedFunctionName::parse("x:y/z");
446 assert!(result.is_err());
447 }
448
449 #[test]
450 fn parse_function_name_global() {
451 let parsed = ParsedFunctionName::parse("run-example").expect("Parsing failed");
452 assert_eq!(parsed.site().interface_name(), None);
453 assert_eq!(parsed.function().function_name(), "run-example");
454 assert_eq!(
455 parsed,
456 ParsedFunctionName {
457 site: ParsedFunctionSite::Global,
458 function: ParsedFunctionReference::Function {
459 function: "run-example".to_string()
460 },
461 }
462 );
463 }
464
465 #[test]
466 fn parse_function_name_in_exported_interface_no_package() {
467 let parsed = ParsedFunctionName::parse("interface.{fn1}").expect("Parsing failed");
468 assert_eq!(
469 parsed.site().interface_name(),
470 Some("interface".to_string())
471 );
472 assert_eq!(parsed.function().function_name(), "fn1".to_string());
473 assert_eq!(
474 parsed,
475 ParsedFunctionName {
476 site: ParsedFunctionSite::Interface {
477 name: "interface".to_string()
478 },
479 function: ParsedFunctionReference::Function {
480 function: "fn1".to_string()
481 },
482 }
483 );
484 }
485
486 #[test]
487 fn wasm_component_export_path_packaged_matches_world_root() {
488 let parsed =
489 ParsedFunctionName::parse("component:rib-smoke/inventory.{lookup-sku}").expect("parse");
490 assert_eq!(
491 parsed.wasm_component_export_path(),
492 vec!["inventory", "lookup-sku"]
493 );
494 let cands = parsed.wasm_component_export_path_candidates();
495 assert!(cands.iter().any(|p| p == &vec!["inventory", "lookup-sku"]));
496 assert!(cands.iter().any(|p| p == &vec!["inventory", "lookup_sku"]));
497 }
498
499 #[test]
500 fn parse_function_name_in_exported_interface() {
501 let parsed = ParsedFunctionName::parse("ns:name/interface.{fn1}").expect("Parsing failed");
502 assert_eq!(
503 parsed.site().interface_name(),
504 Some("ns:name/interface".to_string())
505 );
506 assert_eq!(parsed.function().function_name(), "fn1".to_string());
507 assert_eq!(
508 parsed,
509 ParsedFunctionName {
510 site: ParsedFunctionSite::PackagedInterface {
511 namespace: "ns".to_string(),
512 package: "name".to_string(),
513 interface: "interface".to_string(),
514 version: None,
515 },
516 function: ParsedFunctionReference::Function {
517 function: "fn1".to_string()
518 },
519 }
520 );
521 }
522
523 #[test]
524 fn parse_function_name_in_versioned_exported_interface() {
525 let parsed = ParsedFunctionName::parse("wasi:cli/run@0.2.0.{run}").expect("Parsing failed");
526 assert_eq!(
527 parsed.site().interface_name(),
528 Some("wasi:cli/run@0.2.0".to_string())
529 );
530 assert_eq!(parsed.function().function_name(), "run".to_string());
531 assert_eq!(
532 parsed,
533 ParsedFunctionName {
534 site: ParsedFunctionSite::PackagedInterface {
535 namespace: "wasi".to_string(),
536 package: "cli".to_string(),
537 interface: "run".to_string(),
538 version: Some(SemVer(semver::Version::new(0, 2, 0))),
539 },
540 function: ParsedFunctionReference::Function {
541 function: "run".to_string()
542 },
543 }
544 );
545 }
546
547 #[test]
548 fn parse_function_name_constructor_syntax_sugar() {
549 let parsed =
550 ParsedFunctionName::parse("ns:name/interface.{resource1.new}").expect("Parsing failed");
551 assert_eq!(
552 parsed.site().interface_name(),
553 Some("ns:name/interface".to_string())
554 );
555 assert_eq!(
556 parsed.function().function_name(),
557 "[constructor]resource1".to_string()
558 );
559 assert_eq!(
560 parsed,
561 ParsedFunctionName {
562 site: ParsedFunctionSite::PackagedInterface {
563 namespace: "ns".to_string(),
564 package: "name".to_string(),
565 interface: "interface".to_string(),
566 version: None,
567 },
568 function: ParsedFunctionReference::RawResourceConstructor {
569 resource: "resource1".to_string()
570 },
571 }
572 );
573 }
574
575 #[test]
576 fn parse_function_name_constructor() {
577 let parsed = ParsedFunctionName::parse("ns:name/interface.{[constructor]resource1}")
578 .expect("Parsing failed");
579 assert_eq!(
580 parsed.site().interface_name(),
581 Some("ns:name/interface".to_string())
582 );
583 assert_eq!(
584 parsed.function().function_name(),
585 "[constructor]resource1".to_string()
586 );
587 assert_eq!(
588 parsed,
589 ParsedFunctionName {
590 site: ParsedFunctionSite::PackagedInterface {
591 namespace: "ns".to_string(),
592 package: "name".to_string(),
593 interface: "interface".to_string(),
594 version: None,
595 },
596 function: ParsedFunctionReference::RawResourceConstructor {
597 resource: "resource1".to_string()
598 },
599 }
600 );
601 }
602
603 #[test]
604 fn parse_function_name_method_syntax_sugar() {
605 let parsed = ParsedFunctionName::parse("ns:name/interface.{resource1.do-something}")
606 .expect("Parsing failed");
607 assert_eq!(
608 parsed.site().interface_name(),
609 Some("ns:name/interface".to_string())
610 );
611 assert_eq!(
612 parsed.function().function_name(),
613 "[method]resource1.do-something".to_string()
614 );
615 assert_eq!(
616 parsed,
617 ParsedFunctionName {
618 site: ParsedFunctionSite::PackagedInterface {
619 namespace: "ns".to_string(),
620 package: "name".to_string(),
621 interface: "interface".to_string(),
622 version: None,
623 },
624 function: ParsedFunctionReference::RawResourceMethod {
625 resource: "resource1".to_string(),
626 method: "do-something".to_string(),
627 },
628 }
629 );
630 }
631
632 #[test]
633 fn parse_function_name_method() {
634 let parsed =
635 ParsedFunctionName::parse("ns:name/interface.{[method]resource1.do-something}")
636 .expect("Parsing failed");
637 assert_eq!(
638 parsed.site().interface_name(),
639 Some("ns:name/interface".to_string())
640 );
641 assert_eq!(
642 parsed.function().function_name(),
643 "[method]resource1.do-something".to_string()
644 );
645 assert_eq!(
646 parsed,
647 ParsedFunctionName {
648 site: ParsedFunctionSite::PackagedInterface {
649 namespace: "ns".to_string(),
650 package: "name".to_string(),
651 interface: "interface".to_string(),
652 version: None,
653 },
654 function: ParsedFunctionReference::RawResourceMethod {
655 resource: "resource1".to_string(),
656 method: "do-something".to_string(),
657 },
658 }
659 );
660 }
661
662 #[test]
663 fn parse_function_name_static_method_syntax_sugar() {
664 let parsed = ParsedFunctionName::parse("ns:name/interface.{resource1.do-something-static}")
667 .expect("Parsing failed")
668 .method_as_static()
669 .unwrap();
670 assert_eq!(
671 parsed.site().interface_name(),
672 Some("ns:name/interface".to_string())
673 );
674 assert_eq!(
675 parsed.function().function_name(),
676 "[static]resource1.do-something-static".to_string()
677 );
678 assert_eq!(
679 parsed,
680 ParsedFunctionName {
681 site: ParsedFunctionSite::PackagedInterface {
682 namespace: "ns".to_string(),
683 package: "name".to_string(),
684 interface: "interface".to_string(),
685 version: None,
686 },
687 function: ParsedFunctionReference::RawResourceStaticMethod {
688 resource: "resource1".to_string(),
689 method: "do-something-static".to_string(),
690 },
691 }
692 );
693 }
694
695 #[test]
696 fn parse_function_name_static() {
697 let parsed =
698 ParsedFunctionName::parse("ns:name/interface.{[static]resource1.do-something-static}")
699 .expect("Parsing failed");
700 assert_eq!(
701 parsed.site().interface_name(),
702 Some("ns:name/interface".to_string())
703 );
704 assert_eq!(
705 parsed.function().function_name(),
706 "[static]resource1.do-something-static".to_string()
707 );
708 assert_eq!(
709 parsed,
710 ParsedFunctionName {
711 site: ParsedFunctionSite::PackagedInterface {
712 namespace: "ns".to_string(),
713 package: "name".to_string(),
714 interface: "interface".to_string(),
715 version: None,
716 },
717 function: ParsedFunctionReference::RawResourceStaticMethod {
718 resource: "resource1".to_string(),
719 method: "do-something-static".to_string(),
720 },
721 }
722 );
723 }
724
725 #[test]
726 fn parse_function_name_drop_syntax_sugar() {
727 let parsed = ParsedFunctionName::parse("ns:name/interface.{resource1.drop}")
728 .expect("Parsing failed");
729 assert_eq!(
730 parsed.site().interface_name(),
731 Some("ns:name/interface".to_string())
732 );
733 assert_eq!(
734 parsed.function().function_name(),
735 "[drop]resource1".to_string()
736 );
737 assert_eq!(
738 parsed,
739 ParsedFunctionName {
740 site: ParsedFunctionSite::PackagedInterface {
741 namespace: "ns".to_string(),
742 package: "name".to_string(),
743 interface: "interface".to_string(),
744 version: None,
745 },
746 function: ParsedFunctionReference::RawResourceDrop {
747 resource: "resource1".to_string()
748 },
749 }
750 );
751 }
752
753 #[test]
754 fn parse_function_name_drop() {
755 let parsed = ParsedFunctionName::parse("ns:name/interface.{[drop]resource1}")
756 .expect("Parsing failed");
757 assert_eq!(
758 parsed.site().interface_name(),
759 Some("ns:name/interface".to_string())
760 );
761 assert_eq!(
762 parsed.function().function_name(),
763 "[drop]resource1".to_string()
764 );
765 assert_eq!(
766 parsed,
767 ParsedFunctionName {
768 site: ParsedFunctionSite::PackagedInterface {
769 namespace: "ns".to_string(),
770 package: "name".to_string(),
771 interface: "interface".to_string(),
772 version: None,
773 },
774 function: ParsedFunctionReference::RawResourceDrop {
775 resource: "resource1".to_string()
776 },
777 }
778 );
779 }
780
781 fn round_trip_function_name_parse(input: &str) {
782 let parsed = ParsedFunctionName::parse(input)
783 .unwrap_or_else(|_| panic!("Input Parsing failed for {input}"));
784 let parsed_written =
785 ParsedFunctionName::parse(parsed.to_string()).expect("Round-trip parsing failed");
786 assert_eq!(parsed, parsed_written);
787 }
788
789 #[test]
790 fn test_parsed_function_name_display() {
791 round_trip_function_name_parse("run-example");
792 round_trip_function_name_parse("interface.{fn1}");
793 round_trip_function_name_parse("wasi:cli/run@0.2.0.{run}");
794 round_trip_function_name_parse("ns:name/interface.{resource1.new}");
795 round_trip_function_name_parse("ns:name/interface.{[constructor]resource1}");
796 round_trip_function_name_parse("ns:name/interface.{resource1.do-something}");
797 round_trip_function_name_parse("ns:name/interface.{[static]resource1.do-something-static}");
798 round_trip_function_name_parse("ns:name/interface.{resource1.drop}");
799 round_trip_function_name_parse("ns:name/interface.{[drop]resource1}");
800 }
801}