1use alloc::{borrow::Cow, vec::Vec};
4
5use crate::{
6 Parser, WasmValue,
7 ast::Node,
8 lex::Keyword,
9 parser::{ParserError, ParserErrorKind},
10};
11
12#[derive(Clone, Debug)]
14pub struct UntypedValue<'source> {
15 source: Cow<'source, str>,
16 node: Node,
17}
18
19impl<'source> UntypedValue<'source> {
20 pub(crate) fn new(source: impl Into<Cow<'source, str>>, node: Node) -> Self {
21 Self {
22 source: source.into(),
23 node,
24 }
25 }
26
27 pub fn parse(source: &'source str) -> Result<Self, ParserError> {
29 let mut parser = Parser::new(source);
30 let val = parser.parse_raw_value()?;
31 parser.finish()?;
32 Ok(val)
33 }
34
35 pub fn into_owned(self) -> UntypedValue<'static> {
37 UntypedValue::new(self.source.into_owned(), self.node)
38 }
39
40 pub fn source(&self) -> &str {
42 &self.source
43 }
44
45 pub fn node(&self) -> &Node {
47 &self.node
48 }
49
50 pub fn to_wasm_value<V: WasmValue>(&self, ty: &V::Type) -> Result<V, ParserError> {
52 self.node.to_wasm_value(ty, &self.source)
53 }
54}
55
56impl core::fmt::Display for UntypedValue<'_> {
57 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
58 fmt_node(f, &self.node, &self.source)
59 }
60}
61
62pub struct UntypedFuncCall<'source> {
66 source: Cow<'source, str>,
67 name: logos::Span,
68 params: Option<Node>,
69}
70
71impl<'source> UntypedFuncCall<'source> {
72 pub(crate) fn new(
73 source: impl Into<Cow<'source, str>>,
74 name: logos::Span,
75 params: Option<Node>,
76 ) -> Self {
77 Self {
78 source: source.into(),
79 name,
80 params,
81 }
82 }
83
84 pub fn parse(source: &'source str) -> Result<Self, ParserError> {
86 crate::parser::parse_raw_func_call(source)
87 }
88
89 pub fn into_owned(self) -> UntypedFuncCall<'static> {
91 UntypedFuncCall::new(
92 self.source.into_owned(),
93 self.name.clone(),
94 self.params.clone(),
95 )
96 }
97
98 pub fn source(&self) -> &str {
100 &self.source
101 }
102
103 pub fn params_node(&self) -> Option<&Node> {
107 self.params.as_ref()
108 }
109
110 pub fn name(&self) -> &str {
112 &self.source[self.name.clone()]
113 }
114
115 #[cfg(feature = "wit")]
117 pub fn item_name(&self) -> Result<wit_parser::ItemName, anyhow::Error> {
118 use core::str::FromStr;
119 wit_parser::ItemName::from_str(self.name())
120 }
121
122 pub fn to_wasm_params<'types, V: WasmValue + 'static>(
127 &self,
128 types: impl IntoIterator<Item = &'types V::Type, IntoIter: ExactSizeIterator>,
129 ) -> Result<Vec<V>, ParserError> {
130 match &self.params {
131 Some(params) => params.to_wasm_params(types, self.source()),
132 None => {
133 let num_params = types.into_iter().len();
134 if num_params > 0 {
135 return Err(ParserError::with_detail(
136 ParserErrorKind::InvalidParams,
137 self.name.clone(),
138 alloc::format!("no params provided, but {num_params} required"),
139 ));
140 }
141 Ok(Vec::new())
142 }
143 }
144 }
145}
146
147impl core::fmt::Display for UntypedFuncCall<'_> {
148 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
149 f.write_str(&self.source[self.name.clone()])?;
150 match &self.params {
151 Some(params) => fmt_node(f, params, &self.source),
152 None => f.write_str("()"),
153 }
154 }
155}
156
157fn fmt_node(f: &mut impl core::fmt::Write, node: &Node, src: &str) -> core::fmt::Result {
158 use crate::ast::NodeType::*;
159 match node.ty() {
160 BoolTrue | BoolFalse | Number | Char | String | MultilineString | Label => {
161 f.write_str(node.slice(src))
162 }
163 Tuple => fmt_sequence(f, '(', ')', node.as_tuple()?, src),
164 List => fmt_sequence(f, '[', ']', node.as_list()?, src),
165 TupleSet => {
166 let entries = node.as_map()?;
167 if entries.len() == 0 {
168 return f.write_str("{:}");
169 }
170 f.write_char('{')?;
171 for (idx, (key, value)) in entries.enumerate() {
172 if idx != 0 {
173 f.write_str(", ")?;
174 }
175 fmt_node(f, key, src)?;
176 f.write_str(": ")?;
177 fmt_node(f, value, src)?;
178 }
179 f.write_char('}')
180 }
181 EmptySet => f.write_str("{}"),
182 VariantWithPayload => {
183 let (label, payload) = node.as_variant(src)?;
184 if Keyword::decode(label).is_some() {
185 f.write_char('%')?;
186 }
187 fmt_variant(f, label, payload, src)
188 }
189 OptionSome => fmt_variant(f, "some", node.as_option()?, src),
190 OptionNone => fmt_variant(f, "none", None, src),
191 ResultOk => fmt_variant(f, "ok", node.as_result()?.unwrap(), src),
192 ResultErr => fmt_variant(f, "err", node.as_result()?.unwrap_err(), src),
193 Flags => {
194 f.write_char('{')?;
195 for (idx, flag) in node.as_flags(src)?.enumerate() {
196 if idx != 0 {
197 f.write_str(", ")?;
198 }
199 f.write_str(flag)?;
200 }
201 f.write_char('}')
202 }
203 }
204}
205
206fn fmt_sequence<'a>(
207 f: &mut impl core::fmt::Write,
208 open: char,
209 close: char,
210 nodes: impl Iterator<Item = &'a Node>,
211 src: &str,
212) -> core::fmt::Result {
213 f.write_char(open)?;
214 for (idx, node) in nodes.enumerate() {
215 if idx != 0 {
216 f.write_str(", ")?;
217 }
218 fmt_node(f, node, src)?;
219 }
220 f.write_char(close)
221}
222
223fn fmt_variant(
224 f: &mut impl core::fmt::Write,
225 case: &str,
226 payload: Option<&Node>,
227 src: &str,
228) -> core::fmt::Result {
229 f.write_str(case)?;
230 if let Some(node) = payload {
231 f.write_char('(')?;
232 fmt_node(f, node, src)?;
233 f.write_char(')')?;
234 }
235 Ok(())
236}
237
238impl From<ParserError> for core::fmt::Error {
239 fn from(_: ParserError) -> Self {
240 Self
241 }
242}
243
244#[cfg(test)]
245mod tests {
246 use alloc::string::ToString;
247
248 use super::*;
249
250 #[test]
251 fn round_trips() {
252 for src in [
253 "true",
254 "18446744073709551616",
255 "-9223372036854775808",
256 "[-3.1415, 0, inf, nan, -inf]",
257 "['☃', '\\n']",
258 r#""☃☃☃""#,
259 "(1, false)",
260 "{:}",
261 "{code: red}",
262 "left(1)",
263 "[some(1), none]",
264 "[ok(1), err(2)]",
265 "[ok, err]",
266 "%inf(inf)",
267 "%some",
268 "%none(none)",
269 r#"{"a": 1, "b": {2: {true: '3'}}, "a": 4}"#,
270 "{-1: some(x), 0: none, 1: ok(y)}",
271 ] {
272 let val = UntypedValue::parse(src).unwrap();
273 let encoded = val.to_string();
274 assert_eq!(encoded, src);
275 }
276 }
277}