sphinx/runtime/function/
signature.rs1use core::fmt;
2use crate::language::Access;
3use crate::runtime::Variant;
4use crate::runtime::strings::{StringValue, StringSymbol, StrBuffer, STRING_TABLE};
5use crate::runtime::errors::{ExecResult, RuntimeError};
6
7
8#[derive(Clone, Debug)]
9pub struct Signature {
10 display: String,
11 name: Option<StringSymbol>,
12 required: Box<[Parameter]>,
13 default: Box<[Parameter]>,
14 variadic: Option<Parameter>,
15}
16
17impl Signature {
18 pub fn new(name: Option<impl Into<StringSymbol>>, required: Vec<Parameter>, default: Vec<Parameter>, variadic: Option<Parameter>) -> Self {
19 let name = name.map(|name| name.into());
20
21 let display = format_signature(name.as_ref(), &required, &default, variadic.as_ref());
23
24 Self {
25 name,
26 display,
27 required: required.into_boxed_slice(),
28 default: default.into_boxed_slice(),
29 variadic,
30 }
31 }
32
33 pub fn name(&self) -> Option<StringSymbol> { self.name }
34
35 pub fn fmt_signature(&self) -> StringValue {
36 StringValue::new_uninterned(&self.display)
37 }
38
39 pub fn fmt_name(&self) -> StringValue {
40 fn write_name(name: Option<StringSymbol>, fmt: &mut impl fmt::Write) -> fmt::Result {
41 if let Some(name) = name {
42 write!(fmt, "function \"{}()\"", name)
43 } else {
44 fmt.write_str("anonymous function")
45 }
46 }
47
48 let mut buf = StrBuffer::<64>::new();
49 if write_name(self.name, &mut buf).is_ok() {
50 StringValue::new_maybe_interned(buf)
51 } else {
52 let mut buf = String::new();
53 write_name(self.name, &mut buf).ok();
54 StringValue::new_maybe_interned(buf)
55 }
56 }
57
58
59 pub fn required(&self) -> &[Parameter] { &self.required }
60 pub fn default(&self) -> &[Parameter] { &self.default }
61 pub fn variadic(&self) -> Option<&Parameter> { self.variadic.as_ref() }
62
63 pub fn min_arity(&self) -> usize {
64 self.required.len()
65 }
66
67 pub fn max_arity(&self) -> Option<usize> {
68 if self.variadic().is_some() { None }
69 else { Some(self.required.len() + self.default.len()) }
70 }
71
72 pub fn check_args(&self, args: &[Variant]) -> ExecResult<()> {
73 if args.len() < self.required.len() {
74 return Err(RuntimeError::missing_arguments(self, args.len()))
75 }
76
77 if matches!(self.max_arity(), Some(max_arity) if args.len() > max_arity) {
78 return Err(RuntimeError::too_many_arguments(self, args.len()))
79 }
80
81 Ok(())
82 }
83
84 pub fn param_count(&self) -> usize {
85 self.required.len()
86 + self.default.len()
87 + usize::from(self.variadic.is_some())
88 }
89
90 pub fn arg_len(&self) -> usize {
92 self.required.len() + self.default.len()
93 }
94
95 pub fn bind_args<'a>(&self, args: &'a [Variant], defaults: &'a [Variant], argbuf: &'a mut [Variant]) -> BoundArgs<'a> {
98 debug_assert!(args.len() >= self.required.len());
99 debug_assert!(argbuf.len() == self.arg_len());
100 debug_assert!(defaults.len() == self.default.len());
101
102 let mut arg_idx = 0;
103 for _ in self.required.iter() {
104 argbuf[arg_idx] = args[arg_idx];
105 arg_idx += 1;
106 }
107
108 for (default_idx, _) in self.default.iter().enumerate() {
109 if arg_idx < args.len() {
110 argbuf[arg_idx] = args[arg_idx];
111 } else {
112 argbuf[arg_idx] = defaults[default_idx];
113 }
114 arg_idx += 1;
115 }
116
117 let varargs;
118 if arg_idx > args.len() {
119 varargs = &[] as &[Variant];
120 } else {
121 let (_, rest) = args.split_at(arg_idx);
122 varargs = rest;
123 }
124
125 BoundArgs {
126 args: argbuf,
127 varargs,
128 }
129 }
130}
131
132pub struct BoundArgs<'a> {
133 pub args: &'a [Variant],
134 pub varargs: &'a [Variant],
135}
136
137
138#[derive(Clone, Debug)]
139pub struct Parameter {
140 name: StringSymbol,
141 mode: Access,
142}
143
144impl Parameter {
145 pub fn new(name: impl Into<StringSymbol>, mode: Access) -> Self {
146 Self { name: name.into(), mode }
147 }
148
149 pub fn name(&self) -> &StringSymbol { &self.name }
150 pub fn mode(&self) -> &Access { &self.mode }
151}
152
153
154impl fmt::Display for Signature {
155 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
156 fmt.write_str(&self.display)
157 }
158}
159
160fn format_signature(name: Option<&StringSymbol>, required: &[Parameter], default: &[Parameter], variadic: Option<&Parameter>) -> String {
161 STRING_TABLE.with(|string_table| {
162 let string_table = string_table.borrow();
163
164 let name = name
165 .map(|name| string_table.resolve(name));
166
167 let mut parameters = Vec::new();
168
169 let required_names = required.iter()
170 .map(|param| string_table.resolve(¶m.name).to_string());
171 parameters.extend(required_names);
172
173 let default_names = default.iter()
174 .map(|param| string_table.resolve(¶m.name))
175 .map(|name| format!("{} = ...", name));
176 parameters.extend(default_names);
177
178 let variadic_name = variadic
179 .map(|param| string_table.resolve(¶m.name))
180 .map(|name| format!("{}...", name));
181 parameters.extend(variadic_name);
182
183 format!("fun {}({})", name.unwrap_or(""), parameters.join(", "))
184 })
185}