Enhanced C#
Loyc library documentation
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Events Pages
Properties | Public Member Functions | List of all members
Loyc.Syntax.Impl.ILNodePrinterHelperWithRevokableNewlines< Checkpoint, out Self > Interface Template Reference

Enhances ILNodePrinterHelper{Self} with an ability to revoke newlines. More...


Source file:
Inheritance diagram for Loyc.Syntax.Impl.ILNodePrinterHelperWithRevokableNewlines< Checkpoint, out Self >:
Loyc.Syntax.Impl.ILNodePrinterHelper< out Self > Loyc.Syntax.Impl.IPrinterHelper< out Self > Loyc.Syntax.Impl.ILNodePrinterHelperWithRevokableNewlines< Checkpoint > Loyc.Syntax.Impl.LNodePrinterHelper Loyc.Syntax.Impl.PrinterState

Remarks

Enhances ILNodePrinterHelper{Self} with an ability to revoke newlines.

Template Parameters
SelfThe return type of methods in the base interface.
CheckpointA type returned by GetCheckpoint representing a location in the output stream.

When pretty-printing any language as text, it's a challenge to decide where to place newlines. You may want to break up long lines into shorter ones, as in

if (ReallyLongIdentifier[Fully.Qualified.Name(multiple, parameters)] 
   > SomeConstant)
{
   return ReallyLongIdentifier[firstThing + secondThing] 
      + thirdThing + fourthThing;
}

Conversely, you may want to print something on one line that you would ordinarily print on two:

    if (c) break;

Of course, the problem is, you don't know how long the syntax tree will be in text form until after you try to print it.

My first idea to solve this problem was to use a rope tree data structure - inner syntax trees would produce small strings that could be "roped" together to produce a bigger tree. But ropes tend not to use memory efficiently, and there was the challenge, which I didn't see how to solve, of how to keep the tree balanced efficiently (for this particular application perhaps a balanced tree wasn't needed, but as a perfectionist I didn't want to implement a "half-baked" data structure.)

Next I thought of a simpler solution based on an ordinary StringBuilder. My idea was to insert newlines "pessimistically" - insert them everywhere in which they might be needed - and then selectively "revoke" them later if they turn out to be unnecessary. Only the most recently-written newline(s) can be revoked, which keeps the implementation simple and also limits the performance cost of deleting the newlines.

To use, call Newline() to write a newline (with indentation). To make a decision about whether to keep or revoke the most recent newline(s), call RevokeOrCommitNewlines(cp, maxLineLength) where cp is a "checkpoint" representing some point before the first newline you want to potentially revoke, and maxLineLength is the line length threshold: if the line length after combining lines, starting at the line on which the checkpoint is located, does not exceed maxLineLength, then the newlines are revoked, otherwise ALL newlines are committed (so earlier newlines can no longer be revoked.)

This design allows a potentially long series of newlines to be deleted in the reverse order that they were created, but if any newline is kept then previous ones can no longer be deleted.

For an example of how this is used, see the JSON printer in LLLPG samples or look at the implementation of the LESv3 printer.

Type Constraints
Self :ILNodePrinterHelperWithRevokableNewlines 
Self :Checkpoint 
Self :Self 

Properties

int LineWidth [get]
 Gets the current width of the current line (typically measured in characters). More...
 
- Properties inherited from Loyc.Syntax.Impl.IPrinterHelper< out Self >
bool IsAtStartOfLine [get]
 Returns true iff nothing has been written since the last call to Newline or NewlineIsRequiredHere. More...
 
char LastCharWritten [get]
 Gets the character most recently written to the stream, or '' if no characters have been written. More...
 

Public Member Functions

Checkpoint NewlineAfterCheckpoint ()
 Appends a newline, returning a checkpoint from with indentation afterward according to the current indentation level. More...
 
Checkpoint GetCheckpoint ()
 Gets a value that can be passed later to RevokeNewlinesSince(Checkpoint). More...
 
int RevokeNewlinesSince (Checkpoint cp)
 Deletes uncommitted newlines that were written after the specified checkpoint. More...
 
Self CommitNewlines ()
 Commits all uncommitted newlines permanently. More...
 
