Enhanced C#
Language of your choice: library documentation
Nested classes | Public Types | Properties | Public Member Functions | Static Public Member Functions | List of all members
Loyc.Ecs.EcsNodePrinter Class Reference

Encapsulates the code for printing an LNode to EC# source code. More...


Source file:

Remarks

Encapsulates the code for printing an LNode to EC# source code.

To print EC# code, you not use this class directly. Instead, call EcsLanguageService.Print(LNode, StringBuilder, IMessageSink, ParsingMode, ILNodePrinterOptions) via EcsLanguageService.WithPlainCSharpPrinter or via EcsLanguageService.Value. This class does have some static methods like PrintLiteral(object, NodeStyle) and PrintId that are useful for printing tokens efficiently.

This class is designed to faithfully preserve most Loyc trees; almost 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. Originally this class was meant to provide round-tripping from Loyc trees to text and back, but Enhanced C# is syntactically very complicated and as a result this printer may contain bugs or (for the sake of practicality) minor intentional limitations that cause round-tripping not to work in rare cases. If you need perfect round-tripping, use LES instead (LesLanguageService).

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 (this caveat applies equally to LES). Also, any attribute whose Name starts with the trivia marker % may be dropped, because these attributes are considered extensions of the NodeStyle. However, the style indicated by the % attribute will be used if the printer recognizes it.

For round-tripping to work, there are a couple of restrictions on the input tree:

  1. 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.

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.ForEachInitializer = 0x1000, Ambiguity.ElseClause = 0x2000,
  Ambiguity.NoParentheses = 0x4000, Ambiguity.AllowThisAsCallTarget = 0x8000, Ambiguity.NoIfWithoutElse = 0x10000,
  Ambiguity.ForceAttributeList = 0x40000, Ambiguity.NewlineBeforeChildStmt = 0x80000
}
 Internal enum (marked public for an obscure technical reason). These are flags that represent special situations in EC# syntax. More...
 
enum  IdPrintMode {
  Normal, Symbol, Operator,
  Verbatim
}
 

Properties

INodePrinterWriter Writer [get, set]
 
IMessageSink?? ErrorSink [get, set]
 Any error that occurs during printing is printed to this object. More...
 
EcsPrinterOptions Options [get]
 

Public Member Functions

void SetOptions (ILNodePrinterOptions options)
 

Static Public Member Functions

static void PrintPlainCSharp (LNode node, StringBuilder target, IMessageSink sink, ParsingMode mode, ILNodePrinterOptions options=null)
 Prints a node while avoiding syntax specific to Enhanced C#. More...
 
static void PrintECSharp (LNode node, StringBuilder target, IMessageSink sink, ParsingMode mode, ILNodePrinterOptions options=null)
 Prints a node as EC# code. More...
 
static string PrintId (Symbol name, IdPrintMode mode=IdPrintMode.Normal)
 
static string PrintSymbolLiteral (Symbol name)
 
static string PrintLiteral (object value, NodeStyle style)
 
static string PrintString (string value, char quoteType, bool verbatim=false, bool includeAtSign=true)
 

Member Enumeration Documentation

◆ Ambiguity

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.

This is also used in the case of <tt>~((Foo), x) which must not be printed as (Foo) ~ x

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 

The "expression" being printed is a type, or part of a type, which may have special printing rules (e.g. consider Foo?[], List<(X,Y)>.

InDefinitionName 

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

InOf 

Printing a type inside angle brackets or !(...).

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.

ForEachInitializer 

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

ElseClause 

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

NoParentheses 

A statement is being printed, or the return value or name of a method, so parentheses cannot be emitted here.

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'.

ForceAttributeList 

Force PrintAttrs to print an empty attribute list [] which has the effect of allowing unassigned variable declarations anywhere.

NewlineBeforeChildStmt 

A signal that IF there is no trivia indicating whether or not to print a newline before the current statement, one should be printed.

Member Function Documentation

◆ PrintECSharp()

static void Loyc.Ecs.EcsNodePrinter.PrintECSharp ( LNode  node,
StringBuilder  target,
IMessageSink  sink,
ParsingMode  mode,
ILNodePrinterOptions  options = null 
)
inlinestatic

Prints a node as EC# code.

Referenced by Loyc.Ecs.EcsLanguageService.Print().

◆ PrintPlainCSharp()

static void Loyc.Ecs.EcsNodePrinter.PrintPlainCSharp ( LNode  node,
StringBuilder  target,
IMessageSink  sink,
ParsingMode  mode,
ILNodePrinterOptions  options = null 
)
inlinestatic

Prints a node while avoiding syntax specific to Enhanced C#.

This does not perform a conversion from EC# to C#. If the syntax tree contains code that has no direct C# representation, the EC# representation will be printed.

Referenced by Loyc.Ecs.EcsLanguageService.Print().

Property Documentation

◆ ErrorSink

IMessageSink?? Loyc.Ecs.EcsNodePrinter.ErrorSink
getset

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

The most common error is an unprintable literal.