Estoy trabajando en un finalización (intellisense) instalaciones para C# en emacs.

La idea es, si un usuario escribe un fragmento, a continuación, pide la cumplimentación a través de una particular combinación de teclas, la finalización de la instalación se va a utilizar .NETO de reflexión para determinar las posibles terminaciones.

Esto requiere que el tipo de la cosa a ser completado, ser conocido. Si es una cadena, hay un conocido conjunto de métodos y propiedades; si es un Int32, se tiene un conjunto independiente, y así sucesivamente.

El uso de semántica, un código de lexer/analizador de paquetes disponibles en emacs, me pueden localizar las declaraciones de variables y sus tipos. Dado que, es sencillo utilizar la reflexión para obtener los métodos y propiedades del tipo, y, a continuación presentamos la lista de opciones para el usuario. (Ok, no muy sencillo hacer dentro de emacs, pero el uso de la capacidad para ejecutar un proceso de powershell dentro de emacs, se vuelve mucho más fácil. Escribo en una costumbre .NETO de la asamblea para hacer la reflexión, la carga en el powershell y, a continuación, elisp que se ejecutan dentro de emacs puede enviar comandos de powershell y leer las respuestas, a través de comint. Como resultado de emacs puede obtener los resultados de la reflexión rápidamente.)

El problema llega cuando se utiliza el código var en la declaración de la cosa a ser completado. Eso significa que el tipo no especificado de forma explícita, y la terminación no funciona.

¿Cómo puedo determinar de forma fiable el tipo real que se utiliza, cuando se declara la variable con la var palabra clave? Para que quede claro, yo no necesito a determinar en tiempo de ejecución. Quiero determinar en el Diseño de «tiempo».

Hasta el momento tengo estas ideas:

  1. compilar e invocar:
    • extracto de la declaración, por ejemplo, `var foo = «una cadena de valor»;`
    • concatenar una declaración de `foo.GetType();`
    • dinámicamente compilar la resultante C# fragmento en una nueva asamblea
    • de carga de la asamblea en un nuevo dominio de aplicación, ejecute el framgment y obtener el tipo de retorno.
    • descargar y descartar la asamblea

    Sé cómo hacer todo esto. Pero suena muy pesado, para cada uno de finalización de la solicitud en el editor.

    Supongo que no necesito un nuevo dominio de aplicación en cada momento. Yo podría volver a utilizar un único dominio de aplicación para múltiples temporal asambleas, y amortizar el costo de su puesta en
    y echarlo abajo, a través de múltiples finalización de las solicitudes. Eso es más un tweak de la idea básica.

  2. compilar e inspeccionar IL

    Simplemente compilar la declaración en un módulo y, a continuación, inspeccione la IL, para determinar el tipo real que fue inferida por el compilador. ¿Cómo podría ser esto posible? ¿Qué puedo usar para examinar la IL?

Mejores ideas? Comentarios? sugerencias?


EDITAR – pensar más en ello, compilar y invocar no es aceptable, porque el invocar pueden tener efectos secundarios. Así que la primera opción debe ser descartado.

También, creo que no puede asumir la presencia de .NET 4.0.


ACTUALIZACIÓN – La respuesta correcta, no mencionados anteriormente, pero suavemente, señaló Eric Lippert, es la implantación de una plena fidelidad tipo de inferencia del sistema. ;S la única forma confiable de determinar el tipo de un var en tiempo de diseño. Pero, también no es fácil de hacer. Porque yo no sufren ilusiones que quiero intentar construir tal cosa, me tomé el atajo de la opción 2 – extracto de la declaración correspondiente código y compilarlo, luego de inspeccionar el resultado IL.

Esto funciona en realidad, para una feria subconjunto de la finalización de los escenarios.

Por ejemplo, supongamos que en los siguientes fragmentos de código, la ? es la posición en la que el usuario solicita la terminación. Esto funciona:

var x = "hello there"; 
x.?

La terminación se da cuenta de que x es una Cadena, y proporciona las opciones apropiadas. Esto se hace mediante la generación y, a continuación, compilar el siguiente código fuente:

namespace N1 {
  static class dmriiann5he { //randomly-generated class name
    static void M1 () {
       var x = "hello there"; 
    }
  }
}

…y, a continuación, la inspección de la IL con la simple reflexión.

Esto también funciona:

