[augeas-devel] augeas: master - * src/get.c (get_rec, parse_rec): get/parse for recursive lenses

David Lutterkort lutter at fedoraproject.org
Fri Jan 15 01:31:37 UTC 2010


Gitweb:        http://git.fedorahosted.org/git/augeas.git?p=augeas.git;a=commitdiff;h=d83582a24aeaa344bc383d1a4c4247b0fc3f9c84
Commit:        d83582a24aeaa344bc383d1a4c4247b0fc3f9c84
Parent:        34cfe80a33334141ac2a19d0239603794b662272
Author:        David Lutterkort <lutter at redhat.com>
AuthorDate:    Wed Nov 11 16:09:51 2009 -0800
Committer:     David Lutterkort <lutter at redhat.com>
CommitterDate: Thu Jan 14 14:48:38 2010 -0800

* src/get.c (get_rec, parse_rec): get/parse for recursive lenses

---
 src/get.c |  424 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 416 insertions(+), 8 deletions(-)

diff --git a/src/get.c b/src/get.c
index 9927df1..cdddd7a 100644
--- a/src/get.c
+++ b/src/get.c
@@ -31,6 +31,7 @@
 #include "memory.h"
 #include "info.h"
 #include "lens.h"
+#include "errcode.h"
 
 /* Our favorite error message */
 static const char *const short_iteration =
@@ -69,11 +70,41 @@ struct state {
     uint                 nreg;
 };
 
+/* Used by recursive lenses to stack intermediate results */
+struct frame {
+    struct lens     *lens;
+    char            *key;
+    union {
+        struct {
+            char        *value;
+            struct tree *tree;
+        };
+        struct {
+            struct skel *skel;
+            struct dict *dict;
+        };
+    };
+};
+
+/* Used by recursive lenses in get_rec and parse_rec */
+enum mode_t { M_GET, M_PARSE };
+
+struct rec_state {
+    enum mode_t          mode;
+    struct state        *state;
+    uint                 fsize;
+    uint                 fused;
+    struct frame        *frames;
+    size_t               start;
+    uint                 lvl;  /* Debug only */
+};
+
 #define REG_START(state) ((state)->regs->start[(state)->nreg])
 #define REG_END(state)   ((state)->regs->end[(state)->nreg])
 #define REG_SIZE(state) (REG_END(state) - REG_START(state))
 #define REG_POS(state) ((state)->text + REG_START(state))
-#define REG_VALID(state) ((state)->nreg < (state)->regs->num_regs)
+#define REG_VALID(state) ((state)->regs != NULL &&                      \
+                          (state)->nreg < (state)->regs->num_regs)
 #define REG_MATCHED(state) (REG_VALID(state)                            \
                             && (state)->regs->start[(state)->nreg] >= 0)
 
@@ -90,10 +121,8 @@ void free_lns_error(struct lns_error *err) {
     free(err);
 }
 
