## core-prettyprinter.api
#
# Compiled by:
#
src/lib/prettyprint/big/prettyprinter.lib# This API is implemented in:
#
#
src/lib/prettyprint/big/src/core-prettyprinter-g.pkg#
api Core_Prettyprinter {
#
package typ: Core_Prettyprinter_Types;
Prettyprinter;
Pp = Prettyprinter ;
Npp = Null_Or( Prettyprinter );
Prettyprint_Output_Stream;
Traitful_Text; # Styled_Strings wrap a string plus blink/bold/color/... information
Texttraits;
open_box: (Prettyprinter, typ::Left_Margin_Is, typ::Wrap_Policy, Int) -> Void; # 'Int' == target_width.
indent: (Prettyprinter, Int) -> Void; #
break': (Prettyprinter, { ifnotwrap: { blanks: Int, tab_to: Int, tabstops_are_every: Int },
ifwrap: { blanks: Int, tab_to: Int, tabstops_are_every: Int }
}
)
-> Void;
horizontal: typ::Wrap_Policy;
vertical: typ::Wrap_Policy;
normal: typ::Wrap_Policy;
ragged_right: typ::Wrap_Policy;
make_prettyprinter: Prettyprint_Output_Stream -> List(typ::Prettyprinter_Configuration_Args) -> Pp;
process_mill_options
:
List (typ::Prettyprinter_Configuration_Args)
->
{ default_target_box_width: Int,
default_wrap_policy: typ::Wrap_Policy,
default_left_margin_is: typ::Left_Margin_Is,
tabstops_are_every: Int
};
get_prettyprint_output_stream: Pp -> Prettyprint_Output_Stream;
flush_prettyprinter: Pp -> Void;
close_prettyprinter: Pp -> Void;
traitful_text: Pp -> Traitful_Text -> Void;
set_rulename_for_current_box: (Pp, String) -> Void;
nblanks: Int -> String; # Temporary convenience function. Returns a string containing (only) given number of blanks.
};
####################################################################################################
#
# Note [1]: Prettyprint mill motivation and overview.
#
# Nomenclature:
# Prettyprinter: A package which renders a given datastructure as indented text.
# A system will usually have many datastructures and consequently many prettyprinters.
# Prettyprint mill: A package which provides the underlying infrastructure needed by all prettyprinters.
#
# This dirtree contains my third (2014) rewrite of the Mythryl prettyprint mill.
# It is based on John H Reppy's (2005) SML/NJ prettyprint mill, which in turn
# is based on Pierre Weis' 1995 Ocaml prettyprint mill.
#
# The prettyprint system has a layered architecture.
# Taking a leaf from the X-server playbook, the intent is:
#
# Core layer provides mechanism without policy.
# Base layer adds client-code conveniences.
# Standard layer implements more conveniences and any required policy.
# Data-structure-specific prettyprinters are built on the standard layer.
#
# The central line of development here is
#
# core-prettyprinter-g.pkg # The central formatting engine. Exports an api of minimal complexity.
# base-prettyprinter-g.pkg # Wraps the core prettyprint mill with an API more convenient to code clients.
# standard-prettyprinter-g.pkg # Wraps the base prettyprint mill with additional conveniences.
# standard-prettyprinter.pkg # The standard instantiation of the previous, used pervasively
# # in prettyprinters throughout the codebase.
#
# Independently of the layering, the codebase is also structured to allow
# prettyprinters to be built which output text in various formats such as
# plain ascii, ascii with ansi-terminal escape sequences for bold etc,
# and html, via the 'out' and 'tt' arguments to the above generics.
# However at present in practice we use plain ascii exclusively.
#
#
# Mythryl is assembled from parts built at many institutions, which tend
# to all instantiate their own prettyprint mills for no very good reason.
# I'm working to replace these with standard-prettyprinter.pkg, but
# for the moment I've settled on concentrating them in this directory
# at least so the redundancy is more obvious and easier to work on.
# These redundant prettyprint mills are built on base-prettyprinter-g.pkg.
#
#
# The core concept used to structure text to be prettyprinted is the 'box'.
#
# A box represents text to be printed at a given level of indentation. A box
# has contents to be printed and a target width-in-chars. It tries to format
# the contents to fit within its assigned width. The box width is interpreted
# as a soft limit to be respected on a best-effort basis, rather than a hard
# limit to be obeyed at all costs.
#
# In general a given box may be printed either monoline or multiline, depending
# on the size and complexity of the subexpressions within it. One of the core
# responsibilities of core-prettyprinter-g.pkg is to decide which boxes to
# print monoline and which to print multiline. This is done basically just by
# first trying to print it monoline, and retreating to multiline if that does
# not work.
#
#
#
# In slightly more detail (but still simplified), the prettyprint mill sees
# the contents of a box as consisting of a list of elements drawn from:
#
# o TEXT, just a passive string of characters.
# o BOX, a recursively nested box.
# o NEWLINE, which the mill renders by doing a newline and then indenting
# to the left margin of the current box by printing blanks.
# o BREAK, which the mill is free to render as either a blank or a NEWLINE.
# When rendered as a NEWLINE, we say the break has been "wrapped".
#
# The Ocaml and SML/NJ prettyprint mills process input line-by-line as a
# stream. The resulting limited context makes it hard to wrap breaks in
# an esthetically satisfying way, so the Mythryl prettyprint mill
# instead buffers a complete set of nested boxes before beginning
# formatting, allowing use of more sophisticated wrapping algorithms.
# (This takes more memory, but ram is much cheaper today than in 1995
# when the original Ocaml prettyprint mill was written.)
#
# To a first approximation the algorithm used is:
#
# o Format innermost boxes first. Formatting of a given box is independent
# of boxes exterior to it, and depends only on the height and width of
# boxes immediately within it. (Formatting innermost boxes first means
# that when a given box is formatted, the height and width of subboxes
# within it are known exactly. This makes formatting easier to implement
# and makes the results of formatting more intuitively understandable.)
#
# o To format a box, first decide if it can be formatted monoline.
# A box can be formatted monoline if:
# o It contains no NEWLINEs.
# o All subboxes are monoline.
# o The summed length of all box contents, including subboxes,
# treating BREAKs as blanks, is less than the assigned box width.
#
# o If the box is monoline, just print it as a horizontal string of chars:
# o Print BREAKs as blanks.
# o Print TEXT elements in the obvious way -- output a string of chars.
# o Print monoline subboxes just like TEXT elements.
# o There are no NEWLINES to print, by definition of monoline box.
# o There are no multiline subboxes to print, by definition of monoline box.
#
# o If the box is multiline:
# o Print NEWLINEs by doing a newline and spacing over to assigned left margin of box.
# o Print BREAKs as newlines.
# o Start the box as though it started with a NEWLINE.
# o Print TEXT elements in the obvious way -- output a string of chars.
# o Print monoline subboxes as though they were TEXT elements.
# o Print multiline subboxes recursively just like current multiline box.
#
# (You may want to read the above twice; if you understand it, using and maintaining
# these packages should be fairly straightforward, otherwise it is likely to be an
# exercise in frustration and wasted time.)
#
#
#
# In practice to get acceptable prettyprint results and to be flexible enough to
# accomodate different tastes, we need something more featureful than the above:
#
# o Different users want different base indentation distances, so we want tabstop
# spacing to be configurable on a per prettyprinter instance basis.
#
# o Prettyprinters may want different boxes to be indented different numbers of
# tabstops.
#
# o Sometimes we want indentation by a minimum of (say) one blank, other times we
# are content so long as the box winds up on a tabstop.
#
# o Sometimes we want to move (say) two tabstops, other times we want to
# move to (say) an even-numbered tabstop.
#
# o Prettyprinters may want some boxes to be indented relative to the left margin
# but other boxes to be indented relative to the current cursor position.
#
# o A user may want an non-wrapped BREAK to render not just as a single blank, but
# as several blanks and/or a move-to-tabstop command.
#
# o Prettyprinters may want different boxes to use different algorithms for deciding
# which BREAKs to wrap and which to leave as blanks. The two simplest policies are:
#
# HORIZONTAL: Wrap no BREAKs in the box -- pack box contents horizontally.
# VERTICAL: Wrap all BREAKs in the box -- pack box contents vertically.
#
# For formatting code and datastructures, the workhorse policy is:
#
# ALIGN: Align box contents horizontally if possible, else vertically.
# I.e., wrap no BREAKs if the result fits in the box width (monoline box)
# else wrap all BREAKs (multiline box).
#
# For running text, the traditional policy is:
#
# RAGGED_RIGHT: Paragraph-style wrapping where each line is wrapped at
# the last possible BREAK consistent with fitting the line
# in the given box width.
#
#
# FUTURE DIRECTIONS:
# If we wind up wanting more flexibility, one try might be defining in
#
src/lib/prettyprint/big/src/core-prettyprinter.api# a new Phase1_Token case CUSTOM_BREAK with the semantics that the
# end-user supplies a function which is called after the regular wrapping
# pass and which is given full access to the box.contents (and to
# print_box(box.contents) in order to make a wrap decision; it would
# probably return { wrap: Boolean, blanks: Int, tab_to: Int }. This
# would allow the custom code to look at the mono/multiline status of
# all immediate sub-boxes, peer inside subboxes, do a test rendering
# and look for parallel constructs, whatever.
#
# Or we could just accept a post-optimize function which is allowed
# rewrite the post-wrap/pre-print box-tree arbitrarily... that might
# be more to the point if we want to get really sophisticated along
# the lines of rendering parallel constructs as parallel text. If
# so, we should make explicit in the post-wrap tree the decisions
# which are currently made in the fly by the print pass.
## COPYRIGHT (c) 2005 John Reppy (http://www.cs.uchicago.edu/~jhr)
## All rights reserved.
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.