var x = new XmlDocument();
x.? 

El motor agrega el adecuado uso de cláusulas para generar el código fuente, para que se compila correctamente y, a continuación, la IL inspección es el mismo.

Funciona esto, también:

var x = "hello"; 
var y = x.ToCharArray();    
var z = y.?

Simplemente significa que el IL de inspección tiene que encontrar el tipo de la tercera variable local, en lugar de la primera.

Y este:

var foo = "Tra la la";
var fred = new System.Collections.Generic.List<String>
    {
        foo,
        foo.Length.ToString()
    };
var z = fred.Count;
var x = z.?

…que se encuentra en un nivel más profundo que el ejemplo anterior.

Pero, ¿qué no trabajo es la finalización de cualquier variable local cuya inicialización depende en cualquier punto de un miembro de instancia, o local argumento del método. Como:

var foo = this.InstanceMethod();
foo.?

Ni la sintaxis de LINQ.

Voy a tener que pensar acerca de cuán valiosas son de esas cosas antes de considerar la posibilidad de abordar con ellos a través de lo que es definitivamente un «diseño limitado» (palabra amable para hack) para completar.

Un enfoque para abordar el tema con las dependencias de los argumentos del método o métodos de instancia sería sustituir, en el fragmento de código que se genera, compilado y, a continuación, IL analizado, las referencias a esas cosas con «sintético» vars locales del mismo tipo.


Otra Actualización finalización de variables que dependen de los miembros de instancia, ahora funciona.

Lo que yo hice fue interrogar al tipo (a través de la semántica) y, a continuación, generar sintético de pie en los miembros de todos los miembros existentes. Para un C# buffer como este:

public class CsharpCompletion
{
    private static int PrivateStaticField1 = 17;

    string InstanceMethod1(int index)
    {
        ...lots of code here...
        return result;
    }

