From 36e1f66de0b553fcdf8a6ece368bf8577e002743 Mon Sep 17 00:00:00 2001
From: "Meredith L. Patterson" <mlp@thesmartpolitenerd.com>
Date: Tue, 18 Dec 2012 18:10:40 -0500
Subject: [PATCH] Expanded vtable for methods to determine whether a combinator
 is ok to use with regular or CF grammars.

---
 src/hammer.h                |  2 ++
 src/parsers/action.c        | 12 ++++++++++++
 src/parsers/and.c           |  5 +++++
 src/parsers/attr_bool.c     | 12 ++++++++++++
 src/parsers/bits.c          |  2 ++
 src/parsers/butnot.c        |  8 ++++++++
 src/parsers/ch.c            |  2 ++
 src/parsers/charset.c       |  2 ++
 src/parsers/choice.c        | 20 ++++++++++++++++++++
 src/parsers/difference.c    |  8 ++++++++
 src/parsers/end.c           |  2 ++
 src/parsers/epsilon.c       |  2 ++
 src/parsers/ignore.c        | 12 ++++++++++++
 src/parsers/ignoreseq.c     | 28 ++++++++++++++++++++++++----
 src/parsers/indirect.c      |  9 +++++++++
 src/parsers/int_range.c     |  2 ++
 src/parsers/many.c          | 16 ++++++++++++++++
 src/parsers/not.c           |  2 ++
 src/parsers/nothing.c       |  2 ++
 src/parsers/optional.c      | 12 ++++++++++++
 src/parsers/sequence.c      | 20 ++++++++++++++++++++
 src/parsers/token.c         |  2 ++
 src/parsers/unimplemented.c |  2 ++
 src/parsers/whitespace.c    | 12 ++++++++++++
 src/parsers/xor.c           |  8 ++++++++
 25 files changed, 200 insertions(+), 4 deletions(-)

