Normalización en los representadores


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í:

  • Analizar el código de la solución y convertirlo en un árbol de sintaxis abstracta (AST)
  • Aplicar normalizaciones al AST
  • Convertir el AST normalizado a un string
  • Escribir el string del AST normalizado en un archivo llamado 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.

Normalizar identificadores

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.

Código fuente

public static class Fake
{
    public static int Test(int input)
    {
        var test = input + 2;
        return test;
    }
}

Representación

public static class PLACEHOLDER_1
{
    public static int PLACEHOLDER_2(int PLACEHOLDER_3)
    {
        var PLACEHOLDER_4 = PLACEHOLDER_3 + 2;
        return PLACEHOLDER_4;
    }
}

Normalizar los espacios en blanco

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.

Código fuente

using   System;

     public static    class Fake
{
    public     static   DateTime Add    (DateTime    birthDate)
    {
        return birthDate.Add( TimeSpan.FromSeconds   (   10  ) )   ;
    }
}

Representación

public static class Fake
{
    public static DateTime Add(DateTime birthDate)
    {
        return birthDate.Add(TimeSpan.FromSeconds(10));
    }
}

Normalizar bloques

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.

Código fuente

public static class Fake {
    public static int Test() {
        if (1 > 2) {
            return 0;
        }

        return 1;
    }
}

Representación

public static class Fake
{
    public static int Test()
    {
        if (1 > 2)
        {
            return 0;
        }

        return 1;
    }
}

Eliminar código insignificante

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.

Código fuente

/*
   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
    }
}

Representación

public static class Fake
{
    public static string Test()
    {
        return "Test";
    }
}

Normalizar el orden cuando es insignificante

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:

Código fuente

public static class Fake
{
    public static string Test2()
    {
        int a = "Test2";
        return a;
    }

    public static string Test()
    {
        return "Test";
    }
}

Representación

public static class Fake
{
    public static string Test()
    {
        return "Test";
    }

    public static string Test2()
    {
        int a = "Test2";
        return a;
    }
}