    public void Run(int count)
    {
        var foo = "this is a string";
        var fred = new System.Collections.Generic.List<String>
        {
            foo,
            foo.Length.ToString()
        };
        var z = fred.Count;
        var mmm = count + z + CsharpCompletion.PrivateStaticField1;
        var nnn = this.InstanceMethod1(mmm);
        var fff = nnn.?

        ...more code here...

…el código generado que se compila, por lo que puedo aprender de la salida de IL el tipo de local var nnn, se parece a esto:

namespace Nsbwhi0rdami {
  class CsharpCompletion {
    private static int PrivateStaticField1 = default(int);
    string InstanceMethod1(int index) { return default(string); }

    void M0zpstti30f4 (int count) {
       var foo = "this is a string";
       var fred = new System.Collections.Generic.List<String> { foo, foo.Length.ToString() };
       var z = fred.Count;
       var mmm = count + z + CsharpCompletion.PrivateStaticField1;
       var nnn = this.InstanceMethod1(mmm);
      }
  }
}

Todos los de la instancia y de tipo estático de los miembros están disponibles en el esqueleto de código. Se compila correctamente. En ese punto, la determinación del tipo de local var es sencillo a través de la Reflexión.

Lo que hace esto posible es:

  • la capacidad para ejecutar powershell en emacs
  • el compilador de C# es muy rápido. En mi máquina, se tarda unos 0,5 s para compilar en la memoria de la asamblea. No lo suficientemente rápido como para entre-análisis de las pulsaciones de teclado, pero lo suficientemente rápido como para apoyar la generación de demanda de la terminación de las listas.

No he mirado en LINQ todavía.

Que va a ser un problema mucho más grande debido a que el analizador léxico semántico/analizador de emacs tiene para C#, no «hacer» LINQ.

  • El tipo de foo es descubierto y rellenado por el compilador a través de la inferencia de tipos. Sospecho que los mecanismos son completamente diferentes. Quizás el tipo de inferencia el motor tiene un gancho? Al menos yo uso ‘de inferencia de tipo’ como una etiqueta.
  • Su técnica de la fabricación de un «falso» modelo de objeto que tiene todos los tipos, pero ninguno de la semántica de los objetos reales es una buena. Que es como yo lo hice IntelliSense para JScript en Visual InterDev de vuelta en el día, hacemos una «falsa» la versión de la IE modelo de objetos que tiene todos los métodos y tipos, pero ninguno de los efectos secundarios, y, a continuación, ejecute un poco intérprete sobre el analiza el código en tiempo de compilación y ver de qué tipo es.

8 Comentarios

  1. 202

    Puedo describir, cómo hacerlo de forma eficiente en el «real» C# IDE.

    La primera cosa que hacemos es ejecutar un pase de la cual se analiza sólo el «nivel superior» de cosas en el código fuente. Nos saltamos todos los cuerpos de los métodos. Que nos permite crear rápidamente una base de datos con información acerca de qué espacio de nombres, tipos y métodos (y constructores, etc) están en el código fuente del programa. El análisis de cada línea de código en cada cuerpo del método tomaría demasiado tiempo si usted está tratando de hacer que entre pulsaciones de teclas.

    Cuando el IDE necesaria para averiguar el tipo de una expresión particular en el interior del cuerpo de un método, digamos que has escrito «foo» y tenemos que averiguar cuáles son los miembros de foo, hacemos la misma cosa; nos saltamos el trabajo tanto como sea razonablemente posible.

    Empezamos con un pase de la cual se analiza sólo el variable local declaraciones dentro de ese método. Cuando nos encontramos que de paso hacemos una asignación de un par de «alcance» y «nombre» a un «tipo de determinador». El «tipo de determinador» es un objeto que representa la noción de «puedo trabajar, el tipo de local, si me necesitan». De trabajo el tipo de un local puede ser costoso, por lo que queremos aplazar la que trabajo, si es necesario.

    Ahora tenemos un perezosamente-base de datos construida que nos puede decir el tipo de cada local. Así que, volviendo a la «foo.» — podemos averiguar que declaración la correspondiente expresión es en y, a continuación, ejecutar el analizador semántico en contra de esa afirmación. Por ejemplo, suponga que tiene el cuerpo del método:

    String x = "hello";
    var y = x.ToCharArray();
    var z = from foo in y where foo.

    y ahora tenemos que trabajar que foo es de tipo char. Podemos construir una base de datos que tiene todos los metadatos, los métodos de extensión, origen de los tipos de código, y así sucesivamente. Construimos una base de datos que tiene el tipo determinantes para x, y y z. Analizamos la declaración que contiene la expresión interesante. Empezamos por la transformación sintácticamente a

    var z = y.Where(foo=>foo.

    Con el fin de averiguar el tipo de foo primero debemos conocer el tipo de y. Así que en este punto pedimos el tipo de determinador «¿cuál es el tipo de y»? Entonces se inicia un evaluador de expresiones que analiza x.ToCharArray() y se pregunta «¿cuál es el tipo de x»? Tenemos un tipo de determinante para que el que dice «necesito buscar «Cadena» en el contexto actual». No hay ningún tipo String en el tipo de corriente, así que nos fijamos en el espacio de nombres. No existe así que nos fijamos en el uso de las directivas y descubrir que hay un «uso del Sistema» y que el Sistema tiene un tipo de Cadena. OK, así que ese es el tipo de x.

    Nosotros luego de la consulta del Sistema.La cadena de metadatos para el tipo de ToCharArray y dice que es un Sistema.Char[]. Super. Así que tenemos un tipo de y.

    Ahora nos preguntamos «¿ Sistema.Char[] tiene un método Donde?» No. Así que nos fijamos en el uso de directivas; ya hemos precalculadas una base de datos que contiene todos los metadatos de los métodos de extensión que posiblemente podría ser utilizado.

    Ahora decimos «OK, hay dieciocho docena de métodos de extensión llamado Donde alcance, ¿ alguno de ellos tiene un primer parámetro formal cuyo tipo es compatible con el Sistema.Char[]?» Así que empezamos una ronda de convertibilidad de la prueba. Sin embargo, Donde los métodos de extensión genérico, lo que significa que tenemos que hacer la inferencia de tipos.

    He escrito un tipo especial infererencing motor que puede manejar haciendo incompleta inferencias desde el primer argumento a un método de extensión. Corremos el tipo de inferrer y descubrir que hay una Donde el método que toma un IEnumerable<T>, y que podemos hacer una inferencia del Sistema.Char[] para IEnumerable<System.Char>, por lo que T es el Sistema.Char.

    La firma de este método es Where<T>(this IEnumerable<T> items, Func<T, bool> predicate), y sabemos que T es el Sistema.Char. También sabemos que el primer argumento dentro de los paréntesis para el método de extensión es una expresión lambda. Así que ponemos en marcha una expresión lambda tipo inferrer que dice «el parámetro formal foo se supone para ser el Sistema.Char», el uso de este hecho al analizar el resto de la lambda.

    Ahora tenemos toda la información que necesitamos para analizar el cuerpo de la lambda, que es «foo.». Buscamos el tipo de foo, descubrimos que de acuerdo a la lambda cuaderno es el Sistema.Char, y está hecho; mostrar tipo de información del Sistema.Char.

    Y hacemos de todo, excepto el «nivel superior» análisis entre pulsaciones de teclas. Ese es el verdadero truco. En realidad la escritura de todo el análisis no es difícil; es lo que es lo suficientemente rápido que usted puede hacer en la velocidad de escritura que es el verdadero truco.

    ¡Buena suerte!

    • Eric, gracias por la respuesta completa. Se han abierto mis ojos un poco. Para emacs, yo no era de los que aspiran a producir una dinámica, entre las pulsaciones de teclado del motor que podría competir con Visual Studio en términos de la calidad de la experiencia del usuario. Por un lado, debido a la ~0.5 s latencia inherente en la de diseño, el emacs mecanismo es y seguirá siendo en la demanda solamente; sin type-ahead sugerencias. Por la otra – voy a implementar soporte básico de var lugareños, pero me voy feliz punt cuando las cosas se ponen peludas, o cuando el gráfico de dependencia supera un cierto límite. No estoy seguro de lo que el límite está todavía. Gracias de nuevo.
    • ¿por qué usted tiene que hacer que entre la pulsación de tecla? No puedes construir una verdadera ctags de estilo de la base de datos, y la actualización se basa en el diff de la corriente de pulsación de tecla hizo?
    • … esperando ansiosamente el código de golf de preguntas para implementar todo esto en su idioma de elección… están obligados a aparecer!
    • Me imagino que es porque el cálculo de las diferencias y la mutación de las estructuras complejas, es más caro y más propenso a errores que volver a calcular que la información sólo a partir de un método del cuerpo, dado que ya tienen el nivel superior de información. Hay mucho en común entre un real compilar y proporcionar simbólico conocimiento que no tendría sentido de no compartir mucho de el código; y si usted puede hacer que el código lo suficientemente rápido como para code insight, también cosechar los beneficios en línea recta de compilación. También, ctags es extremadamente primitiva; la debida simbólico insight se basa en la información de tipo.
    • Honestamente perturba mi mente que de todo esto se puede trabajar de manera rápida y fiable, especialmente con las expresiones lambda y el tipo genérico de la inferencia. Yo estaba muy sorprendido la primera vez que me escribió una expresión lambda y Intellisense sabía el tipo de mi parámetro cuando presioné ., aunque la declaración no ha acabado todavía y yo nunca explícitamente especificado los parámetros genéricos de los métodos de extensión. Gracias por este pequeño vistazo a la magia.
    • He visto (o escrito) el código fuente y se perturba mi mente que trabaja demasiado. 🙂 Hay algunas cosas peludas allí.
    • Todavía me pregunto cómo Eclipse es capaz de hacerlo mucho mejor y más rápido para Java, C#, esencialmente, un equivalente de la misma.
    • El Eclipse chicos probablemente lo haría mejor, ya que son más impresionante que el compilador de C# IDE y de equipo.
    • de hecho. Como TomA señala, a pesar del hecho de que Java y C# son prácticamente idénticos idiomas, Eclipse type-ahead características no parecen ser más lento en todo por el análisis de las lambdas, los métodos de extensión, o implícitamente locales. Pura genialidad parece ser la única explicación plausible.
    • Voy a contestar más rápido, pero mejor? ¿Qué es mejor que el 100%?
    • Curiosamente Eclipse es la forma más lenta para todo esto para mí. Pero tal vez estoy haciendo algo mal (como tratando de escribir código con ella … tal vez).
    • No recuerdo hacer este estúpido comentario en absoluto. Es que no tiene sentido. Debo de haber estado borracho. Lo siento.
    • Así que más utilizamos var en un método, más el IDE tiene que trabajar para encontrar la expresión actual del tipo, ¿verdad? Suena como var (cuando no sea necesario) podría ser un poco de sobrecarga en ese caso…
    • Me he dado cuenta de que Resharper de autocompletar es mucho más rápido que VS incorporado en la función autocompletar. También es más rica y más a menudo predice correctamente.
    • por desgracia, tengo la experiencia opuesta. Tengo que activar la R# solo cuando sea absolutamente necesaria, de lo contrario trae la experiencia de usuario de VS a un rastreo (y normalmente termina en un accidente dentro de un par de horas de trabajo, esp. con muchas ventanas abiertas). Estoy de acuerdo en que «sabe más» y es impresionante con la maquinilla de Afeitar, pero es taaaan sloooow y buggy…
    • Algo debe estar mal con su configuración o instalación, porque para mí R# es bastante rápido. No sé la complejidad de su situación, pero si te molesta, me gustaría probar a reinstalar ambos VS y R# y ver si eso ayuda a la situación.
    • puede ser debido a que el tamaño de las aplicaciones que estoy tratando, que normalmente reciben más de 200k de líneas y de 50 a 100 proyectos en una solución. Incluso con la solución de análisis fuera de ella a menudo se bloquea y definitivamente se ralentiza. Ya he hablado con el R# equipo y ellos pueden repro, pero hasta el momento no hay solución viable. Así que hoy en día normalmente yo sólo lo uso con proyectos más pequeños solamente.
    • y por cierto, hay un montón de posts que hay sobre R# y matar / desaceleración VS, así que yo sé que no estoy solo con mi dolor. No estoy diciendo que sea un mal producto, pero tiene sus límites.

  2. 15

    Me puede decir más o menos cómo el IDE de Delphi trabaja con el compilador de Delphi para hacer intellisense (code insight es lo que Delphi se llama). No es 100% aplicable a la C#, pero es un enfoque interesante que merece consideración.

    La mayoría de los análisis semántico en Delphi se realiza en el analizador de sí mismo. Las expresiones se escriben como se analiza, excepto para situaciones en las que esto no es fácil, en cuyo caso look-ahead de análisis se utiliza para trabajar de lo previsto, y, a continuación, que la decisión se utiliza en el análisis.

    El análisis es en gran parte LL(2) recursiva descenso, excepto para las expresiones, las cuales se analiza el uso de precedencia de operadores. Una de las cosas distintas acerca de Delphi es que es un solo paso la lengua, por lo que las construcciones deben ser declaradas antes de ser utilizadas, por lo que ningún alto nivel de aprobación es necesaria para llevar a esa información.

    Esta combinación de características significa que el analizador tiene alrededor de toda la información necesaria para el código de la visión para cualquier punto donde sea necesario. La forma en que funciona es este: el IDE informa al compilador del analizador léxico de la posición del cursor (el punto donde el código insight es deseado) y el analizador léxico se convierte en un token especial (que así se llama el kibitz token). Cada vez que el analizador cumple con este token (que podría estar en cualquier lugar) se sabe que esta es la señal para que envíe toda la información que ha de vuelta al editor. Esto se hace utilizando un longjmp porque está escrito en C, lo que hace es que notifica a la última llamada del tipo de construcción sintáctica (es decir, gramaticales contexto) el kibitz punto fue encontrado en, así como todos los simbólica tablas necesarias para ese punto. Así, por ejemplo, si el contexto es de una expresión que es un argumento a un método, el que podemos comprobar el método de las sobrecargas, mirar a los tipos de argumento, y el filtro de los símbolos válidos sólo a aquellos que pueden resolver ese tipo de argumento (esto reduce en un montón de irrelevante resto en el desplegable). Si es un anidados ámbito de contexto (por ejemplo, después de un «.»), el analizador le han devuelto una referencia al ámbito de aplicación, y el IDE puede enumerar todos los símbolos que se encuentran en ese ámbito.

    Otras cosas también se hacen; por ejemplo, el método de los cuerpos se omite si el kibitz token no se encuentran en su rango – esto se hace con optimismo, y se revierte si se omite el símbolo (token). El equivalente a la extensión de los métodos de la clase ayudantes en Delphi – tienen una especie de versiones de caché, por lo que su búsqueda es razonablemente rápido. Pero Delphi genérico de un tipo de inferencia es mucho más débil que el de C#.

    Ahora, a la pregunta concreta: inferir los tipos de las variables declaradas con var es equivalente a la forma en que Pascal se deduce el tipo de constantes. Se trata de el tipo de la expresión de inicialización. Estos tipos se construyen de abajo hacia arriba. Si x es de tipo Integer, y y es de tipo Double, entonces x + y será de tipo Double, porque esas son las reglas de la lengua; etc. Usted siga estas reglas hasta que usted tiene un tipo para la plena expresión en el lado derecho, y ese es el tipo de uso del símbolo de la izquierda.

  3. 7

    Si usted no quiere tener que escribir su propio parser para construir el árbol de sintaxis abstracta, usted podría mirar en el uso de los analizadores de cualquiera de SharpDevelop o MonoDevelop, ambos de los cuales son de código abierto.

  4. 4

    Intellisense sistemas suelen representar el código mediante el uso de un Árbol de Sintaxis Abstracta, lo que les permite resolver el tipo de retorno de la función que se asigna a la ‘var’ variable en más o menos de la misma manera como el compilador. Si utiliza el VS Intellisense, usted puede notar que no se le dará el tipo de var hasta que hayas terminado de introducir un válido (determinable) expresión de asignación. Si la expresión es todavía ambigua (por ejemplo, no puede totalmente inferir los argumentos genéricos para la expresión), el var de tipo no va a resolver. Esto puede ser un proceso bastante complejo, como usted puede ser que necesite para caminar bastante profundo en un árbol en orden a resolver el tipo. Por ejemplo:

    var items = myList.OfType<Foo>().Select(foo => foo.Bar);

    El tipo de retorno es IEnumerable<Bar>, pero la resolución de este necesario conocer:

    1. myList es del tipo que implementa IEnumerable.
    2. Hay un método de extensión OfType<T> que se aplica a IEnumerable.
    3. El valor resultante es IEnumerable<Foo> y no es un método de extensión Select que se aplica a este.
    4. La expresión lambda foo => foo.Bar tiene el parámetro foo de tipo Foo. Esto se deduce por el uso de Select, que tiene un Func<TIn,TOut> y desde Estaño es conocido (Foo), el tipo de foo puede ser inferido.
    5. El tipo Foo tiene una Barra de propiedades, que es de tipo Barra. Sabemos que Seleccione devuelve IEnumerable<TOut> y TOut puede ser inferido a partir del resultado de la expresión lambda, por lo que el tipo resultante de los artículos deben ser IEnumerable<Bar>.
    • A la derecha, puede llegar a ser bastante profunda. Me siento cómodo con la resolución de todas las dependencias. Sólo de pensar en esta, la primera opción que he descrito – compilar y invoke – no es en absoluto aceptable, porque la invocación de código puede tener efectos secundarios, como la actualización de una base de datos, y eso no es algo que un editor debe hacer. La compilación está bien, invocando no lo es. Tan lejos como la construcción de la AST, no creo que quieras hacer eso. Realmente quiero aplazar la que trabajo para el compilador, que ya sabe cómo hacerlo. Quiero ser capaz de pedir al compilador para que me diga lo que quiero saber. Yo sólo quiero una respuesta simple.
    • El reto con la inspección de compilación es que las dependencias pueden ser arbitrariamente de profundidad, lo que significa que usted puede necesitar para construir todo en orden para que el compilador genere código. Si haces eso, creo que se puede utilizar el depurador de símbolos con la generada IL y que coincida con el tipo de cada uno de los locales con el símbolo.
    • el compilador no ofrece ese tipo de análisis tipo como un servicio. Espero que en el futuro, pero no prometo nada.
    • sí, creo que podría ser el camino a seguir – resolver todas las dependencias y, a continuación, compile e inspeccionar IL. @Eric, es bueno saber. Por ahora, si yo no aspiro a hacer la completa AST análisis, por lo que deben recurrir a un sucio truco para producir este servicio de utilización de las herramientas existentes. Por ejemplo, la compilación de una forma inteligente construido fragmento de código y, a continuación, utilizar ILDASM (o similar) en programación para obtener la respuesta que buscan.
  5. 4

    Ya que están dirigidas a Emacs, puede ser mejor comenzar con el CEDET suite. Todos los detalles que Eric Lippert están cubiertos en el analizador de código en el CEDET/Semántica herramienta para C++ ya. También hay un C# parser (que probablemente necesita un poco de TLC) así que la única partes que no están relacionados con la optimización de las piezas necesarias para C#.

    Básicos comportamientos se definen en el núcleo de algoritmos que dependen de overloadable funciones que se definen por el lenguaje base. El éxito de la finalización del motor depende de la cantidad de sintonía que se ha hecho. Con c++ como una guía, recibiendo el apoyo similar a la de C++ no debería ser demasiado malo.

    De Daniel respuesta sugiere el uso de MonoDevelop para hacer el análisis sintáctico y el análisis. Este podría ser un mecanismo alternativo en lugar de la existente en C# parser, o podría ser usado para aumentar los existentes analizador.

    • A la derecha, que yo sé acerca de CEDET, y la estoy usando C# de apoyo en el directorio contrib para la semántica. Semántica proporciona la lista de variables locales y sus tipos. La conclusión motor puede escanear la lista y de ofrecer opciones al usuario. El problema es cuando la variable es var. Semántica identifica correctamente como var, pero no proporciona el tipo de inferencia. Mi pregunta fue, específicamente en torno a cómo abordar el que. También busqué en enchufar a la existente CEDET finalización, pero no pude averiguar cómo. La documentación de CEDET es…ah…no es completa.
    • Comentario – CEDET es admirablemente ambicioso, pero he encontrado que es difícil de usar y extender. Actualmente el intérprete trata de «espacio de nombres» como un clase indicador en C#. No podía siquiera imaginar cómo agregar «espacio de nombres» como una clara sintáctica del elemento. Haciendo así evitar todos los otros análisis sintáctico, y yo no podía entender por qué. Yo ya se explicó anteriormente la dificultad que he tenido con la finalización del marco. Más allá de estos problemas, hay costuras y el solapamiento entre las piezas. Como un ejemplo, la navegación es parte de la semántica y el senador. CEDET parece atractivo, pero al final… es demasiado difícil de manejar para comprometernos.
    • Cheeso, si usted desea obtener el máximo provecho de los menos documentados partes de CEDET, su mejor apuesta es tratar a la lista de correo. Es fácil de preguntas para profundizar en las áreas que no se han desarrollado aún, por lo que toma un par de iteraciones para el trabajo de buenas soluciones, o para explicar los ya existentes. Para C# en particular, ya que no sé nada acerca de eso, no habrá ningún simple de las respuestas.
  6. 2

    Es un problema difícil de hacer bien. Básicamente, usted necesita para modelar el lenguaje de especificación/compilador a través de la mayoría de los gramatical/análisis sintáctico/validación de tipos y construir un modelo interno de la fuente de código que a continuación, puede consultar. Eric describe en detalle en C#. Siempre puedes descargar el compilador F# código fuente (parte de la F# CTP) y echar un vistazo a service.fsi para ver la interfaz expuesta de que el compilador F# que el lenguaje F# servicio consume para la prestación de intellisense, la información sobre herramientas para inferir los tipos, etc. Le da un sentido de una posible ‘interfaz’ si ya tenía el compilador disponible como una API para llamar a.

    La otra vía es la de re-uso de los compiladores como-es tal como lo describes, y, a continuación, utilizar la reflexión o ver el código generado. Esto es problemático desde el punto de vista que usted necesita completos de los programas’ para conseguir una compilación de salida de un compilador, mientras que cuando la edición de código fuente en el editor, a menudo sólo tienen ‘parcial de los programas que aún no analizar, no tiene todos los métodos implementados, etc.

    En resumen, creo que la de «bajo presupuesto» de la versión es muy difícil de hacer bien, y lo ‘real’ es muy, muy difícil de hacer bien. (Donde ‘duro’ aquí medidas tanto «esfuerzo» y «dificultad técnica’.)

    • Ya, la de «bajo presupuesto» versión tiene algunas limitaciones claras. Estoy tratando de decidir lo «suficientemente bueno» es, y si yo puedo encontrar a ese bar. En mi propia experiencia dogfooding lo que he conseguido hasta ahora, se hace la escritura de C# dentro de emacs mucho más agradable.
  7. 0

    Para la solución «1» tiene un nuevo centro en .NET 4 para hacer esto de manera rápida y sencilla.
    Así que si usted puede tener su programa a convertir .NET 4 sería su mejor opción.

Dejar respuesta

Please enter your comment!
Please enter your name here