diff --git a/src/hammer.h b/src/hammer.h
index 0791769d..ecb60654 100644
--- a/src/hammer.h
+++ b/src/hammer.h
@@ -112,6 +112,8 @@ typedef bool (*HPredicate)(HParseResult *p);
 
 typedef struct HParserVtable_ {
   HParseResult* (*parse)(void *env, HParseState *state);
+  bool (*isValidRegular)(void *env);
+  bool (*isValidCF)(void *env);
 } HParserVtable;
 
 typedef struct HParser_ {
diff --git a/src/parsers/action.c b/src/parsers/action.c
index 0f1686f2..33e33bc3 100644
--- a/src/parsers/action.c
+++ b/src/parsers/action.c
@@ -19,8 +19,20 @@ static HParseResult* parse_action(void *env, HParseState *state) {
     return NULL;
 }
 
+static bool action_isValidRegular(void *env) {
+  HParseAction *a = (HParseAction*)env;
+  return a->p->vtable->isValidRegular(a->p->env);
+}
+
+static bool action_isValidCF(void *env) {
+  HParseAction *a = (HParseAction*)env;
+  return a->p->vtable->isValidCF(a->p->env);
+}
+
 static const HParserVtable action_vt = {
   .parse = parse_action,
+  .isValidRegular = action_isValidRegular,
+  .isValidCF = action_isValidCF,
 };
 
 const HParser* h_action(const HParser* p, const HAction a) {
diff --git a/src/parsers/and.c b/src/parsers/and.c
index 532cbbaf..ac51be29 100644
--- a/src/parsers/and.c
+++ b/src/parsers/and.c
@@ -11,6 +11,11 @@ static HParseResult *parse_and(void* env, HParseState* state) {
 
 static const HParserVtable and_vt = {
   .parse = parse_and,
+  .isValidRegular = h_false, /* TODO: strictly speaking this should be regular,
+				but it will be a huge amount of work and difficult
+				to get right, so we're leaving it for a future
+				revision. --mlp, 18/12/12 */
+  .isValidCF = h_false,      /* despite TODO above, this remains false. */
 };
 
 
diff --git a/src/parsers/attr_bool.c b/src/parsers/attr_bool.c
index 6fa36f84..bfc4976a 100644
--- a/src/parsers/attr_bool.c
+++ b/src/parsers/attr_bool.c
@@ -17,8 +17,20 @@ static HParseResult* parse_attr_bool(void *env, HParseState *state) {
     return NULL;
 }
 
+static bool ab_isValidRegular(void *env) {
+  HAttrBool *ab = (HAttrBool*)env;
+  return ab->p->vtable->isValidRegular(ab->p->env);
+}
+
+static bool ab_isValidCF(void *env) {
+  HAttrBool *ab = (HAttrBool*)env;
+  return ab->p->vtable->isValidCF(ab->p->env);
+}
+
 static const HParserVtable attr_bool_vt = {
   .parse = parse_attr_bool,
+  .isValidRegular = ab_isValidRegular,
+  .isValidCF = ab_isValidCF,
 };
 
 
diff --git a/src/parsers/bits.c b/src/parsers/bits.c
index 196e33bb..c3a40da6 100644
--- a/src/parsers/bits.c
+++ b/src/parsers/bits.c
@@ -18,6 +18,8 @@ static HParseResult* parse_bits(void* env, HParseState *state) {
 
 static const HParserVtable bits_vt = {
   .parse = parse_bits,
+  .isValidRegular = h_true,
+  .isValidCF = h_true,
 };
 const HParser* h_bits(size_t len, bool sign) {
   return h_bits__m(&system_allocator, len, sign);
diff --git a/src/parsers/butnot.c b/src/parsers/butnot.c
index 422e0e1f..4d5bf578 100644
--- a/src/parsers/butnot.c
+++ b/src/parsers/butnot.c
@@ -35,8 +35,16 @@ static HParseResult* parse_butnot(void *env, HParseState *state) {
   }
 }
 
+static bool bn_isValidCF(void *env) {
+  HTwoParsers *tp = (HTwoParsers*)env;
+  return (tp->p1->vtable->isValidCF(tp->p1->env) &&
+	  tp->p2->vtable->isValidCF(tp->p2->env));
+}
+
 static const HParserVtable butnot_vt = {
   .parse = parse_butnot,
+  .isValidRegular = h_false,
+  .isValidCF = bn_isValidCF,
 };
 
 const HParser* h_butnot(const HParser* p1, const HParser* p2) {
diff --git a/src/parsers/ch.c b/src/parsers/ch.c
index 032731e9..8b67744e 100644
--- a/src/parsers/ch.c
+++ b/src/parsers/ch.c
@@ -14,6 +14,8 @@ static HParseResult* parse_ch(void* env, HParseState *state) {
 
 static const HParserVtable ch_vt = {
   .parse = parse_ch,
+  .isValidRegular = h_true,
+  .isValidCF = h_true,
 };
 
 const HParser* h_ch(const uint8_t c) {
diff --git a/src/parsers/charset.c b/src/parsers/charset.c
index f11715ff..7341e007 100644
--- a/src/parsers/charset.c
+++ b/src/parsers/charset.c
@@ -34,6 +34,8 @@ static HParseResult* parse_charset(void *env, HParseState *state) {
 
 static const HParserVtable charset_vt = {
   .parse = parse_charset,
+  .isValidRegular = h_true,
+  .isValidCF = h_true,
 };
 
 const HParser* h_ch_range(const uint8_t lower, const uint8_t upper) {
diff --git a/src/parsers/choice.c b/src/parsers/choice.c
index 73dedde6..d48ed229 100644
--- a/src/parsers/choice.c
+++ b/src/parsers/choice.c
@@ -21,8 +21,28 @@ static HParseResult* parse_choice(void *env, HParseState *state) {
   return NULL;
 }
 
+static bool choice_isValidRegular(void *env) {
+  HSequence *s = (HSequence*)env;
+  for (size_t i=0; i<s->len; ++i) {
+    if (!s->p_array[i]->vtable->isValidRegular(s->p_array[i]->env))
+      return false;
+  }
+  return true;
+}
+
+static bool choice_isValidCF(void *env) {
+  HSequence *s = (HSequence*)env;
+  for (size_t i=0; i<s->len; ++i) {
+    if (!s->p_array[i]->vtable->isValidCF(s->p_array[i]->env))
+      return false;
+  }
+  return true;
+}
+
 static const HParserVtable choice_vt = {
   .parse = parse_choice,
+  .isValidRegular = choice_isValidRegular,
+  .isValidCF = choice_isValidCF,
 };
 
 const HParser* h_choice(const HParser* p, ...) {
diff --git a/src/parsers/difference.c b/src/parsers/difference.c
index c6cc69ce..e3c41ec3 100644
--- a/src/parsers/difference.c
+++ b/src/parsers/difference.c
@@ -34,8 +34,16 @@ static HParseResult* parse_difference(void *env, HParseState *state) {
   }
 }
 
+static bool diff_isValidCF(void *env) {
+  HTwoParsers *tp = (HTwoParsers*)env;
+  return (tp->p1->vtable->isValidCF(tp->p1->env) &&
+	  tp->p2->vtable->isValidCF(tp->p2->env));
+}
+
 static HParserVtable difference_vt = {
   .parse = parse_difference,
+  .isValidRegular = h_false,
+  .isValidCF = diff_isValidCF,
 };
 
 const HParser* h_difference(const HParser* p1, const HParser* p2) {
diff --git a/src/parsers/end.c b/src/parsers/end.c
index 0f0d1c7d..45ba37d9 100644
--- a/src/parsers/end.c
+++ b/src/parsers/end.c
@@ -12,6 +12,8 @@ static HParseResult* parse_end(void *env, HParseState *state) {
 
 static const HParserVtable end_vt = {
   .parse = parse_end,
+  .isValidRegular = h_true,
+  .isValidCF = h_true,
 };
 
 const HParser* h_end_p() {
diff --git a/src/parsers/epsilon.c b/src/parsers/epsilon.c
index ae959cd5..5ae91e36 100644
--- a/src/parsers/epsilon.c
+++ b/src/parsers/epsilon.c
@@ -10,6 +10,8 @@ static HParseResult* parse_epsilon(void* env, HParseState* state) {
 
 static const HParserVtable epsilon_vt = {
   .parse = parse_epsilon,
+  .isValidRegular = h_true,
+  .isValidCF = h_true,
 };
 
 static const HParser epsilon_p = {
diff --git a/src/parsers/ignore.c b/src/parsers/ignore.c
index 03cdc107..6191eff9 100644
--- a/src/parsers/ignore.c
+++ b/src/parsers/ignore.c
@@ -10,8 +10,20 @@ static HParseResult* parse_ignore(void* env, HParseState* state) {
   return res;
 }
 
+static bool ignore_isValidRegular(void *env) {
+  HParser *p = (HParser*)env;
+  return (p->vtable->isValidRegular(p->env));
+}
+
+static bool ignore_isValidCF(void *env) {
+  HParser *p = (HParser*)env;
+  return (p->vtable->isValidCF(p->env));
+}
+
 static const HParserVtable ignore_vt = {
   .parse = parse_ignore,
+  .isValidRegular = ignore_isValidRegular,
+  .isValidCF = ignore_isValidCF,
 };
 
 const HParser* h_ignore(const HParser* p) {
diff --git a/src/parsers/ignoreseq.c b/src/parsers/ignoreseq.c
index 228f6357..319f1ebe 100644
--- a/src/parsers/ignoreseq.c
+++ b/src/parsers/ignoreseq.c
@@ -7,7 +7,7 @@
 
 typedef struct {
   const HParser **parsers;
-  size_t count;         // how many parsers in 'ps'
+  size_t len;         // how many parsers in 'ps'
   size_t which;         // whose result to return
 } HIgnoreSeq;
 
@@ -15,7 +15,7 @@ static HParseResult* parse_ignoreseq(void* env, HParseState *state) {
   const HIgnoreSeq *seq = (HIgnoreSeq*)env;
   HParseResult *res = NULL;
 
-  for (size_t i=0; i < seq->count; ++i) {
+  for (size_t i=0; i < seq->len; ++i) {
     HParseResult *tmp = h_do_parse(seq->parsers[i], state);
     if (!tmp)
       return NULL;
@@ -26,8 +26,28 @@ static HParseResult* parse_ignoreseq(void* env, HParseState *state) {
   return res;
 }
 
+static bool is_isValidRegular(void *env) {
+  HIgnoreSeq *seq = (HIgnoreSeq*)env;
+  for (size_t i=0; i<seq->len; ++i) {
+    if (!seq->parsers[i]->vtable->isValidRegular(seq->parsers[i]->env))
+      return false;
+  }
+  return true;
+}
+
+static bool is_isValidCF(void *env) {
+  HIgnoreSeq *seq = (HIgnoreSeq*)env;
+  for (size_t i=0; i<seq->len; ++i) {
+    if (!seq->parsers[i]->vtable->isValidCF(seq->parsers[i]->env))
+      return false;
+  }
+  return true;
+}
+
 static const HParserVtable ignoreseq_vt = {
   .parse = parse_ignoreseq,
+  .isValidRegular = is_isValidRegular,
+  .isValidCF = is_isValidCF,
 };
 
 
@@ -40,7 +60,7 @@ static const HParser* h_leftright__m(HAllocator* mm__, const HParser* p, const H
   seq->parsers = h_new(const HParser*, 2);
   seq->parsers[0] = p;
   seq->parsers[1] = q;
-  seq->count = 2;
+  seq->len = 2;
   seq->which = which;
 
   HParser *ret = h_new(HParser, 1);
@@ -73,7 +93,7 @@ const HParser* h_middle__m(HAllocator* mm__, const HParser* p, const HParser* x,
   seq->parsers[0] = p;
   seq->parsers[1] = x;
   seq->parsers[2] = q;
-  seq->count = 3;
+  seq->len = 3;
   seq->which = 1;
 
   HParser *ret = h_new(HParser, 1);
diff --git a/src/parsers/indirect.c b/src/parsers/indirect.c
index 96e2a65d..4415f067 100644
--- a/src/parsers/indirect.c
+++ b/src/parsers/indirect.c
@@ -3,8 +3,17 @@
 static HParseResult* parse_indirect(void* env, HParseState* state) {
   return h_do_parse(env, state);
 }
+
+static bool indirect_isValidCF(void *env) {
+  HParser *p = (HParser*)env;
+  HParser *inner = (HParser*)p->env;
+  return inner->vtable->isValidCF(inner->env);
+}
+
 static const HParserVtable indirect_vt = {
   .parse = parse_indirect,
+  .isValidRegular = h_false,
+  .isValidCF = indirect_isValidCF,
 };
 
 void h_bind_indirect(HParser* indirect, const HParser* inner) {
diff --git a/src/parsers/int_range.c b/src/parsers/int_range.c
index 2a1db63c..d1920589 100644
--- a/src/parsers/int_range.c
+++ b/src/parsers/int_range.c
@@ -30,6 +30,8 @@ static HParseResult* parse_int_range(void *env, HParseState *state) {
 
 static const HParserVtable int_range_vt = {
   .parse = parse_int_range,
+  .isValidRegular = h_true,
+  .isValidCF = h_true,
 };
 
 const HParser* h_int_range(const HParser *p, const int64_t lower, const int64_t upper) {
diff --git a/src/parsers/many.c b/src/parsers/many.c
index 6cb818bc..2c2577ef 100644
--- a/src/parsers/many.c
+++ b/src/parsers/many.c
@@ -44,8 +44,22 @@ static HParseResult *parse_many(void* env, HParseState *state) {
   return NULL;
 }
 
+static bool many_isValidRegular(void *env) {
+  HRepeat *repeat = (HRepeat*)env;
+  return (repeat->p->vtable->isValidRegular(repeat->p->env) &&
+	  repeat->sep->vtable->isValidRegular(repeat->sep->env));
+}
+
+static bool many_isValidCF(void *env) {
+  HRepeat *repeat = (HRepeat*)env;
+  return (repeat->p->vtable->isValidCF(repeat->p->env) &&
+	  repeat->sep->vtable->isValidCF(repeat->sep->env));
+}
+
 static const HParserVtable many_vt = {
   .parse = parse_many,
+  .isValidRegular = many_isValidRegular,
+  .isValidCF = many_isValidCF,
 };
 
 const HParser* h_many(const HParser* p) {
@@ -147,6 +161,8 @@ static HParseResult* parse_length_value(void *env, HParseState *state) {
 
 static const HParserVtable length_value_vt = {
   .parse = parse_length_value,
+  .isValidRegular = h_false,
+  .isValidCF = h_false,
 };
 
 const HParser* h_length_value(const HParser* length, const HParser* value) {
diff --git a/src/parsers/not.c b/src/parsers/not.c
index 73cf1295..6642d9e8 100644
--- a/src/parsers/not.c
+++ b/src/parsers/not.c
@@ -12,6 +12,8 @@ static HParseResult* parse_not(void* env, HParseState* state) {
 
 static const HParserVtable not_vt = {
   .parse = parse_not,
+  .isValidRegular = h_false,  /* see and.c for why */
+  .isValidCF = h_false,       /* also see and.c for why */
 };
 
 const HParser* h_not(const HParser* p) {
diff --git a/src/parsers/nothing.c b/src/parsers/nothing.c
index 120c8ef3..01c029eb 100644
--- a/src/parsers/nothing.c
+++ b/src/parsers/nothing.c
@@ -8,6 +8,8 @@ static HParseResult* parse_nothing() {
 
 static const HParserVtable nothing_vt = {
   .parse = parse_nothing,
+  .isValidRegular = h_true,
+  .isValidCF = h_true,
 };
 
 const HParser* h_nothing_p() {
diff --git a/src/parsers/optional.c b/src/parsers/optional.c
index 9625fa0f..0b405e5a 100644
--- a/src/parsers/optional.c
+++ b/src/parsers/optional.c
@@ -11,8 +11,20 @@ static HParseResult* parse_optional(void* env, HParseState* state) {
   return make_result(state, ast);
 }
 
+static bool opt_isValidRegular(void *env) {
+  HParser *p = (HParser*) env;
+  return p->vtable->isValidRegular(p->env);
+}
+
+static bool opt_isValidCF(void *env) {
+  HParser *p = (HParser*) env;
+  return p->vtable->isValidCF(p->env);
+}
+
 static const HParserVtable optional_vt = {
   .parse = parse_optional,
+  .isValidRegular = opt_isValidRegular,
+  .isValidCF = opt_isValidCF,
 };
 
 const HParser* h_optional(const HParser* p) {
diff --git a/src/parsers/sequence.c b/src/parsers/sequence.c
index 21ae31d9..f5e19246 100644
--- a/src/parsers/sequence.c
+++ b/src/parsers/sequence.c
@@ -24,8 +24,28 @@ static HParseResult* parse_sequence(void *env, HParseState *state) {
   return make_result(state, tok);
 }
 
+static bool sequence_isValidRegular(void *env) {
+  HSequence *s = (HSequence*)env;
+  for (size_t i=0; i<s->len; ++i) {
+    if (!s->p_array[i]->vtable->isValidRegular(s->p_array[i]->env))
+      return false;
+  }
+  return true;
+}
+
+static bool sequence_isValidCF(void *env) {
+  HSequence *s = (HSequence*)env;
+  for (size_t i=0; i<s->len; ++i) {
+    if (!s->p_array[i]->vtable->isValidCF(s->p_array[i]->env))
+      return false;
+  }
+  return true;
+}
+
 static const HParserVtable sequence_vt = {
   .parse = parse_sequence,
+  .isValidRegular = sequence_isValidRegular,
+  .isValidCF = sequence_isValidCF,
 };
 
 const HParser* h_sequence(const HParser* p, ...) {
diff --git a/src/parsers/token.c b/src/parsers/token.c
index 13bafbb0..f5df9d4c 100644
--- a/src/parsers/token.c
+++ b/src/parsers/token.c
@@ -22,6 +22,8 @@ static HParseResult* parse_token(void *env, HParseState *state) {
 
 const HParserVtable token_vt = {
   .parse = parse_token,
+  .isValidRegular = h_true,
+  .isValidCF = h_true,
 };
 
 const HParser* h_token(const uint8_t *str, const size_t len) {
diff --git a/src/parsers/unimplemented.c b/src/parsers/unimplemented.c
index 35ee391c..32838ce5 100644
--- a/src/parsers/unimplemented.c
+++ b/src/parsers/unimplemented.c
@@ -14,6 +14,8 @@ static HParseResult* parse_unimplemented(void* env, HParseState *state) {
 
 static const HParserVtable unimplemented_vt = {
   .parse = parse_unimplemented,
+  .isValidRegular = h_false,
+  .isValidCF = h_false,
 };
 
 static HParser unimplemented = {
diff --git a/src/parsers/whitespace.c b/src/parsers/whitespace.c
index 8e009a43..7b2477be 100644
--- a/src/parsers/whitespace.c
+++ b/src/parsers/whitespace.c
@@ -14,8 +14,20 @@ static HParseResult* parse_whitespace(void* env, HParseState *state) {
   return h_do_parse((HParser*)env, state);
 }
 
+static bool ws_isValidRegular(void *env) {
+  HParser *p = (HParser*)env;
+  return p->vtable->isValidRegular(p->env);
+}
+
+static bool ws_isValidCF(void *env) {
+  HParser *p = (HParser*)env;
+  return p->vtable->isValidCF(p->env);
+}
+
 static const HParserVtable whitespace_vt = {
   .parse = parse_whitespace,
+  .isValidRegular = ws_isValidRegular,
+  .isValidCF = ws_isValidCF,
 };
 
 const HParser* h_whitespace(const HParser* p) {
diff --git a/src/parsers/xor.c b/src/parsers/xor.c
index a11ad4ae..7679a645 100644
--- a/src/parsers/xor.c
+++ b/src/parsers/xor.c
@@ -31,8 +31,16 @@ static HParseResult* parse_xor(void *env, HParseState *state) {
   }
 }
 
+static bool xor_isValidCF(void *env) {
+  HTwoParsers *tp = (HTwoParsers*)env;
+  return (tp->p1->vtable->isValidCF(tp->p1->env) &&
+	  tp->p2->vtable->isValidCF(tp->p2->env));
+}
+
 static const HParserVtable xor_vt = {
   .parse = parse_xor,
+  .isValidRegular = h_false,
+  .isValidCF = xor_isValidCF,
 };
 
 const HParser* h_xor(const HParser* p1, const HParser* p2) {
-- 
GitLab