int RevokeOrCommitNewlines (Checkpoint cp, int maxLineWidth)
 Revokes or commits newlines added since the specified checkpoint. Recent newlines are revoked if the combined line length after revokation does not exceed maxLineWidth, otherwise ALL newlines are committed permanently. More...
 
- Public Member Functions inherited from Loyc.Syntax.Impl.ILNodePrinterHelper< out Self >
Self BeginNode (ILNode node)
 
Self EndNode ()
 Informs the helper that the printer is done writing the most recently started node. The helper may save the range of the node, e.g. by calling ILNodePrinterOptions.SaveRange. More...
 
Self BeginNode (ILNode node, PrinterIndentHint indentHint)
 Combines the BeginNode and Indent operations. More...
 
Self EndNode (PrinterIndentHint indentHint)
 Combines the EndNode and Dedent operations. More...
 
- Public Member Functions inherited from Loyc.Syntax.Impl.IPrinterHelper< out Self >
Self Write (char c)
 Appends a character to the output stream or StringBuilder. More...
 
Self Write (string s)
 Appends a string to the output stream or StringBuilder. More...
 
Self Write (UString s)
 Appends a string to the output stream or StringBuilder. More...
 
Self Space ()
 Writes a space character unless the last character written was a space. More...
 
Self Newline (bool deferIndent=false)
 Appends a newline, with indentation afterward according to the current indentation level. More...
 
Self FlushIndent ()
 Writes the pending indent, if applicable. This allows you to call Indent or Dedent afterward while making sure the indentation on the current line is unaffected. More...
 
Self NewlineIsRequiredHere ()
 Requests that a newline be written at this location. If this method is called multiple times at the same location, or if Newline(int) is called immediately afterward, only a single newline is written. More...
 
Self Indent (PrinterIndentHint?hint=null)
 Informs the helper that the printer is starting to write the specified node. The printer must call EndNode when it is done. This information may be used to record range information (to understand why this is useful, please read about LNodeRangeMapper) More...
 
Self Dedent (PrinterIndentHint?hint=null)
 Decreases the current indent level. More...
 

Member Function Documentation

Self Loyc.Syntax.Impl.ILNodePrinterHelperWithRevokableNewlines< Checkpoint, out Self >.CommitNewlines ( )

Commits all uncommitted newlines permanently.

Also causes ranges after the uncommitted newlines to be saved.

Implemented in Loyc.Syntax.Impl.LNodePrinterHelper.

Checkpoint Loyc.Syntax.Impl.ILNodePrinterHelperWithRevokableNewlines< Checkpoint, out Self >.GetCheckpoint ( )

Gets a value that can be passed later to RevokeNewlinesSince(Checkpoint).

Implemented in Loyc.Syntax.Impl.LNodePrinterHelper.

Checkpoint Loyc.Syntax.Impl.ILNodePrinterHelperWithRevokableNewlines< Checkpoint, out Self >.NewlineAfterCheckpoint ( )

Appends a newline, returning a checkpoint from with indentation afterward according to the current indentation level.

Implemented in Loyc.Syntax.Impl.LNodePrinterHelper.

int Loyc.Syntax.Impl.ILNodePrinterHelperWithRevokableNewlines< Checkpoint, out Self >.RevokeNewlinesSince ( Checkpoint  cp)

Deletes uncommitted newlines that were written after the specified checkpoint.

Returns
The number of newlines that were just revoked.

Newlines created after a call to ILNodePrinterHelper{Self}.NewlineIsRequiredHere or LNodePrinterHelperExt.IrrevokableNewline are not revoked.

int Loyc.Syntax.Impl.ILNodePrinterHelperWithRevokableNewlines< Checkpoint, out Self >.RevokeOrCommitNewlines ( Checkpoint  cp,
int  maxLineWidth 
)

Revokes or commits newlines added since the specified checkpoint. Recent newlines are revoked if the combined line length after revokation does not exceed maxLineWidth, otherwise ALL newlines are committed permanently.

Returns
0 if the method had no effect, -N if N newlines were revoked, and +N if N newlines were committed.

This method does not affect the indent level.

Property Documentation

int Loyc.Syntax.Impl.ILNodePrinterHelperWithRevokableNewlines< Checkpoint, out Self >.LineWidth
get

Gets the current width of the current line (typically measured in characters).