[augeas-devel] Prototype of square lens
David Lutterkort
lutter at redhat.com
Thu Jun 17 15:56:09 UTC 2010
Hi Francis,
On Sat, 2010-05-29 at 17:25 -0400, Francis Giraldeau wrote:
> Here is a small patch that add the new primitive square lens with test.
The square lens is actually a lens combinator, not a primitive lens -
it's closer in nature to things like the star operator and other
combinators, except that they are all handled as syntax in the parser,
not as builtin functions.
In the .aug files, we want to write something like
let s = square re l
so that 'square re l' behaves like 'key re . l . del k k' where k is
whatever was matched by the 'key re' lens.
There's a few steps you need to go through to make that happen:
(1) Add the function glue to builtin.c. That should be a function like
struct value *lns_square(struct info *, struct value *rxp, struct value *lns)
The function needs to unpack the values and call into a new constructor
lns_make_square in lens.c, similar to lns_make_star. It also needs to
add that glue function to the interpreter with
DEFINE_NATIVE(modl, "square", 2, lns_square, T_REGEXP, T_LENS, T_LENS);
(2) Add a constructor lns_make_square to lens.c. These functions have
two responsibilities: (i) set up the data structures for a lens and (ii)
set up the types for the lens and typecheck it if it is a nonrecursive
lens
To keep things relatively simple, you can build the square lens up from
existing parts. I'd store it by building a tree of lenses like so:
L_SQUARE
| (child pointer)
L_CONCAT
| (children pointers)
+-----------+--------------+
| | |
L_KEY l L_DEL
with regexp = re with regexp = re
string = NULL
With this setup, the changes to the get and put functions will be
minimal, especially typechecking will work for free, and there should be
no headaches when l is a recursive lens. You will need to go through the
code and make sure that it still works for L_DEL lenses with a NULL
string (should only be an issue in lns_make_prim and in create_del in
put.c)
(3) Write get_square and parse_square
These functions can get by with doing very little. get_square will look
something like
static struct tree *get_square(struct lens *lens, struct state *state) {
struct tree *tree = NULL;
struct lens *concat = lens->child;
uint keyreg, delreg;
tree = get_concat(concat, state);
keyreg = state->nreg + 1;
delreg = keyreg + (1 + regexp_nsub(concat->children[0]->ctype)) + 1;
/* Check that the matches in registers keyreg and delreg are identical
otherwise report an error */
}
parse_square is completely analogous.
(4) Write put_square and create_square
They should both just pass lens->child to put_concat and create_concat.
To make that work, you need to modify create_del so that it prints out
state->key when lens->string->str is NULL.
There's also lots of places where you need to add L_SQUARE to switch
statements throughout the code (including jmt.c) Those should only
require that you call the same function again with lens->child; for
example, in conv_rhs in jmt.c, you need to add something like
case L_SQUARE:
conv(jmt, lens->child, &s, &e, &f);
break;
to the switch statement.
(5) Tests
Write basic tests in a file tests/modules/pass_square.aug. They should
test that 'square re l' works for both non-recursive and recursive l,
and that a square lens can be used inside another recursive lens. The
main point of these tests is to exercise the interpreter, rather than do
anything useful.
Of course, it would also be great to have a working lens that uses
square; a lens that handles XML in general would be a great addition ;)
Let me know if you get stuck with any of the above - there are lots of
subtle details in the code that might throw you off course.
David
More information about the augeas-devel
mailing list