nimbus_fml/backends/swift/gen_structs/
primitives.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use std::fmt::Display;
6
7use super::common::{self, code_type};
8use crate::backends::{CodeOracle, CodeType, LiteralRenderer, VariablesType};
9use crate::intermediate_representation::Literal;
10
11pub(crate) struct BooleanCodeType;
12
13impl CodeType for BooleanCodeType {
14    /// The language specific label used to reference this type. This will be used in
15    /// method signatures and property declarations.
16    fn type_label(&self, _oracle: &dyn CodeOracle) -> String {
17        "Bool".into()
18    }
19
20    fn property_getter(
21        &self,
22        oracle: &dyn CodeOracle,
23        vars: &dyn Display,
24        prop: &dyn Display,
25        default: &dyn Display,
26    ) -> String {
27        code_type::property_getter(self, oracle, vars, prop, default)
28    }
29
30    fn value_getter(
31        &self,
32        oracle: &dyn CodeOracle,
33        vars: &dyn Display,
34        prop: &dyn Display,
35    ) -> String {
36        code_type::value_getter(self, oracle, vars, prop)
37    }
38
39    fn value_mapper(&self, oracle: &dyn CodeOracle) -> Option<String> {
40        code_type::value_mapper(self, oracle)
41    }
42
43    /// The name of the type as it's represented in the `Variables` object.
44    /// The string return may be used to combine with an identifier, e.g. a `Variables` method name.
45    fn variables_type(&self, _oracle: &dyn CodeOracle) -> VariablesType {
46        VariablesType::Bool
47    }
48
49    /// A representation of the given literal for this type.
50    /// N.B. `Literal` is aliased from `serde_json::Value`.
51    fn literal(
52        &self,
53        _oracle: &dyn CodeOracle,
54        _ctx: &dyn Display,
55        _renderer: &dyn LiteralRenderer,
56        literal: &Literal,
57    ) -> String {
58        match literal {
59            serde_json::Value::Bool(v) => {
60                if *v {
61                    "true".to_string()
62                } else {
63                    "false".to_string()
64                }
65            }
66            _ => unreachable!("Expecting a boolean"),
67        }
68    }
69}
70
71pub(crate) struct IntCodeType;
72
73impl CodeType for IntCodeType {
74    /// The language specific label used to reference this type. This will be used in
75    /// method signatures and property declarations.
76    fn type_label(&self, _oracle: &dyn CodeOracle) -> String {
77        "Int".into()
78    }
79
80    fn property_getter(
81        &self,
82        oracle: &dyn CodeOracle,
83        vars: &dyn Display,
84        prop: &dyn Display,
85        default: &dyn Display,
86    ) -> String {
87        code_type::property_getter(self, oracle, vars, prop, default)
88    }
89
90    fn value_getter(
91        &self,
92        oracle: &dyn CodeOracle,
93        vars: &dyn Display,
94        prop: &dyn Display,
95    ) -> String {
96        code_type::value_getter(self, oracle, vars, prop)
97    }
98
99    fn value_mapper(&self, oracle: &dyn CodeOracle) -> Option<String> {
100        code_type::value_mapper(self, oracle)
101    }
102
103    /// The name of the type as it's represented in the `Variables` object.
104    /// The string return may be used to combine with an identifier, e.g. a `Variables` method name.
105    fn variables_type(&self, _oracle: &dyn CodeOracle) -> VariablesType {
106        VariablesType::Int
107    }
108
109    /// A representation of the given literal for this type.
110    /// N.B. `Literal` is aliased from `serde_json::Value`.
111    fn literal(
112        &self,
113        _oracle: &dyn CodeOracle,
114        _ctx: &dyn Display,
115        _renderer: &dyn LiteralRenderer,
116        literal: &Literal,
117    ) -> String {
118        match literal {
119            serde_json::Value::Number(v) => {
120                format!("{:.0}", v)
121            }
122            _ => unreachable!("Expecting a number"),
123        }
124    }
125}
126
127pub(crate) struct StringCodeType;
128
129impl CodeType for StringCodeType {
130    /// The language specific label used to reference this type. This will be used in
131    /// method signatures and property declarations.
132    fn type_label(&self, _oracle: &dyn CodeOracle) -> String {
133        "String".into()
134    }
135
136    fn property_getter(
137        &self,
138        oracle: &dyn CodeOracle,
139        vars: &dyn Display,
140        prop: &dyn Display,
141        default: &dyn Display,
142    ) -> String {
143        code_type::property_getter(self, oracle, vars, prop, default)
144    }
145
146    fn value_getter(
147        &self,
148        oracle: &dyn CodeOracle,
149        vars: &dyn Display,
150        prop: &dyn Display,
151    ) -> String {
152        code_type::value_getter(self, oracle, vars, prop)
153    }
154
155    fn value_mapper(&self, oracle: &dyn CodeOracle) -> Option<String> {
156        code_type::value_mapper(self, oracle)
157    }
158
159    /// The name of the type as it's represented in the `Variables` object.
160    /// The string return may be used to combine with an identifier, e.g. a `Variables` method name.
161    fn variables_type(&self, _oracle: &dyn CodeOracle) -> VariablesType {
162        VariablesType::String
163    }
164
165    /// A representation of the given literal for this type.
166    /// N.B. `Literal` is aliased from `serde_json::Value`.
167    fn literal(
168        &self,
169        _oracle: &dyn CodeOracle,
170        _ctx: &dyn Display,
171        _renderer: &dyn LiteralRenderer,
172        literal: &Literal,
173    ) -> String {
174        match literal {
175            serde_json::Value::String(v) => common::quoted(v),
176            _ => unreachable!("Expecting a string"),
177        }
178    }
179}
180
181#[cfg(test)]
182mod unit_tests {
183
184    use serde_json::json;
185
186    use crate::backends::TypeIdentifier;
187
188    use super::*;
189
190    struct TestCodeOracle;
191    impl CodeOracle for TestCodeOracle {
192        fn find(&self, _type_: &TypeIdentifier) -> Box<dyn CodeType> {
193            unreachable!()
194        }
195    }
196
197    struct TestRenderer;
198    impl LiteralRenderer for TestRenderer {
199        fn literal(
200            &self,
201            _oracle: &dyn CodeOracle,
202            _typ: &TypeIdentifier,
203            _value: &Literal,
204            _ctx: &dyn Display,
205        ) -> String {
206            unreachable!()
207        }
208    }
209
210    fn oracle() -> Box<dyn CodeOracle> {
211        Box::new(TestCodeOracle) as Box<dyn CodeOracle>
212    }
213
214    fn bool_type() -> Box<dyn CodeType> {
215        Box::new(BooleanCodeType) as Box<dyn CodeType>
216    }
217
218    fn string_type() -> Box<dyn CodeType> {
219        Box::new(StringCodeType) as Box<dyn CodeType>
220    }
221
222    fn int_type() -> Box<dyn CodeType> {
223        Box::new(IntCodeType) as Box<dyn CodeType>
224    }
225
226    #[test]
227    fn test_type_label() {
228        let oracle = &*oracle();
229
230        let ct = bool_type();
231        assert_eq!("Bool".to_string(), ct.type_label(oracle));
232
233        let ct = string_type();
234        assert_eq!("String".to_string(), ct.type_label(oracle));
235
236        let ct = int_type();
237        assert_eq!("Int".to_string(), ct.type_label(oracle));
238    }
239
240    #[test]
241    fn test_literal() {
242        let oracle = &*oracle();
243        let finder = &TestRenderer;
244        let ctx = String::from("ctx");
245        let ct = bool_type();
246        assert_eq!(
247            "true".to_string(),
248            ct.literal(oracle, &ctx, finder, &json!(true))
249        );
250        assert_eq!(
251            "false".to_string(),
252            ct.literal(oracle, &ctx, finder, &json!(false))
253        );
254
255        let ct = string_type();
256        assert_eq!(
257            r#""no""#.to_string(),
258            ct.literal(oracle, &ctx, finder, &json!("no"))
259        );
260        assert_eq!(
261            r#""yes""#.to_string(),
262            ct.literal(oracle, &ctx, finder, &json!("yes"))
263        );
264
265        let ct = int_type();
266        assert_eq!("1".to_string(), ct.literal(oracle, &ctx, finder, &json!(1)));
267        assert_eq!("2".to_string(), ct.literal(oracle, &ctx, finder, &json!(2)));
268    }
269
270    #[test]
271    fn test_get_value() {
272        let oracle = &*oracle();
273
274        let ct = bool_type();
275        assert_eq!(
276            r#"v.getBool("the-property")"#.to_string(),
277            ct.value_getter(oracle, &"v", &"the-property")
278        );
279
280        let ct = string_type();
281        assert_eq!(
282            r#"v.getString("the-property")"#.to_string(),
283            ct.value_getter(oracle, &"v", &"the-property")
284        );
285
286        let ct = int_type();
287        assert_eq!(
288            r#"v.getInt("the-property")"#.to_string(),
289            ct.value_getter(oracle, &"v", &"the-property")
290        );
291    }
292}