• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

type-ruby / t-ruby / 20560974963

28 Dec 2025 11:21PM UTC coverage: 79.076% (+1.7%) from 77.331%
20560974963

push

github

web-flow
refactor: migrate parser from regex to token-based parser combinator (#29)

* refactor: migrate parser from regex to token-based parser combinator

- Replace monolithic parser_combinator.rb (2833 lines) with modular architecture
- Add Scanner for tokenization with regex literal support
- Create IR::InterpolatedString for string interpolation parsing
- Fix type inference for interpolated strings (returns String)
- Add TRuby::ParseError for unified error handling
- Organize parsers into primitives/, combinators/, and token/ directories
- Each file contains exactly one class (snake_case filename matches PascalCase class)

* fix: enhance parser to support ternary, splat args, and statement expressions

- Add ternary operator (? :) parsing in ExpressionParser
- Support double splat (**opts) and single splat (*args) in method calls
- Support keyword arguments (name: value) in method calls
- Allow case/if/unless/begin as assignment right-hand side values
- Improve generic type compatibility (Array[untyped] with Array[T])

Fixes type inference errors in keyword_args samples.

* style: fix RuboCop violations and adjust metrics limits

* fix: require set for Ruby 3.1 compatibility

1849 of 2098 new or added lines in 53 files covered. (88.13%)

6 existing lines in 2 files now uncovered.

6644 of 8402 relevant lines covered (79.08%)

908.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.18
/lib/t_ruby/parser_combinator/token/token_body_parser.rb
1
# frozen_string_literal: true
2

3
module TRuby
1✔
4
  module ParserCombinator
1✔
5
    # Token-based body parser - replaces regex-based BodyParser
6
    # Provides the same interface as BodyParser.parse(lines, start_line, end_line)
7
    class TokenBodyParser
1✔
8
      def initialize
1✔
9
        @statement_parser = StatementParser.new
284✔
10
      end
11

12
      # Parse method body from lines array
13
      # @param lines [Array<String>] source code lines
14
      # @param start_line [Integer] starting line index (0-based)
15
      # @param end_line [Integer] ending line index (exclusive)
16
      # @return [IR::Block] parsed block of statements
17
      def parse(lines, start_line, end_line)
1✔
18
        # Extract the body source
19
        body_lines = lines[start_line...end_line]
3,630✔
20
        source = body_lines.join("\n")
3,630✔
21

22
        return IR::Block.new(statements: []) if source.strip.empty?
3,630✔
23

24
        # Scan and parse
25
        scanner = TRuby::Scanner.new(source)
3,630✔
26
        tokens = scanner.scan_all
3,630✔
27

28
        result = @statement_parser.parse_block(tokens, 0)
3,630✔
29

30
        if result.success?
3,630✔
31
          result.value
3,630✔
32
        else
33
          # Fallback to empty block on parse failure
NEW
34
          IR::Block.new(statements: [])
×
35
        end
36
      end
37

38
      # Parse a single expression string
39
      # @param expr [String] expression to parse
40
      # @return [IR::Node] parsed expression node
41
      def parse_expression(expr)
1✔
NEW
42
        return nil if expr.nil? || expr.strip.empty?
×
43

NEW
44
        scanner = TRuby::Scanner.new(expr)
×
NEW
45
        tokens = scanner.scan_all
×
46

NEW
47
        expression_parser = ExpressionParser.new
×
NEW
48
        result = expression_parser.parse_expression(tokens, 0)
×
49

NEW
50
        result.success? ? result.value : IR::RawCode.new(code: expr)
×
51
      end
52
    end
53
  end
54
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc