Dynamic DRC proposal 1: a Declarative DRC language.

P0  A DRC program is an unordered list of rules. Rules are evaluated and
    violations reported. The advantage of a declarative language is that
    intermediate results can be cached and reused.

P1  The language is intended to be human readable and human writable, but
    the main goal is to let programs and scripts (e.g. netlisters) to
    generate it.

P2  A rule consists of three parts:
     - the rule keyword; syntax: rule NAME
     - build variables (lists) using search statements
     - state assertions about those lists.
     - comments, empty lines

P3  Variables are named by the user and are local to the rule (TODO)

P4  Lists are ordered.

P5  A list is consists of zero or more objects. An object is:
P6   - the board
P7   - a layer
P8   - a board drawing primitive (line, arc, polygon, via, text)
P9   - an element primitive (element line, element arc(?), pin, pad, element name)
P10  - an element as a whole
P11  - a net
P61  - a 2D coordinate with or without layer information

P12 Objects have named properties (or fields):
P13  - core attributes: for each object type a predefined set of key=value
       pairs that always exist (e.g. thickness of a line, start angle of
       an arc); these field names starts with "p."
P14  - user attributes: free-form key=value pairs optionally assigned by
       the user; these field names start with "a."

P15 Note: the language is case sensitive with keywords and builtins using
    lowercase only. For better readability, in syntax description in this
    document uppercase words are user chosen identifiers or fields. Whitespace
    character sequences are usually treated as a single whitespace. (This
    does not mean identifiers have to be uppercase in a program.)

    The syntax of a search statement is:

P16   let LISTNAME EXPR

P17 It creates a list called LISTNAME and evaluates expression EXPR to all
    available objects and adds the objects that match EXPR to the list. Each
    matching object is added only once. The particular order of objects on
    the list is random. Object "matches EXPR" when the EXPR evaluated on
    the object yields true.

P18 The current object used in the iteration during the search is called
    @.

P19 An expression returns a value. A value can be:
P20   - an object
P21   - a list
P22   - scalar: a number or string (might be suffixed, like "42 mm")
P23   - void (empty, also known as false)

P23 A value is considered true if:
P24  - it is an existing object
P25  - it is a non-empty list
P26  - it is a non-zero number or non-empty string
P69  - it is a valid coordinate

    An expression is one of:

    syntax                      meaning
    ----------------------------------------------------------------
P27 (EXPR)                      change precedence
P28 EXPR || EXPR                logical OR (result: number)
P29 EXPR && EXPR                logical AND (result: number)
P72 EXPR1 thus EXPR2            evaluate to EXPR2 if EXPR1 is true, else to void
P30 EXPR + EXPR                 add (number only)
P31 EXPR - EXPR                 subtract (number only)
P32 EXPR * EXPR                 multiply or ... (number only)
P32 EXPR / EXPR                 multiply or ... (number only)
P32 EXPR == EXPR                the two values are equal
P33 EXPR != EXPR                the two values are not equal
P71 EXPR ~ string               regex match left EXPR using pattern right string
P34 EXPR > EXPR                 left EXPR is greater than right EXPR (number only)
P35 EXPR >= EXPR                left EXPR is greater than or equal to right EXPR (number only)
P36 EXPR < EXPR                 left EXPR is less than right EXPR (number only)
P37 EXPR <= EXPR                left EXPR is less than or equal to right EXPR (number only)
P38 !EXPR                       logical NOT (result: number, 0 or 1)
P39 FUNC(EXPR, EXPR, ...)       call a function with 0 or more arguments
P40 EXPR.field                  evaluated to the value of an object field (see P45, P46)

    The syntax of an assertion is:

P41   assert EXPR

P42 If the EXPR in an assert evaluates to false, a DRC violation is generated.

P43 If an assert EXPR is a list anywhere else than in a function argument, it is
    evaluated for all valid members of the list (see P45, P46). For example
    if there is a variable called FOO, which is a list of objects
    (built using a search statement), expression

      FOO.p.thickness

    is evaluated as many times as many objects are on the list, and the
    full assert is checked each case. If there is another similar list
    called BAR, an expression:

     (FOO.p.thickness < BAR.p.thickness)

    will compare each possible pair of FOO and BAR objects. That is, if
    FOO has 4 objects and BAR has 15 objects, that is 4*15 = 60 comparisons.

P44 However, each list is iterated only once, even if it is referenced multiple
    times in the same expression. For example, with the above lists:

    (FOO.p.clearance > 10 mil) && (FOO.p.thickness < BAR.p.thickness)

    the potential number of iterations is still 4*15, and not 4*4*15. In
    practice the engine leverages lazy evaluation so if FOO.p.clearance
    is smaller than 10 mil, the right size is not evaluated. See also: P45, P46.

