Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 46 additions & 15 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ fn main() {
.blocklist_type("JsonTablePlan")
// Yes, we want doc comments
.clang_arg("-fparse-all-comments")
.derive_debug(false)
.generate()
.unwrap()
// SAFETY: YOLO
Expand Down Expand Up @@ -213,12 +214,15 @@ fn generate_node_structs(

let sname = &s.ident;
let mut impl_: syn::ItemImpl = parse_quote!(impl #sname {});
let mut debug_expr: syn::Expr = parse_quote!(f.debug_struct(stringify!(#sname)));

for field in s.fields.iter_mut() {
clean_doc_comments(&mut field.attrs);

let fname = &field.ident;
let fattrs = &field.attrs;
let debug_kind;

if field.ty == ty(parse_quote!(NodeTag))
|| field.ty == ty(parse_quote!(Expr))
|| field.ty == ty(parse_quote!(ValUnion))
Expand All @@ -235,7 +239,6 @@ fn generate_node_structs(
field.ty = parse_quote!(*mut Node);
} else if field.ty == ty(parse_quote!(Expr)) {
field.ty = parse_quote!(NodeTag);
s.attrs.push(parse_quote!(#[derive(Debug)]));
}

if let syn::Type::Ptr(ty) = &field.ty
Expand All @@ -249,9 +252,8 @@ fn generate_node_structs(
unsafe { self.#fname.as_ref() }
}
});
}

if field.ty == ty(parse_quote!(*mut List)) {
debug_kind = DebugKind::Method;
} else if field.ty == ty(parse_quote!(*mut List)) {
let return_ty: syn::Type;
let mut list_expr: syn::Expr = parse_quote! {
// SAFETY: The lifetime is not longer than self
Expand Down Expand Up @@ -308,19 +310,17 @@ fn generate_node_structs(
crate::util::to_flat_iter(#list_expr)
}
});
}

if field.ty == ty(parse_quote!(*mut Node)) {
debug_kind = DebugKind::List;
} else if field.ty == ty(parse_quote!(*mut Node)) {
impl_.items.push(parse_quote! {
#(#fattrs)*
pub fn #fname(&self) -> crate::Node<'_> {
// SAFETY: The lifetime is not longer than self
unsafe { crate::Node::from_ptr(self.#fname) }
}
});
}

if is_c_string(&field.ty) {
debug_kind = DebugKind::Method;
} else if is_c_string(&field.ty) {
impl_.items.push(parse_quote! {
#(#fattrs)*
pub fn #fname(&self) -> Option<&str> {
Expand All @@ -335,10 +335,9 @@ fn generate_node_structs(
)
}
}
})
}

if field.ty == ty(parse_quote!(ValUnion)) {
});
debug_kind = DebugKind::Method;
} else if field.ty == ty(parse_quote!(ValUnion)) {
impl_.items.push(parse_quote! {
#(#fattrs)*
pub fn #fname(&self) -> Option<ConstValue<'_>> {
Expand All @@ -348,10 +347,35 @@ fn generate_node_structs(
Some(ConstValue(&self.val))
}
}
})
});
debug_kind = DebugKind::Method;
} else if field.ty == parse_quote!(NodeTag) || field.ty == parse_quote!(ParseLoc) {
debug_kind = DebugKind::Skip;
} else {
debug_kind = DebugKind::Field;
}

let debug_value: Option<syn::Expr> = match debug_kind {
DebugKind::Method => Some(parse_quote!(&self.#fname())),
DebugKind::List => Some(parse_quote!(&__DebugIterator(|| self.#fname()))),
DebugKind::Field => Some(parse_quote!(&self.#fname)),
DebugKind::Skip => None,
};

if let Some(debug_value) = debug_value {
debug_expr = parse_quote! {
#debug_expr.field(stringify!(#fname), #debug_value)
};
}
}

out_file.items.push(parse_quote! {
impl fmt::Debug for #sname {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#debug_expr.finish_non_exhaustive()
}
}
});
out_file.items.push(s.into());
out_file.items.push(impl_.into());
}
Expand Down Expand Up @@ -539,3 +563,10 @@ fn doc_comments<'a>(
fn ty(ty: syn::Type) -> syn::Type {
ty
}

enum DebugKind {
Method,
List,
Field,
Skip,
}
19 changes: 12 additions & 7 deletions src/const_val.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,18 @@ impl ConstValue<'_> {

impl fmt::Debug for ConstValue<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.tag() {
NodeTag_T_Integer => write!(f, "{:?}", self.numeric_value::<i32>().unwrap()),
NodeTag_T_Float => write!(f, "{:?}", self.numeric_value::<f64>().unwrap()),
NodeTag_T_String => write!(f, "{:?}", self.str_value().unwrap()),
NodeTag_T_Boolean => write!(f, "{:?}", self.bool_value().unwrap()),
_ => write!(f, "{{unknown type}}"),
}
f.debug_tuple("ConstValue")
// SAFETY: We're checking the tag
.field(unsafe {
match self.tag() {
NodeTag_T_Integer => self.0.ival.as_ref(),
NodeTag_T_Float => self.0.fval.as_ref(),
NodeTag_T_Boolean => self.0.boolval.as_ref(),
NodeTag_T_String => self.0.sval.as_ref(),
_ => return Ok(()),
}
})
.finish()
}
}

Expand Down
119 changes: 113 additions & 6 deletions src/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,119 @@ impl Bitmapset {
}
}

impl fmt::Debug for A_Const {
struct __DebugIterator<F>(F);

impl<F, I> fmt::Debug for __DebugIterator<F>
where
F: Fn() -> I,
I: IntoIterator,
I::Item: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("A_Const")
.field("val", &self.val())
.field("isnull", &self.isnull)
.field("location", &self.location)
.finish_non_exhaustive()
f.debug_list().entries(self.0()).finish()
}
}

#[test]
// If this test begins failing due to a change in the standard library's
// formatter, update this test as long as the output continues to look
// reasonable
fn test_debug_output() {
let result = crate::parse("SELECT * FROM users WHERE id = 1").unwrap();
let stmt = result.stmts().next().unwrap();
let expected = r#"SelectStmt(
SelectStmt {
distinctClause: [],
intoClause: None,
targetList: [
ResTarget {
name: None,
indirection: [],
val: ColumnRef(
ColumnRef {
fields: [
A_Star(
A_Star { .. },
),
],
..
},
),
..
},
],
fromClause: [
RangeVar(
RangeVar {
catalogname: None,
schemaname: None,
relname: Some(
"users",
),
inh: true,
relpersistence: 112,
alias: None,
..
},
),
],
whereClause: A_Expr(
A_Expr {
kind: 0,
name: [
String(
String {
sval: Some(
"=",
),
..
},
),
],
lexpr: ColumnRef(
ColumnRef {
fields: [
String(
String {
sval: Some(
"id",
),
..
},
),
],
..
},
),
rexpr: A_Const(
A_Const {
val: Some(
1,
),
isnull: false,
..
},
),
..
},
),
groupClause: [],
groupDistinct: false,
havingClause: None,
windowClause: [],
valuesLists: [],
sortClause: [],
limitOffset: None,
limitCount: None,
limitOption: 0,
lockingClause: [],
withClause: None,
op: 0,
all: false,
larg: None,
rarg: None,
..
},
)"#;
assert_eq!(expected, format!("{:#?}", stmt));
}