1use std::borrow::Cow;
4
5use crate::{Parser, WasmValue, ast::Node, lex::Keyword, parser::ParserError};
6
7#[derive(Clone, Debug)]
9pub struct UntypedValue<'source> {
10 source: Cow<'source, str>,
11 node: Node,
12}
13
14impl<'source> UntypedValue<'source> {
15 pub(crate) fn new(source: impl Into<Cow<'source, str>>, node: Node) -> Self {
16 Self {
17 source: source.into(),
18 node,
19 }
20 }
21
22 pub fn parse(source: &'source str) -> Result<Self, ParserError> {
24 let mut parser = Parser::new(source);
25 let val = parser.parse_raw_value()?;
26 parser.finish()?;
27 Ok(val)
28 }
29
30 pub fn into_owned(self) -> UntypedValue<'static> {
32 UntypedValue::new(self.source.into_owned(), self.node)
33 }
34
35 pub fn source(&self) -> &str {
37 &self.source
38 }
39
40 pub fn node(&self) -> &Node {
42 &self.node
43 }
44
45 pub fn to_wasm_value<V: WasmValue>(&self, ty: &V::Type) -> Result<V, ParserError> {
47 self.node.to_wasm_value(ty, &self.source)
48 }
49}
50
51impl std::fmt::Display for UntypedValue<'_> {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 fmt_node(f, &self.node, &self.source)
54 }
55}
56
57pub struct UntypedFuncCall<'source> {
61 source: Cow<'source, str>,
62 name: Node,
63 params: Option<Node>,
64}
65
66impl<'source> UntypedFuncCall<'source> {
67 pub(crate) fn new(
68 source: impl Into<Cow<'source, str>>,
69 name: Node,
70 params: Option<Node>,
71 ) -> Self {
72 Self {
73 source: source.into(),
74 name,
75 params,
76 }
77 }
78
79 pub fn parse(source: &'source str) -> Result<Self, ParserError> {
81 let mut parser = Parser::new(source);
82 let call = parser.parse_raw_func_call()?;
83 parser.finish()?;
84 Ok(call)
85 }
86
87 pub fn into_owned(self) -> UntypedFuncCall<'static> {
89 UntypedFuncCall::new(
90 self.source.into_owned(),
91 self.name.clone(),
92 self.params.clone(),
93 )
94 }
95
96 pub fn source(&self) -> &str {
98 &self.source
99 }
100
101 pub fn name_node(&self) -> &Node {
103 &self.name
104 }
105
106 pub fn params_node(&self) -> Option<&Node> {
110 self.params.as_ref()
111 }
112
113 pub fn name(&self) -> &str {
115 self.name.slice(&self.source)
116 }
117
118 pub fn to_wasm_params<'types, V: WasmValue + 'static>(
123 &self,
124 types: impl IntoIterator<Item = &'types V::Type>,
125 ) -> Result<Vec<V>, ParserError> {
126 match &self.params {
127 Some(params) => params.to_wasm_params(types, self.source()),
128 None => Ok(vec![]),
129 }
130 }
131}
132
133impl std::fmt::Display for UntypedFuncCall<'_> {
134 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135 f.write_str(self.name.slice(&self.source))?;
136 match &self.params {
137 Some(params) => fmt_node(f, params, &self.source),
138 None => f.write_str("()"),
139 }
140 }
141}
142
143fn fmt_node(f: &mut impl std::fmt::Write, node: &Node, src: &str) -> std::fmt::Result {
144 use crate::ast::NodeType::*;
145 match node.ty() {
146 BoolTrue | BoolFalse | Number | Char | String | MultilineString | Label => {
147 f.write_str(node.slice(src))
148 }
149 Tuple => fmt_sequence(f, '(', ')', node.as_tuple()?, src),
150 List => fmt_sequence(f, '[', ']', node.as_list()?, src),
151 Record => {
152 let fields = node.as_record(src)?;
153 if fields.len() == 0 {
154 return f.write_str("{:}");
155 }
156 f.write_char('{')?;
157 for (idx, (name, value)) in node.as_record(src)?.enumerate() {
158 if idx != 0 {
159 f.write_str(", ")?;
160 }
161 write!(f, "{name}: ")?;
162 fmt_node(f, value, src)?;
163 }
164 f.write_char('}')
165 }
166 VariantWithPayload => {
167 let (label, payload) = node.as_variant(src)?;
168 if Keyword::decode(label).is_some() {
169 f.write_char('%')?;
170 }
171 fmt_variant(f, label, payload, src)
172 }
173 OptionSome => fmt_variant(f, "some", node.as_option()?, src),
174 OptionNone => fmt_variant(f, "none", None, src),
175 ResultOk => fmt_variant(f, "ok", node.as_result()?.unwrap(), src),
176 ResultErr => fmt_variant(f, "err", node.as_result()?.unwrap_err(), src),
177 Flags => {
178 f.write_char('{')?;
179 for (idx, flag) in node.as_flags(src)?.enumerate() {
180 if idx != 0 {
181 f.write_str(", ")?;
182 }
183 f.write_str(flag)?;
184 }
185 f.write_char('}')
186 }
187 }
188}
189
190fn fmt_sequence<'a>(
191 f: &mut impl std::fmt::Write,
192 open: char,
193 close: char,
194 nodes: impl Iterator<Item = &'a Node>,
195 src: &str,
196) -> std::fmt::Result {
197 f.write_char(open)?;
198 for (idx, node) in nodes.enumerate() {
199 if idx != 0 {
200 f.write_str(", ")?;
201 }
202 fmt_node(f, node, src)?;
203 }
204 f.write_char(close)
205}
206
207fn fmt_variant(
208 f: &mut impl std::fmt::Write,
209 case: &str,
210 payload: Option<&Node>,
211 src: &str,
212) -> std::fmt::Result {
213 f.write_str(case)?;
214 if let Some(node) = payload {
215 f.write_char('(')?;
216 fmt_node(f, node, src)?;
217 f.write_char(')')?;
218 }
219 Ok(())
220}
221
222impl From<ParserError> for std::fmt::Error {
223 fn from(_: ParserError) -> Self {
224 Self
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231
232 #[test]
233 fn round_trips() {
234 for src in [
235 "true",
236 "18446744073709551616",
237 "-9223372036854775808",
238 "[-3.1415, 0, inf, nan, -inf]",
239 "['☃', '\\n']",
240 r#""☃☃☃""#,
241 "(1, false)",
242 "{:}",
243 "{code: red}",
244 "left(1)",
245 "[some(1), none]",
246 "[ok(1), err(2)]",
247 "[ok, err]",
248 "%inf(inf)",
249 "%some",
250 "%none(none)",
251 ] {
252 let val = UntypedValue::parse(src).unwrap();
253 let encoded = val.to_string();
254 assert_eq!(encoded, src);
255 }
256 }
257}