Skip to main content

rulox_types/
primitive_methods.rs

1#![allow(clippy::redundant_pub_crate)]
2#![allow(clippy::unnecessary_wraps)]
3
4use crate::functions::LoxArgs;
5use crate::LoxError;
6use crate::LoxObject;
7use crate::LoxResult;
8use crate::LoxValue;
9use crate::MapKey;
10use crate::Shared;
11
12use std::collections::HashMap;
13
14pub(super) fn is_bool(args: LoxArgs) -> LoxResult {
15    Ok(LoxValue::Bool(matches!(
16        args.head.unwrap(),
17        LoxValue::Bool(_)
18    )))
19}
20
21pub(super) fn is_str(args: LoxArgs) -> LoxResult {
22    Ok(LoxValue::Bool(matches!(
23        args.head.unwrap(),
24        LoxValue::Str(_)
25    )))
26}
27
28pub(super) fn is_num(args: LoxArgs) -> LoxResult {
29    Ok(LoxValue::Bool(matches!(
30        args.head.unwrap(),
31        LoxValue::Num(_)
32    )))
33}
34
35pub(super) fn is_arr(args: LoxArgs) -> LoxResult {
36    Ok(LoxValue::Bool(matches!(
37        args.head.unwrap(),
38        LoxValue::Arr(_)
39    )))
40}
41
42pub(super) fn is_function(args: LoxArgs) -> LoxResult {
43    Ok(LoxValue::Bool(matches!(
44        args.head.unwrap(),
45        LoxValue::BoundMethod(_, _) | LoxValue::Coroutine(_) | LoxValue::PrimitiveMethod(_, _)
46    )))
47}
48
49pub(super) fn is_class(args: LoxArgs) -> LoxResult {
50    Ok(LoxValue::Bool(matches!(
51        args.head.unwrap(),
52        LoxValue::Class(_)
53    )))
54}
55
56pub(super) fn is_map(args: LoxArgs) -> LoxResult {
57    Ok(LoxValue::Bool(matches!(
58        args.head.unwrap(),
59        LoxValue::Map(_)
60    )))
61}
62
63pub(super) fn is_bytes(args: LoxArgs) -> LoxResult {
64    Ok(LoxValue::Bool(matches!(
65        args.head.unwrap(),
66        LoxValue::Bytes(_)
67    )))
68}
69
70pub(super) fn is_error(args: LoxArgs) -> LoxResult {
71    Ok(LoxValue::Bool(matches!(
72        args.head.unwrap(),
73        LoxValue::Error(_)
74    )))
75}
76
77pub(super) fn is_nil(args: LoxArgs) -> LoxResult {
78    Ok(LoxValue::Bool(matches!(args.head.unwrap(), LoxValue::Nil)))
79}
80
81macro_rules! default_collection {
82    ( $name:ident, $inner:ty, $loxvalue_variant:ident, $( $index:tt )+ ) => {
83        #[derive(Debug, Clone)]
84        struct $name($inner, LoxValue);
85
86        impl LoxObject for $name {
87            fn type_name() -> String
88            where
89                Self: Sized,
90            {
91                stringify!($name).to_string()
92            }
93
94            fn get(
95                &self,
96                _this: Shared<dyn LoxObject>,
97                key: &str,
98            ) -> Result<LoxValue, Option<LoxError>> {
99                Ok(LoxValue::$loxvalue_variant(self.0.clone()).get(key)?)
100            }
101
102            fn set(
103                &mut self,
104                _this: Shared<dyn LoxObject>,
105                key: &str,
106                value: LoxValue,
107            ) -> Result<(), Option<LoxError>> {
108                LoxValue::$loxvalue_variant(self.0.clone()).set(key, value)?;
109                Ok(())
110            }
111
112            $( $index )+
113
114            fn index_set(
115                &mut self,
116                key: LoxValue,
117                value: LoxValue,
118            ) -> Result<(), LoxError> {
119                LoxValue::$loxvalue_variant(self.0.clone()).index_set(key, value)
120            }
121        }
122    };
123}
124
125pub(super) fn set_default(mut args: LoxArgs) -> LoxResult {
126    match args.head.clone().unwrap() {
127        LoxValue::Arr(arr) => {
128            default_collection!(
129                DefaultArray,
130                Shared<Vec<LoxValue>>,
131                Arr,
132                fn index(&self, key: LoxValue) -> Result<LoxValue, LoxError> {
133                    self.0
134                        .read()
135                        .get(usize::try_from(key)?)
136                        .map_or_else(|| self.1.call([].into()), |value| Ok(value.clone()))
137                }
138            );
139
140            Ok(LoxValue::external(DefaultArray(
141                arr,
142                args.drain().next().unwrap(),
143            )))
144        }
145        LoxValue::Map(map) => {
146            default_collection!(
147                DefaultMap,
148                Shared<HashMap<MapKey, LoxValue>>,
149                Map,
150                fn index(&self, key: LoxValue) -> Result<LoxValue, LoxError> {
151                    self.0
152                        .read()
153                        .get(&MapKey::verify_key(key)?)
154                        .map_or_else(|| self.1.call([].into()), |value| Ok(value.clone()))
155                }
156            );
157
158            Ok(LoxValue::external(DefaultMap(
159                map,
160                args.drain().next().unwrap(),
161            )))
162        }
163        _ => Err(LoxError::type_error(
164            format!("'{}' has no attribute 'set_default'", args.head.unwrap()).into(),
165        )),
166    }
167}