1use quote::ToTokens;
2use serde::Serialize;
3use syn::{Expr, File, Item, Lit, Pat, Stmt, visit::Visit};
4
5#[derive(Serialize, Debug, Default)]
10pub struct AstJson {
11 #[serde(skip_serializing_if = "Vec::is_empty")]
12 pub items: Vec<ItemJson>,
13}
14
15#[derive(Serialize, Debug)]
21#[serde(tag = "type")]
22pub enum ItemJson {
23 Function {
24 name: String,
25 parameters: Vec<ParameterJson>,
26 return_type: Option<String>,
27 body: Vec<StmtJson>,
28 },
29 Struct {
30 name: String,
31 fields: Vec<FieldJson>,
32 },
33 Enum {
34 name: String,
35 variants: Vec<VariantJson>,
36 },
37 Other {
38 description: String,
39 },
40}
41
42#[derive(Serialize, Debug)]
46pub struct ParameterJson {
47 pub name: String,
48 pub type_info: String,
49}
50
51#[derive(Serialize, Debug)]
55pub struct FieldJson {
56 pub name: Option<String>,
57 pub type_info: String,
58}
59
60#[derive(Serialize, Debug)]
63pub struct VariantJson {
64 pub name: String,
65}
66
67#[derive(Serialize, Debug)]
71#[serde(tag = "type")]
72pub enum StmtJson {
73 VariableDeclaration {
74 name: String,
75 initializer: Option<Box<ExprJson>>,
76 },
77 Expression {
78 expr: Box<ExprJson>,
79 },
80 Other {
81 description: String,
82 },
83}
84
85#[derive(Serialize, Debug)]
88#[serde(tag = "type")]
89pub enum ExprJson {
90 IntLiteral {
91 value: String,
92 },
93 FloatLiteral {
94 value: String,
95 },
96 StringLiteral {
97 value: String,
98 },
99 BoolLiteral {
100 value: bool,
101 },
102 Binary {
103 operator: String,
104 left: Box<ExprJson>,
105 right: Box<ExprJson>,
106 },
107 FunctionCall {
108 function: Box<ExprJson>,
109 arguments: Vec<ExprJson>,
110 },
111 Identifier {
112 name: String,
113 },
114 If {
115 condition: Box<ExprJson>,
116 then_branch: Vec<StmtJson>,
117 else_branch: Option<Box<ExprJson>>,
118 },
119 Loop {
120 body: Vec<StmtJson>,
121 },
122 While {
123 condition: Box<ExprJson>,
124 body: Vec<StmtJson>,
125 },
126 Return {
127 value: Option<Box<ExprJson>>,
128 },
129 Other {
130 description: String,
131 },
132}
133
134pub struct JsonVisitor {
139 pub ast: AstJson,
140}
141
142impl JsonVisitor {
148 pub fn new() -> Self {
156 JsonVisitor {
157 ast: AstJson::default(),
158 }
159 }
160
161 pub fn to_json(&self) -> String {
169 match serde_json::to_string_pretty(&self.ast) {
170 Ok(json) => json,
171 Err(_) => String::from("{}"),
172 }
173 }
174
175 pub fn process_file(&mut self, file: &File) {
184 for item in &file.items {
185 self.process_item(item);
186 }
187 }
188
189 fn process_item(&mut self, item: &Item) {
198 match item {
199 Item::Fn(item_fn) => {
200 let mut parameters = Vec::new();
201 for param in &item_fn.sig.inputs {
202 match param {
203 syn::FnArg::Typed(pat_type) => {
204 if let Pat::Ident(pat_ident) = &*pat_type.pat {
205 parameters.push(ParameterJson {
206 name: pat_ident.ident.to_string(),
207 type_info: format!("{}", (*pat_type.ty).to_token_stream()),
208 });
209 }
210 }
211 syn::FnArg::Receiver(receiver) => {
212 parameters.push(ParameterJson {
213 name: "self".to_string(),
214 type_info: format!("{}", receiver.to_token_stream()),
215 });
216 }
217 }
218 }
219
220 let return_type = match &item_fn.sig.output {
221 syn::ReturnType::Default => None,
222 syn::ReturnType::Type(_, return_type) => {
223 Some(format!("{}", return_type.to_token_stream()))
224 }
225 };
226
227 let mut statements = Vec::new();
228 for stmt in &item_fn.block.stmts {
229 statements.push(self.visit_stmt_json(stmt));
230 }
231
232 self.ast.items.push(ItemJson::Function {
233 name: item_fn.sig.ident.to_string(),
234 parameters,
235 return_type,
236 body: statements,
237 });
238 }
239 Item::Struct(item_struct) => {
240 let mut fields = Vec::new();
241 for field in &item_struct.fields {
242 fields.push(FieldJson {
243 name: field.ident.as_ref().map(|ident| ident.to_string()),
244 type_info: format!("{}", field.ty.to_token_stream()),
245 });
246 }
247
248 self.ast.items.push(ItemJson::Struct {
249 name: item_struct.ident.to_string(),
250 fields,
251 });
252 }
253 Item::Enum(item_enum) => {
254 let mut variants = Vec::new();
255 for variant in &item_enum.variants {
256 variants.push(VariantJson {
257 name: variant.ident.to_string(),
258 });
259 }
260
261 self.ast.items.push(ItemJson::Enum {
262 name: item_enum.ident.to_string(),
263 variants,
264 });
265 }
266 _ => {
267 self.ast.items.push(ItemJson::Other {
268 description: format!("{}", item.to_token_stream()),
269 });
270 }
271 }
272 }
273}
274
275impl<'ast> Visit<'ast> for JsonVisitor {
278 fn visit_file(&mut self, file: &'ast File) {
287 self.process_file(file);
288 }
289}
290
291impl JsonVisitor {
294 fn visit_stmt_json(&mut self, stmt: &Stmt) -> StmtJson {
302 match stmt {
303 Stmt::Local(local) => {
304 let name = if let Pat::Ident(pat_ident) = &local.pat {
305 pat_ident.ident.to_string()
306 } else {
307 "unknown".to_string()
308 };
309
310 let initializer = if let Some(init) = &local.init {
311 Some(Box::new(self.visit_expr_json(&init.expr)))
312 } else {
313 None
314 };
315
316 StmtJson::VariableDeclaration { name, initializer }
317 }
318 Stmt::Expr(expr, _) => StmtJson::Expression {
319 expr: Box::new(self.visit_expr_json(expr)),
320 },
321 _ => StmtJson::Other {
322 description: format!("{}", stmt.to_token_stream()),
323 },
324 }
325 }
326
327 fn visit_expr_json(&mut self, expr: &Expr) -> ExprJson {
336 match expr {
337 Expr::Lit(expr_lit) => match &expr_lit.lit {
338 Lit::Int(lit_int) => ExprJson::IntLiteral {
339 value: lit_int.base10_digits().to_string(),
340 },
341 Lit::Float(lit_float) => ExprJson::FloatLiteral {
342 value: lit_float.base10_digits().to_string(),
343 },
344 Lit::Str(lit_str) => ExprJson::StringLiteral {
345 value: lit_str.value(),
346 },
347 Lit::Bool(lit_bool) => ExprJson::BoolLiteral {
348 value: lit_bool.value,
349 },
350 _ => ExprJson::Other {
351 description: format!("{}", expr_lit.to_token_stream()),
352 },
353 },
354 Expr::Binary(expr_bin) => {
355 let op = match expr_bin.op {
356 syn::BinOp::Add(_) => "+",
357 syn::BinOp::Sub(_) => "-",
358 syn::BinOp::Mul(_) => "*",
359 syn::BinOp::Div(_) => "/",
360 syn::BinOp::Eq(_) => "==",
361 syn::BinOp::Lt(_) => "<",
362 syn::BinOp::Le(_) => "<=",
363 syn::BinOp::Ne(_) => "!=",
364 syn::BinOp::Ge(_) => ">=",
365 syn::BinOp::Gt(_) => ">",
366 _ => "other_operator",
367 };
368
369 ExprJson::Binary {
370 operator: op.to_string(),
371 left: Box::new(self.visit_expr_json(&expr_bin.left)),
372 right: Box::new(self.visit_expr_json(&expr_bin.right)),
373 }
374 }
375 Expr::Call(expr_call) => ExprJson::FunctionCall {
376 function: Box::new(self.visit_expr_json(&expr_call.func)),
377 arguments: expr_call
378 .args
379 .iter()
380 .map(|arg| self.visit_expr_json(arg))
381 .collect(),
382 },
383 Expr::Path(expr_path) => ExprJson::Identifier {
384 name: format!("{}", expr_path.to_token_stream()),
385 },
386 Expr::If(expr_if) => {
387 let mut then_stmts = Vec::new();
388 for stmt in &expr_if.then_branch.stmts {
389 then_stmts.push(self.visit_stmt_json(stmt));
390 }
391
392 let else_branch = if let Some((_, else_expr)) = &expr_if.else_branch {
393 Some(Box::new(self.visit_expr_json(else_expr)))
394 } else {
395 None
396 };
397
398 ExprJson::If {
399 condition: Box::new(self.visit_expr_json(&expr_if.cond)),
400 then_branch: then_stmts,
401 else_branch,
402 }
403 }
404 Expr::Loop(expr_loop) => {
405 let mut stmts = Vec::new();
406 for stmt in &expr_loop.body.stmts {
407 stmts.push(self.visit_stmt_json(stmt));
408 }
409
410 ExprJson::Loop { body: stmts }
411 }
412 Expr::While(expr_while) => {
413 let mut stmts = Vec::new();
414 for stmt in &expr_while.body.stmts {
415 stmts.push(self.visit_stmt_json(stmt));
416 }
417
418 ExprJson::While {
419 condition: Box::new(self.visit_expr_json(&expr_while.cond)),
420 body: stmts,
421 }
422 }
423 Expr::Return(expr_return) => ExprJson::Return {
424 value: expr_return
425 .expr
426 .as_ref()
427 .map(|e| Box::new(self.visit_expr_json(e))),
428 },
429 _ => ExprJson::Other {
430 description: format!("{}", expr.to_token_stream()),
431 },
432 }
433 }
434}
435
436#[cfg(test)]
437mod tests {
438 use super::*;
439 use crate::parse_rust_source;
440 use serde_json::Value;
441
442 #[test]
443 fn test_json_serialization_function() {
444 let source = r#"
445 fn add(a: i32, b: i32) -> i32 {
446 a + b
447 }
448 "#;
449
450 let file = parse_rust_source(source).unwrap();
451 let mut visitor = JsonVisitor::new();
452 visitor.process_file(&file);
453
454 let json = visitor.to_json();
455
456 let parsed: Value = serde_json::from_str(&json).expect("JSONのパースに失敗");
458
459 assert!(parsed["items"].is_array());
461
462 let first_item = &parsed["items"][0];
464
465 assert_eq!(first_item["type"], "Function");
467 assert_eq!(first_item["name"], "add");
468
469 assert!(first_item["parameters"].is_array());
471 assert_eq!(first_item["parameters"][0]["name"], "a");
472 assert_eq!(first_item["parameters"][1]["name"], "b");
473
474 assert_eq!(first_item["return_type"], "i32");
476 }
477
478 #[test]
479 fn test_json_serialization_struct() {
480 let source = r#"
481 struct Point {
482 x: f64,
483 y: f64,
484 }
485 "#;
486
487 let file = parse_rust_source(source).unwrap();
488 let mut visitor = JsonVisitor::new();
489 visitor.process_file(&file);
490
491 let json = visitor.to_json();
492
493 let parsed: Value = serde_json::from_str(&json).expect("JSONのパースに失敗");
495
496 assert!(parsed["items"].is_array());
498
499 let first_item = &parsed["items"][0];
501
502 assert_eq!(first_item["type"], "Struct");
504 assert_eq!(first_item["name"], "Point");
505
506 assert!(first_item["fields"].is_array());
508 assert_eq!(first_item["fields"][0]["name"], "x");
509 assert_eq!(first_item["fields"][1]["name"], "y");
510 }
511
512 #[test]
513 fn test_json_serialization_enum() {
514 let source = r#"
515 enum Direction {
516 North,
517 East,
518 South,
519 West,
520 }
521 "#;
522
523 let file = parse_rust_source(source).unwrap();
524 let mut visitor = JsonVisitor::new();
525 visitor.process_file(&file);
526
527 let json = visitor.to_json();
528
529 let parsed: Value = serde_json::from_str(&json).expect("JSONのパースに失敗");
531
532 assert!(parsed["items"].is_array());
534
535 let first_item = &parsed["items"][0];
537
538 assert_eq!(first_item["type"], "Enum");
540 assert_eq!(first_item["name"], "Direction");
541
542 assert!(first_item["variants"].is_array());
544 assert_eq!(first_item["variants"][0]["name"], "North");
545 assert_eq!(first_item["variants"][1]["name"], "East");
546 assert_eq!(first_item["variants"][2]["name"], "South");
547 assert_eq!(first_item["variants"][3]["name"], "West");
548 }
549
550 #[test]
551 fn test_json_serialization_complex() {
552 let source = r#"
553 fn complex_expr() {
554 let result = (10 + 20) * 30 / (5 - 2);
555 if result > 100 {
556 println!("Large result: {}", result);
557 } else {
558 println!("Small result: {}", result);
559 }
560 }
561 "#;
562
563 let file = parse_rust_source(source).unwrap();
564 let mut visitor = JsonVisitor::new();
565 visitor.process_file(&file);
566
567 let json = visitor.to_json();
568
569 let parsed: Value = serde_json::from_str(&json).expect("JSONのパースに失敗");
571
572 assert!(parsed["items"].is_array());
574
575 let first_item = &parsed["items"][0];
577
578 assert_eq!(first_item["type"], "Function");
580 assert_eq!(first_item["name"], "complex_expr");
581
582 assert!(first_item["body"].is_array());
584 assert_eq!(first_item["body"][0]["type"], "VariableDeclaration");
585 assert_eq!(first_item["body"][0]["name"], "result");
586
587 assert_eq!(first_item["body"][1]["type"], "Expression");
589 assert_eq!(first_item["body"][1]["expr"]["type"], "If");
590 }
591
592 #[test]
594 fn test_debug_json_output() {
595 let source = r#"
596 fn test_func() {
597 println!("Hello");
598 }
599 "#;
600
601 let file = parse_rust_source(source).unwrap();
602 let mut visitor = JsonVisitor::new();
603 visitor.process_file(&file);
604
605 let json = visitor.to_json();
607
608 assert!(!visitor.ast.items.is_empty(), "AST項目が空です!");
610
611 let parsed: Value = serde_json::from_str(&json).expect("JSONのパースに失敗");
613
614 assert!(parsed["items"].is_array());
616
617 let first_item = &parsed["items"][0];
619
620 assert_eq!(first_item["type"], "Function");
622 assert_eq!(first_item["name"], "test_func");
623 }
624
625 #[test]
627 fn test_basic_serialization() {
628 let mut ast = AstJson::default();
630
631 ast.items.push(ItemJson::Function {
633 name: "manual_func".to_string(),
634 parameters: vec![],
635 return_type: Some("i32".to_string()),
636 body: vec![],
637 });
638
639 let json = serde_json::to_string_pretty(&ast).unwrap();
641
642 let parsed: Value = serde_json::from_str(&json).expect("JSONのパースに失敗");
644
645 assert!(parsed["items"].is_array());
647
648 let first_item = &parsed["items"][0];
650
651 assert_eq!(first_item["type"], "Function");
653 assert_eq!(first_item["name"], "manual_func");
654 }
655}