Class: TRuby::BodyParser

Inherits:
Object
  • Object
show all
Defined in:
lib/t_ruby/body_parser.rb

Overview

BodyParser - T-Ruby 메서드 본문을 IR 노드로 변환Prism은 순수 Ruby만 파싱하므로, T-Ruby 타입 어노테이션을 포함한메서드 본문을 파싱하기 위해 자체 구현

Instance Method Summary collapse

Instance Method Details

#parse(lines, start_line, end_line) ⇒ IR::Block

메서드 본문을 IR::Block으로 변환

Parameters:

  • lines (Array<String>)

    전체 소스 라인 배열

  • start_line (Integer)

    메서드 본문 시작 라인 (0-indexed)

  • end_line (Integer)

    메서드 본문 끝 라인 (exclusive)

Returns:

  • (IR::Block)

    본문을 표현하는 IR 블록



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/t_ruby/body_parser.rb', line 13

def parse(lines, start_line, end_line)
  statements = []
  i = start_line

  while i < end_line
    line = lines[i]
    stripped = line.strip

    # 빈 줄이나 주석은 건너뛰기
    if stripped.empty? || stripped.start_with?("#")
      i += 1
      next
    end

    # if/unless 조건문 처리
    if stripped.match?(/^(if|unless)\s+/)
      node, next_i = parse_conditional(lines, i, end_line)
      if node
        statements << node
        i = next_i
        next
      end
    end

    node = parse_statement(stripped, i)
    statements << node if node
    i += 1
  end

  IR::Block.new(statements: statements)
end

#parse_conditional(lines, start_line, block_end) ⇒ Array(IR::Conditional, Integer)

if/unless/elsif 조건문 파싱

Returns:

  • (Array(IR::Conditional, Integer))

    조건문 노드와 다음 라인 인덱스



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/t_ruby/body_parser.rb', line 47

def parse_conditional(lines, start_line, block_end)
  line = lines[start_line].strip
  match = line.match(/^(if|unless|elsif)\s+(.+)$/)
  return [nil, start_line] unless match

  # elsif는 내부적으로 if처럼 처리
  kind = match[1] == "elsif" ? :if : match[1].to_sym
  condition = parse_expression(match[2])

  # then/elsif/else/end 블록 찾기
  then_statements = []
  else_statements = []
  current_branch = :then
  depth = 1
  i = start_line + 1

  while i < block_end && depth.positive?
    current_line = lines[i].strip

    if current_line.match?(/^(if|unless|case|while|until|for|begin)\b/)
      depth += 1
      if current_branch == :then
        then_statements << IR::RawCode.new(code: current_line)
      else
        else_statements << IR::RawCode.new(code: current_line)
      end
    elsif current_line == "end"
      depth -= 1
      break if depth.zero?
    elsif depth == 1 && current_line.match?(/^elsif\s+/)
      # elsif는 중첩된 if로 처리
      nested_cond, next_i = parse_conditional(lines, i, block_end)
      else_statements << nested_cond if nested_cond
      i = next_i
      break
    elsif depth == 1 && current_line == "else"
      current_branch = :else
    elsif !current_line.empty? && !current_line.start_with?("#")
      node = parse_statement(current_line, i)
      next unless node

      if current_branch == :then
        then_statements << node
      else
        else_statements << node
      end
    end

    i += 1
  end

  then_block = IR::Block.new(statements: then_statements)
  else_block = else_statements.empty? ? nil : IR::Block.new(statements: else_statements)

  conditional = IR::Conditional.new(
    condition: condition,
    then_branch: then_block,
    else_branch: else_block,
    kind: kind,
    location: start_line
  )

  [conditional, i + 1]
end