class Bytewise::Lexer

Constants

ALLOW_ESCAPE_FOR
ESCAPE_CHAR
WHITESPACES

Attributes

input[R]
pos[R]

Public Class Methods

new(input) click to toggle source
# File lib/brace_markup/lexer.rb, line 9
def initialize(input)
  @input = input
  @pos = 0
end

Public Instance Methods

escaped?(offset: 0) click to toggle source
# File lib/brace_markup/lexer.rb, line 154
def escaped?(offset: 0)
  prev_char = peek(offset: offset - 1, skip_whitespace: false)[:chunk]

  if prev_char == ESCAPE_CHAR
    !escaped?(offset: offset - 1)
  else
    false
  end
end
escapes?(offset: 0, escape: nil) click to toggle source

Test if the current character is the escape char () and escapes another character

# File lib/brace_markup/lexer.rb, line 144
def escapes?(offset: 0, escape: nil)
  escape = ALLOW_ESCAPE_FOR if escape.nil?
  #escape << ESCAPE_CHAR unless escape.include? ESCAPE_CHAR

  current_char = peek(offset: offset - 1, skip_whitespace: false)[:chunk]
  next_char = peek(offset: offset, skip_whitespace: false)[:chunk]

  current_char == ESCAPE_CHAR && !escaped?(offset: offset - 1)
end
expect(chars, skip_whitespace: true, offset: 0, continue: true, raise_error: false, ignore_escaped: false) { || ... } click to toggle source

Test if the given chars are found.

If continue is set to true it will automatically run next if the given chars are found

# File lib/brace_markup/lexer.rb, line 58
def expect(chars, skip_whitespace: true, offset: 0, continue: true, raise_error: false, ignore_escaped: false, &block)
  result = peek(length: chars.length, skip_whitespace: skip_whitespace, offset: offset)
  matches = result[:chunk] == chars

  if ignore_escaped && escaped?(offset: result[:offset] - chars.length)
    matches = false
  end

  if matches && continue
    self.next(length: result[:offset], skip_whitespace: false)
  end

  if raise_error && !matches
    raise UnexpectedCharactersException.new chars, self
  end

  # Call block
  if block_given? && matches
    yield
  end

  matches
end
line_and_col() click to toggle source
# File lib/brace_markup/lexer.rb, line 164
def line_and_col
  buffer = @input[0...@pos]
  lines = buffer.split "\n"

  line = lines.length

  col = lines[-1].length

  "#{line}:#{col}"
end
next(length: 1, skip_whitespace: true) click to toggle source
# File lib/brace_markup/lexer.rb, line 82
def next(length: 1, skip_whitespace: true)
  result = peek(length: length, skip_whitespace: skip_whitespace)

  @pos += result[:offset]

  result[:chunk]
end
next_loop(length: 1, skip_whitespace: true, ignore_escaped: false) { |current, current_buffer| ... } click to toggle source
# File lib/brace_markup/lexer.rb, line 95
def next_loop(length: 1, skip_whitespace: true, ignore_escaped: false, &block)
  beginning = @pos
  last_was_escaped = false

  if block_given?
    loop do
      current = self.next(length: length, skip_whitespace: skip_whitespace)
      current_buffer = @input[beginning...@pos]

      if ignore_escaped.is_a?(Array) && escapes?(escape: ignore_escaped)
        self.next
        last_was_escaped = true
      else
        last_was_escaped = false
        yield current, current_buffer
      end

      break if @pos == @input.length || current.nil?
    end
  end
end
next_nowhitespace() click to toggle source
# File lib/brace_markup/lexer.rb, line 90
def next_nowhitespace
  self.next
  rewind 1
end
next_until(string:, skip_whitespace: true) click to toggle source
# File lib/brace_markup/lexer.rb, line 117
def next_until(string:, skip_whitespace: true)
  if skip_whitespace
    string = string.chomp
  end

  start = @pos

  loop do
    current = peek(length: string.length, skip_whitespace: skip_whitespace)

    if string == current[:chunk]
      return @input[start...@pos]
    else
      @pos += 1
    end
  end
end
peek(length: 1, skip_whitespace: true, offset: 0) click to toggle source
# File lib/brace_markup/lexer.rb, line 14
def peek(length: 1, skip_whitespace: true, offset: 0)
  buffer = ''
  counter = 0

  loop do
    current_pos = @pos + offset + counter
    current_char = @input[current_pos]

    break if buffer.length >= length

    unless skip_whitespace && WHITESPACES.include?(current_char)
      buffer += current_char.to_s
    end

    break if current_pos == @input.length

    counter += 1
  end

  { :chunk => buffer == '' ? nil : buffer, :offset => offset + counter }
end
peek_loop(length: 1, skip_whitespace: true) { |current, current| ... } click to toggle source
# File lib/brace_markup/lexer.rb, line 36
def peek_loop(length: 1, skip_whitespace: true, &block)
  if block_given?
    i = 0

    loop do
      current = peek(length: length, skip_whitespace: skip_whitespace, offset: i)
      i = current[:offset]

      yield current[:chunk], current[:offset]
      break if current[:offset] == @input.length

      break if peek(length: length, skip_whitespace: skip_whitespace, offset: i)[:chunk].nil?
    end
  end
end
rewind(length = 1) click to toggle source
# File lib/brace_markup/lexer.rb, line 135
def rewind(length = 1)
  if @pos - length >= 0
    @pos -= length
  else
    raise Exception.new('Length can\'t be below 0')
  end
end