1#![warn(missing_docs)]
6
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11pub enum RubyValue {
12 Nil,
14 Boolean(bool),
16 Integer(i32),
18 Float(f64),
20 String(String),
22 Symbol(String),
24 Array(Vec<RubyValue>),
26 Hash(std::collections::HashMap<String, RubyValue>),
28 Object(String, std::collections::HashMap<String, RubyValue>),
30 Closure(usize), }
33
34impl RubyValue {
35 pub fn is_nil(&self) -> bool {
37 matches!(self, RubyValue::Nil)
38 }
39
40 pub fn to_i32(&self) -> i32 {
42 match self {
43 RubyValue::Integer(i) => *i,
44 RubyValue::Float(f) => *f as i32,
45 RubyValue::Boolean(b) => {
46 if *b {
47 1
48 }
49 else {
50 0
51 }
52 }
53 _ => 0,
54 }
55 }
56
57 pub fn to_f64(&self) -> f64 {
59 match self {
60 RubyValue::Float(f) => *f,
61 RubyValue::Integer(i) => *i as f64,
62 RubyValue::Boolean(b) => {
63 if *b {
64 1.0
65 }
66 else {
67 0.0
68 }
69 }
70 _ => 0.0,
71 }
72 }
73
74 pub fn to_bool(&self) -> bool {
76 match self {
77 RubyValue::Nil => false,
78 RubyValue::Boolean(b) => *b,
79 RubyValue::Integer(i) => *i != 0,
80 RubyValue::Float(f) => *f != 0.0,
81 _ => true,
82 }
83 }
84
85 pub fn to_string(&self) -> String {
87 match self {
88 RubyValue::String(s) => s.clone(),
89 RubyValue::Symbol(s) => s.clone(),
90 RubyValue::Integer(i) => i.to_string(),
91 RubyValue::Float(f) => f.to_string(),
92 RubyValue::Boolean(b) => b.to_string(),
93 RubyValue::Nil => "nil".to_string(),
94 _ => format!("{:?}", self),
95 }
96 }
97
98 pub fn mark(&self, marked: &mut std::collections::HashSet<*const RubyValue>) {
100 let ptr = self as *const RubyValue;
101 if marked.contains(&ptr) {
102 return;
103 }
104 marked.insert(ptr);
105
106 match self {
107 RubyValue::Array(values) => {
108 for value in values {
109 value.mark(marked);
110 }
111 }
112 RubyValue::Hash(map) => {
113 for (_, value) in map {
114 value.mark(marked);
115 }
116 }
117 RubyValue::Object(_, fields) => {
118 for (_, value) in fields {
119 value.mark(marked);
120 }
121 }
122 _ => {}
123 }
124 }
125
126 pub fn concat(&self, other: &RubyValue) -> RubyValue {
128 match (self, other) {
129 (RubyValue::String(s1), RubyValue::String(s2)) => RubyValue::String(format!("{}{}", s1, s2)),
130 (RubyValue::Array(arr1), RubyValue::Array(arr2)) => {
131 let mut result = arr1.clone();
132 result.extend(arr2.clone());
133 RubyValue::Array(result)
134 }
135 _ => RubyValue::String(format!("{}{}", self.to_string(), other.to_string())),
136 }
137 }
138
139 pub fn array_length(&self) -> Option<usize> {
141 match self {
142 RubyValue::Array(arr) => Some(arr.len()),
143 _ => None,
144 }
145 }
146
147 pub fn array_get(&self, index: usize) -> Option<RubyValue> {
149 match self {
150 RubyValue::Array(arr) => arr.get(index).cloned(),
151 _ => None,
152 }
153 }
154
155 pub fn array_set(&mut self, index: usize, value: RubyValue) -> Option<()> {
157 match self {
158 RubyValue::Array(arr) => {
159 if index < arr.len() {
160 arr[index] = value;
161 Some(())
162 }
163 else {
164 None
165 }
166 }
167 _ => None,
168 }
169 }
170
171 pub fn hash_get(&self, key: &str) -> Option<RubyValue> {
173 match self {
174 RubyValue::Hash(map) => map.get(key).cloned(),
175 _ => None,
176 }
177 }
178
179 pub fn hash_set(&mut self, key: &str, value: RubyValue) -> Option<()> {
181 match self {
182 RubyValue::Hash(map) => {
183 map.insert(key.to_string(), value);
184 Some(())
185 }
186 _ => None,
187 }
188 }
189
190 pub fn hash_keys(&self) -> Option<Vec<String>> {
192 match self {
193 RubyValue::Hash(map) => Some(map.keys().cloned().collect()),
194 _ => None,
195 }
196 }
197
198 pub fn hash_values(&self) -> Option<Vec<RubyValue>> {
200 match self {
201 RubyValue::Hash(map) => Some(map.values().cloned().collect()),
202 _ => None,
203 }
204 }
205
206 pub fn object_get(&self, field: &str) -> Option<RubyValue> {
208 match self {
209 RubyValue::Object(_, fields) => fields.get(field).cloned(),
210 _ => None,
211 }
212 }
213
214 pub fn object_set(&mut self, field: &str, value: RubyValue) -> Option<()> {
216 match self {
217 RubyValue::Object(_, fields) => {
218 fields.insert(field.to_string(), value);
219 Some(())
220 }
221 _ => None,
222 }
223 }
224}
225
226#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
228pub enum RubyError {
229 MethodNotFound(String),
231 ClassNotFound(String),
233 LexicalError(String),
235 SyntaxError(String),
237 RuntimeError(String),
239 TypeError(String),
241 ArgumentError(String),
243}
244
245impl std::fmt::Display for RubyError {
246 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
247 match self {
248 RubyError::MethodNotFound(name) => write!(f, "Method not found: {}", name),
249 RubyError::ClassNotFound(name) => write!(f, "Class not found: {}", name),
250 RubyError::LexicalError(msg) => write!(f, "Lexical error: {}", msg),
251 RubyError::SyntaxError(msg) => write!(f, "Syntax error: {}", msg),
252 RubyError::RuntimeError(msg) => write!(f, "Runtime error: {}", msg),
253 RubyError::TypeError(msg) => write!(f, "Type error: {}", msg),
254 RubyError::ArgumentError(msg) => write!(f, "Argument error: {}", msg),
255 }
256 }
257}
258
259impl std::error::Error for RubyError {}
260
261pub type RubyResult<T> = std::result::Result<T, RubyError>;