Enhanced C#
Language of your choice: library documentation
|
All nodes in a Loyc syntax tree share this base class. More...
All nodes in a Loyc syntax tree share this base class.
Loyc defines only three types of nodes: simple symbols, literals, and calls.
f(x)
, generic specifications like f<x>
(represented as #of(f, x)
), braced blocks of statements (represented as <tt>{}
(stmt1, stmt2, ...)), and so on. Also, parenthesized expressions are represented as a call with one argument and null
as the Target. This class provides access to all properties of all three types of nodes, in order to make this class easier to access from plain C#, and to avoid unnecessary downcasting in some cases.
Loyc nodes are always immutable, except for the 8-bit Style property which normally affects printing only.
EC# (enhanced C#) is intended to be the starting point of the Loyc (Language of your choice) project, which will be a family of programming languages that will share a common representation for the syntax tree and other compiler-related data structures.
Just as LLVM assembly has emerged as a nearly universal standard intermediate representation for back-ends, Loyc nodes are intended to be a universal intermediate representation for syntax trees, and Loyc will (eventually) include a generic set of tools for semantic analysis so that it provides a generic representation for front-ends.
EC#, then, will be the first language to use the Loyc syntax tree representation, known as the "Loyc tree" for short. Most syntax trees are very strongly typed, with separate data types for, say, variable declarations, binary operators, method calls, method declarations, unary operators, and so forth. Loyc, however, defines only three types of Nodes, and this one class provides access to all the parts of a node. There are several reasons for this design:
Loyc trees are comparable to LISP trees, except that "attributes" and position information are added to the tree, and the concept of a "list" is replaced with the concept of a "call", which I feel is a more intuitive notion in most programming languages that are not LISP.
Loyc's representation is both an blessing and a curse. The advantage is that Loyc nodes can be used for almost any purpose, perhaps even representing data instead of code in some cases. However, there is no guarantee that a given AST follows the structure prescribed by a particular programming language, unless a special validation step is performed after parsing. In this way, Loyc trees are similar to XML trees, only simpler.
Another major disadvantage is that it is more difficult to interpret a syntax tree correctly: you have to remember that a method definition has the structure #fn(return_type, name, args, body)
, so if "node" is a method definition then node.Args[2]
represents the return type, for example. In contrast, most compilers have an AST class called MethodDefinition
or something, that provides properties such as Name and ReturnType. Once EC# is developed, however, aliases could help avoid this problem by providing a more friendly veneer over the raw nodes.
For optimization purposes, the node class is a class hierarchy, but most users should only use this class and perhaps the three derived classes IdNode, LiteralNode and CallNode. Some users will also find it useful to use LNodeFactory for generating synthetic code snippets (bits of code that never existed in any source file), although you can also use the methods defined here in this class: Id(), Literal(), Call(), InParens().
Normal LNodes are "persistent" in the comp-sci sense, which means that a subtree can be shared among multiple syntax trees, and nodes do not know their own parents. This allows a single node to exist at multiple locations in a syntax tree. This makes manipulation of trees convenient, as there is no need to "detach" a node from one place, or duplicate it, before it can be inserted in another place. Immutable nodes can be safely re-used within different source files or multiple versions of one source file in an IDE's "intellisense" or "code completion" engine.
This implementation has been redesigned (in Subversion, the last version based on the old design is revision 289.) The core concept is the same as described in my blog at http://loyc-etc.blogspot.ca/2013/04/the-loyc-tree-and-prefix-notation-in-ec.html except that the concept of a "Head" has mostly been eliminated, although you might see it occasionally because it still has a meaning. The "head" of a node refers either to the Name of a symbol, the Value of a literal, or the Target of a call (i.e. the name of the method being called, which could be an arbitrarily complex node). In the original implementation, it was also possible to have a complex head (a head that is itself a node) even when the node was not a call; this situation was used to represent an expression in parenthesis.
This didn't quite feel right, so I changed it. Now, only calls can be complex, and the head of a call (the method being called) is called the Target.
In the new version, there are explicitly three types of nodes: symbols, literals, and calls. There is no longer a Head property, instead there are three separate properties for the three kinds of heads, Name (a Symbol), Value (an Object), and Target (an LNode). Only call nodes have a Target, and only literal nodes have a Value (as an optimization, StdTriviaNode breaks this rule; it can only do this because it represents special attributes that are outside the normal syntax tree, such as comments). Symbol nodes have a Name, but I thought it would be useful for some call nodes to also have a Name, which is defined as the name of the Target if the Target is a symbol (if the Target is not a symbol, the Name must be blank.)
An expression in parenthesis is now represented by a call with a blank name (use IsParenthesizedExpr to detect this case; it is incorrect to test Name == $``
because a call with a non-symbol Target also has a blank name.)
The following differences in implementation have been made:
The problems that motivated a redesign are described at http://loyc-etc.blogspot.ca/2013/05/redesigning-loyc-tree-code.html
One very common use of mutable nodes is building lists of statements, e.g. you might create an empty braced block or an empty loop and then add statements to the body of the block or loop. To do this without mutable nodes, create a mutable WList{LNode} instead and add statements there; once the list is finished, create the braced block or loop afterward. The new design stores arguments and attributes in VList{LNode} objects; you can instantly convert your WList to a VList by calling WListBase{LNode}.ToVList().
During the redesign I've decided on some small changes to the representation of certain expressions in EC#.
a.b.c
is now represented #.(#.(a, b), c)
rather than #.(a, b, c)
mainly because it's easier that way, and because the second representation doesn't buy anything significant other than a need for special-casing. int x = 0
will now be represented #var(int, x = 0)
rather than #var(int, x(0))
. I chose the latter representation initially because it is slightly more convenient, because you can always learn the name of the declared variable by calling var.Args[1].Name
. However, I decided that it was more important for the syntax tree to be predictable, with obvious connections between normal and prefix notations. Since I decided that alias X = Y;
was to be represented #alias(X = Y, #())
, it made sense for the syntax tree of a variable declaration to also resemble its C# syntax. There's another small reason: C++ has both styles Foo x(y)
and Foo x = y
; if Loyc were to ever support C++, it would make sense to use #var(Foo, x(y))
and #var(Foo, x = y)
for these two cases, and I believe C#'s variable declarations are semantically closer to the latter. (Note: another possibility was #var(int, x) = 0, but I decided this wasn't an improvement, it would just shift the pain around.) new int[] { x }
must have an empty set of arguments on int[], i.e. #new(#of(#[],int)(), x)
; this rule makes the different kinds of new expressions easier to interpret by making them consistent with each other. The main properties of a node are
The argument and attribute lists cannot be null, since they have type VList{Node} which is a struct.
LNode
implements INegListSource{T}, so you can loop through all children of the node like this:
You can also use foreach
. The children are numbered like this:
Target
(but throws if there is no target) LNode also provides Select(child => result)
and ReplaceRecursive(child => result)
methods which allows you to transform all children (Atrrs, Target and Args). Currently there is no Where(child => bool)
method because it is not possible to remove the Target of an LNode (you can still use standard LINQ Where(), of course, but the result is not an LNode).
The argument and attribute lists should never contain null nodes. Any code that puts nulls in Args or Attrs is buggy. However, we can't ensure nulls are not placed into VList{T} since it's a general-purpose data type, not specialized for LNode. There is code to ensure nulls are not placed in Args and Attrs (NoNulls), but only in debug builds, since null-checking is fairly expensive.
Nested classes | |
class | DeepComparer |
An IEqualityComparer that compares nodes structurally. More... | |
struct | PushedPrinter |
Returned by PushPrinter(LNodePrinter). More... | |
Public static fields | |
static readonly EmptySourceFile | SyntheticSource = new EmptySourceFile("<Synthetic Code>") |
static readonly IdNode | Missing = Id(CodeSymbols.Missing) |
static readonly LNode | InParensTrivia = Id(CodeSymbols.TriviaInParens) |
Properties | |
virtual SourceRange | Range [get] |
Returns the location and range in source code of this node. More... | |
ISourceFile | Source [get] |
Returns the source file (shortcut for Range.Source ). More... | |
NodeStyle | Style [get, set] |
Indicates the preferred style to use when printing the node to a text string. More... | |
NodeStyle | BaseStyle [get, set] |
virtual VList< LNode > | Attrs [get] |
Returns the attribute list for this node. More... | |
virtual bool | IsFrozen [get] |
Returns true if the node is immutable, and false if any part of it can be edited. Currently, mutable nodes are not implemented. More... | |
abstract LNodeKind | Kind [get] |
Returns the LNodeKind: Symbol, Literal, or Call. More... | |
bool | IsCall [get] |
bool | IsId [get] |
bool | IsLiteral [get] |
abstract Symbol | Name [get] |
Returns the Symbol if IsId. If this node is a call (IsCall) and Target.IsId is true, this property returns Target.Name . In all other cases, the name is GSymbol.Empty. Shall not return null. More... | |
bool | HasSpecialName [get] |
Returns true if Name starts with '#'. More... | |
bool | HasValue [get] |
abstract object | Value [get] |
Returns the value of a literal node, or NoValue.Value if this node is not a literal (IsLiteral is false). More... | |
abstract LNode | Target [get] |
Returns the target of a method call, or null if IsCall is false. The target can be a symbol with no name (GSymbol.Empty) to represent a parenthesized expression, if there is one argument. More... | |
abstract VList< LNode > | Args [get] |
Returns the argument list of this node. Always empty when IsCall==false . More... | |
static LNodePrinter | Printer [get, set] |
Gets or sets the default node printer on the current thread, which controls how nodes are serialized to text by default. More... | |
virtual object | TriviaValue [get] |
Gets the value of Args[0].Value , if Args[0] exists; otherwise, returns NoValue.Value. More... | |
bool | HasTokenValue [get] |
int | ArgCount [get] |
int | AttrCount [get] |
bool | HasAttrs [get] |
bool | IsTrivia [get] |
int | Min [get] |
virtual int | Max [get] |
LNode | this[int index] [get] |
int | Count [get] |
Properties inherited from Loyc.IHasLocation | |
object | Location [get] |
Properties inherited from Loyc.IHasValue< out T > | |
T | Value [get] |
Public Member Functions | |
LNode | SetBaseStyle (NodeStyle s) |
LNode | SetStyle (NodeStyle s) |
virtual LNode | WithName (Symbol name) |
Creates a node with a new value for Name. More... | |
abstract LiteralNode | WithValue (object value) |
Creates a new literal node with a different Value than the current literal node. More... | |
virtual CallNode | WithTarget (LNode target) |
virtual CallNode | WithTarget (Symbol name) |
abstract CallNode | WithArgs (VList< LNode > args) |
Creates a Node with a new argument list. If this node is not a call, a new node is created using this node as its target. Otherwise, the existing argument list is replaced. More... | |
virtual CallNode | With (LNode target, VList< LNode > args) |
Creates a CallNode with the same attributes and Range, but a different target and argument list. If the current node is not a CallNode, it becomes one (the Range, Style and attributes of the current node are kept, but the Kind, Value, and Name are discarded.) More... | |
virtual CallNode | With (Symbol target, VList< LNode > args) |
Creates a CallNode with the same attributes and Range, but a different target and argument list. If the current node is not a CallNode, it becomes one (the Range, Style and attributes of the current node are kept, but the Kind, Value, and Name are discarded.) More... | |
CallNode | With (Symbol target, params LNode[] args) |
abstract LNode | Clone () |
Creates a copy of the node. Since nodes are immutable, there is little reason for an end-user to call this, but Clone() is used internally as a helper method by the WithXyz() methods. More... | |
LNode | WithRange (SourceRange range) |
LNode | WithRange (int startIndex, int endIndex) |
LNode | WithStyle (NodeStyle style) |
virtual LNode | With (SourceRange range, NodeStyle style) |
virtual LNode | WithoutAttrs () |
abstract LNode | WithAttrs (VList< LNode > attrs) |
LNode | WithAttrs (params LNode[] attrs) |
CallNode | WithArgs (params LNode[] args) |
LNode | PlusAttr (LNode attr) |
LNode | PlusAttrs (VList< LNode > attrs) |
LNode | PlusAttrs (IEnumerable< LNode > attrs) |
LNode | PlusAttrs (params LNode[] attrs) |
LNode | PlusArg (LNode arg) |
LNode | PlusArgs (VList< LNode > args) |
LNode | PlusArgs (IEnumerable< LNode > args) |
LNode | PlusArgs (params LNode[] args) |
LNode | WithArgChanged (int index, LNode newValue) |
LNode | WithAttrChanged (int index, LNode newValue) |
abstract void | Call (LNodeVisitor visitor) |
abstract void | Call (ILNodeVisitor visitor) |
virtual string | Print (object mode=null, string indentString="\t", string lineSeparator="\n") |
override string | ToString () |
abstract bool | Equals (LNode other, bool compareStyles) |
Compares two nodes for structural equality. Two green nodes are considered equal if they have the same name, the same value, the same arguments, and the same attributes. IsCall must be the same, but they need not have the same values of SourceWidth or IsFrozen. More... | |
bool | Equals (LNode other) |
override bool | Equals (object other) |
override int | GetHashCode () |
Gets the hash code based on the structure of the tree. More... | |
bool | HasPAttrs () |
VList< LNode > | PAttrs () |
virtual bool | Calls (Symbol name, int argCount) |
virtual bool | Calls (string name, int argCount) |
virtual bool | Calls (Symbol name) |
virtual bool | Calls (string name) |
virtual bool | CallsMin (Symbol name, int argCount) |
virtual bool | CallsMin (string name, int argCount) |
virtual bool | HasSimpleHead () |
Returns true if this is not a call, or if the call's Target is an Id or a Literal. More... | |
virtual bool | HasSimpleHeadWithoutPAttrs () |
Returns true if this is not a call, or if the call's Target is an Id or a Literal, and the Target has only trivia attributes. More... | |
LNode | WithAttrs (Func< LNode, Maybe< LNode >> selector) |
virtual LNode | WithArgs (Func< LNode, Maybe< LNode >> selector) |
virtual bool | IsIdWithoutPAttrs () |
virtual bool | IsIdWithoutPAttrs (Symbol name) |
virtual bool | IsIdNamed (Symbol name) |
virtual bool | IsIdNamed (string name) |
virtual bool | IsParenthesizedExpr () |
CallNode | WithSplicedArgs (int index, LNode from, Symbol listName) |
CallNode | WithSplicedArgs (LNode from, Symbol listName) |
LNode | WithSplicedAttrs (int index, LNode from, Symbol listName) |
LNode | WithSplicedAttrs (LNode from, Symbol listName) |
NestedEnumerable < DescendantsFrame, LNode > | Descendants (NodeScanMode mode=NodeScanMode.YieldAllChildren) |
NestedEnumerable < DescendantsFrame, LNode > | DescendantsAndSelf () |
LNode | TryGet (int index, out bool fail) |
IRange< LNode > | Slice (int start, int count=int.MaxValue) |
IEnumerator< LNode > | GetEnumerator () |
abstract LNode | Select (Func< LNode, LNode > selector) |
Transforms the attributes, Target, and parameters of an LNode, returning another LNode of the same Kind. If the selector makes no changes, Select() returns this . More... | |
abstract LNode | ReplaceRecursive (Func< LNode, LNode > selector, bool replaceRoot=true) |
Performs a recursive find-and-replace operation, by attempting to replace each child (among Attrs, Target, Args) using the specified selector. This method can also be used for simple searching, by giving a selector that always returns null. More... | |
Static Public Member Functions | |
static IdNode | Id (Symbol name, LNode prototype) |
static IdNode | Id (string name, LNode prototype) |
static IdNode | Id (VList< LNode > attrs, Symbol name, LNode prototype) |
static IdNode | Id (VList< LNode > attrs, string name, LNode prototype) |
static LiteralNode | Literal (object value, LNode prototype) |
static LiteralNode | Literal (VList< LNode > attrs, object value, LNode prototype) |
static CallNode | Call (Symbol name, LNode prototype) |
static CallNode | Call (LNode target, LNode prototype) |
static CallNode | Call (Symbol name, VList< LNode > args, LNode prototype) |
static CallNode | Call (LNode target, VList< LNode > args, LNode prototype) |
static CallNode | Call (VList< LNode > attrs, Symbol name, VList< LNode > args, LNode prototype) |
static CallNode | Call (VList< LNode > attrs, LNode target, VList< LNode > args, LNode prototype) |
static CallNode | Trivia (Symbol name, object value, LNode prototype) |
static LNode | InParens (LNode node) |
static IdNode | Id (Symbol name, SourceRange range, NodeStyle style=NodeStyle.Default) |
static IdNode | Id (string name, SourceRange range, NodeStyle style=NodeStyle.Default) |
static IdNode | Id (VList< LNode > attrs, Symbol name, SourceRange range, NodeStyle style=NodeStyle.Default) |
static IdNode | Id (VList< LNode > attrs, string name, SourceRange range, NodeStyle style=NodeStyle.Default) |
static LiteralNode | Literal (object value, SourceRange range, NodeStyle style=NodeStyle.Default) |
static LiteralNode | Literal (VList< LNode > attrs, object value, SourceRange range, NodeStyle style=NodeStyle.Default) |
static CallNode | Call (Symbol name, SourceRange range, NodeStyle style=NodeStyle.Default) |
static CallNode | Call (LNode target, SourceRange range, NodeStyle style=NodeStyle.Default) |
static CallNode | Call (Symbol name, VList< LNode > args, SourceRange range, NodeStyle style=NodeStyle.Default) |
static CallNode | Call (LNode target, VList< LNode > args, SourceRange range, NodeStyle style=NodeStyle.Default) |
static CallNode | Call (VList< LNode > attrs, Symbol name, VList< LNode > args, SourceRange range, NodeStyle style=NodeStyle.Default) |
static CallNode | Call (VList< LNode > attrs, LNode target, VList< LNode > args, SourceRange range, NodeStyle style=NodeStyle.Default) |
static CallNode | Trivia (Symbol name, object value, SourceRange range, NodeStyle style=NodeStyle.Default) |
static LNode | InParens (LNode node, SourceRange range) |
static IdNode | Id (Symbol name, ISourceFile file=null, int position=-1, int width=-1) |
static IdNode | Id (string name, ISourceFile file=null, int position=-1, int width=-1) |
static IdNode | Id (VList< LNode > attrs, Symbol name, ISourceFile file=null, int position=-1, int width=-1) |
static IdNode | Id (VList< LNode > attrs, string name, ISourceFile file=null, int position=-1, int width=-1) |
static LiteralNode | Literal (object value, ISourceFile file=null, int position=-1, int width=-1, NodeStyle style=NodeStyle.Default) |
static LiteralNode | Literal (VList< LNode > attrs, object value, ISourceFile file=null, int position=-1, int width=-1, NodeStyle style=NodeStyle.Default) |
static CallNode | Call (Symbol name, ISourceFile file=null, int position=-1, int width=-1, NodeStyle style=NodeStyle.Default) |
static CallNode | Call (LNode target, ISourceFile file=null, int position=-1, int width=-1, NodeStyle style=NodeStyle.Default) |
static CallNode | Call (Symbol name, VList< LNode > args, ISourceFile file=null, int position=-1, int width=-1, NodeStyle style=NodeStyle.Default) |
static CallNode | Call (LNode target, VList< LNode > args, ISourceFile file=null, int position=-1, int width=-1, NodeStyle style=NodeStyle.Default) |
static CallNode | Call (VList< LNode > attrs, Symbol name, VList< LNode > args, ISourceFile file=null, int position=-1, int width=-1, NodeStyle style=NodeStyle.Default) |
static CallNode | Call (VList< LNode > attrs, LNode target, VList< LNode > args, ISourceFile file=null, int position=-1, int width=-1, NodeStyle style=NodeStyle.Default) |
static CallNode | Trivia (Symbol name, object value, ISourceFile file=null, int position=-1, int width=-1, NodeStyle style=NodeStyle.Default) |
static LNode | InParens (LNode node, ISourceFile file=null, int position=-1, int width=-1) |
static VList< LNode > | List () |
static VList< LNode > | List (LNode list_0) |
static VList< LNode > | List (LNode list_0, LNode list_1) |
static VList< LNode > | List (params LNode[] list) |
static VList< LNode > | List (IEnumerable< LNode > list) |
static VList< LNode > | List (VList< LNode > list) |
static PushedPrinter | PushPrinter (LNodePrinter printer) |
Helps you change printers temporarily. Usage in C#: using (LNode.PushPrinter(myPrinter)) { ... } More... | |
static bool | Equals (LNode a, LNode b, bool compareStyles=false) |
static bool | Equals (VList< LNode > a, VList< LNode > b, bool compareStyles=false) |
Compares two lists of nodes for structural equality. More... | |
static LNode | MergeLists (LNode node1, LNode node2, Symbol listName) |
Some CallNodes are used to represent lists. This method merges two nodes, forming or appending a list (see remarks). More... | |
static LNode | MergeBinary (LNode node1, LNode node2, Symbol binaryOpName) |
Combines two nodes using a binary operator or function. More... | |
Protected Member Functions | |
LNode (LNode prototype) | |
LNode (SourceRange range, NodeStyle style) | |
Static Protected Member Functions | |
static void | NoNulls (VList< LNode > list, string propName) |
Protected fields | |
RangeAndStyle | RAS |
|
pure virtual |
Creates a copy of the node. Since nodes are immutable, there is little reason for an end-user to call this, but Clone() is used internally as a helper method by the WithXyz() methods.
Implements Loyc.ICloneable< out T >.
Implemented in Loyc.Syntax.CallNode, Loyc.Syntax.LiteralNode, and Loyc.Syntax.IdNode.
|
inlinestatic |
Compares two lists of nodes for structural equality.
compareStyles | Whether to compare values of Style |
Position information is not compared.
|
pure virtual |
Compares two nodes for structural equality. Two green nodes are considered equal if they have the same name, the same value, the same arguments, and the same attributes. IsCall must be the same, but they need not have the same values of SourceWidth or IsFrozen.
compareStyles | Whether to compare values of Style |
Position information (Range) is not compared.
Implemented in Loyc.Syntax.CallNode, Loyc.Syntax.LiteralNode, and Loyc.Syntax.IdNode.
|
inline |
Gets the hash code based on the structure of the tree.
If the tree is large, less than the entire tree is scanned to produce the hashcode (in the absolute worst case, about 4000 nodes are examined, but usually it is less than 100).
References Loyc.Syntax.LNode.GetHashCode().
Referenced by Loyc.Syntax.LNode.GetHashCode().
|
inlinevirtual |
Returns true if this is not a call, or if the call's Target is an Id or a Literal.
Reimplemented in Loyc.Syntax.CallNode.
|
inlinevirtual |
Returns true if this is not a call, or if the call's Target is an Id or a Literal, and the Target has only trivia attributes.
Reimplemented in Loyc.Syntax.CallNode.
|
inlinestatic |
Combines two nodes using a binary operator or function.
node1 | First node, list, or null. |
node2 | Second node, list, or null. |
binaryOpName | Binary operator to use when the nodes are not null. |
|
inlinestatic |
Some CallNodes are used to represent lists. This method merges two nodes, forming or appending a list (see remarks).
node1 | First node, list, or null. |
node2 | Second node, list, or null. |
listName | The Name used to detect whether a node is a list (typically "#splice"). Any other name is considered a normal call, not a list. If this method creates a list from two non- lists, this parameter specifies the Name that the list will have. |
The order of the data is retained (i.e. the data in node1 is inserted before the data in node2).
|
inlinestatic |
Helps you change printers temporarily. Usage in C#: using (LNode.PushPrinter(myPrinter)) { ... }
For example, to switch to the EC# printer, use using (LNode.PushPrinter(EcsNodePrinter.Printer)) { ... }
. This changes the default printer. If you don't want to change the default printer, please invoke the printer directly:
|
pure virtual |
Performs a recursive find-and-replace operation, by attempting to replace each child (among Attrs, Target, Args) using the specified selector. This method can also be used for simple searching, by giving a selector that always returns null.
selector | The selector is called for each descendant, and optionally the root node. If the selector returns a node, the new node replaces the node that was passed to selector and the children of the new node are ignored. If the selector returns null, children of the child are scanned recursively. |
replaceRoot | Whether to call selector(this) . |
If replaceFunc
always returns null (or if replaceRoot
is false and the root has no children), ReplaceRecursive
returns this
.
Implemented in Loyc.Syntax.CallNode, Loyc.Syntax.LiteralNode, and Loyc.Syntax.IdNode.
Transforms the attributes, Target, and parameters of an LNode, returning another LNode of the same Kind. If the selector makes no changes, Select() returns this
.
The selector is not allowed to return null.
Implemented in Loyc.Syntax.CallNode, Loyc.Syntax.LiteralNode, and Loyc.Syntax.IdNode.
Creates a Node with a new argument list. If this node is not a call, a new node is created using this node as its target. Otherwise, the existing argument list is replaced.
args | New argument list |
Implemented in Loyc.Syntax.CallNode, Loyc.Syntax.LiteralNode, and Loyc.Syntax.IdNode.
Creates a node with a new value for Name.
If IsId, the Name is simply changed. If IsCall, this method returns the equivalent of WithTarget(Target.WithName(name))
(which may be optimized for the particular call type). If IsLiteral, the Kind changes to LNodeKind.Id in order to set the name.
Reimplemented in Loyc.Syntax.CallNode, and Loyc.Syntax.IdNode.
|
pure virtual |
Creates a new literal node with a different Value than the current literal node.
InvalidOperationException | The node was not a literal already. |
Implemented in Loyc.Syntax.CallNode, Loyc.Syntax.LiteralNode, and Loyc.Syntax.IdNode.
|
get |
Returns the argument list of this node. Always empty when IsCall==false
.
Depending on the Target, Args may represent an actual argument list, or it may represent some other kind of list. For example, if the target is "{}" then Args represents a list of statements in a braced block, and if the target is ">=" then Args represents the two arguments to the ">=" operator.
Referenced by Loyc.Syntax.LNodeExt.AsList(), Loyc.LLParserGenerator.CodeGenHelperBase.CallRule(), Loyc.LLParserGenerator.IntStreamCodeGenHelper.CodeToTerminalPred(), Loyc.Syntax.CallNode.Equals(), Loyc.Ecs.EcsValidators.KeyNameComponentOf(), Loyc.LLPG.Macros.LLLPG_parser(), Loyc.LLParserGenerator.CodeGenHelperBase.SetListInitializer(), and Loyc.Ecs.EcsValidators.SpaceStatementKind().
|
get |
Returns the attribute list for this node.
Referenced by Loyc.Syntax.IdNode.Equals(), Loyc.Syntax.LiteralNode.Equals(), Loyc.Syntax.CallNode.Equals(), and Loyc.Ecs.EcsValidators.IsPrintableTypeParam().
|
get |
Returns true if Name starts with '#'.
Note that this property returns false for the empty identifier @``
.
|
get |
Returns true if the node is immutable, and false if any part of it can be edited. Currently, mutable nodes are not implemented.
Debugger-hidden until such time as mutable nodes actually exist.
|
get |
Returns the LNodeKind: Symbol, Literal, or Call.
Referenced by Loyc.Syntax.IdNode.Equals(), Loyc.Syntax.LiteralNode.Equals(), Loyc.Syntax.CallNode.Equals(), and Loyc.Syntax.LNodeExt.MatchesPattern().
|
get |
Returns the Symbol if IsId. If this node is a call (IsCall) and Target.IsId
is true, this property returns Target.Name
. In all other cases, the name is GSymbol.Empty. Shall not return null.
Examples (using C#/LES syntax):
Expression Kind Name (blank if empty) hello Id hello #if Id #if Foo(x, y) Call Foo x += y Call += x.Foo(y) Call 5.0 Literal
Referenced by Loyc.LLParserGenerator.GeneralCodeGenHelper.CodeToTerminalPred(), and Loyc.Syntax.LNodeExt.MatchesPattern().
|
staticgetset |
Gets or sets the default node printer on the current thread, which controls how nodes are serialized to text by default.
The LES printer is the default, and will be used if you try to set this property to null.
|
get |
Returns the location and range in source code of this node.
A parser should record a sufficiently wide range for each parent node, such that all children are fully contained within the range. However, this is not an invariant; macros can splice together syntax trees from different source files or add synthetic nodes, so that the parent range does not necessarily include all child ranges. (In fact, in general it is impossible to ensure that parent ranges include child ranges because a parent can only specify a single source file, while children can come from several source files.)
|
get |
Returns the source file (shortcut for Range.Source
).
|
getset |
Indicates the preferred style to use when printing the node to a text string.
The Style is an 8-bit value that acts as a hint to the node printer about how the node should be printed. Custom display styles that do not fit in the Style property can be expressed with special attributes that have a Name starting with "#trivia_". ("#trivia" attributes, which are also used to store comments in the syntax tree, are not printed like normal attributes and are normally ignored if the node printer does not specifically recognize them.)
Referenced by Loyc.Syntax.IdNode.Equals(), Loyc.Syntax.LiteralNode.Equals(), and Loyc.Syntax.CallNode.Equals().
|
get |
Returns the target of a method call, or null if IsCall is false. The target can be a symbol with no name (GSymbol.Empty) to represent a parenthesized expression, if there is one argument.
Referenced by Loyc.Syntax.CallNode.Equals(), Loyc.Ecs.EcsValidators.KeyNameComponentOf(), and Loyc.Syntax.LNodeExt.MatchesPattern().
|
get |
Gets the value of Args[0].Value
, if Args[0] exists; otherwise, returns NoValue.Value.
"Trivia nodes" are used to efficiently represent the value of trivia and non-tree Lexing.Tokens; they can be created by calling the LNode.Trivia function. Since an LNode is not allowed to have both a Name and a Value (as there is no syntax in LES or EC# for such a node), a trivia node pretends that there is an argument list with one item, and that one item is always a literal whose Value is the value stored in the trivia node. Thus, a token node is printed out as TokenType(Value)
where Value
is some literal.
If you suspect you're dealing with a trivia node, it is wasteful to actually call node.Args[0].Value
since this causes a temporary token list to be allocated. Instead you should use this property, which returns the token value without allocating memory. Of course, if this property is called on a non-trivia node, it simply returns Args[0].Value
.
|
get |
Returns the value of a literal node, or NoValue.Value if this node is not a literal (IsLiteral is false).
Referenced by Loyc.LLParserGenerator.IntStreamCodeGenHelper.CodeToTerminalPred(), and Loyc.LLPG.Macros.LLLPG_parser().