son sintaxis locales llamado lenguaje las funciones definicion declaracion cuales c# syntactic-sugar language-construct

sintaxis - llamado de funciones en c#



¿Hay alguna manera de implementar funciones de lenguaje personalizado en C#? (5)

La gran pieza que falta está enganchada a la tubería, de lo contrario no estás mucho más .Emit que lo que .Emit . No malinterprete, Roslyn trae muchas cosas buenas, pero para aquellos de nosotros que deseamos implementar preprocesadores y metaprogramación, parece que por ahora no estaba en el plato. Puede implementar "sugerencias de código" o lo que ellos llaman "problemas" / "acciones" como una extensión, pero esto es básicamente una transformación única del código que actúa como un reemplazo en línea sugerido y no es la forma en que implementaría un nuevo idioma característica. Esto es algo que siempre se puede hacer con las extensiones, pero Roslyn hace que el análisis / transformación del código sea tremendamente más fácil:

Por lo que he leído de los comentarios de los desarrolladores de Roslyn en los foros de codeplex, proporcionar ganchos en la tubería no ha sido un objetivo inicial. Todas las nuevas características del lenguaje C # que han proporcionado en la vista previa de C # 6 implicaron la modificación de Roslyn. Entonces, esencialmente necesitarías bifurcar a Roslyn. Tienen documentación sobre cómo construir Roslyn y probarlo con Visual Studio. Esta sería una forma pesada de bifurcar a Roslyn y hacer que Visual Studio lo use. Digo "mano dura" porque ahora cualquiera que quiera usar las características de su nuevo idioma debe reemplazar el compilador predeterminado por el suyo. Podrías ver dónde esto comenzaría a complicarse.

Creando Roslyn y reemplazando el compilador de Visual Studio 2015 Preview con tu propia compilación

Otro enfoque sería construir un compilador que actúe como proxy para Roslyn. Hay API estándar para compilar compiladores que VS puede aprovechar. Aunque no es una tarea trivial. Leería en los archivos de código, invocaría las API de Roslyn para transformar los árboles de sintaxis y emitir los resultados.

El otro desafío con el enfoque de proxy será lograr que intellisense funcione bien con las nuevas funciones de lenguaje que implemente. Probablemente tendrías que tener tu "nueva" variante de C #, usar una extensión de archivo diferente e implementar todas las API que Visual Studio requiere para que intellisense funcione.

Por último, considere el ecosistema C # y lo que significaría un compilador extensible. Digamos que Roslyn apoyó estos ganchos, y fue tan fácil como proporcionar un paquete Nuget o una extensión VS para admitir una nueva función de idioma. Toda su C # aprovechando la nueva característica Do-Until es esencialmente inválida C #, y no se compilará sin el uso de su extensión personalizada. Si vas lo suficientemente lejos en este camino con suficientes personas implementando nuevas características, muy rápidamente encontrarás funciones de lenguaje incompatibles. Tal vez alguien implemente una sintaxis de macros del preprocesador, pero no puede usarse junto con la sintaxis nueva de otra persona porque usaron una sintaxis similar para delinear el comienzo de la macro. Si aprovechas una gran cantidad de proyectos de código abierto y te encuentras explorando su código, te encontrarás con una gran cantidad de sintaxis extraña que te requerirá un seguimiento lateral e investigar las extensiones de idioma particulares que el proyecto está aprovechando. Podría ser una locura. No quiero sonar como un pesimista, ya que tengo muchas ideas para las características del lenguaje y estoy muy interesado en esto, pero uno debe considerar las implicaciones de esto, y cuán sostenible podría ser. Imagínese si lo contrataron para trabajar en algún lugar y habían implementado todo tipo de nueva sintaxis que tenía que aprender, y sin que esas características hayan sido examinadas de la misma manera que las características de C #, puede apostar que algunas de ellas no estarían bien diseñadas / implementadas .

He estado desconcertando sobre esto por un tiempo y he mirado alrededor un poco, sin poder encontrar ninguna discusión sobre el tema.

Supongamos que quería implementar un ejemplo trivial, como una nueva construcción de bucle: do ... hasta

Escrito muy similarmente a hacer ... mientras

do { //Things happen here } until (i == 15)

Esto podría transformarse en csharp válido al hacerlo:

do { //Things happen here } while (!(i == 15))

Obviamente, este es un ejemplo simple, pero ¿hay alguna manera de agregar algo de esta naturaleza? Idealmente como una extensión de Visual Studio para habilitar el resaltado de sintaxis, etc.


Microsoft propone Rolsyn API como una implementación del compilador de C # con API pública. Contiene API individuales para cada etapa del pipeline del compilador: análisis de sintaxis, creación de símbolos, enlace, emisión de MSIL. Puede proporcionar su propia implementación de analizador sintáctico o ampliar el existente para obtener el compilador C # con las características que desee.

Roslyn CTP

Extendamos el lenguaje C # usando Roslyn! En mi ejemplo, estoy reemplazando la instrucción do-until con do-while correspondiente:

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)); // } // }

Ahora podemos compilar un árbol de sintaxis actualizado utilizando la API de Roslyn o guardar syntaxRoot.GetFullText () en un archivo de texto y pasarlo a csc.exe.


No puedes crear tus propias abstracciones sintácticas en C #, así que lo mejor que puedes hacer es crear tu propia función de orden superior. Puede crear un método de extensión de Action :

public static void DoUntil(this Action act, Func<bool> condition) { do { act(); } while (!condition()); }

Que puedes usar como:

int i = 1; new Action(() => { Console.WriteLine(i); i++; }).DoUntil(() => i == 15);

aunque es cuestionable si esto es preferible a usar un do..while directamente.


No, no hay manera de lograr lo que estás diciendo.

Porque lo que estás preguntando es definir una nueva construcción del lenguaje, por lo tanto, un nuevo análisis léxico, un analizador de lenguaje, un analizador semántico, una compilación y una optimización de IL generado.

Lo que puede hacer en tales casos es el uso de algunas macros / funciones.

public bool Until(int val, int check) { return !(val == check); }

y usarlo como

do { //Things happen here } while (Until(i, 15))


Puede consultar www.metaprogramming.ninja (soy el desarrollador), proporciona una forma sencilla de realizar extensiones de idioma (proporciono ejemplos para constructores, propiedades, incluso funciones js-style) así como DSL basadas en gramática completas.

El proyecto es de código abierto también. Puede encontrar documentaciones, ejemplos, etc. en github .

Espero eso ayude.