Similar to:
height(t) = if (t==NULL) then 0 else 1+max(height(t.left),height(t.right))
You have:
perfect(t) = if (t==NULL) then 0 else {
let h=perfect(t.left)
if (h != -1 && h==perfect(t.right)) then 1+h else -1
}
Where perfect(t) returns -1 if the leaves aren't all at the same depth, or any node has only one child; otherwise, it returns the height.
Edit: this is for "complete" = "A perfect binary tree is a full binary tree in which all leaves are at the same depth or same level.[1] (This is ambiguously also called a complete binary tree.)" (Wikipedia).
Here's a recursive check for: "A complete binary tree is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible.". It returns (-1,false) if the tree isn't complete, otherwise (height,full) if it is, with full==true iff it's perfect.
complete(t) = if (t==NULL) then (0,true) else {
let (hl,fl)=complete(t.left)
let (hr,fr)=complete(t.right)
if (fl && hl==hr) then (1+h,fr)
else if (fr && hl==hr+1) then (1+h,false)
else (-1,false)
}