Skip to content

Commit 1fa340b

Browse files
committedAug 30, 2023
refactor: migrate get_location to codegen (not working yet)
1 parent 49ccaa0 commit 1fa340b

File tree

8 files changed

+6482
-255
lines changed

8 files changed

+6482
-255
lines changed
 

‎SomeFile.txt

+3,137
Large diffs are not rendered by default.

‎crates/codegen/src/get_children.rs

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
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+
// }

‎crates/codegen/src/get_location.rs

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use pg_query_proto_parser::{FieldType, Node, ProtoParser};
2+
use proc_macro2::{Ident, TokenStream};
3+
use quote::{format_ident, quote};
4+
5+
pub fn get_location_mod(_item: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
6+
let parser = ProtoParser::new("./libpg_query/protobuf/pg_query.proto");
7+
let proto_file = parser.parse();
8+
9+
let manual_node_names = manual_node_names();
10+
11+
let node_identifiers = node_identifiers(&proto_file.nodes, &manual_node_names);
12+
let location_idents = location_idents(&proto_file.nodes, &manual_node_names);
13+
14+
quote! {
15+
use pg_query::NodeEnum;
16+
17+
//! Returns the location of a node
18+
pub fn get_location(node: &NodeEnum) -> Option<i32> {
19+
let location = match node {
20+
// for some nodes, the location of the node itself is after their childrens location.
21+
// we implement the logic for those nodes manually.
22+
// if you add one, make sure to add its name to `manual_node_names()`.
23+
NodeEnum::BoolExpr(n) => {
24+
let a = n.args.iter().min_by(|a, b| {
25+
let loc_a = get_location(&a.node.as_ref().unwrap());
26+
let loc_b = get_location(&b.node.as_ref().unwrap());
27+
loc_a.cmp(&loc_b)
28+
});
29+
get_location(&a.unwrap().node.as_ref().unwrap())
30+
},
31+
NodeEnum::AExpr(n) => get_location(&n.lexpr.as_ref().unwrap().node.as_ref().unwrap()),
32+
#(NodeEnum::#node_identifiers(n) => #location_idents),*
33+
};
34+
if location.is_some() && location.unwrap() < 0 {
35+
None
36+
} else {
37+
location
38+
}
39+
}
40+
}
41+
}
42+
43+
fn manual_node_names() -> Vec<&'static str> {
44+
vec!["BoolExpr", "AExpr"]
45+
}
46+
47+
fn location_idents(nodes: &[Node], exclude_nodes: &[&str]) -> Vec<TokenStream> {
48+
nodes
49+
.iter()
50+
.filter(|n| !exclude_nodes.contains(&n.name.as_str()))
51+
.map(|node| {
52+
if node
53+
.fields
54+
.iter()
55+
.find(|n| n.name == "location" && n.field_type == FieldType::Int32)
56+
.is_some()
57+
{
58+
quote! { Some(n.location) }
59+
} else {
60+
quote! { None }
61+
}
62+
})
63+
.collect()
64+
}
65+
66+
fn node_identifiers(nodes: &[Node], exclude_nodes: &[&str]) -> Vec<Ident> {
67+
nodes
68+
.iter()
69+
.filter(|n| !exclude_nodes.contains(&n.name.as_str()))
70+
.map(|node| format_ident!("{}", &node.name))
71+
.collect()
72+
}

‎crates/codegen/src/lib.rs

+14
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
1+
// mod get_children;
2+
mod get_location;
13
mod syntax_kind;
24

5+
// use get_children::get_children_mod;
6+
use get_location::get_location_mod;
37
use syntax_kind::syntax_kind_mod;
48

9+
// #[proc_macro]
10+
// pub fn get_children(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
11+
// get_children_mod(item.into()).into()
12+
// }
13+
514
#[proc_macro]
615
pub fn syntax_kind(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
716
syntax_kind_mod(item.into()).into()
817
}
18+
19+
#[proc_macro]
20+
pub fn get_location(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
21+
get_location_mod(item.into()).into()
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
use codegen::get_location;
2+
3+
get_location!();

‎crates/parser/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
//! To see how these drawbacks are mitigated, see the `statement.rs` and the `source_file.rs` module.
1717
1818
mod ast_node;
19+
mod get_location_codegen;
1920
mod parser;
2021
mod pg_query_utils_generated;
2122
mod pg_query_utils_generated_test;

0 commit comments

Comments
 (0)
Please sign in to comment.