Representer 내 정규화


본질적이지 않은 차이가 있는 풀이들이 같은 표현을 갖도록 하려면, Representer가 정규화를 적용해야 해요. 일반적으로 정규화된 표현을 만드는 과정은 다음과 같아요:

  • 풀이의 코드를 추상 구문 트리(AST)로 파싱해요
  • AST에 정규화를 적용해요
  • 정규화된 AST를 문자열로 변환해요
  • 정규화된 AST 문자열을 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;
    }
}