class Parser::Lexer::Dedenter
def dedent(string)
Of course, lexer could do it but once again: it's all because of dedenting.
It has no effect for non-squiggly heredocs, i.e. it simply removes "\\\n"
but it has to be concatenated __after__ dedenting.
This is important because technically it's a single line,
calls this method only once with a string " a\\\n b\n"
HERE
b
a\
<<-HERE
However, the following heredoc:
this method gets called with " a\n" and " b\n"
HERE
b
a
<<-HERE
For a heredoc like
def dedent(string) original_encoding = string.encoding # Prevent the following error when processing binary encoded source. # "\xC0".split # => ArgumentError (invalid byte sequence in UTF-8) lines = string.force_encoding(Encoding::BINARY).split("\\\n") if lines.length == 1 # If the line continuation sequence was found but there is no second # line, it was not really a line continuation and must be ignored. lines = [string.force_encoding(original_encoding)] else lines.map! {|s| s.force_encoding(original_encoding) } end if @at_line_begin lines_to_dedent = lines else _first, *lines_to_dedent = lines end lines_to_dedent.each do |line| left_to_remove = @dedent_level remove = 0 line.each_char do |char| break if left_to_remove <= 0 case char when ?\s remove += 1 left_to_remove -= 1 when ?\t break if TAB_WIDTH * (remove / TAB_WIDTH + 1) > @dedent_level remove += 1 left_to_remove -= TAB_WIDTH else # no more spaces or tabs break end end line.slice!(0, remove) end string.replace(lines.join) @at_line_begin = string.end_with?("\n") end
def initialize(dedent_level)
def initialize(dedent_level) @dedent_level = dedent_level @at_line_begin = true @indent_level = 0 end
def interrupt
def interrupt @at_line_begin = false end