1use std::fmt;
8
9use backhopper_core::{Arity, FunctionName, Mfa, ModuleName};
10use serde::{Deserialize, Serialize};
11
12use crate::loc::Loc;
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
15pub struct FunctionSig {
16 pub name: FunctionName,
17 pub arity: Arity,
18}
19
20impl FunctionSig {
21 pub fn new(name: FunctionName, arity: Arity) -> Self {
22 Self { name, arity }
23 }
24}
25
26impl fmt::Display for FunctionSig {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 write!(f, "{}/{}", self.name, self.arity)
29 }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
33#[serde(tag = "ref", rename_all = "snake_case")]
34pub enum FunctionRef {
35 Concrete(Mfa),
36 UnresolvedModule {
37 function: FunctionName,
38 arity: Option<Arity>,
39 },
40 UnresolvedFunction {
41 module: ModuleName,
42 arity: Option<Arity>,
43 },
44 UnresolvedBoth {
45 arity: Option<Arity>,
46 },
47}
48
49impl FunctionRef {
50 pub fn as_concrete(&self) -> Option<&Mfa> {
51 if let FunctionRef::Concrete(mfa) = self {
52 Some(mfa)
53 } else {
54 None
55 }
56 }
57
58 pub fn module(&self) -> Option<&ModuleName> {
59 match self {
60 FunctionRef::Concrete(m) => Some(&m.module),
61 FunctionRef::UnresolvedFunction { module, .. } => Some(module),
62 _ => None,
63 }
64 }
65
66 pub fn arity(&self) -> Option<Arity> {
67 match self {
68 FunctionRef::Concrete(m) => Some(m.arity),
69 FunctionRef::UnresolvedModule { arity, .. }
70 | FunctionRef::UnresolvedFunction { arity, .. }
71 | FunctionRef::UnresolvedBoth { arity } => *arity,
72 }
73 }
74}
75
76impl fmt::Display for FunctionRef {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 match self {
79 FunctionRef::Concrete(mfa) => write!(f, "{mfa}"),
80 FunctionRef::UnresolvedModule { function, arity } => {
81 write!(f, "'$M_EXPR':{}/{}", function, fmt_arity(*arity))
82 }
83 FunctionRef::UnresolvedFunction { module, arity } => {
84 write!(f, "{}:'$F_EXPR'/{}", module, fmt_arity(*arity))
85 }
86 FunctionRef::UnresolvedBoth { arity } => {
87 write!(f, "'$M_EXPR':'$F_EXPR'/{}", fmt_arity(*arity))
88 }
89 }
90 }
91}
92
93fn fmt_arity(a: Option<Arity>) -> String {
94 match a {
95 Some(a) => a.to_string(),
96 None => "-1".to_string(),
97 }
98}
99
100#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
101pub enum LocalFunctionRef {
102 Concrete {
103 function: FunctionName,
104 arity: Arity,
105 },
106 Unresolved {
107 arity: Option<Arity>,
108 },
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
112#[serde(tag = "target", rename_all = "snake_case")]
113pub enum CallTarget {
114 External(FunctionRef),
115 Local(LocalFunctionRef),
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
119#[serde(rename_all = "snake_case")]
120#[non_exhaustive]
121pub enum CallKind {
122 Direct,
123 Apply,
124 Spawn,
125 FunRef,
126}
127
128#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
129pub struct UnresolvedCallSite {
130 pub caller: Mfa,
131 pub partial: FunctionRef,
132 pub kind: CallKind,
133 pub loc: Loc,
134}