IRB 코드 분석의 기존 방식과 한계
- Ripper::Lexer 활용: IRB는 Ripper::Lexer를 사용하여 토큰화하고, 이를 기반으로 구문 강조 및 기본적인 중첩 상태를 파악했습니다.
- IRB 자체 파서의 중복: Ripper가 토큰화를 위해 내부적으로 파싱을 수행함에도 불구하고, IRB는 다시 이 토큰 스트림을 자체 파서로 재분석하는 비효율적인 구조를 가지고 있었습니다. 이는 유지보수성을 저해하는 요인이었습니다.
- 불완전한 코드 처리: Ripper::Lexer는 불완전한 코드도 토큰화할 수 있었지만, 복잡한 Ruby 구문(예: 연산자 우선순위, Endless Method, Modifier If)을 IRB의 자체 “서브셋 언어” 파서로 정확히 처리하는 데 한계가 있었습니다. 특히, 연산자 우선순위를 무시한 중첩 분석은 잘못된 자동 들여쓰기 결과를 초래하기도 했습니다.
Prism으로의 전환: 개선 방향
- Prism 도입 배경: Ruby 3.2부터 AbstractSyntaxTree에 오류 허용 옵션이 추가되고, Prism이 번들드 젬으로 제공되면서 오류 허용 파싱이 가능해졌습니다. 이는 불완전한 IRB 입력 코드 분석에 적합한 환경을 제공합니다.
- 하이브리드 구문 강조: Ripper 토큰 기반의 단순한 색상 지정 방식은 :”#{var}”와 같은 복잡한 심볼이나 문자열 삽입 구문에서 정확한 색상 적용이 어려웠습니다. Prism의 AST를 활용하여 InterpolatedSymbolNode와 같은 노드를 식별, 토큰 기반 색상 지정 규칙을 오버라이드하는 하이브리드 방식을 통해 정확도를 높입니다. Prism.parse_lex 메서드는 토큰과 AST를 동시에 제공하여 이러한 접근을 용이하게 합니다.
- AST 기반 중첩 분석: 기존의 단순한 괄호/def/end 기반 중첩 분석 대신, Prism의 AST를 트래버스하여 BlockNode, CallNode, StringNode 등 실제 구문 요소의 시작과 끝 위치를 기반으로 중첩 상태를 계산합니다. 이는 Ruby의 복잡한 구문 규칙을 정확하게 반영하여 자동 들여쓰기 및 프롬프트 변경의 정확도를 향상시킵니다.
- 코드 종료 판정 표준화: 기존에는 CRuby, JRuby, eval 등 여러 방법으로 코드 종료 여부를 판단했으며, eval을 활용한 트릭은 매직 코멘트 무효화와 같은 부작용을 일으켰습니다. Prism.parse(…).success? 및 errors API를 사용하여 코드 종료 판정을 단일화하고, 1행에 불필요한 코드를 삽입하는 문제를 해결합니다.
- 자동 완성 기능 강화: Prism의 AST와 scopes API를 활용하여 커서 위치의 노드를 정확히 파악하고, replete_type_completer 젬과 연동하여 더욱 정교한 타입 기반 자동 완성을 제공합니다. 특히, 런타임 값을 활용한 타입 파라미터 지연 전개 방식을 통해 Array와 같은 컬렉션의 중첩된 요소에 대한 타입 정보를 유지하며 정확한 완성을 지원합니다.