hlShowOTerms :: [(Int, TeakOTerm)] -> PNExpr -> ShowS
    hlShowOTerms terms expr = snd $ last termShows
        where
            getTerm :: Int -> TeakOTerm
            getTerm termNo = fromJust $ lookup termNo terms

            termShows :: [(Int, ShowS)]
            termShows = (0, hlShowPNExpr expr) : mapSnd showTerm terms

            subTerm :: TeakOSlice -> ShowS
            subTerm (termNo, slice)
                | termNo /= 0 && isConstant rawTerm = shows $
                    extractBitfield slice constValue
                | termNo /= 0 && sliceWidth slice == resultWidth = hlShr term $ sliceOffset slice
                | otherwise = hlBitfield slice term
                where
                    isConstant (TeakOConstant {}) = True
                    isConstant _ = False

                    TeakOConstant _ constValue = rawTerm

                    term = fromJust $ lookup termNo termShows
                    rawTerm = getTerm termNo
                    resultWidth = oTermResultWidth rawTerm

            showTerm :: TeakOTerm -> ShowS
            showTerm (TeakOConstant _ int) = shows int
            showTerm (TeakOAppend count slices) = hlAppend
                (concat $ replicate count $ map oSliceWidth slices)
                (concat $ replicate count $ map subTerm slices)
            showTerm term@(TeakOBuiltin {}) -- FIXME
                | oTermResultWidth term == 0 = showString "dot"
                | otherwise = shows (0 :: Integer)
            showTerm (TeakOp op slices) = case (op, slices) of
                (TeakOpAdd, [l, r]) -> clip "+" l r
                (TeakOpSub, [l, r]) -> clip "-" l r
                (TeakOpAnd, [l, r]) -> logical "&" l r
                (TeakOpOr, [l, r]) -> logical "|" l r
                (TeakOpXor, [l, r]) -> logical "#" l r
                (TeakOpNot, [r]) -> hlInfixOp "-" (shows ((bit (oSliceWidth r) :: Integer) - 1)) (subTerm r)
                (TeakOpSignedGT, [l, r]) -> signedInEq ">" l r
                (TeakOpSignedGE, [l, r]) -> signedInEq ">=" l r
                (TeakOpUnsignedGT, [l, r]) -> hlBoolToBit $ bin ">" l r
                (TeakOpUnsignedGE, [l, r]) -> hlBoolToBit $ bin ">=" l r
                (TeakOpEqual, [l, r]) -> bin "=" l r
                (TeakOpNotEqual, [l, r]) -> bin "#" l r
                _ -> error $ "hlShowOTerms.showTerm: bad TeakOp `" ++ show op ++ "' with slices `" ++ show slices ++ "'"
                where
                    width = oSliceWidth $ head slices
                    signedInEq op l r = hlBoolToBit $ hlInfixOp op (padSigned l) (padSigned r)
                    bin op l r = hlInfixOp op (subTerm l) (subTerm r)
                    clip op l r = hlInfixOp "%" (hlInfixOp op
                        (hlInfixOp "+" (showsBit (oSliceWidth l)) (subTerm l))
                        (subTerm r)) (showsBit $ oSliceWidth l)

                    logical op l r = foldl1' (hlInfixOp "+") $ map bitOp [0..width-1]
                        where
                            lStr = subTerm l
                            rStr = subTerm r
                            bitOp i = hlIf (hlInfixOp op (bitBool lStr i) (bitBool rStr i))
                                (showsBit i) (shows (0::Int))

                    -- padSigned : add 2^width to positive numbers to keep numbers is order and
                    --    nice and positive for signed comparisons
                    padSigned slice = hlInfixOp "+" (hlIf (bitBool str (width - 1))
                        (shows (0::Int)) (showsBit width)) str
                        where str = subTerm slice

                    bitBool expr i = hlInfixOp ">="
                        (hlInfixOp "%" expr (showsBit (i + 1))) (showsBit i)
            showTerm (TeakOMux spec (choiceSlice:slices)) =
                foldr ($) (shows (0::Int)) $ zipWith makeMatch spec slices
                where
                    makeMatch imps inSlice = hlIf (hlImpsMatch choiceWidth imps choiceStr) (subTerm inSlice)
                    choiceWidth = oSliceWidth choiceSlice
                    choiceStr = subTerm choiceSlice
            showTerm term = error $ "hlShowOTerms.showTerm: bad TeakOTerm `" ++ show term ++ "'"