P45 A field reference is valid if the field exists. For example a line object
    has a thickness attribute, thus the .p.thickness is valid, but a polygon
    object does not have a thickness and .p.thickness on a polygon is invalid.
    An user attribute reference (e.g. field .a.baz) is valid if the attribute
    key exists in the given object.

P46 Invalid fields are skipped in iterations. Thus if variable BLOBB is a list
    that consists of 3 line, 2 arc and a layer objects, the following assert
    will result in 2 comparisons only:

      (BLOBB.p.width >= 10 mm)

    (because only arc objects have valid .p.width field).

P47. An invalid field in an expression is never considered an
     error. In an assert statement it causes skipping an iteration. In a
     search statement it evaluates to void.

P48. A void value is never equal to anything. A void value is not equal
     even to another void value.

P49. Comments are lines starting with #


     BUILTIN FUNCTIONS

P70 list(LISTNAME)
    Within an expression, a reference to a list may become an iterator and
    refer to a single object. In case the expression needs the list, the
    list() function protects LISTNAME from becoming an iterator. For
    example llen(list(@)) is the number of all objects the design consists.

P50 llen(EXPR)
    Returns to the number of items of a list (an integer number >= 0).

P51 lvalid(EXPR, field)
    Returns a list of items on the list for which field is valid.
    EXPR can be a list or an object.

P52 lunion(EXPR1, EXPR2)
    A new list is created; items of EXPR1 are copied to the new list in order.
    Those items from EXPR2 that are not on the list already are appended,
    keeping their order. The new list is returned.

    Both EXPR1 and EXPR2 can be either a list or an object.

    Note: order of arguments does matter (affects order of objects on the
    resulting list).

P53 lintersect(EXPR1, EXPR2)
    A new list is created; items that are present on both EXPR1 and EXPR2
    are copied onto the new list. The new list is returned.

    Both EXPR1 and EXPR2 can be either a list or an object.

    Note 1: this function can be used as "is this object on the list" query:
    list_intersection(LIST, OBJ) will result an empty list (which means false)
    if OBJ is not on the list.

    Note 2: similarly, if both argument are objects, the result is false
    if the two arguments are not the same object.

P54 lcomplement(EXPR1, EXPR2)
    Creates a new list with all items that are present in EXPR1 but not in
    EXPR2. The new list is returned.

    Both EXPR1 and EXPR2 can be either a list or an object.


P55 ldiff(EXPR1, EXPR2)
    Creates a new list with all items that are present either in EXPR1 or in
    EXPR2 but not in both. The new list is returned.


P56 distance(EXPR1, EXPR2)
    Calculates the shortest distance between two objects. Returns a number.

    Note: if any expression is a layer, the stack distance is calculated
    (which will be 0 for now, as pcb-rnd doesn't yet know about layer thickness).
    If the expression is a net, the whole shape of the net is used
    (expensive! use is_closer() instead)
    If the expression is the board, the operation is invalid (see P46).

P57 is_closer(EXPR1, EXPR2, NUMBER)
    Checks if EXPR1 and EXPR2 are closer to each-other than NUMBER. It uses
    the classic bloat-and-find algorithm originally used by the classic DRC,
    thus it is much cheaper than distance(EXPR1, EXPR2) < NUMBER.

P58 netlen(EXPR)
    Network length of EXRP1: sum of all non-overlapping trace/arc lengths that
    make up a network; polygons are approximated with their average diameter
    (TODO). If EXPR is an object, its length is returned.

P59 netobjs(EXPR)
    Creates and returns a list of objects consists of a net.

P60 type(EXPR, TYPENAME)
    EXPR is an object. Returns the object if it's type matches TYPENAME, else
    returns void (a.k.a. false). This call is useful to decide whether an
    object is of a specific type. TYPENAME is one of:
     - drawing primitive type: arc, line, polygon, text, via, element
     - element primitive type: element_line, element_name, pin, pad
     - misc type: layer, net
     - meta-type, or a group:
       - copper: primitive that results in copper (arc, line, polygon, text (on copper), via, pin, pad)
       - drilled: anything that drills the board (via, pin)

P62 gridup(EXPR, NUM1, NUM2)
    If expression is an object, return a list of coordinates that are on
    the object, evenly spaced:
P63  - for lines and arcs, the points are evenly spaced on the centerlane with
        a gap of NUM1, starting from both endpoints, having the corner case in
        the middle; if NUM2 is 0, the gap at the middle may be larger than NUM1,
        else it may be smaller than NUM1.
P64  - for polygons take a grid of NUM1*NUM2 spacing (NUM1 is always axis
       aligned to X, NUM2 to Y). The offset of the grid is unspecified
P65  - element and text are ignored
P66  - a pad or pin is approximated with a polygon
P67  - for networks, iterate over all objects and append unique coordinates on
       the resulting list
P68 There's no guarantee on the particular order of the list.

