Enhanced C#
Language of your choice: library documentation

Documentation moved to ecsharp.net

GitHub doesn't support HTTP redirects, so you'll be redirected in 3 seconds.

 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Events Pages
Nested classes | Public Types | Public static fields | Properties | Public Member Functions | Static Public Member Functions | List of all members
Loyc.Ecs.EcsNodePrinter Class Reference

Prints a Loyc tree to EC# source code. More...


Source file:

Remarks

Prints a Loyc tree to EC# source code.

This class is designed to faithfully represent Loyc trees by default; any Loyc tree that can be represented as EC# source code will be represented properly by this class, so that it is possible to parse the output text back into a Loyc tree equivalent to the one that was printed. In other words, EcsNodePrinter is designed to support round-tripping. For round- tripping to work, there are a couple of restrictions on the input tree:

  1. The Value property must only be used in LiteralNodes, and only literals that can exist in C# source code are allowed. For example, Values of type int, string, and double are acceptable, but Values of type Regex or int[] are not, because single tokens cannot represent these types in C# source code. The printer ignores Values of non-literal nodes, and non-representable literals are printed out using ToString().
  2. Names must come from the global symbol pool (GSymbol.Pool). The printer will happily print Symbols from other pools, but there is no way to indicate the pool in source code, so the parser always recreates symbols in the global pool. Non-global symbols are used after semantic analysis, so there is no way to faithfully represent the results of semantic analysis.

Only the attributes, head (LiteralNode.Value, IdNode.Name or CallNode.Target), and arguments of nodes are round-trippable. Superficial properties such as original source code locations and the LNode.Style are, in general, lost, although the printer can faithfully reproduce some (not all) NodeStyles. Also, any attribute whose Name starts with "#trivia_" will be dropped, because these attributes are considered extensions of the NodeStyle. However, the style indicated by the #trivia_* attribute will be used if the printer recognizes it.

Because EC# is based on C# which has some tricky ambiguities, there is a lot of code in this class dedicated to special cases and ambiguities. Even so, it is likely that some cases have been missed–that some unusual trees will not round-trip properly. Any failure to round-trip is a bug, and your bug reports are welcome. If this class uses prefix notation (with #specialNames) unnecessarily, that's also a bug, but it has low priority unless it affects plain C# output (where #specialNames are illegal.)

This class contains some configuration options that will defeat round- tripping but will make the output look better. For example, AllowExtraBraceForIfElseAmbig will print a tree such as #if(a, #if(b, f()), g()) as if (a) { if (b) f(); } else g();, by adding braces to eliminate prefix notation, even though braces make the Loyc tree different.

To avoid printing EC# syntax that does not exist in C#, you can call SetPlainCSharpMode, but this only works if the syntax tree does not contain invalid structure or EC#-specific code such as "==>", "alias", and template arguments ($T).

Public Types

enum  Ambiguity {
  Ambiguity.AllowUnassignedVarDecl = 0x0001, Ambiguity.CastRhs = 0x0002, Ambiguity.IsCallTarget = 0x0004,
  Ambiguity.NoBracedBlock = 0x0008, Ambiguity.FinalStmt = 0x0010, Ambiguity.TypeContext = 0x0020,
  Ambiguity.InDefinitionName = 0x0040, Ambiguity.InOf = 0x0080, Ambiguity.AllowPointer = 0x0100,
  Ambiguity.UseBacktick = 0x0400, Ambiguity.DropAttributes = 0x0800, Ambiguity.ForEachInitializer = 0x1000,
  Ambiguity.ElseClause = 0x2000, Ambiguity.AllowThisAsCallTarget = 0x8000, Ambiguity.NoIfWithoutElse = 0x10000,
  Ambiguity.NoParenthesis = 0x20000
}
 Internal enum (marked public for an obscure technical reason). These are flags that represent special situations in EC# syntax. More...
 

Public static fields

static readonly LNodePrinter Printer = PrintECSharp
 

Properties

LNode Node [get, set]
 
INodePrinterWriter Writer [get, set]
 
IMessageSink Errors [get, set]
 Any error that occurs during printing is printed to this object. More...
 
bool MixImmiscibleOperators [get, set]
 Allows operators to be mixed that will cause the parser to produce a warning. An example is x & @==(y, z): if you enable this option, it will be printed as x & y == z, which the parser will complain about because mixing those operators is deprecated. More...
 
bool AllowChangeParentheses [get, set]
 Permits extra parentheses to express precedence, instead of resorting to prefix notation (defaults to true). Also permits removal of parenthesis if necessary to print special constructs. More...
 
bool AllowExtraBraceForIfElseAmbig [get, set]
 Solve if-else ambiguity by adding braces rather than reverting to prefix notation. More...
 
