Για να έχουν οι λύσεις με μη ουσιώδεις διαφορές την ίδια αναπαράσταση, ο Representer θα πρέπει να εφαρμόζει κανονικοποιήσεις. Γενικά, η διαδικασία δημιουργίας μιας κανονικοποιημένης αναπαράστασης έχει ως εξής:
representation.txt (δείτε τη διεπαφή)Σημείωσε ωστόσο ότι η αναπαράσταση δεν χρειάζεται να είναι ένα AST, μπορεί να είναι κανονικός (κανονικοποιημένος) κώδικας, ό,τι δουλεύει καλύτερα για το track σου.
Για να σε βοηθήσουμε να ξεκινήσεις, θα παρουσιάσουμε τώρα μερικές συνηθισμένες στρατηγικές κανονικοποίησης.
Σημείωση 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;
}
}