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