Para que las soluciones con diferencias no esenciales tengan la misma representación, el Representer debe aplicar normalizaciones. En general, el proceso de crear una representación normalizada se ve así:
representation.txt (ver la interfaz)Ten en cuenta, sin embargo, que la representación no tiene que ser un AST; puede ser código regular (normalizado), lo que funcione mejor para tu track.
Para ayudarte a empezar, veamos ahora algunas estrategias de normalización comunes.
Nota 1: los ejemplos de normalización no se construyen uno sobre otro, solo muestran una normalización específica. Un Representer real querría aplicarlas sucesivamente.
Nota 2: el código de estas guías estará en C#, pero las guías no dependen del lenguaje.
Para permitir que las representaciones sean independientes de los nombres, los nombres definidos por el usuario (como variables, funciones, etc.) se pueden reemplazar con marcadores de posición. En este caso, se debe producir un mapping.json (ver la interfaz).
Es importante notar que todos los nombres idénticos deben reemplazarse con el mismo marcador de posición, independientemente del ámbito.
public static class Fake
{
public static int Test(int input)
{
var test = input + 2;
return test;
}
}
public static class PLACEHOLDER_1
{
public static int PLACEHOLDER_2(int PLACEHOLDER_3)
{
var PLACEHOLDER_4 = PLACEHOLDER_3 + 2;
return PLACEHOLDER_4;
}
}
Los espacios en blanco inconsistentes son tan frecuentes que normalizarlos es un paso de normalización común. Los finales de línea también deben normalizarse.
using System;
public static class Fake
{
public static DateTime Add (DateTime birthDate)
{
return birthDate.Add( TimeSpan.FromSeconds ( 10 ) ) ;
}
}
public static class Fake
{
public static DateTime Add(DateTime birthDate)
{
return birthDate.Add(TimeSpan.FromSeconds(10));
}
}
En muchos lenguajes, el usuario tiene cierta libertad para definir un bloque (o ámbito). Por ejemplo, en la mayoría de los lenguajes tipo C, el ámbito se declara entre llaves. Por lo general, no importa si las pones en la misma línea o en la siguiente, así que se podría normalizar esto.
public static class Fake {
public static int Test() {
if (1 > 2) {
return 0;
}
return 1;
}
}
public static class Fake
{
public static int Test()
{
if (1 > 2)
{
return 0;
}
return 1;
}
}
No todos los fragmentos de código son significativos para el Representer, por lo que se pueden eliminar. Por ejemplo, en la mayoría de los lenguajes los comentarios serán insignificantes y se pueden eliminar sin problema.
/*
These are some very nice
comments spanning multiple lines
*/
public static class Fake
{
// Nice method
public static string Test()
{
return "Test"; // This is very nice
}
}
public static class Fake
{
public static string Test()
{
return "Test";
}
}
En algunos casos, el orden del código no importa. Para evitar que el mismo código en un orden diferente cree representaciones distintas, puede ser útil ordenarlo. Por lo general, los elementos a ordenar son funciones o declaraciones. Puede ser complicado encontrar la(s) métrica(s) para ordenar, y también complicado de implementar. Una métrica podría ser cuántos nodos hijos del AST contiene el nodo; otra, el nombre del tipo del primer nodo hijo.
Este ejemplo ordena por algún tipo de longitud de función:
public static class Fake
{
public static string Test2()
{
int a = "Test2";
return a;
}
public static string Test()
{
return "Test";
}
}
public static class Fake
{
public static string Test()
{
return "Test";
}
public static string Test2()
{
int a = "Test2";
return a;
}
}