1mod exec;
2mod filesystem;
3mod parser;
4
5use crate::{exec::*, parser::parse_str};
6use proc_macro::{TokenStream, TokenTree};
7
8const USE_MSG_STR_CODE: &str =
9 "Wrong usage:\nUse ruby_code_str!(\"literal\")\nExample: ruby_code_str!(\"print 'something'\")";
10
11const USE_MSG_TYPE_CODE: &str =
12 "Wrong usage:\nUse ruby_code_to!(type \"literal\")\nExample: ruby_code_to!(i32 \"print 2+2\")";
13
14const USE_MSG_AST_CODE: &str =
15 "Wrong usage:\nUse ruby_code_ast!(\"literal\")\nExample: ruby_code_ast!(\"puts 'let a = 1;'\")";
16
17const USE_MSG_STR_FILE: &str =
18 "Wrong usage:\nUse ruby_code_str!(\"filepath\")\nExample: ruby_file_str!(\"print 'something'\")";
19
20const USE_MSG_TYPE_FILE: &str =
21 "Wrong usage:\nUse ruby_code_to!(type \"filepath\")\nExample: ruby_file_to!(i32 \"print 2+2\")";
22
23const USE_MSG_AST_FILE: &str =
24 "Wrong usage:\nUse ruby_code_ast!(\"filepath\")\nExample: ruby_file_ast!(\"puts 'let a = 1;'\")";
25
26
27#[proc_macro]
44pub fn ruby_code_str(input: TokenStream) -> TokenStream {
45 let input: Vec<proc_macro::TokenTree> = input.into_iter().collect();
46 let code = input.get(0).expect(USE_MSG_STR_CODE);
47
48 let code = match code {
49 TokenTree::Literal(literal) => parse_str(&literal.to_string()),
50 _ => panic!("{}", USE_MSG_STR_CODE),
51 };
52
53 let mut result = String::from("r#\"");
54 result.push_str(&execute_code(&code));
55 result.push_str("\"#");
56
57 result.parse::<TokenStream>().expect(
58 "Couldn't parse ruby output, perhaps check for presence of comments in your ruby code",
59 )
60}
61
62#[proc_macro]
84pub fn ruby_code_to(input: TokenStream) -> TokenStream {
85 let input: Vec<proc_macro::TokenTree> = input.into_iter().collect();
86 let return_type = input.get(0).expect(USE_MSG_TYPE_CODE);
87 let code = input.get(1).expect(USE_MSG_TYPE_CODE);
88
89 let return_type = match return_type {
90 TokenTree::Ident(t) => t.to_string(),
91 _ => panic!(
92 "Should be type but found '{}': {}",
93 return_type, USE_MSG_TYPE_CODE
94 ),
95 };
96
97 let code = match code {
98 TokenTree::Literal(literal) => parse_str(&literal.to_string()),
99 TokenTree::Punct(_) => match input.get(2).expect(USE_MSG_TYPE_CODE) {
100 TokenTree::Literal(literal) => parse_str(&literal.to_string()),
101 _ => panic!(
102 "Should be string literal but found '{}':\n{}",
103 code, USE_MSG_TYPE_CODE
104 ),
105 },
106 _ => panic!(
107 "Should be string literal but found '{}':\n{}",
108 code, USE_MSG_TYPE_CODE
109 ),
110 };
111
112 macro_rules! eval_type {
113 ( $($type:ty),* ) => {
114 match return_type.as_ref() {
115 $(stringify!($type) => {
116
117 let result = execute_code(&code)
118 .trim_end()
119 .parse::<$type>();
120
121 let result = match result {
122 Ok(v) => v,
123 Err(e) => {
124 panic!("Couldn't convert to type: {}{}",
125 stringify!($type),
126 match e.kind() {
127 &std::num::IntErrorKind::Empty => "\nPerhaps you forgot to print the result?",
128 _ => ""
129 }
130 );
131 }
132 };
133
134 let mut result = result.to_string();
135 result.push_str(concat!(" as ", stringify!($type)));
136
137 result.parse::<TokenStream>().expect("Couldn't parse token stream")
138
139 }),*
140
141 "f32" => {
142 let result = execute_code(&code)
143 .trim_end()
144 .parse::<f32>();
145
146 let result = match result {
147 Ok(v) => v,
148 Err(e) => {
149 panic!(
150 "Couldn't convert to type: f32{}",
151 if e == "".parse::<f32>().unwrap_err() { "\nPerhaps you forgot to print the result?"
153 } else {
154 ""
155 }
156 )
157 }
158 };
159
160 let mut result = result.to_string();
161 result.push_str(" as f32");
162
163 result.parse::<TokenStream>().expect("Couldn't parse token stream")
164 },
165
166 "f64" => {
167 let result = execute_code(&code)
168 .trim_end()
169 .parse::<f64>();
170
171 let result = match result {
172 Ok(v) => v,
173 Err(e) => {
174 panic!(
175 "Couldn't convert to type: f64{}",
176 if e == "".parse::<f64>().unwrap_err() { "\nPerhaps you forgot to print the result?"
178 } else {
179 ""
180 }
181 )
182 }
183 };
184
185 let mut result = result.to_string();
186 result.push_str(" as f64");
187
188 result.parse::<TokenStream>().expect("Couldn't parse token stream")
189 },
190
191 "char" => {
192 let result = execute_code(&code)
193 .trim_end()
194 .parse::<char>();
195
196 let result = match result {
197 Ok(v) => v,
198 Err(e) => {
199 panic!(
200 "Couldn't convert to type: char{}",
201 if e == "".parse::<char>().unwrap_err() { "\nPerhaps you forgot to print the result?"
203 } else {
204 ""
205 }
206 )
207 }
208 };
209
210 let mut result = result.to_string();
211 result.push_str(" as char");
212
213 result.parse::<TokenStream>().expect("Couldn't parse token stream")
214
215 }
216 _ => panic!("Unsupported type")
217 }
218 }
219 }
220
221 eval_type!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize)
222}
223
224#[proc_macro]
245pub fn ruby_code_ast(input: TokenStream) -> TokenStream {
246 let input: Vec<proc_macro::TokenTree> = input.into_iter().collect();
247 let code = input.get(0).expect(USE_MSG_AST_CODE);
248
249 let code = match code {
250 TokenTree::Literal(literal) => parse_str(&literal.to_string()),
251 _ => panic!("{}", USE_MSG_AST_CODE),
252 };
253
254 execute_code(&code)
255 .parse::<TokenStream>()
256 .expect("Couldn't parse ruby output")
257}
258
259#[proc_macro]
282pub fn ruby_file_str(input: TokenStream) -> TokenStream {
283 let input: Vec<proc_macro::TokenTree> = input.into_iter().collect();
284 let file = input.get(0).expect(USE_MSG_STR_FILE);
285
286 let file = match file {
287 TokenTree::Literal(literal) => parse_str(&literal.to_string()),
288 _ => panic!("{}", USE_MSG_STR_FILE),
289 };
290
291 let mut result = String::from("r#\"");
292 result.push_str(&execute_file(&file));
293 result.push_str("\"#");
294
295 result.parse::<TokenStream>().expect(
296 "Couldn't parse ruby output, perhaps check for presence of comments in your ruby code",
297 )
298}
299
300#[proc_macro]
328pub fn ruby_file_to(input: TokenStream) -> TokenStream {
329 let input: Vec<proc_macro::TokenTree> = input.into_iter().collect();
330 let return_type = input.get(0).expect(USE_MSG_TYPE_FILE);
331 let file = input.get(1).expect(USE_MSG_TYPE_FILE);
332
333 let return_type = match return_type {
334 TokenTree::Ident(t) => t.to_string(),
335 _ => panic!(
336 "Should be type but found '{}': {}",
337 return_type, USE_MSG_TYPE_FILE
338 ),
339 };
340
341 let file = match file {
342 TokenTree::Literal(literal) => parse_str(&literal.to_string()),
343 TokenTree::Punct(_) => match input.get(2).expect(USE_MSG_TYPE_FILE) {
344 TokenTree::Literal(literal) => parse_str(&literal.to_string()),
345 _ => panic!(
346 "Should be string literal but found '{}':\n{}",
347 file, USE_MSG_TYPE_FILE
348 ),
349 },
350 _ => panic!(
351 "Should be string literal but found '{}':\n{}",
352 file, USE_MSG_TYPE_FILE
353 ),
354 };
355
356 macro_rules! eval_type {
357 ( $($type:ty),* ) => {
358 match return_type.as_ref() {
359 $(stringify!($type) => {
360
361 let result = execute_file(&file)
362 .trim_end()
363 .parse::<$type>();
364
365 let result = match result {
366 Ok(v) => v,
367 Err(e) => {
368 panic!("Couldn't convert to type: {}{}",
369 stringify!($type),
370 match e.kind() {
371 &std::num::IntErrorKind::Empty => "\nPerhaps you forgot to print the result?",
372 _ => ""
373 }
374 );
375 }
376 };
377
378 let mut result = result.to_string();
379 result.push_str(concat!(" as ", stringify!($type)));
380
381 result.parse::<TokenStream>().expect("Couldn't parse token stream")
382
383 }),*
384
385 "f32" => {
386 let result = execute_file(&file)
387 .trim_end()
388 .parse::<f32>();
389
390 let result = match result {
391 Ok(v) => v,
392 Err(e) => {
393 panic!(
394 "Couldn't convert to type: f32{}",
395 if e == "".parse::<f32>().unwrap_err() { "\nPerhaps you forgot to print the result?"
397 } else {
398 ""
399 }
400 )
401 }
402 };
403
404 let mut result = result.to_string();
405 result.push_str(" as f32");
406
407 result.parse::<TokenStream>().expect("Couldn't parse token stream")
408 },
409
410 "f64" => {
411 let result = execute_file(&file)
412 .trim_end()
413 .parse::<f64>();
414
415 let result = match result {
416 Ok(v) => v,
417 Err(e) => {
418 panic!(
419 "Couldn't convert to type: f64{}",
420 if e == "".parse::<f64>().unwrap_err() { "\nPerhaps you forgot to print the result?"
422 } else {
423 ""
424 }
425 )
426 }
427 };
428
429 let mut result = result.to_string();
430 result.push_str(" as f64");
431
432 result.parse::<TokenStream>().expect("Couldn't parse token stream")
433 },
434
435 "bool" => {
436
437 let result = execute_file(&file)
438 .trim_end()
439 .parse::<bool>()
440 .expect("Couldn't convert to type: bool.\nPerhaps you forgot to print the result?");
441
442 let result = result.to_string();
443
444 result.parse::<TokenStream>().expect("Couldn't parse token stream")
445 },
446
447 "char" => {
448 let result = execute_file(&file)
449 .trim_end()
450 .parse::<char>();
451
452 let result = match result {
453 Ok(v) => v,
454 Err(e) => {
455 panic!(
456 "Couldn't convert to type: char{}",
457 if e == "".parse::<char>().unwrap_err() { "\nPerhaps you forgot to print the result?"
459 } else {
460 ""
461 }
462 )
463 }
464 };
465
466 let mut result = result.to_string();
467 result.push_str(" as char");
468
469 result.parse::<TokenStream>().expect("Couldn't parse token stream")
470
471 }
472 _ => panic!("Unsupported type")
473 }
474 }
475 }
476
477 eval_type!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize)
478}
479
480#[proc_macro]
504pub fn ruby_file_ast(input: TokenStream) -> TokenStream {
505 let input: Vec<proc_macro::TokenTree> = input.into_iter().collect();
506 let file = input.get(0).expect(USE_MSG_AST_FILE);
507
508 let file = match file {
509 TokenTree::Literal(literal) => parse_str(&literal.to_string()),
510 _ => panic!("{}", USE_MSG_AST_FILE),
511 };
512
513 execute_file(&file)
514 .parse::<TokenStream>()
515 .expect("Couldn't parse ruby output")
516}