|
| 1 | +// use pg_query_proto_parser::{FieldType, Node, ProtoParser}; |
| 2 | +// use proc_macro2::{Ident, TokenStream}; |
| 3 | +// use quote::{format_ident, quote}; |
| 4 | +// |
| 5 | +// // todo: get_children should only return a Vec<NestedNode> with location being an Option<i32> |
| 6 | +// // we then pass the results into a resolve_locations function that takes a Vec<NestedNode> and returns a Vec<NestedNode>, but where location is an i32 |
| 7 | +// |
| 8 | +// pub fn get_children_mod(_item: proc_macro2::TokenStream) -> proc_macro2::TokenStream { |
| 9 | +// let parser = ProtoParser::new("./libpg_query/protobuf/pg_query.proto"); |
| 10 | +// let proto_file = parser.parse(); |
| 11 | +// |
| 12 | +// let manual_node_names = manual_node_names(); |
| 13 | +// |
| 14 | +// let node_identifiers = node_identifiers(&proto_file.nodes, &manual_node_names); |
| 15 | +// let node_handlers = node_handlers(&proto_file.nodes, &manual_node_names); |
| 16 | +// |
| 17 | +// quote! { |
| 18 | +// use pg_query::NodeEnum; |
| 19 | +// use std::collections::VecDeque; |
| 20 | +// |
| 21 | +// #[derive(Debug, Clone)] |
| 22 | +// pub struct ChildrenNode { |
| 23 | +// pub node: NodeEnum, |
| 24 | +// pub depth: i32, |
| 25 | +// pub location: Option<i32>, |
| 26 | +// pub path: String, |
| 27 | +// } |
| 28 | +// |
| 29 | +// /// Returns all children of the node, recursively |
| 30 | +// pub fn get_children(node: &NodeEnum, text: String, current_depth: i32) -> Vec<ChildrenNode> { |
| 31 | +// let mut nodes: Vec<ChildrenNode> = vec![]; |
| 32 | +// // Node, depth, path |
| 33 | +// let mut stack: VecDeque<(NodeEnum, i32, String)> = |
| 34 | +// VecDeque::from(vec![(node.to_owned(), current_depth, "0".to_string())]); |
| 35 | +// while !stack.is_empty() { |
| 36 | +// let (node, depth, path) = stack.pop_front().unwrap(); |
| 37 | +// let current_depth = depth + 1; |
| 38 | +// let mut child_ctr: i32 = 0; |
| 39 | +// let mut handle_child = |c: NodeEnum| { |
| 40 | +// let location = get_location(&c); |
| 41 | +// let path = path.clone() + "." + child_ctr.to_string().as_str(); |
| 42 | +// child_ctr = child_ctr + 1; |
| 43 | +// stack.push_back((c.to_owned(), current_depth, path.clone())); |
| 44 | +// nodes.push(ChildrenNode { |
| 45 | +// node: c, |
| 46 | +// depth: current_depth, |
| 47 | +// location, |
| 48 | +// path: path.clone(), |
| 49 | +// }); |
| 50 | +// }; |
| 51 | +// match &node { |
| 52 | +// // `AConst` is the only node with a `one of` property, so we handle it manually |
| 53 | +// // if you need to handle other nodes manually, add them to the `manual_node_names` function below |
| 54 | +// NodeEnum::AConst(n) => { |
| 55 | +// if n.val.is_some() { |
| 56 | +// handle_child(match n.val.to_owned().unwrap() { |
| 57 | +// pg_query::protobuf::a_const::Val::Ival(v) => NodeEnum::Integer(v), |
| 58 | +// pg_query::protobuf::a_const::Val::Fval(v) => NodeEnum::Float(v), |
| 59 | +// pg_query::protobuf::a_const::Val::Boolval(v) => NodeEnum::Boolean(v), |
| 60 | +// pg_query::protobuf::a_const::Val::Sval(v) => NodeEnum::String(v), |
| 61 | +// pg_query::protobuf::a_const::Val::Bsval(v) => NodeEnum::BitString(v), |
| 62 | +// }); |
| 63 | +// } |
| 64 | +// } |
| 65 | +// #(NodeEnum::#node_identifiers(n) => { |
| 66 | +// #node_handlers |
| 67 | +// }),*, |
| 68 | +// }; |
| 69 | +// } |
| 70 | +// nodes |
| 71 | +// } |
| 72 | +// } |
| 73 | +// } |
| 74 | +// |
| 75 | +// fn manual_node_names() -> Vec<&'static str> { |
| 76 | +// vec!["AConst"] |
| 77 | +// } |
| 78 | +// |
| 79 | +// fn node_identifiers(nodes: &[Node], exclude_nodes: &[&str]) -> Vec<Ident> { |
| 80 | +// nodes |
| 81 | +// .iter() |
| 82 | +// .filter(|node| !exclude_nodes.contains(&node.name.as_str())) |
| 83 | +// .map(|node| format_ident!("{}", &node.name)) |
| 84 | +// .collect() |
| 85 | +// } |
| 86 | +// |
| 87 | +// fn node_handlers(nodes: &[Node], exclude_nodes: &[&str]) -> Vec<TokenStream> { |
| 88 | +// nodes |
| 89 | +// .iter() |
| 90 | +// .filter(|node| !exclude_nodes.contains(&node.name.as_str())) |
| 91 | +// .map(|node| { |
| 92 | +// let property_handlers = property_handlers(&node); |
| 93 | +// quote! { |
| 94 | +// #(#property_handlers)* |
| 95 | +// } |
| 96 | +// }) |
| 97 | +// .collect() |
| 98 | +// } |
| 99 | +// |
| 100 | +// fn property_handlers(node: &Node) -> Vec<TokenStream> { |
| 101 | +// node.fields |
| 102 | +// .iter() |
| 103 | +// .map(|field| { |
| 104 | +// if field.field_type == FieldType::Node && field.repeated { |
| 105 | +// let field_name = field.name.as_str(); |
| 106 | +// quote! { |
| 107 | +// n.#field_name |
| 108 | +// .iter() |
| 109 | +// .for_each(|x| handle_child(x.node.as_ref().unwrap().to_owned())); |
| 110 | +// } |
| 111 | +// } else if field.field_type == FieldType::Node && field.is_one_of == false { |
| 112 | +// if field.node_name == Some("Node".to_owned()) { |
| 113 | +// let field_name = field.name.as_str(); |
| 114 | +// quote! { |
| 115 | +// if n.#field_name.is_some() { |
| 116 | +// handle_child(n.#field_name.to_owned().unwrap().node.unwrap()); |
| 117 | +// } |
| 118 | +// } |
| 119 | +// } else { |
| 120 | +// let enum_variant_name = field.enum_variant_name.as_ref().unwrap(); |
| 121 | +// let field_name = field.name.as_str(); |
| 122 | +// quote! { |
| 123 | +// if n.#field_name.is_some() { |
| 124 | +// handle_child(NodeEnum::#enum_variant_name(n.#field_name.to_owned().unwrap())); |
| 125 | +// } |
| 126 | +// } |
| 127 | +// } |
| 128 | +// } else { |
| 129 | +// panic!("Unhandled field type: {:?}", field); |
| 130 | +// } |
| 131 | +// }) |
| 132 | +// .collect() |
| 133 | +// } |
0 commit comments