class Liquid::Expression

def inner_parse(markup, ss, cache)

def inner_parse(markup, ss, cache)
  if (markup.start_with?("(") && markup.end_with?(")")) && markup =~ RANGES_REGEX
    return RangeLookup.parse(
      Regexp.last_match(1),
      Regexp.last_match(2),
      ss,
      cache,
    )
  end
  if (num = parse_number(markup, ss))
    num
  else
    VariableLookup.parse(markup, ss, cache)
  end
end

def parse(markup, ss = StringScanner.new(""), cache = nil)

def parse(markup, ss = StringScanner.new(""), cache = nil)
  return unless markup
  markup = markup.strip # markup can be a frozen string
  if (markup.start_with?('"') && markup.end_with?('"')) ||
    (markup.start_with?("'") && markup.end_with?("'"))
    return markup[1..-2]
  elsif LITERALS.key?(markup)
    return LITERALS[markup]
  end
  # Cache only exists during parsing
  if cache
    return cache[markup] if cache.key?(markup)
    cache[markup] = inner_parse(markup, ss, cache).freeze
  else
    inner_parse(markup, ss, nil).freeze
  end
end

def parse_number(markup, ss)

def parse_number(markup, ss)
  # check if the markup is simple integer or float
  case markup
  when INTEGER_REGEX
    return Integer(markup, 10)
  when FLOAT_REGEX
    return markup.to_f
  end
  ss.string = markup
  # the first byte must be a digit or  a dash
  byte = ss.scan_byte
  return false if byte != DASH && (byte < ZERO || byte > NINE)
  if byte == DASH
    peek_byte = ss.peek_byte
    # if it starts with a dash, the next byte must be a digit
    return false if peek_byte.nil? || !(peek_byte >= ZERO && peek_byte <= NINE)
  end
  # The markup could be a float with multiple dots
  first_dot_pos = nil
  num_end_pos = nil
  while (byte = ss.scan_byte)
    return false if byte != DOT && (byte < ZERO || byte > NINE)
    # we found our number and now we are just scanning the rest of the string
    next if num_end_pos
    if byte == DOT
      if first_dot_pos.nil?
        first_dot_pos = ss.pos
      else
        # we found another dot, so we know that the number ends here
        num_end_pos = ss.pos - 1
      end
    end
  end
  num_end_pos = markup.length if ss.eos?
  if num_end_pos
    # number ends with a number "123.123"
    markup.byteslice(0, num_end_pos).to_f
  else
    # number ends with a dot "123."
    markup.byteslice(0, first_dot_pos).to_f
  end
end