Щоб рішення з несуттєвими відмінностями мали однакове представлення, Representer має застосовувати нормалізацію. Загалом процес створення нормалізованого представлення має такий вигляд:
representation.txt (див. інтерфейс)Зауважте, що представлення не обовʼязково має бути AST; це може бути звичайний (нормалізований) код, залежно від того, що краще підходить для треку.
Щоб допомогти на початку, розгляньмо кілька поширених стратегій нормалізації.
Примітка 1: приклади нормалізації не надбудовуються один над одним, кожен показує лише одну конкретну нормалізацію. Справжній Representer застосовував би їх послідовно.
Примітка 2: код у цих рекомендаціях буде написано мовою C#, але самі рекомендації не залежать від конкретної мови.
Щоб представлення не залежали від назв, визначені користувачем назви (змінних, функцій тощо) можна замінити на заповнювачі. У такому разі слід створити mapping.json (див. інтерфейс).
Важливо, що всі однакові назви мають бути замінені на той самий заповнювач, незалежно від області видимості.
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;
}
}
Неоднакові пробіли трапляються так часто, що їхня нормалізація є звичним кроком. Закінчення рядків теж слід нормалізувати.
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));
}
}
У багатьох мовах користувач має певну свободу в тому, як визначати блок (або область видимості). Наприклад, у більшості C-подібних мов область видимості оголошують між фігурними дужками. Зазвичай не має значення, поставити їх в одному рядку чи в наступному, тож це можна нормалізувати.
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;
}
}
Не всі фрагменти коду є суттєвими для Representer, тож їх можна вилучити. Наприклад, у більшості мов коментарі несуттєві, і їх можна сміливо вилучити.
/*
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";
}
}
У деяких випадках порядок коду не має значення. Щоб той самий код у різному порядку не створював різні представлення, його корисно відсортувати. Зазвичай сортувати доводиться функції або оголошення. Буває непросто знайти мірило для сортування, а також непросто це реалізувати. Одним мірилом може бути кількість дочірніх вузлів AST у вузлі, іншим - назва типу першого дочірнього вузла.
У цьому прикладі сортування відбувається за певною мірою довжини функції:
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;
}
}