-static void get_error(struct state *state, struct lens *lens,
-                      const char *format, ...)
-{
-    va_list ap;
+static void vget_error(struct state *state, struct lens *lens,
+                       const char *format, va_list ap) {
     int r;
 
     if (state->error != NULL)
@@ -104,13 +133,21 @@ static void get_error(struct state *state, struct lens *lens,
         state->error->pos  = REG_END(state);
     else
         state->error->pos = 0;
-    va_start(ap, format);
     r = vasprintf(&state->error->message, format, ap);
-    va_end(ap);
     if (r == -1)
         state->error->message = NULL;
 }
 
+static void get_error(struct state *state, struct lens *lens,
+                      const char *format, ...)
+{
+    va_list ap;
+
+    va_start(ap, format);
+    vget_error(state, lens, format, ap);
+    va_end(ap);
+}
+
 static struct skel *make_skel(struct lens *lens) {
     struct skel *skel;
     enum lens_tag tag = lens->tag;
@@ -631,6 +668,371 @@ static struct skel *parse_subtree(struct lens *lens, struct state *state,
     return make_skel(lens);
 }
 
+/*
+ * Helpers for recursive lenses
+ */
+
+ATTRIBUTE_UNUSED
+static void print_frames(struct rec_state *state) {
+    for (int j = state->fused - 1; j >=0; j--) {
+        struct frame *f = state->frames + j;
+        for (int i=0; i < state->lvl; i++) fputc(' ', stderr);
+        fprintf(stderr, "%2d %s %s", j, f->key, f->value);
+        if (f->tree == NULL) {
+            fprintf(stderr, " - ");
+        } else {
+            fprintf(stderr, " { %s = %s } ", f->tree->label, f->tree->value);
+        }
+        fprintf(stderr, "%s\n", format_lens(f->lens));
+    }
+}
+
+ATTRIBUTE_PURE
+static struct frame *top_frame(struct rec_state *state) {
+    assert(state->fsize > 0);
+    return state->frames + state->fused - 1;
+}
+
+/* The nth frame from the top of the stack, where 0th frame is the top */
+ATTRIBUTE_PURE
+static struct frame *nth_frame(struct rec_state *state, uint n) {
+    assert(state->fsize > n);
+    return state->frames + state->fused - (n+1);
+}
+
+static struct frame *push_frame(struct rec_state *state, struct lens *lens) {
+    int r;
+
+    if (state->fused >= state->fsize) {
+        uint expand = state->fsize;
+        if (expand < 8)
+            expand = 8;
+        r = REALLOC_N(state->frames, state->fsize + expand);
+        ERR_NOMEM(r < 0, &state->state->info);
+        state->fsize += expand;
+    }
+
+    state->fused += 1;
+
+    struct frame *top = top_frame(state);
+    MEMZERO(top, 1);
+    top->lens = lens;
+    return top;
+ error:
+    return NULL;
+}
+
+static struct frame *pop_frame(struct rec_state *state) {
+    assert(state->fused > 0);
+
+    state->fused -= 1;
+    if (state->fused > 0)
+        return top_frame(state);
+    else
+        return NULL;
+}
+
+static void dbg_visit(struct lens *lens, char action, size_t start, size_t end,
+                      int fused, int lvl) {
+
+    for (int i=0; i < lvl; i++)
+        fputc(' ', stderr);
+    fprintf(stderr, "%c %zd..%zd %d %s\n", action, start, end,
+            fused, format_lens(lens));
+}
+
+static void get_terminal(struct frame *top, struct lens *lens,
+                         struct state *state) {
+    top->tree = get_lens(lens, state);
+    top->key = state->key;
+    top->value = state->value;
+    state->key = NULL;
+    state->value = NULL;
+}
+
+static void parse_terminal(struct frame *top, struct lens *lens,
+                           struct state *state) {
+    top->dict = NULL;
+    top->skel = parse_lens(lens, state, &top->dict);
+    top->key = state->key;
+    state->key = NULL;
+}
+
+static void visit_terminal(struct lens *lens, size_t start, size_t end,
+                           void *data) {
+    struct rec_state *rec_state = data;
+    struct state *state = rec_state->state;
+    struct re_registers *old_regs = state->regs;
+    uint old_nreg = state->nreg;
+
+    if (state->error != NULL)
+        return;
+
+    if (debugging("cf.get"))
+        dbg_visit(lens, 'T', start, end, rec_state->fused, rec_state->lvl);
+    match(state, lens, lens->ctype, end, start);
+    struct frame *top = push_frame(rec_state, lens);
+    if (rec_state->mode == M_GET)
+        get_terminal(top, lens, state);
+    else
+        parse_terminal(top, lens, state);
+    free_regs(state);
+    state->regs = old_regs;
+    state->nreg = old_nreg;
+}
+
+static void visit_enter(struct lens *lens,
+                        ATTRIBUTE_UNUSED size_t start,
+                        ATTRIBUTE_UNUSED size_t end,
+                        void *data) {
+    struct rec_state *rec_state = data;
+    struct state *state = rec_state->state;
+
+    if (state->error != NULL)
+        return;
+
+    if (debugging("cf.get"))
+        dbg_visit(lens, '{', start, end, rec_state->fused, rec_state->lvl);
+    rec_state->lvl += 1;
+    if (lens->tag == L_SUBTREE) {
+        /* Same for parse and get */
+        struct frame *f = push_frame(rec_state, lens);
+        f->key = state->key;
+        f->value = state->value;
+        state->key = NULL;
+        state->value = NULL;
+    }
+}
+
+static void get_combine(struct rec_state *rec_state,
+                        struct lens *lens, uint n) {
+    struct tree *tree = NULL, *tail = NULL;
+    char *key = NULL, *value = NULL;
+    struct frame *top = NULL;
+
+    if (n > 0)
+        top = top_frame(rec_state);
+
+    for (int i=0; i < n; i++, top = pop_frame(rec_state)) {
+        list_tail_cons(tree, tail, top->tree);
+        /* top->tree might have more than one node, update tail */
+        if (tail != NULL)
+            while (tail->next != NULL) tail = tail->next;
+
+        if (top->key != NULL) {
+            assert(key == NULL);
+            key = top->key;
+        }
+        if (top->value != NULL) {
+            assert(value == NULL);
+            value = top->value;
+        }
+    }
+    top = push_frame(rec_state, lens);
+    top->tree = tree;
+    top->key = key;
+    top->value = value;
+}
+
+static void parse_combine(struct rec_state *rec_state,
+                          struct lens *lens, uint n) {
+    struct skel *skel = make_skel(lens), *tail = NULL;
+    struct dict *dict = NULL;
+    char *key = NULL;
+    struct frame *top = NULL;
+
+    if (n > 0)
+        top = top_frame(rec_state);
+
+    for (int i=0; i < n; i++, top = pop_frame(rec_state)) {
+        list_tail_cons(skel->skels, tail, top->skel);
+        /* top->skel might have more than one node, update skel */
+        if (tail != NULL)
+            while (tail->next != NULL) tail = tail->next;
+        dict_append(&dict, top->dict);
+        if (top->key != NULL) {
+            assert(key == NULL);
+            key = top->key;
+        }
+    }
+    top = push_frame(rec_state, lens);
+    top->skel = skel;
+    top->dict = dict;
+    top->key = key;
+}
+
+static void visit_exit(struct lens *lens,
+                       ATTRIBUTE_UNUSED size_t start,
+                       ATTRIBUTE_UNUSED size_t end,
+                       void *data) {
+    struct rec_state *rec_state = data;
+    struct state *state = rec_state->state;
+
+    if (state->error != NULL)
+        return;
+
+    rec_state->lvl -= 1;
+    if (debugging("cf.get"))
+        dbg_visit(lens, '}', start, end, rec_state->fused, rec_state->lvl);
+
+    ERR_BAIL(lens->info);
+
+    if (lens->tag == L_SUBTREE) {
+        struct frame *top = top_frame(rec_state);
+        if (rec_state->mode == M_GET) {
+            struct tree *tree;
+            tree = make_tree(top->key, top->value, NULL, top->tree);
+            ERR_NOMEM(tree == NULL, lens->info);
+            top = pop_frame(rec_state);
+            assert(lens == top->lens);
+            state->key = top->key;
+            state->value = top->value;
+            pop_frame(rec_state);
+            top = push_frame(rec_state, lens);
+            top->tree = tree;
+        } else {
+            struct skel *skel;
+            struct dict *dict;
+            skel = make_skel(lens);
+            ERR_NOMEM(skel == NULL, lens->info);
+            dict = make_dict(top->key, top->skel, top->dict);
+            ERR_NOMEM(dict == NULL, lens->info);
+            top = pop_frame(rec_state);
+            assert(lens == top->lens);
+            state->key = top->key;
+            pop_frame(rec_state);
+            top = push_frame(rec_state, lens);
+            top->skel = skel;
+            top->dict = dict;
+        }
+    } else if (lens->tag == L_CONCAT) {
+        assert(rec_state->fused >= lens->nchildren);
+        for (int i = 0; i < lens->nchildren; i++) {
+            struct frame *fr = nth_frame(rec_state, i);
+            BUG_ON(lens->children[i] != fr->lens,
+                    lens->info,
+             "Unexpected lens in concat %zd..%zd\n  Expected: %s\n  Actual: %s",
+                    start, end,
+                    format_lens(lens->children[i]),
+                    format_lens(fr->lens));
+        }
+        if (rec_state->mode == M_GET)
+            get_combine(rec_state, lens, lens->nchildren);
+        else
+            parse_combine(rec_state, lens, lens->nchildren);
+    } else if (lens->tag == L_STAR) {
+        uint n = 0;
+        while (n < rec_state->fused &&
+               nth_frame(rec_state, n)->lens == lens->child)
+            n++;
+        if (rec_state->mode == M_GET)
+            get_combine(rec_state, lens, n);
+        else
+            parse_combine(rec_state, lens, n);
+    } else {
+        top_frame(rec_state)->lens = lens;
+    }
+ error:
+    return;
+}
+
+static void visit_error(struct lens *lens, void *data, size_t pos,
+                        const char *format, ...) {
+    struct rec_state *rec_state = data;
+    va_list ap;
+
+    va_start(ap, format);
+    vget_error(rec_state->state, lens, format, ap);
+    va_end(ap);
+    rec_state->state->error->pos = rec_state->start + pos;
+}
+
+static struct frame *rec_process(enum mode_t mode, struct lens *lens,
+                                 struct state *state) {
+    assert(lens->tag == L_REC && lens->jmt != NULL);
+
+    uint end = REG_END(state);
+    uint start = REG_START(state);
+    size_t len;
+    struct re_registers *old_regs = state->regs;
+    uint old_nreg = state->nreg;
+    struct jmt_visitor visitor;
+    struct rec_state rec_state;
+
+    MEMZERO(&rec_state, 1);
+    MEMZERO(&visitor, 1);
+
+    state->regs = NULL;
+    state->nreg = 0;
+
+    rec_state.mode  = mode;
+    rec_state.state = state;
+    rec_state.fused = 0;
+    rec_state.lvl   = 0;
+    rec_state.start = start;
+
+    visitor.parse = jmt_parse(lens->jmt, state->text + start, end - start);
+    ERR_BAIL(lens->info);
+    visitor.terminal = visit_terminal;
+    visitor.enter = visit_enter;
+    visitor.exit = visit_exit;
+    visitor.error = visit_error;
+    visitor.data = &rec_state;
+    jmt_visit(&visitor, &len);
+    ERR_BAIL(lens->info);
+    if (len < end - start || (len == 0 && rec_state.fused == 0)) {
+        get_error(state, lens, "Syntax error");
+        state->error->pos = start + len;
+    }
+    if (rec_state.fused == 0) {
+        get_error(state, lens,
+                  "Parse did not leave a result on the stack");
+        goto error;
+    } else if (rec_state.fused > 1) {
+        get_error(state, lens,
+                  "Parse left additional garbage on the stack");
+        goto error;
+    }
+
+ done:
+    state->regs = old_regs;
+    state->nreg = old_nreg;
+    jmt_free_parse(visitor.parse);
+    return rec_state.frames;
+ error:
+    FREE(rec_state.frames);
+    goto done;
+}
+
+static struct tree *get_rec(struct lens *lens, struct state *state) {
+    struct frame *fr;
+    struct tree *tree = NULL;
+
+    fr = rec_process(M_GET, lens, state);
+    if (fr != NULL) {
+        tree = fr->tree;
+        state->key = fr->key;
+        state->value = fr->value;
+        FREE(fr);
+    }
+    return tree;
+}
+
+static struct skel *parse_rec(struct lens *lens, struct state *state,
+                              struct dict **dict) {
+    struct skel *skel = NULL;
+    struct frame *fr;
+
+    fr = rec_process(M_PARSE, lens, state);
+    if (fr != NULL) {
+        skel = fr->skel;
+        *dict = fr->dict;
+        state->key = fr->key;
+        FREE(fr);
+    }
+    return skel;
+}
+
 static struct tree *get_lens(struct lens *lens, struct state *state) {
     struct tree *tree = NULL;
 
@@ -668,6 +1070,9 @@ static struct tree *get_lens(struct lens *lens, struct state *state) {
     case L_MAYBE:
         tree = get_quant_maybe(lens, state);
         break;
+    case L_REC:
+        tree = get_rec(lens, state);
+        break;
     default:
         assert_error(state, "illegal lens tag %d", lens->tag);
         break;
@@ -681,7 +1086,7 @@ static struct tree *get_lens(struct lens *lens, struct state *state) {
 static int init_regs(struct state *state, struct lens *lens, uint size) {
     int r;
 
-    if (lens->tag != L_STAR) {
+    if (lens->tag != L_STAR && lens->tag != L_REC) {
         r = match(state, lens, lens->ctype, size, 0);
         if (r == -1)
             get_error(state, lens, "Input string does not match at all");
@@ -791,6 +1196,9 @@ static struct skel *parse_lens(struct lens *lens, struct state *state,
     case L_MAYBE:
         skel = parse_quant_maybe(lens, state, dict);
         break;
+    case L_REC:
+        skel = parse_rec(lens, state, dict);
+        break;
     default:
         assert_error(state, "illegal lens tag %d", lens->tag);
         break;




More information about the augeas-devel mailing list