bool DropNonDeclarationAttributes [get, set]
 Suppresses printing of all attributes that are not on declaration or definition statements (such as classes, methods and variable declarations at statement level). Also, avoids prefix notation when the attributes would have required it, e.g. @+([Foo] a, b) can be printed "a+b" instead. More...
 
bool OmitMissingArguments [get, set]
 When an argument to a method or macro has an empty name (@``), it will be omitted completely if this flag is set. More...
 
bool OmitSpaceTrivia [get, set]
 When this flag is set, space trivia attributes are ignored (e.g. CodeSymbols.TriviaSpaceAfter). More...
 
bool OmitComments [get, set]
 When this flag is set, comment trivia attributes are ignored (e.g. CodeSymbols.TriviaSLCommentAfter). More...
 
bool OmitRawText [get, set]
 When this flag is set, raw text trivia attributes are ignored (e.g. CodeSymbols.TriviaRawTextBefore). More...
 
bool QuoteUnprintableLiterals [get, set]
 When the printer encounters an unprintable literal, it calls Value.ToString(). When this flag is set, the string is placed in double quotes; when this flag is clear, it is printed as raw text. More...
 
bool AllowConstructorAmbiguity [get, set]
 Causes the ambiguity between constructors and method calls to be ignored; see EcsPrinterAndParserTests.ConstructorAmbiguities(). More...
 
bool AvoidMacroSyntax [get, set]
 Prints statements like "foo (...) bar()" in the equivalent form "foo (..., bar())" instead. Does not affect foo {...} because property and event definitions require this syntax (get {...}, set {...}). More...
 
bool PreferPlainCSharp [get, set]
 Prefers plain C# syntax for certain other things (not covered by the other options), even when the syntax tree requests a different style, e.g. EC# cast operators are blocked so x(->int) becomes (int) x. More...
 
SpaceOpt SpaceOptions [get, set]
 Controls the locations where spaces should be emitted. More...
 
NewlineOpt NewlineOptions [get, set]
 Controls the locations where newlines should be emitted. More...
 
int SpaceAroundInfixStopPrecedence [get, set]
 
int SpaceAfterPrefixStopPrecedence [get, set]
 

Public Member Functions

void Print (LNode node, StringBuilder target, IMessageSink errors, object mode, string indentString, string lineSeparator)
 
 EcsNodePrinter (LNode node, INodePrinterWriter target)
 
EcsNodePrinter SetPlainCSharpMode ()
 Sets AllowChangeParentheses, PreferPlainCSharp and DropNonDeclarationAttributes to true. More...
 

Static Public Member Functions

static EcsNodePrinter New (LNode node, StringBuilder target, string indentString="\t", string lineSeparator="\n")
 
static EcsNodePrinter New (LNode node, TextWriter target, string indentString="\t", string lineSeparator="\n")
 
static void PrintPlainCSharp (LNode node, StringBuilder target, IMessageSink errors, object mode, string indentString, string lineSeparator)
 

Member Enumeration Documentation

Internal enum (marked public for an obscure technical reason). These are flags that represent special situations in EC# syntax.

Enumerator
AllowUnassignedVarDecl 

The expression can contain uninitialized variable declarations, e.g. because it is the subject of an assignment. In the tree "(x + y, int z) = (a, b)", this flag is passed down to "(x + y, int z)" and then down to "int y" and "x + y", but it doesn't propagate down to "x", "y" and "int".

CastRhs 

The expression is the right side of a traditional cast, so the printer must avoid ambiguity in case of the following prefix operators: (Foo)&x, (Foo)*x, (Foo)++(x), (Foo)–(x) (the (Foo)++(x) case is parsed as a post-increment and a call).

IsCallTarget 

The expression is in a location where, if it is parenthesized and has the syntax of a data type inside, it will be treated as a cast. This occurs when a call that is printed with prefix notation has a parenthesized target node, e.g. (target)(arg). The target node can avoid the syntax of a data type by adding "[ ]" (an empty set of attributes) at the beginning of the expression.

NoBracedBlock 

No braced block permitted directly here (inside "if" clause)

FinalStmt 

The current statement is the last one in the enclosing block, so #result can be represented by omitting a semicolon.

TypeContext 

An expression is being printed in a context where a type is expected (its syntax has been verified in advance.)

InDefinitionName 

The expression being printed is a complex identifier that may contain special attributes, e.g. Foo<out T>.

InOf 

Inside angle brackets or (of ...).

AllowPointer 

Allow pointer notation (when combined with TypeContext). Also, a pointer is always allowed at the beginning of a statement, which is detected by the precedence context (StartStmt).

UseBacktick 

Used to communicate to the operator printers that a binary call should be expressed with the backtick operator.

DropAttributes 

Drop attributes only on the immediate expression being printed. Used when printing the return type on a method, whose attributes were already described by [return: ...].

ForEachInitializer 

