printSPEC :: LogicGraph -> SPEC -> Doc
printSPEC lg spec = case spec of
    Basic_spec (G_basic_spec lid basic_spec) _ ->
        case lookupCurrentSyntax "" lg of
      Just (Logic lid2, sm) -> if language_name lid2 /= language_name lid
          then error "printSPEC: logic mismatch"
          else case basicSpecPrinter sm lid of
        Just p -> p basic_spec
        _ -> error $ "printSPEC: no basic spec printer for "
             ++ showSyntax lid sm
      _ -> error "printSPEC: incomplete logic graph"
    EmptySpec _ -> specBraces empty
    Extraction aa ab -> sep [condBracesTransReduct lg aa, printEXTRACTION ab]
    Translation aa ab -> sep [condBracesTransReduct lg aa, printRENAMING ab]
    Reduction aa ab -> sep [condBracesTransReduct lg aa, printRESTRICTION ab]
    Approximation aa ab ->
      sep [condBracesTransReduct lg aa, printAPPROXIMATION ab]
    Minimization aa ab ->
      sep [condBracesTransReduct lg aa, printMINIMIZATION ab]
    Filtering aa ab -> sep [condBracesTransReduct lg aa, printFILTERING ab]
    Union aa _ -> sep $ printUnion lg aa
    Intersection aa _ -> sep $ printIntersection lg aa
    Extension aa _ -> sep $ printExtension lg aa
    Free_spec aa _ -> sep [keyword freeS, printGroupSpec lg aa]
    Cofree_spec aa _ -> sep [keyword cofreeS, printGroupSpec lg aa]
    Minimize_spec aa _ -> sep [keyword minimizeS, printGroupSpec lg aa]
    Local_spec aa ab _ -> fsep
      [keyword localS, prettyLG lg aa, keyword withinS, condBracesWithin lg ab]
    Closed_spec aa _ -> sep [keyword closedS, printGroupSpec lg aa]
    Group aa _ -> prettyLG lg aa
    Spec_inst aa ab mi _ -> let
      r = cat [structIRI aa, print_fit_arg_list lg ab]
      in maybe r (\ i -> sep [r, pretty i]) mi
    Qualified_spec ln asp _ -> pretty ln <> colon
      $+$ prettyLG (setLogicName ln lg) asp
    Data ld _ s1 s2 _ -> keyword dataS
        <+> printGroupSpec (setCurLogic (show ld) lg) s1
        $+$ prettyLG lg s2
    Combination n _ -> sep [keyword combineS, pretty n]
    Apply i bs _ ->
      sep [keyword "apply" <+> pretty i, prettyLG lg $ Basic_spec bs nullRange]
    Bridge s1 rs s2 _ -> fsep $ [condBraces lg s1, keyword "bridge"]
      ++ map pretty rs ++ [condBraces lg s2]
