I'm trying to create a small code generator using Roslyn or as it is called now .NET Compiler Platform, prevously I worked with codedom, which was cumbersome but MSDN got a reference, now Roslyn has little documentation and all documentation is focused on code analysis instead of code generation.
So my question is simple:
How can I create something like:
private const string MyString = "This is my string";
using the Compiler Platform classes? I've found something like FieldDeclarationSyntax and ExpressionSyntax, but all samples I've found generate things like
Myclass myvariable = new Myclass();
And there is nothing telling me something so simple as how to produce the
string type declaration.
any clue will be great.
Thank you in advance
You can use Roslyn Quoter to easily figure out how to build different pieces of syntax. In this case you're wanting to add the const and private modifiers to a field declaration so it would look something like:
var constField = SyntaxFactory.FieldDeclaration(
SyntaxFactory.VariableDeclaration(
SyntaxFactory.PredefinedType(
SyntaxFactory.Token(SyntaxKind.StringKeyword)))
.WithVariables(
SyntaxFactory.SingletonSeparatedList<VariableDeclaratorSyntax>(
SyntaxFactory.VariableDeclarator(
SyntaxFactory.Identifier("MyString"))
.WithInitializer(
SyntaxFactory.EqualsValueClause(
SyntaxFactory.LiteralExpression(
SyntaxKind.StringLiteralExpression,
SyntaxFactory.Literal("This is my string")))))))
.WithModifiers(
SyntaxFactory.TokenList(
new []{
SyntaxFactory.Token(SyntaxKind.PrivateKeyword),
SyntaxFactory.Token(SyntaxKind.ConstKeyword)}))))))
Related
I'm using Roslyn to generate code for a tool I'm building. I'm using the SyntaxGenerator (as opposed to SyntaxFactory) as I'd prefer to not have to write implementations for both C# and VB.NET.
According to the reference source, the AssignmentStatement deliberately adds parentheses to the right side node. E.g.
Key = (key)
Whereas what I'm looking for is without parentheses:
Key = key
Example
This is a very basic, very watered down example which should reproduce this behaviour.
public void Example()
{
using (var workspace = new AdhocWorkspace())
{
var generator = SyntaxGenerator.GetGenerator(workspace, LanguageNames.CSharp);
var statement = generator.AssignmentStatement(generator.IdentifierName("Key"), generator.IdentifierName("key"));
var result = statement.NormalizeWhitespace().ToFullString();
}
}
I've searched extensively both here on SO as well as on Github, Roslyn Reference Source and various blogs and examples* but can't seem to find an elegant way to remove these redundant parentheses.
Although this is still legal syntax and will compile, it's really annoying.
Any ideas? Am I doing something wrong? Tips? Hopeless case?
*This example generates a constructor with redundant parentheses in the assignments as well.
I would like to generate syntax nodes with the Roslyn API without having a pre-existing syntax node. That is, I cannot simply use the WithXYZ() methods on an existing object to modify it because there is no existing object.
For example, I would like to generate an InvocationExpressionSyntax object. Assuming a constructor was available, I could do something like
var invoke = new InvocationExpressionSyntax(expression, arguments);
But the constructor for InvocationExpressionSyntax seems to not be public.
http://www.philjhale.com/2012/10/getting-started-with-roslyn.html
this blog suggests that I can use an API such as
Syntax.InvocationExpression()
but I don't see what Syntax refers to, and I don't see anything that resembles it in the Roslyn API.
I did find Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory that lets me do
var invoke = SyntaxFactory.InvocationExpression().WithExpression(expression);
And this works well enough for me. There is also Microsoft.CodeAnalysis.CSharp.SyntaxFactory for anyone wondering.
Is SyntaxFactory the proper way to create new syntax nodes?
The way I found SyntaxFactory.InvocationExpression was by looking at the PublicAPI.txt file in the roslyn source code (https://github.com/dotnet/roslyn) under the src/Compilers/VisualBasic/Portable directory. Otherwise, I don't see where SyntaxFactory is documented.
As the other answer stated, the SyntaxFactory is the correct class to use. As you have found there are two syntax factories available, Microsoft.CodeAnalysis.CSharp.SyntaxFactory and Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory, depending on which language you are using.
Usually the calls into the SyntaxFactory are chained together, so you end up with many calls to the SytnaxFactory methods to generate even simple lines of code. For example, the code Console.WriteLine("A"); would be represented by the following calls to the Syntax Factory:
var console = SyntaxFactory.IdentifierName("Console");
var writeline = SyntaxFactory.IdentifierName("WriteLine");
var memberaccess = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, console, writeline);
var argument = SyntaxFactory.Argument(SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal("A")));
var argumentList = SyntaxFactory.SeparatedList(new[] { argument });
var writeLineCall =
SyntaxFactory.ExpressionStatement(
SyntaxFactory.InvocationExpression(memberaccess,
SyntaxFactory.ArgumentList(argumentList)));
If you are unsure of how to generate nodes for some specific code, Kirill Osenkov created the Roslyn Quoter project on GitHub, which you can use to generate the SyntaxFactory code for you.
I recently did a blog post on this topic if you would like to read further.
Yes, the SyntaxFactory type is the way to create syntax nodes from scratch.
I've been puzzling about this for a while and I've looked around a bit, unable to find any discussion about the subject.
Lets assume I wanted to implement a trivial example, like a new looping construct: do..until
Written very similarly to do..while
do {
//Things happen here
} until (i == 15)
This could be transformed into valid csharp by doing so:
do {
//Things happen here
} while (!(i == 15))
This is obviously a simple example, but is there any way to add something of this nature? Ideally as a Visual Studio extension to enable syntax highlighting etc.
Microsoft proposes Rolsyn API as an implementation of C# compiler with public API. It contains individual APIs for each of compiler pipeline stages: syntax analysis, symbol creation, binding, MSIL emission. You can provide your own implementation of syntax parser or extend existing one in order to get C# compiler w/ any features you would like.
Roslyn CTP
Let's extend C# language using Roslyn! In my example I'm replacing do-until statement w/ corresponding do-while:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Roslyn.Compilers.CSharp;
namespace RoslynTest
{
class Program
{
static void Main(string[] args)
{
var code = #"
using System;
class Program {
public void My() {
var i = 5;
do {
Console.WriteLine(""hello world"");
i++;
}
until (i > 10);
}
}
";
//Parsing input code into a SynaxTree object.
var syntaxTree = SyntaxTree.ParseCompilationUnit(code);
var syntaxRoot = syntaxTree.GetRoot();
//Here we will keep all nodes to replace
var replaceDictionary = new Dictionary<DoStatementSyntax, DoStatementSyntax>();
//Looking for do-until statements in all descendant nodes
foreach (var doStatement in syntaxRoot.DescendantNodes().OfType<DoStatementSyntax>())
{
//Until token is treated as an identifier by C# compiler. It doesn't know that in our case it is a keyword.
var untilNode = doStatement.Condition.ChildNodes().OfType<IdentifierNameSyntax>().FirstOrDefault((_node =>
{
return _node.Identifier.ValueText == "until";
}));
//Condition is treated as an argument list
var conditionNode = doStatement.Condition.ChildNodes().OfType<ArgumentListSyntax>().FirstOrDefault();
if (untilNode != null && conditionNode != null)
{
//Let's replace identifier w/ correct while keyword and condition
var whileNode = Syntax.ParseToken("while");
var condition = Syntax.ParseExpression("(!" + conditionNode.GetFullText() + ")");
var newDoStatement = doStatement.WithWhileKeyword(whileNode).WithCondition(condition);
//Accumulating all replacements
replaceDictionary.Add(doStatement, newDoStatement);
}
}
syntaxRoot = syntaxRoot.ReplaceNodes(replaceDictionary.Keys, (node1, node2) => replaceDictionary[node1]);
//Output preprocessed code
Console.WriteLine(syntaxRoot.GetFullText());
}
}
}
///////////
//OUTPUT://
///////////
// using System;
// class Program {
// public void My() {
// var i = 5;
// do {
// Console.WriteLine("hello world");
// i++;
// }
//while(!(i > 10));
// }
// }
Now we can compile updated syntax tree using Roslyn API or save syntaxRoot.GetFullText() to text file and pass it to csc.exe.
The big missing piece is hooking into the pipeline, otherwise you're not much further along than what .Emit provided. Don't misunderstand, Roslyn brings alot of great things, but for those of us who want to implement preprocessors and meta programming, it seems for now that was not on the plate. You can implement "code suggestions" or what they call "issues"/"actions" as an extension, but this is basically a one off transformation of code that acts as a suggested inline replacement and is not the way you would implement a new language feature. This is something you could always do with extensions, but Roslyn makes the code analysis/transformation tremendously easier:
From what I've read of comments from Roslyn developers on the codeplex forums, providing hooks into the pipeline has not been an initial goal. All of the new C# language features they've provided in C# 6 preview involved modifying Roslyn itself. So you'd essentially need to fork Roslyn. They have documentation on how to build Roslyn and test it with Visual Studio. This would be a heavy handed way to fork Roslyn and have Visual Studio use it. I say heavy-handed because now anyone who wants to use your new language features must replace the default compiler with yours. You could see where this would begin to get messy.
Building Roslyn and replacing Visual Studio 2015 Preview's compiler with your own build
Another approach would be to build a compiler that acts as a proxy to Roslyn. There are standard APIs for building compilers that VS can leverage. It's not a trivial task though. You'd read in the code files, call upon the Roslyn APIs to transform the syntax trees and emit the results.
The other challenge with the proxy approach is going to be getting intellisense to play nicely with any new language features you implement. You'd probably have to have your "new" variant of C#, use a different file extension, and implement all the APIs that Visual Studio requires for intellisense to work.
Lastly, consider the C# ecosystem, and what an extensible compiler would mean. Let's say Roslyn did support these hooks, and it was as easy as providing a Nuget package or a VS extension to support a new language feature. All of your C# leveraging the new Do-Until feature is essentially invalid C#, and will not compile without the use of your custom extension. If you go far enough down this road with enough people implementing new features, very quickly you will find incompatible language features. Maybe someone implements a preprocessor macro syntax, but it can't be used along side someone else's new syntax because they happened to use similar syntax to delineate the beginning of the macro. If you leverage alot of open source projects and find yourself digging into their code, you would encounter alot of strange syntax that would require you side track and research the particular language extensions that project is leveraging. It could be madness. I don't mean to sound like a naysayer, as I have alot of ideas for language features and am very interested in this, but one should consider the implications of this, and how maintainable it would be. Imagine if you got hired to work somewhere and they had implemented all kinds of new syntax that you had to learn, and without those features having been vetted the same way C#'s features have, you can bet some of them would be not well designed/implemented.
You can check www.metaprogramming.ninja (I am the developer), it provides an easy way to accomplish language extensions (I provide examples for constructors, properties, even js-style functions) as well as full-blown grammar based DSLs.
The project is open source as well. You can find documentations, examples, etc at github.
Hope it helps.
You can't create your own syntactic abstractions in C#, so the best you can do is to create your own higher-order function. You could create an Action extension method:
public static void DoUntil(this Action act, Func<bool> condition)
{
do
{
act();
} while (!condition());
}
Which you can use as:
int i = 1;
new Action(() => { Console.WriteLine(i); i++; }).DoUntil(() => i == 15);
although it's questionable whether this is preferable to using a do..while directly.
I found the easiest way to extend the C# language is to use the T4 text processor to preprocess my source. The T4 Script would read my C# and then call a Roslyn based parser, which would generate a new source with custom generated code.
During build time, all my T4 scripts would be executed, thus effectively working as an extended preprocessor.
In your case, the none-compliant C# code could be entered as follows:
#if ExtendedCSharp
do
#endif
{
Console.WriteLine("hello world");
i++;
}
#if ExtendedCSharp
until (i > 10);
#endif
This would allow syntax checking the rest of your (C# compliant) code during development of your program.
No there is no way to achieve what you'are talking about.
Cause what you're asking about is defining new language construct, so new lexical analysis, language parser, semantic analyzer, compilation and optimization of generated IL.
What you can do in such cases is use of some macros/functions.
public bool Until(int val, int check)
{
return !(val == check);
}
and use it like
do {
//Things happen here
} while (Until(i, 15))
I am converting some code from VB.NET to C#. In VB.NET, I have this code:
Dim ind As Foo.Index
Dim ed As Foo.Edit
ind = New Foo.Index
ed = ind.InFunction()
That works. So in C# my code will look like this:
Foo.Index ind;
Foo.Edit ed;
ind = New Foo.Index();
ed = ind.InFunction();
But this doesn't work. I am sure that I did not forget to import namespaces. And now I've been wondering, is there any difference between those two?
EDIT:
And I finally add
ed = New Foo.Edit();
into my C# code, but it also doesn't work. IMHO, I think there is a feature in VB.NET that allows auto initializing in variables (like the comment from Bex below suggests). Is it true?
FINAL:
Seems I do need to show all the code. But I need to talk directly to you as well (or you just install the software of mine). It makes me really confused. Thank you all. Sorry for this kind of newbie question.
C-like languages (like C#) require you follow the pattern of [type] [variable name] at a minimum. C#, using the simplest form of initialization, requires you to use the new keyword.
A simple C# class definition:
class Foo
{
public Foo()
{
}
}
Then, to initialize an instance:
Foo myFooIsStrong = new Foo();
//instantiation
IndexServer.ClientInfo ci = new IndexServer.ClientInfo();
IndexServer.IXServicePortC konst = new IndexServer.IXServicePortC();
IndexServer.IndexServer ix = new IndexServer.IndexServer();
IndexServer.EditInfo ed = new IndexServer.EditInfo();
I don't quite understand what you are asking but this may help.
VB auto initializes a lot of variables and c# doesn't.
So in c# you should initialize your variables.
The problem is that vb.net let's you import namespace roots, while C# requires you to import the full namespace. Your VB code has a statement like this at the top:
Imports MyLibrary
This puts the MyLibrary namespace sort of "in scope", such that you can use the type MyLibrary.Foo.Index either through the full name or by simply saying Foo.Index. C# does not allow this. You must either also import MyLibrary.Foo or reference the entire name in your code.
C# is case sensitive. So the
ed = New Foo.Edit();
should be
ed = new Foo.Edit();
Here's an example
using IndexServer;
...
IndexServer ix = new IndexServer();
ClientInfo ci = new ClientInfo();
EditInfo ed = ix.checkoutSord(ci, Konstanta.EDIT_INFO.mbSord, Konstanta.LOCK.NO);
Without knowing what those classes look like, hard to tell you more. But instantiation is basically the same, just need to change some syntax for declaring variable.
I'm translating some example code line by line from C# to VB.NET.
The lines which confuse me looks like this:
[Kernel(CustomFallbackMethod = "AddCpu")]
I see in the code that these lines appear just before the method declaration:
private static void
What kind of line appears before a method declaration? Or is it a continuation of the last? I hope this is obvious to a native C Sharper.
It's an Attribute. It's a way to mark up code that can be used at runtime or compile time.
I would google VB.NET and Attributes. You can read some passages here on O'Reilly
Your example would be converted to:
<Kernel(CustomFallbackMethod:="AddCpu")>
Be sure to use _ if you decide to put it on the line before your method.