본 발표는 Ruby 프로그래밍 언어에서 개행(Newline)이 문법적으로 어떻게 해석되고 처리되는지에 대한 심층적인 분석을 제공합니다. Ruby는 개행을 통해 의미 있는 코드 블록을 구분하는 특성을 가지고 있지만, 특정 상황에서는 개행이 무시되거나 예외적으로 처리되는 경우가 발생합니다. 발표자는 이러한 현상을 설명하기 위해 언어(Language), 문법(Grammar), 오토마톤(Automaton), 그리고 파서(Parser)라는 네 가지 핵심 개념을 소개하며, 특히 'Ruby에서는 원칙적으로 문이 종료될 수 있는 곳에 개행이 있으면 문이 종료된다'는 가설을 검증하는 것을 목표로 합니다.
Ruby의 개행 처리 메커니즘을 이해하기 위해서는 Lexer의 역할이 중요합니다. Lexer는 입력된 문자열을 의미 있는 토큰(Token)으로 분리하는 역할을 수행하며, 이때 lex_state
라는 13가지 플래그로 구성된 복잡한 데이터 구조를 사용하여 개행을 무시할지(skip) 또는 개행 토큰을 반환할지 결정합니다. 예를 들어, EXPRESSION_CLASS
상태(클래스 키워드를 읽은 직후)나 EXPRESSION_DOT
상태(메서드 호출의 점을 읽은 직후)에서는 개행이 무시되어 코드가 정상적으로 동작합니다. 반면, EXPRESSION_END
상태에서는 개행 토큰이 반환되어 문법적 구분을 야기할 수 있습니다. lex_state
는 개발자들 사이에서도 ‘혼돈의 문’, ‘개발자의 이성을 갉아먹는 상태 전이’ 등으로 불릴 만큼 그 복잡성이 인정되고 있습니다. 이는 파서와 렉서가 독립적으로 동작하면서 발생하는 문제로, 특정 토큰의 lex_state
전이를 예측하고 제어하는 것이 매우 어렵기 때문입니다.
이러한 복잡성을 해결하고 개행 원칙의 예외를 찾기 위해 발표자는 Yacc 문법을 확장하여 lex_state
를 문법 파일 내에서 기술할 수 있도록 하는 모델링 기법을 제안합니다. 이를 통해 파서와 렉서의 상태를 통합된 오토마톤으로 관리함으로써 lex_state
의 전이와 각 문법 규칙에서의 동작을 기계적으로 분석할 수 있게 됩니다. 이 모델링을 통해 발견된 주요 예외 사례는 다음과 같습니다.
첫째, 문법적으로는 개행이 허용되지만 렉서가 개행을 무시하는 경우입니다. 대표적인 예시로는 endless range
(예: ..b
)와 무명 인자(*args
, **kwargs
)가 있습니다. 이 경우 .
또는 *
뒤의 lex_state
가 EXPRESSION_BEG
가 되어 직후의 개행이 무시됩니다. 이는 Ruby의 문법 확장 과정에서 발생한 디자인된 동작일 수 있으나, 가독성 측면에서는 논의의 여지가 있습니다.
둘째, 문법적으로 개행이 허용되지 않아야 하지만 렉서가 개행을 반환하여 문법 오류를 발생시키는 경우입니다. 전역 변수의 alias
(alias $new_var $old_var
) 정의 시 변수 이름 사이에 개행이 삽입되면 문법 오류가 발생합니다. 또한, BEGIN
및 END
블록의 키워드 사이에 개행이 있는 경우에도 유사한 오류가 발생합니다. 이러한 경우는 의도되지 않은 동작, 즉 ‘고려 누락’일 가능성이 제기됩니다.
결론적으로, ‘문이 종료될 수 있는 곳에 개행이 있으면 문이 종료된다’는 초기 가설은 대부분의 경우에 유효하지만, endless range
, 무명 인자, 전역 변수 alias
, BEGIN/END
블.록 등 일부 예외 사례가 존재함을 확인했습니다. 이러한 예외는 lex_state
의 복잡한 동작과 문법 디자인의 미묘한 차이에서 비롯됩니다.
본 발표는 Ruby 문법에서 개행이 처리되는 원리와 그 예외들을 심도 있게 탐구했습니다. `lex_state`의 복잡성을 이해하고 제어하기 위해 문법 모델링이라는 새로운 접근 방식을 제시하였으며, 이를 통해 `lex_state`의 동작을 인간이 이해할 수 있는 수준으로 끌어올리는 데 성공했습니다. Ruby의 개행 처리는 '문 또는 식이 종료될 수 있는 곳에서 개행이 있으면 종료된다'는 대원칙을 따르지만, `endless range`와 무명 인자처럼 개행을 무시하는 예외, 그리고 전역 변수 `alias`나 `BEGIN/END` 블록처럼 개행을 허용하지 않는 예외가 일부 존재함을 명확히 하였습니다. 향후 Ruby 개발에서는 이러한 예외 사례들을 명시적으로 문법 파일에 기술하여, `lex_state`의 복잡성을 줄이고 문법의 일관성을 높이는 방향으로 개선이 필요하다는 점을 강조하며 발표를 마무리합니다.