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 Record => {
166 let fields = node.as_record(src)?;
167 if fields.len() == 0 {
168 return f.write_str("{:}");
169 }
170 f.write_char('{')?;
171 for (idx, (name, value)) in node.as_record(src)?.enumerate() {
172 if idx != 0 {
173 f.write_str(", ")?;
174 }
175 write!(f, "{name}: ")?;
176 fmt_node(f, value, src)?;
177 }
178 f.write_char('}')
179 }
180 VariantWithPayload => {
181 let (label, payload) = node.as_variant(src)?;
182 if Keyword::decode(label).is_some() {
183 f.write_char('%')?;
184 }
185 fmt_variant(f, label, payload, src)
186 }
187 OptionSome => fmt_variant(f, "some", node.as_option()?, src),
188 OptionNone => fmt_variant(f, "none", None, src),
189 ResultOk => fmt_variant(f, "ok", node.as_result()?.unwrap(), src),
190 ResultErr => fmt_variant(f, "err", node.as_result()?.unwrap_err(), src),
191 Flags => {
192 f.write_char('{')?;
193 for (idx, flag) in node.as_flags(src)?.enumerate() {
194 if idx != 0 {
195 f.write_str(", ")?;
196 }
197 f.write_str(flag)?;
198 }
199 f.write_char('}')
200 }
201 }
202}
203
204fn fmt_sequence<'a>(
205 f: &mut impl core::fmt::Write,
206 open: char,
207 close: char,
208 nodes: impl Iterator<Item = &'a Node>,
209 src: &str,
210) -> core::fmt::Result {
211 f.write_char(open)?;
212 for (idx, node) in nodes.enumerate() {
213 if idx != 0 {
214 f.write_str(", ")?;
215 }
216 fmt_node(f, node, src)?;
217 }
218 f.write_char(close)
219}
220
221fn fmt_variant(
222 f: &mut impl core::fmt::Write,
223 case: &str,
224 payload: Option<&Node>,
225 src: &str,
226) -> core::fmt::Result {
227 f.write_str(case)?;
228 if let Some(node) = payload {
229 f.write_char('(')?;
230 fmt_node(f, node, src)?;
231 f.write_char(')')?;
232 }
233 Ok(())
234}
235
236impl From<ParserError> for core::fmt::Error {
237 fn from(_: ParserError) -> Self {
238 Self
239 }
240}
241
242#[cfg(test)]
243mod tests {
244 use alloc::string::ToString;
245
246 use super::*;
247
248 #[test]
249 fn round_trips() {
250 for src in [
251 "true",
252 "18446744073709551616",
253 "-9223372036854775808",
254 "[-3.1415, 0, inf, nan, -inf]",
255 "['☃', '\\n']",
256 r#""☃☃☃""#,
257 "(1, false)",
258 "{:}",
259 "{code: red}",
260 "left(1)",
261 "[some(1), none]",
262 "[ok(1), err(2)]",
263 "[ok, err]",
264 "%inf(inf)",
265 "%some",
266 "%none(none)",
267 ] {
268 let val = UntypedValue::parse(src).unwrap();
269 let encoded = val.to_string();
270 assert_eq!(encoded, src);
271 }
272 }
273}