hlShowOTerms :: [(Int, TeakOTerm)] -> PNExpr -> ShowS
hlShowOTerms terms expr = snd $ last termShows
        where
            getTerm :: Int -> TeakOTerm
            getTerm termNo = fromJust $ lookup termNo terms

            termShows :: [(Int, ShowS)]
            termShows = (0, hlShowPNExpr expr) : mapSnd showTerm terms

            subTerm :: TeakOSlice -> ShowS
            subTerm (termNo, slice)
                | termNo /= 0 && isConstant rawTerm = shows $
                    extractBitfield slice constValue
                | termNo /= 0 && sliceWidth slice == resultWidth = hlShr term $ sliceOffset slice
                | otherwise = hlBitfield slice term
                where
                    isConstant (TeakOConstant {}) = True
                    isConstant _ = False

                    TeakOConstant _ constValue = rawTerm

                    term = fromJust $ lookup termNo termShows
                    rawTerm = getTerm termNo
                    resultWidth = oTermResultWidth rawTerm

            showTerm :: TeakOTerm -> ShowS
            showTerm (TeakOConstant _ int) = shows int
            showTerm (TeakOAppend count slices) = hlAppend
                (concat $ replicate count $ map oSliceWidth slices)
                (concat $ replicate count $ map subTerm slices)
            showTerm term@(TeakOBuiltin {}) -- FIXME
                | oTermResultWidth term == 0 = showString "dot"
                | otherwise = shows (0 :: Integer)
            showTerm (TeakOp op slices) = case (op, slices) of
                (TeakOpAdd, [l, r]) -> clip "+" l r
                (TeakOpSub, [l, r]) -> clip "-" l r
                (TeakOpAnd, [l, r]) -> logical "&" l r
                (TeakOpOr, [l, r]) -> logical "|" l r
                (TeakOpXor, [l, r]) -> logical "#" l r
                (TeakOpNot, [r]) -> hlInfixOp "-" (shows ((bit (oSliceWidth r) :: Integer) - 1)) (subTerm r)
                (TeakOpSignedGT, [l, r]) -> signedInEq ">" l r
                (TeakOpSignedGE, [l, r]) -> signedInEq ">=" l r
                (TeakOpUnsignedGT, [l, r]) -> hlBoolToBit $ bin ">" l r
                (TeakOpUnsignedGE, [l, r]) -> hlBoolToBit $ bin ">=" l r
                (TeakOpEqual, [l, r]) -> bin "=" l r
                (TeakOpNotEqual, [l, r]) -> bin "#" l r
                _ -> error $ "hlShowOTerms.showTerm: bad TeakOp `" ++ show op ++ "' with slices `" ++ show slices ++ "'"
                where
                    width = oSliceWidth $ head slices
                    signedInEq op l r = hlBoolToBit $ hlInfixOp op (padSigned l) (padSigned r)
                    bin op l r = hlInfixOp op (subTerm l) (subTerm r)
                    clip op l r = hlInfixOp "%" (hlInfixOp op
                        (hlInfixOp "+" (showsBit (oSliceWidth l)) (subTerm l))
                        (subTerm r)) (showsBit $ oSliceWidth l)

                    logical op l r = foldl1' (hlInfixOp "+") $ map bitOp [0..width-1]
                        where
                            lStr = subTerm l
                            rStr = subTerm r
                            bitOp i = hlIf (hlInfixOp op (bitBool lStr i) (bitBool rStr i))
                                (showsBit i) (shows (0::Int))

                    -- padSigned : add 2^width to positive numbers to keep numbers is order and
                    --    nice and positive for signed comparisons
                    padSigned slice = hlInfixOp "+" (hlIf (bitBool str (width - 1))
                        (shows (0::Int)) (showsBit width)) str
                        where str = subTerm slice

                    bitBool expr i = hlInfixOp ">="
                        (hlInfixOp "%" expr (showsBit (i + 1))) (showsBit i)
            showTerm (TeakOMux spec (choiceSlice:slices)) =
                foldr ($) (shows (0::Int)) $ zipWith makeMatch spec slices
                where
                    makeMatch imps inSlice = hlIf (hlImpsMatch choiceWidth imps choiceStr) (subTerm inSlice)
                    choiceWidth = oSliceWidth choiceSlice
                    choiceStr = subTerm choiceSlice
            showTerm term = error $ "hlShowOTerms.showTerm: bad TeakOTerm `" ++ show term ++ "'"