printSPEC :: LogicGraph -> SPEC -> Doc
printSPEC lg spec = case spec of
    Basic_spec (G_basic_spec lid basic_spec) _ ->
        case lookupCurrentSyntax "" lg of
      Just (Logic lid2, sm) -> if language_name lid2 /= language_name lid
          then error "printSPEC: logic mismatch"
          else case basicSpecPrinter sm lid of
        Just p -> p basic_spec
        _ -> error $ "printSPEC: no basic spec printer for "
             ++ showSyntax lid sm
      _ -> error "printSPEC: incomplete logic graph"
    EmptySpec _ -> specBraces empty
    Extraction aa ab -> sep [condBracesTransReduct lg aa, printEXTRACTION ab]
    Translation aa ab -> sep [condBracesTransReduct lg aa, printRENAMING ab]
    Reduction aa ab -> sep [condBracesTransReduct lg aa, printRESTRICTION ab]
    Approximation aa ab ->
      sep [condBracesTransReduct lg aa, printAPPROXIMATION ab]
    Minimization aa ab ->
      sep [condBracesTransReduct lg aa, printMINIMIZATION ab]
    Filtering aa ab -> sep [condBracesTransReduct lg aa, printFILTERING ab]
    Union aa _ -> sep $ printUnion lg aa
    Intersection aa _ -> sep $ printIntersection lg aa
    Extension aa _ -> sep $ printExtension lg aa
    Free_spec aa _ -> sep [keyword freeS, printGroupSpec lg aa]
    Cofree_spec aa _ -> sep [keyword cofreeS, printGroupSpec lg aa]
    Minimize_spec aa _ -> sep [keyword minimizeS, printGroupSpec lg aa]
    Local_spec aa ab _ -> fsep
      [keyword localS, prettyLG lg aa, keyword withinS, condBracesWithin lg ab]
    Closed_spec aa _ -> sep [keyword closedS, printGroupSpec lg aa]
    Group aa _ -> prettyLG lg aa
    Spec_inst aa ab mi _ -> let
      r = cat [structIRI aa, print_fit_arg_list lg ab]
      in maybe r (\ i -> sep [r, pretty i]) mi
    Qualified_spec ln asp _ -> pretty ln <> colon
      $+$ prettyLG (setLogicName ln lg) asp
    Data ld _ s1 s2 _ -> keyword dataS
        <+> printGroupSpec (setCurLogic (show ld) lg) s1
        $+$ prettyLG lg s2
    Combination n _ -> sep [keyword combineS, pretty n]
    Apply i bs _ ->
      sep [keyword "apply" <+> pretty i, prettyLG lg $ Basic_spec bs nullRange]
    Bridge s1 rs s2 _ -> fsep $ [condBraces lg s1, keyword "bridge"]
      ++ map pretty rs ++ [condBraces lg s2]
printSPEC lg spec = case spec of
    Basic_spec (G_basic_spec lid basic_spec) _ ->
        case lookupCurrentSyntax "" lg of
      Just (Logic lid2, sm) -> if language_name lid2 /= language_name lid
          then error "printSPEC: logic mismatch"
          else case basicSpecPrinter sm lid of
        Just p -> p basic_spec
        _ -> error $ "printSPEC: no basic spec printer for "
             ++ showSyntax lid sm
      _ -> error "printSPEC: incomplete logic graph"
    EmptySpec _ -> specBraces empty
    Extraction aa ab -> sep [condBracesTransReduct lg aa, printEXTRACTION ab]
    Translation aa ab -> sep [condBracesTransReduct lg aa, printRENAMING ab]
    Reduction aa ab -> sep [condBracesTransReduct lg aa, printRESTRICTION ab]
    Approximation aa ab ->
      sep [condBracesTransReduct lg aa, printAPPROXIMATION ab]
    Minimization aa ab ->
      sep [condBracesTransReduct lg aa, printMINIMIZATION ab]
    Filtering aa ab -> sep [condBracesTransReduct lg aa, printFILTERING ab]
    Union aa _ -> sep $ printUnion lg aa
    Intersection aa _ -> sep $ printIntersection lg aa
    Extension aa _ -> sep $ printExtension lg aa
    Free_spec aa _ -> sep [keyword freeS, printGroupSpec lg aa]
    Cofree_spec aa _ -> sep [keyword cofreeS, printGroupSpec lg aa]
    Minimize_spec aa _ -> sep [keyword minimizeS, printGroupSpec lg aa]
    Local_spec aa ab _ -> fsep
      [keyword localS, prettyLG lg aa, keyword withinS, condBracesWithin lg ab]
    Closed_spec aa _ -> sep [keyword closedS, printGroupSpec lg aa]
    Group aa _ -> prettyLG lg aa
    Spec_inst aa ab mi _ -> let
      r = cat [structIRI aa, print_fit_arg_list lg ab]
      in maybe r (\ i -> sep [r, pretty i]) mi
    Qualified_spec ln asp _ -> pretty ln <> colon
      $+$ prettyLG (setLogicName ln lg) asp
    Data ld _ s1 s2 _ -> keyword dataS
        <+> printGroupSpec (setCurLogic (show ld) lg) s1
        $+$ prettyLG lg s2
    Combination n _ -> sep [keyword combineS, pretty n]
    Apply i bs _ ->
      sep [keyword "apply" <+> pretty i, prettyLG lg $ Basic_spec bs nullRange]
    Bridge s1 rs s2 _ -> fsep $ [condBraces lg s1, keyword "bridge"]
      ++ map pretty rs ++ [condBraces lg s2]