showPNExpr :: Int -> PNExpr -> ShowS
    showPNExpr prec expr = showParen (prec > thisPrec) $ body expr
        where
            body (PNLiteral NoSimValue) = showString "token"
            body (PNLiteral (SimValue int [])) = shows int
            body (PNBool bool) = shows bool
            body (PNInput inp) = showString "i" . shows inp
            body (PNBitfield slice expr) = showPNExpr (thisPrec + 1) expr . verilogShowSlice slice
            body (PNInsertBitfield slice expr1 expr2) = showString "insert " . paren (verilogShowSlice slice .
                showString "," . showPNExpr 0 expr1 . showString "," . showPNExpr 0 expr2)
            body (PNOp terms expr) = if listAtLeastLength 2 termStrs
                then showString "let " .  showListWithSep (showString ";") showString (init termStrs) .
                    showString " in " . showString (last termStrs)
                else showString (last termStrs)
                where
                    termStrs = prettyPrintOTerms 0 (\prec -> showPNExpr prec expr) terms
            body (PNAppend widths exprs) = case exprs' of
                [] -> showString "token"
                [expr] -> showPNExpr prec expr
                _ -> showChar '{' . showListWithSep (showString ", ") (showPNExpr 0) exprs' .
                    showChar '}'
                where
                    exprs' = map fst $ filter nonZeroWidth $ zip exprs widths

                    nonZeroWidth (_, 0) = False
                    nonZeroWidth _ = True

            body (PNMatch slice imps expr) = showString "match " . paren (verilogShowSlice slice . showString "," .
                showString "[" .
                showString (joinWith "," $ map (showImp True True 4) imps) .
                showString "]," .
                showPNExpr 0 expr)
            body expr = showString "?" . shows expr

            thisPrec = pnExprPrec expr
            paren = showParen True
showPNExpr :: Int -> PNExpr -> ShowS
showPNExpr prec expr = showParen (prec > thisPrec) $ body expr
        where
            body (PNLiteral NoSimValue) = showString "token"
            body (PNLiteral (SimValue int [])) = shows int
            body (PNBool bool) = shows bool
            body (PNInput inp) = showString "i" . shows inp
            body (PNBitfield slice expr) = showPNExpr (thisPrec + 1) expr . verilogShowSlice slice
            body (PNInsertBitfield slice expr1 expr2) = showString "insert " . paren (verilogShowSlice slice .
                showString "," . showPNExpr 0 expr1 . showString "," . showPNExpr 0 expr2)
            body (PNOp terms expr) = if listAtLeastLength 2 termStrs
                then showString "let " .  showListWithSep (showString ";") showString (init termStrs) .
                    showString " in " . showString (last termStrs)
                else showString (last termStrs)
                where
                    termStrs = prettyPrintOTerms 0 (\prec -> showPNExpr prec expr) terms
            body (PNAppend widths exprs) = case exprs' of
                [] -> showString "token"
                [expr] -> showPNExpr prec expr
                _ -> showChar '{' . showListWithSep (showString ", ") (showPNExpr 0) exprs' .
                    showChar '}'
                where
                    exprs' = map fst $ filter nonZeroWidth $ zip exprs widths

                    nonZeroWidth (_, 0) = False
                    nonZeroWidth _ = True

            body (PNMatch slice imps expr) = showString "match " . paren (verilogShowSlice slice . showString "," .
                showString "[" .
                showString (joinWith "," $ map (showImp True True 4) imps) .
                showString "]," .
                showPNExpr 0 expr)
            body expr = showString "?" . shows expr

            thisPrec = pnExprPrec expr
            paren = showParen True
showPNExpr prec expr = showParen (prec > thisPrec) $ body expr
        where
            body (PNLiteral NoSimValue) = showString "token"
            body (PNLiteral (SimValue int [])) = shows int
            body (PNBool bool) = shows bool
            body (PNInput inp) = showString "i" . shows inp
            body (PNBitfield slice expr) = showPNExpr (thisPrec + 1) expr . verilogShowSlice slice
            body (PNInsertBitfield slice expr1 expr2) = showString "insert " . paren (verilogShowSlice slice .
                showString "," . showPNExpr 0 expr1 . showString "," . showPNExpr 0 expr2)
            body (PNOp terms expr) = if listAtLeastLength 2 termStrs
                then showString "let " .  showListWithSep (showString ";") showString (init termStrs) .
                    showString " in " . showString (last termStrs)
                else showString (last termStrs)
                where
                    termStrs = prettyPrintOTerms 0 (\prec -> showPNExpr prec expr) terms
            body (PNAppend widths exprs) = case exprs' of
                [] -> showString "token"
                [expr] -> showPNExpr prec expr
                _ -> showChar '{' . showListWithSep (showString ", ") (showPNExpr 0) exprs' .
                    showChar '}'
                where
                    exprs' = map fst $ filter nonZeroWidth $ zip exprs widths

                    nonZeroWidth (_, 0) = False
                    nonZeroWidth _ = True

            body (PNMatch slice imps expr) = showString "match " . paren (verilogShowSlice slice . showString "," .
                showString "[" .
                showString (joinWith "," $ map (showImp True True 4) imps) .
                showString "]," .
                showPNExpr 0 expr)
            body expr = showString "?" . shows expr

            thisPrec = pnExprPrec expr
            paren = showParen True