Forces a variable declaration to be allowed as the initializer of a foreach loop.

ElseClause 

After 'else', valid 'if' statements are not indented.

AllowThisAsCallTarget 

Print #this(...) as this(...) inside a method

NoIfWithoutElse 

This location is the 'true' side of an if-else statement. At this location, no 'if' without 'else' is allowed because the outer else would, upon parsing, be associated with the inner 'if'.

NoParenthesis 

Avoids printing illegal opening paren at statement level

Member Function Documentation

EcsNodePrinter Loyc.Ecs.EcsNodePrinter.SetPlainCSharpMode ( )
inline

Property Documentation

bool Loyc.Ecs.EcsNodePrinter.AllowChangeParentheses
getset

Permits extra parentheses to express precedence, instead of resorting to prefix notation (defaults to true). Also permits removal of parenthesis if necessary to print special constructs.

For example, the Loyc tree x * @+(a, b) will be printed x * (a + b). Originally, the second tree had a significantly different structure from the first, as parenthesis were represented by a call to the empty symbol @``. This was annoyingly restrictive, so I reconsidered the design; now, parenthesis will be represented only by a trivia attribute #trivia_inParens, so adding new parenthesis no longer changes the Loyc tree in an important way, so the default has changed from false to true (except in the test suite).

bool Loyc.Ecs.EcsNodePrinter.AllowConstructorAmbiguity
getset

Causes the ambiguity between constructors and method calls to be ignored; see EcsPrinterAndParserTests.ConstructorAmbiguities().

bool Loyc.Ecs.EcsNodePrinter.AllowExtraBraceForIfElseAmbig
getset

Solve if-else ambiguity by adding braces rather than reverting to prefix notation.

For example, the tree #if(c1, #if(c2, x++), y++) will be parsed incorrectly if it is printed if (c1) if (c2) x++; else y++;. This problem can be resolved either by adding braces around if (c2) x++;, or by printing #if(c2, x++) in prefix notation.

bool Loyc.Ecs.EcsNodePrinter.AvoidMacroSyntax
getset

Prints statements like "foo (...) bar()" in the equivalent form "foo (..., bar())" instead. Does not affect foo {...} because property and event definitions require this syntax (get {...}, set {...}).

bool Loyc.Ecs.EcsNodePrinter.DropNonDeclarationAttributes
getset

Suppresses printing of all attributes that are not on declaration or definition statements (such as classes, methods and variable declarations at statement level). Also, avoids prefix notation when the attributes would have required it, e.g. @+([Foo] a, b) can be printed "a+b" instead.

This also affects the validation methods such as IsVariableDecl. With this flag, validation methods will ignore attributes in locations where they don't belong instead of returning false.

IMessageSink Loyc.Ecs.EcsNodePrinter.Errors
getset

Any error that occurs during printing is printed to this object.

bool Loyc.Ecs.EcsNodePrinter.MixImmiscibleOperators
getset

Allows operators to be mixed that will cause the parser to produce a warning. An example is x & @==(y, z): if you enable this option, it will be printed as x & y == z, which the parser will complain about because mixing those operators is deprecated.

NewlineOpt Loyc.Ecs.EcsNodePrinter.NewlineOptions
getset

Controls the locations where newlines should be emitted.

bool Loyc.Ecs.EcsNodePrinter.OmitComments
getset

When this flag is set, comment trivia attributes are ignored (e.g. CodeSymbols.TriviaSLCommentAfter).

bool Loyc.Ecs.EcsNodePrinter.OmitMissingArguments
getset

When an argument to a method or macro has an empty name (@``), it will be omitted completely if this flag is set.

bool Loyc.Ecs.EcsNodePrinter.OmitRawText
getset

When this flag is set, raw text trivia attributes are ignored (e.g. CodeSymbols.TriviaRawTextBefore).

bool Loyc.Ecs.EcsNodePrinter.OmitSpaceTrivia
getset

When this flag is set, space trivia attributes are ignored (e.g. CodeSymbols.TriviaSpaceAfter).

Note: since EcsNodePrinter inserts its own spaces automatically, space trivia (if any) may be redundant unless you set SpaceOptions and/or NewlineOptions to zero.

bool Loyc.Ecs.EcsNodePrinter.PreferPlainCSharp
getset

Prefers plain C# syntax for certain other things (not covered by the other options), even when the syntax tree requests a different style, e.g. EC# cast operators are blocked so x(->int) becomes (int) x.

bool Loyc.Ecs.EcsNodePrinter.QuoteUnprintableLiterals
getset

When the printer encounters an unprintable literal, it calls Value.ToString(). When this flag is set, the string is placed in double quotes; when this flag is clear, it is printed as raw text.

SpaceOpt Loyc.Ecs.EcsNodePrinter.SpaceOptions
getset

Controls the locations where spaces should be emitted.