hlShowOTerms terms expr = snd $ last termShows
        where
            getTerm :: Int -> TeakOTerm
            getTerm termNo = fromJust $ lookup termNo terms

            termShows :: [(Int, ShowS)]
            termShows = (0, hlShowPNExpr expr) : mapSnd showTerm terms

            subTerm :: TeakOSlice -> ShowS
            subTerm (termNo, slice)
                | termNo /= 0 && isConstant rawTerm = shows $
                    extractBitfield slice constValue
                | termNo /= 0 && sliceWidth slice == resultWidth = hlShr term $ sliceOffset slice
                | otherwise = hlBitfield slice term
                where
                    isConstant (TeakOConstant {}) = True
                    isConstant _ = False

                    TeakOConstant _ constValue = rawTerm

                    term = fromJust $ lookup termNo termShows
                    rawTerm = getTerm termNo
                    resultWidth = oTermResultWidth rawTerm

            showTerm :: TeakOTerm -> ShowS
            showTerm (TeakOConstant _ int) = shows int
            showTerm (TeakOAppend count slices) = hlAppend
                (concat $ replicate count $ map oSliceWidth slices)
                (concat $ replicate count $ map subTerm slices)
            showTerm term@(TeakOBuiltin {}) -- FIXME
                | oTermResultWidth term == 0 = showString "dot"
                | otherwise = shows (0 :: Integer)
            showTerm (TeakOp op slices) = case (op, slices) of
                (TeakOpAdd, [l, r]) -> clip "+" l r
                (TeakOpSub, [l, r]) -> clip "-" l r
                (TeakOpAnd, [l, r]) -> logical "&" l r
                (TeakOpOr, [l, r]) -> logical "|" l r
                (TeakOpXor, [l, r]) -> logical "#" l r
                (TeakOpNot, [r]) -> hlInfixOp "-" (shows ((bit (oSliceWidth r) :: Integer) - 1)) (subTerm r)
                (TeakOpSignedGT, [l, r]) -> signedInEq ">" l r
                (TeakOpSignedGE, [l, r]) -> signedInEq ">=" l r
                (TeakOpUnsignedGT, [l, r]) -> hlBoolToBit $ bin ">" l r
                (TeakOpUnsignedGE, [l, r]) -> hlBoolToBit $ bin ">=" l r
                (TeakOpEqual, [l, r]) -> bin "=" l r
                (TeakOpNotEqual, [l, r]) -> bin "#" l r
                _ -> error $ "hlShowOTerms.showTerm: bad TeakOp `" ++ show op ++ "' with slices `" ++ show slices ++ "'"
                where
                    width = oSliceWidth $ head slices
                    signedInEq op l r = hlBoolToBit $ hlInfixOp op (padSigned l) (padSigned r)
                    bin op l r = hlInfixOp op (subTerm l) (subTerm r)
                    clip op l r = hlInfixOp "%" (hlInfixOp op
                        (hlInfixOp "+" (showsBit (oSliceWidth l)) (subTerm l))
                        (subTerm r)) (showsBit $ oSliceWidth l)

                    logical op l r = foldl1' (hlInfixOp "+") $ map bitOp [0..width-1]
                        where
                            lStr = subTerm l
                            rStr = subTerm r
                            bitOp i = hlIf (hlInfixOp op (bitBool lStr i) (bitBool rStr i))
                                (showsBit i) (shows (0::Int))

                    -- padSigned : add 2^width to positive numbers to keep numbers is order and
                    --    nice and positive for signed comparisons
                    padSigned slice = hlInfixOp "+" (hlIf (bitBool str (width - 1))
                        (shows (0::Int)) (showsBit width)) str
                        where str = subTerm slice

                    bitBool expr i = hlInfixOp ">="
                        (hlInfixOp "%" expr (showsBit (i + 1))) (showsBit i)
            showTerm (TeakOMux spec (choiceSlice:slices)) =
                foldr ($) (shows (0::Int)) $ zipWith makeMatch spec slices
                where
                    makeMatch imps inSlice = hlIf (hlImpsMatch choiceWidth imps choiceStr) (subTerm inSlice)
                    choiceWidth = oSliceWidth choiceSlice
                    choiceStr = subTerm choiceSlice
            showTerm term = error $ "hlShowOTerms.showTerm: bad TeakOTerm `" ++ show term ++ "'"