我一直在纳闷这一段时间,我已经四处张望了一下,找不到这个话题的讨论。
让我们假设我想实现一个简单的例子,像一个新的循环结构:do..until
写的很相似do..while
do {
//Things happen here
} until (i == 15)
这可以通过这样转化为有效CSHARP:
do {
//Things happen here
} while (!(i == 15))
这显然是一个简单的例子,但有什么办法可以增加这种性质的东西吗? 理想的情况是作为一个Visual Studio扩展,使语法高亮显示等。
Answer 1:
微软提出Rolsyn API为C#编译器的公共API的实现。 它包含了每个编译器流水线阶段的个体的API:语法分析,符号创建,装订,MSIL排放。 您可以提供自己的句法分析器的或扩展现有一个为了得到C#编译器瓦特/你想的任何功能。
罗斯林CTP
让我们用罗斯林延长C#语言! 在我的例子,我做替换,直到声明W /对应的DO-同时:
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));
// }
// }
现在我们可以使用罗斯林API编译更新过的语法树或保存syntaxRoot.GetFullText()为文本文件,并把它传递给CSC.EXE。
Answer 2:
大遗漏片挂钩到管道,否则你一起比是没有太大的进一步.Emit
提供。 别误会,罗斯林带来了很多伟大的事情,但对于我们这些谁想要实现预处理器和元编程,看来现在是不是上盘。 您可以实现“代码的建议”或他们称之为“问题” /“行动”作为扩展名,但是这基本上是一次性的代码转换,可以作为一个建议的在线更换, 不是你们想实现一个新的语言的方式是什么特征。 这是你总是可以用做扩展,但罗斯林使代码分析/转型带来极大的便利:
从我读过的从上CodePlex上论坛罗斯林开发商的意见,提供挂钩插入管道一直没有最初的目标。 所有的他们已经在C#6预览提供新的C#语言功能涉案修改罗斯林本身。 所以你基本上是需要到餐桌罗斯林。 他们对如何建立罗斯林与Visual Studio的测试文档。 这将是叉罗斯林和有Visual Studio中使用它重手的方式。 我说的重手,因为现在谁想要使用新的语言功能必须与你替换默认的编译器。 你可以看到这将开始变得混乱。
罗斯林建设,并与自己的身材替换的Visual Studio 2015年预览的编译器
另一种方法是建立一个编译器,它充当代理罗斯林。 有用于构建VS可以利用编译器的标准API。 这不是一个简单的任务,但。 你会在代码文件中读取,于罗斯林的API调用来转换语法树,放出的结果。
与代理方法的另一个挑战是要越来越智能感知与任何新的语言功能,您实现发挥很好。 你可能得有C#的你的“新”的变种,使用不同的文件扩展名,并执行所有的Visual Studio需要智能感知工作的API。
最后,考虑到C#的生态系统,有什么可扩展的编译器的意思。 比方说,罗斯林没有支持这些挂钩,这是作为提供NuGet包或VS扩展,以支持新的语言功能一样简单。 所有你的C#的利用新的DO-直到特性本质上是无效的C#,且无需使用您的自定义扩展将无法编译。 如果你走得足够远沿着这条路有足够多的人实现新的功能,很快你会发现不兼容的语言功能。 也许有人实现了一个预处理宏的语法,但它不能沿侧别人的新语法,因为它们发生在使用类似的语法来描绘宏观的开始使用。 如果你充分利用了很多开源项目,并发现自己挖掘到他们的代码,你会遇到很多奇怪的语法,将要求你身边的跟踪和研究项目是利用特定的语言扩展。 这可能是疯狂。 我的意思不是听起来像一个唱反调,因为我有很多的想法,语言功能和我对此很感兴趣,但应该考虑这意味着什么,以及它是如何维护的是。 试想一下,如果你被雇佣到地方工作,他们已经实施了各种新语法的,你必须学习,没有处于被审核这些功能以同样的方式C#的功能有,你可以打赌,他们中有些人也可以没有设计/实施。
Answer 3:
您可以检查www.metaprogramming.ninja (我是开发者),它提供了一种简单的方法来完成语言扩展(我提供的构造,性能,甚至JS风格的函数的例子)以及基于全面的语法的DSL。
该项目是开源的为好。 您可以找到文档,示例等github上 。
希望能帮助到你。
Answer 4:
你不能在C#创建自己的语法抽象,所以你能做的最好的就是创建自己的高阶函数。 你可以创建一个Action
扩展方法:
public static void DoUntil(this Action act, Func<bool> condition)
{
do
{
act();
} while (!condition());
}
您可以为使用:
int i = 1;
new Action(() => { Console.WriteLine(i); i++; }).DoUntil(() => i == 15);
虽然这是值得怀疑这是否是最好使用do..while
直接。
Answer 5:
没有就没有办法达到什么you'are谈论。
原因你问的就是定义新的语言结构,因此新的词法分析,语言分析,语义分析,编译和生成的优化是什么IL
。
你能在这种情况下,做的是使用一些宏/功能。
public bool Until(int val, int check)
{
return !(val == check);
}
并使用它像
do {
//Things happen here
} while (Until(i, 15))
Answer 6:
我发现扩展C#语言最简单的方法就是使用T4文本处理器进行预处理我的源代码。 T4的脚本会读我的C#,然后调用基于罗斯林分析器,它会生成自定义生成的代码的新来源。
在编译的时候,我所有的T4脚本会被执行,从而有效的工作为扩展预处理器。
在你的情况下,没有兼容的C#代码可输入如下:
#if ExtendedCSharp
do
#endif
{
Console.WriteLine("hello world");
i++;
}
#if ExtendedCSharp
until (i > 10);
#endif
这将允许语法程序的开发过程中检查你的(C#标准)代码的其余部分。
文章来源: Is there a way to implement custom language features in C#?