Quite a long time passed, since Roslyn CTP was made publicly available. Ever since October 2011 I am thinking about, wrting a post about Roslyn. Now I feel inspired enough to write about this exciting new thing.
What is Project Roslyn All About?
In short: Roslyn turns the inner workings of your C# and VB compiler functions inside/out. By writing this post, I am reading the Roslyn Project Overwiev. I like to cite a passage, which will help to understand the purpose of Roslyn clearly:
This is the core mission of the Roslyn project: opening up the black boxes and allowing tools and end users to share in the wealth of information compilers have about our code. Instead of being opaque source-code-in and object-code-out translators, through the Roslyn project, compilers become services—APIs that you can use for code related tasks in your tools and applications.
This concludes, that compilers can be used as a service in the future. All the functionality of your C# or VB compiler is now available. Let’s see what you can do with this information.
Exposing the Compiler Functions through an API
The Roslyn people talk about a “Compiler Pipeline” which is offered through separate components to you via an C#/VB API.
Here an image, which explains, how the compiler pipline works (taken from the original overview):
As you can see, the compiler pipeline consists of four phases:
- Source is parsed into syntax
- Declaration phase. Declarations from source and metadata get analyzed.
- Identifiers in code are matched to symbols
- Everything is emmited as assemlby
To demonstrate the syntax tree, I will use a simple example, taken from the “Roslyn Project Overview” which I have extended with a recursive method to display a syntax tree:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
namespace RoslynConsoleApp
{
internal class Program
{
private static void Main(string[] args)
{
//Building a syntax tree from a a Hello World sample
SyntaxTree tree = SyntaxTree.ParseCompilationUnit(
@"using System;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(""Hello, World!"");
}
}
}");
PrintSyntaxTree(tree.Root,1);
}
private static void PrintSyntaxTree(SyntaxNode node, int level)
{
foreach (var childNode in node.ChildNodes())
{
string indicator = new String('=', level);
indicator += ">";
Console.WriteLine("Level {0} {1}",level, indicator);
Console.WriteLine(childNode.GetText());
Console.WriteLine("===SYNTAX LIST FOR CHILD NODE===");
ChildSyntaxList syntaxList = childNode.ChildNodesAndTokens();
foreach (var syntaxEntry in syntaxList)
{
Console.WriteLine("Kind:{0} Text:{1}",syntaxEntry.Kind.ToString(),syntaxEntry.GetText());
}
if (childNode.HasChildren)
{
PrintSyntaxTree(childNode,++level);
}
}
}
}
}
This code will print out the internal structure of the above source, made available through the Syntax Tree Api of the Roslyn project:
Level 1 =>
using System;
===SYNTAX LIST FOR CHILD NODE===
Kind:UsingKeyword Text:using
Kind:IdentifierName Text:System
Kind:SemicolonToken Text:;
Level 2 ==>
System
===SYNTAX LIST FOR CHILD NODE===
Kind:IdentifierToken Text:System
Level 2 ==>
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
}
===SYNTAX LIST FOR CHILD NODE===
Kind:NamespaceKeyword Text:namespace
Kind:IdentifierName Text:HelloWorld
Kind:OpenBraceToken Text:{
Kind:ClassDeclaration Text:class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
Kind:CloseBraceToken Text:}
Level 3 ===>
HelloWorld
===SYNTAX LIST FOR CHILD NODE===
Kind:IdentifierToken Text:HelloWorld
Level 4 ====>
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
===SYNTAX LIST FOR CHILD NODE===
Kind:ClassKeyword Text:class
Kind:IdentifierToken Text:Program
Kind:OpenBraceToken Text:{
Kind:MethodDeclaration Text:static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
Kind:CloseBraceToken Text:}
Level 5 =====>
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
===SYNTAX LIST FOR CHILD NODE===
Kind:StaticKeyword Text:static
Kind:PredefinedType Text:void
Kind:IdentifierToken Text:Main
Kind:ParameterList Text:(string[] args)
Kind:Block Text:{
Console.WriteLine("Hello, World!");
}
Level 6 ======>
void
===SYNTAX LIST FOR CHILD NODE===
Kind:VoidKeyword Text:void
Level 7 =======>
(string[] args)
===SYNTAX LIST FOR CHILD NODE===
Kind:OpenParenToken Text:(
Kind:Parameter Text:string[] args
Kind:CloseParenToken Text:)
Level 8 ========>
string[] args
===SYNTAX LIST FOR CHILD NODE===
Kind:ArrayType Text:string[]
Kind:IdentifierToken Text:args
Level 9 =========>
string[]
===SYNTAX LIST FOR CHILD NODE===
Kind:PredefinedType Text:string
Kind:ArrayRankSpecifier Text:[]
Level 10 ==========>
string
===SYNTAX LIST FOR CHILD NODE===
Kind:StringKeyword Text:string
Level 11 ===========>
[]
===SYNTAX LIST FOR CHILD NODE===
Kind:OpenBracketToken Text:[
Kind:CloseBracketToken Text:]
Level 8 ========>
{
Console.WriteLine("Hello, World!");
}
===SYNTAX LIST FOR CHILD NODE===
Kind:OpenBraceToken Text:{
Kind:ExpressionStatement Text:Console.WriteLine("Hello, World!");
Kind:CloseBraceToken Text:}
Level 9 =========>
Console.WriteLine("Hello, World!");
===SYNTAX LIST FOR CHILD NODE===
Kind:InvocationExpression Text:Console.WriteLine("Hello, World!")
Kind:SemicolonToken Text:;
Level 10 ==========>
Console.WriteLine("Hello, World!")
===SYNTAX LIST FOR CHILD NODE===
Kind:MemberAccessExpression Text:Console.WriteLine
Kind:ArgumentList Text:("Hello, World!")
Level 11 ===========>
Console.WriteLine
===SYNTAX LIST FOR CHILD NODE===
Kind:IdentifierName Text:Console
Kind:DotToken Text:.
Kind:IdentifierName Text:WriteLine
Level 12 ============>
Console
===SYNTAX LIST FOR CHILD NODE===
Kind:IdentifierToken Text:Console
Level 13 =============>
WriteLine
===SYNTAX LIST FOR CHILD NODE===
Kind:IdentifierToken Text:WriteLine
Level 12 ============>
("Hello, World!")
===SYNTAX LIST FOR CHILD NODE===
Kind:OpenParenToken Text:(
Kind:Argument Text:"Hello, World!"
Kind:CloseParenToken Text:)
Level 13 =============>
"Hello, World!"
===SYNTAX LIST FOR CHILD NODE===
Kind:StringLiteralExpression Text:"Hello, World!"
Level 14 ==============>
"Hello, World!"
===SYNTAX LIST FOR CHILD NODE===
Kind:StringLiteralToken Text:"Hello, World!"
Press any key to continue . . .
In the next part I will focus on the Symbol API and I will extend the existing sample with some visual extensions.



