Project author Jean-Philippe Paradis
Project type Library
Programming language Common Lisp
Status Ready-to-use
License Public Domain
Library type Thematic utilities
Project complexity Simple
Latest release Version 1.0
Date 26 oct 2012
Quicklisp
(Nov 2012 dist and later)
Status Available
Version Latest
Depends on Depended on by
Directly Nothing
Indirectly Nothing Nothing

parse-number-range parses loop's convenient for-as-arithmetic syntax into 5 simple values: from, to, limit-kind (:inclusive, :exclusive or nil if unbounded), by (step) and direction (+ or -)). Further related utilities are provided. Intended for easy implementation of analogous functionality in other constructs.

Here's the package name, along with 2 nicknames:

Explicit qualification of the exported symbols is recommended, and one might (:import-from) select symbols, but (:use) is strongly discouraged.

parse-number-range » API

parse-number-range » API » Generalities

Here are the 5 "fundamental" values returned from parse and accepted by unparse:
from

The form introduced by :from, :upfrom or :downfrom. Defaults to 0;

to

The form introduced by :to, :upto, :downto, :below or :above. nil means "unbounded";

limit-kind

:inclusive or :exclusive if there's a limit, or nil if unbounded;

by

The form introduced by :by;

direction

+ or -.

Some functions accept a keyword-policy &key argument, which must be either :strict or :loose. (from 1 to 10) would be valid with :loose but not with :strict, which demands (:from 1 :to 10). Use of :loose is strongly discouraged, as it's an unnecessary and evil feature that typically results in arbitrary interning of symbols in arbitrary packages.

parse-number-range » API » Parse API

Function parse range &key (keyword-policy :strict)
                          (extrasp nil)
                          (clause-kinds-p extrasp)
                          (clause-keywords-p extrasp)
                          (clauses-alist-p extrasp)
  => from to limit-kind by direction
       &key clause-kinds clause-keywords clauses-alist

By default, parse returns only the 5 "fundamental" values (see above):

from

Defaults to 0;

to

Defaults to nil;

limit-kind

Defaults to nil (unbounded);

by

Defaults to 1;

direction

Defaults to +.

parse can compute and return 3 additional pieces of information, on request:

return value request-keyword description
clause-kinds :clause-kinds-p

The clause kinds that were present,
in the order they appeared in.

clause-keywords :clause-keywords-p

The clause keywords that were present,
in the order they appeared in.

clauses-alist :clauses-alist-p

Alist: (clause-kind . clause-keyword)

Function unparse from to limit-kind by direction &key clause-kinds
  => range

As you might have guessed, this does the reverse of parse...

unparse uses flags-to-keywords internally and thus inherits its biases.

clause-kinds should be a list of up to 3 elements being a permutation of the clause-kinds :from, :to and :by. This determines the order that the clauses will appear in, which might matter in the presence of side-effects. nil designates the default order, (:from :to :by).

If the list has 0 or 1 elements, then the default order is used, (:from :to :by).

If the list has 2 elements, then those clauses will appear in the order specified but no order is specified between the other elements and these ones and between the other elements among themselves. (Yeah, a less simplistic implementation would allow simpler and more useful semantics.)

If the list has 3 elements, then the order is completely specified, explicitly.

Function canonicalize range &key (clause-kinds :preserve)
                                 (keyword-policy :strict)

This simply feeds the results of parse into unparse. If clause-kinds is :preserve, then :clause-kinds-p t will be specified for parse and the resulting clause-kinds result will be fed to unparse. Else, the provided clause-kinds is fed directly to unparse.

parse-number-range » API » Info API

Function kind keyword &key (errorp t) (keyword-policy :strict)
                => kind direction limit-kind

This function takes a loop keyword and returns the following information:

Argument Return values
keyword kind direction limit-kind
:from:fromnilnil
:downfrom:from-nil
:upfrom:from+nil
:to:tonil:inclusive
:upto:to+:inclusive
:downto:to-:inclusive
:below:to+:exclusive
:above:to-:exclusive
:by:bynilnil
Function flags keyword &key (errorp t) (keyword-policy :strict)
  => direction limit-kind

This convenience function simply forwards to kind and returns all values but the first.

Function flags-to-keywords direction limit-kind
  => from-keyword to-keyword

This function does roughly the opposite of the KIND function. It returns a FROM-KEYWORD and a TO-KEYWORD (nil if unbounded) that properly indicate the supplied DIRECTION and LIMIT-KIND.

There are typically multiple valid sets of answers that could be returned. This function is currently biased as follows, with no way to request a different bias:

  • The direction and limit-kind will always be represented in the to-keyword, and never in the from-keyword, except for the following exception:

    (flags-to-keywords '- :exclusive) => :downfrom, nil
  • :to is always returned in preference to :upto.