r5130 - in trunk/varnish-cache: bin/varnishtest/tests lib/libvcl
phk at varnish-cache.org
phk at varnish-cache.org
Wed Aug 25 21:01:35 CEST 2010
Author: phk
Date: 2010-08-25 21:01:35 +0200 (Wed, 25 Aug 2010)
New Revision: 5130
Modified:
trunk/varnish-cache/bin/varnishtest/tests/v00016.vtc
trunk/varnish-cache/lib/libvcl/vcc_acl.c
trunk/varnish-cache/lib/libvcl/vcc_action.c
trunk/varnish-cache/lib/libvcl/vcc_compile.h
trunk/varnish-cache/lib/libvcl/vcc_expr.c
trunk/varnish-cache/lib/libvcl/vcc_parse.c
trunk/varnish-cache/lib/libvcl/vcc_token.c
Log:
Rewrite of the "if (foo)" code in VCC to actually build expressions
the way we learned to do it back in the 1950'ies.
Until now, VCC has used sort of a massaged C-expression and with
the introduction of things like regexp matching and ACLs that turned
sort of ugly.
This code is classic recursive expression parsing with a couple of
twists:
1. We don't build a tree, because we are not going to optimize stuff,
we leave that to the C compiler.
2. Instead of the tree we build a string with magic markers that
let us get the indentation of the produced C code right anyway.
3. We do type-hinted parsing, in an attempt to produce intelligent
error messages and sensible semantics.
This code passes all testcases with a single change: We can now
compile "if (2 == 3)". This is probably a good thing (?)
Beware of bugs...
Modified: trunk/varnish-cache/bin/varnishtest/tests/v00016.vtc
===================================================================
--- trunk/varnish-cache/bin/varnishtest/tests/v00016.vtc 2010-08-25 09:47:48 UTC (rev 5129)
+++ trunk/varnish-cache/bin/varnishtest/tests/v00016.vtc 2010-08-25 19:01:35 UTC (rev 5130)
@@ -95,7 +95,7 @@
sub vcl_hash { if (req.hash != "foo") { } }
}
-varnish v1 -badvcl {
+varnish v1 -vcl {
backend b { .host = "127.0.0.1"; }
sub vcl_hash { if (2 == 3) { } }
}
Modified: trunk/varnish-cache/lib/libvcl/vcc_acl.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_acl.c 2010-08-25 09:47:48 UTC (rev 5129)
+++ trunk/varnish-cache/lib/libvcl/vcc_acl.c 2010-08-25 19:01:35 UTC (rev 5130)
@@ -449,41 +449,19 @@
}
void
-vcc_Cond_Ip(struct vcc *tl, const char *a1)
+vcc_Acl_Hack(struct vcc *tl, char *b)
{
- unsigned tcond;
char acln[32];
+ unsigned tcond;
- switch (tl->t->tok) {
- /* XXX: T_NOMATCH */
- case '~':
- vcc_NextToken(tl);
- ExpectErr(tl, ID);
- vcc_AddRef(tl, tl->t, R_ACL);
- Fb(tl, 1, "match_acl_named_%.*s(sp, %s)\n",
- PF(tl->t), a1);
- vcc_NextToken(tl);
- break;
- case T_EQ:
- case T_NEQ:
-
- VTAILQ_INIT(&tl->acl);
- tcond = tl->t->tok;
- vcc_NextToken(tl);
- bprintf(acln, "%u", tl->cnt);
- vcc_acl_entry(tl);
- vcc_acl_emit(tl, acln, 1);
- Fb(tl, 1, "%smatch_acl_anon_%s(sp, %s)\n",
- (tcond == T_NEQ ? "!" : ""), acln, a1);
- break;
- default:
- vsb_printf(tl->sb, "Invalid condition ");
- vcc_ErrToken(tl, tl->t);
- vsb_printf(tl->sb, " on IP number variable\n");
- vsb_printf(tl->sb, " only '==', '!=' and '~' are legal\n");
- vcc_ErrWhere(tl, tl->t);
- break;
- }
+ VTAILQ_INIT(&tl->acl);
+ tcond = tl->t->tok;
+ vcc_NextToken(tl);
+ bprintf(acln, "%u", tl->cnt);
+ vcc_acl_entry(tl);
+ vcc_acl_emit(tl, acln, 1);
+ sprintf(b, "%smatch_acl_anon_%s(sp, \v1)",
+ (tcond == T_NEQ ? "!" : ""), acln);
}
void
Modified: trunk/varnish-cache/lib/libvcl/vcc_action.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_action.c 2010-08-25 09:47:48 UTC (rev 5129)
+++ trunk/varnish-cache/lib/libvcl/vcc_action.c 2010-08-25 19:01:35 UTC (rev 5130)
@@ -101,6 +101,7 @@
/*--------------------------------------------------------------------*/
+#if 1
static void
illegal_assignment(const struct vcc *tl, const char *type)
{
@@ -110,12 +111,14 @@
vsb_printf(tl->sb,
" only '=' is legal for %s\n", type);
}
+#endif
static void
parse_set(struct vcc *tl)
{
const struct var *vp;
- struct token *at, *vt;
+ struct token *vt;
+ struct token *at;
vcc_NextToken(tl);
ExpectErr(tl, ID);
@@ -124,7 +127,12 @@
ERRCHK(tl);
assert(vp != NULL);
Fb(tl, 1, "%s", vp->lname);
+#if 0
vcc_NextToken(tl);
+ SkipToken(tl, '=');
+ vcc_Expr(tl, vp->fmt);
+#else
+ vcc_NextToken(tl);
switch (vp->fmt) {
case INT:
case TIME:
@@ -212,6 +220,7 @@
vcc_ErrWhere(tl, tl->t);
return;
}
+#endif
}
/*--------------------------------------------------------------------*/
Modified: trunk/varnish-cache/lib/libvcl/vcc_compile.h
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_compile.h 2010-08-25 09:47:48 UTC (rev 5129)
+++ trunk/varnish-cache/lib/libvcl/vcc_compile.h 2010-08-25 19:01:35 UTC (rev 5130)
@@ -174,7 +174,7 @@
/* vcc_acl.c */
void vcc_Acl(struct vcc *tl);
-void vcc_Cond_Ip(struct vcc *tl, const char *a1);
+void vcc_Acl_Hack(struct vcc *tl, char *b);
/* vcc_action.c */
int vcc_ParseAction(struct vcc *tl);
@@ -224,7 +224,7 @@
void vcc_TimeVal(struct vcc *tl, double *);
unsigned vcc_UintVal(struct vcc *tl);
double vcc_DoubleVal(struct vcc *tl);
-void vcc_Expr(struct vcc *tl, enum var_type fmt);
+void vcc_Expr(struct vcc *tl, enum var_type typ);
/* vcc_dir_dns.c */
parsedirector_f vcc_ParseDnsDirector;
Modified: trunk/varnish-cache/lib/libvcl/vcc_expr.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_expr.c 2010-08-25 09:47:48 UTC (rev 5129)
+++ trunk/varnish-cache/lib/libvcl/vcc_expr.c 2010-08-25 19:01:35 UTC (rev 5130)
@@ -25,6 +25,8 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * XXX: add VRT_count()'s
*/
#include "config.h"
@@ -43,21 +45,18 @@
#include "vcc_compile.h"
#include "libvarnish.h"
-/*--------------------------------------------------------------------*/
+static const char *
+vcc_Type(enum var_type fmt)
+{
+ switch(fmt) {
+#define VCC_TYPE(a) case a: return(#a);
+#include "vcc_types.h"
+#undef VCC_TYPE
+ default:
+ return("Unknown Type");
+ }
+}
-#define L(tl, foo) do { \
- tl->indent += INDENT; \
- foo; \
- tl->indent -= INDENT; \
-} while (0)
-
-#if 0
-#define C(tl, sep) do { \
- Fb(tl, 1, "VRT_count(sp, %u)%s\n", ++tl->cnt, sep); \
- tl->t->cnt = tl->cnt; \
-} while (0)
-#endif
-
/*--------------------------------------------------------------------
* Recognize and convert units of time, return seconds.
*/
@@ -190,158 +189,507 @@
*d = v * sc;
}
-/*--------------------------------------------------------------------*/
+/*--------------------------------------------------------------------
+ *
+ */
+struct expr {
+ unsigned magic;
+#define EXPR_MAGIC 0x38c794ab
+ enum var_type fmt;
+ struct vsb *vsb;
+ /* XXX: first and last token */
+};
+
+static void vcc_expr0(struct vcc *tl, struct expr **e, enum var_type fmt);
+
+static struct expr *
+vcc_new_expr(void)
+{
+ struct expr *e;
+
+ /* XXX: use TlAlloc() ? */
+ ALLOC_OBJ(e, EXPR_MAGIC);
+ AN(e);
+ e->vsb = vsb_newauto();
+ e->fmt = VOID;
+ return (e);
+}
+
static void
-vcc_Expr2(struct vcc *tl, enum var_type *fmt)
+vcc_delete_expr(struct expr *e)
{
+ if (e == NULL)
+ return;
+ CHECK_OBJ_NOTNULL(e, EXPR_MAGIC);
+ vsb_delete(e->vsb);
+ FREE_OBJ(e);
+}
+
+/*--------------------------------------------------------------------
+ * We want to get the indentation right in the emitted C code so we have
+ * to represent it symbolically until we are ready to render.
+ *
+ * Many of the operations have very schematic output syntaxes, so we
+ * use the same facility to simplify the text-processing of emitting
+ * a given operation on two subexpressions.
+ *
+ * We use '\v' as the magic escape character.
+ * \v1 insert subexpression 1
+ * \v2 insert subexpression 2
+ * \v+ increase indentation
+ * \v- increase indentation
+ * anything else is literal
+ *
+ * When editing, we check if any of the subexpressions contain a newline
+ * and issue it as an indented block of so.
+ *
+ * XXX: check line lengths in edit, should pass indent in for this
+ */
+
+static struct expr *
+vcc_expr_edit(enum var_type fmt, const char *p, struct expr *e1, struct expr *e2)
+{
+ struct expr *e;
+ char *q;
+
+ q = strchr(vsb_data(e1->vsb), '\n');
+ if (q == NULL && e2 != NULL)
+ q = strchr(vsb_data(e2->vsb), '\n');
+ e = vcc_new_expr();
+ while (*p != '\0') {
+ if (*p != '\v') {
+ vsb_putc(e->vsb, *p);
+ p++;
+ continue;
+ }
+ p++;
+ switch(*p) {
+ case '+': vsb_cat(e->vsb, "\v+"); break;
+ case '-': vsb_cat(e->vsb, "\v-"); break;
+ case '1':
+ case '2':
+ if (q != NULL)
+ vsb_cat(e->vsb, "\v+\n");
+ if (*p == '1')
+ vsb_cat(e->vsb, vsb_data(e1->vsb));
+ else
+ vsb_cat(e->vsb, vsb_data(e2->vsb));
+ if (q != NULL)
+ vsb_cat(e->vsb, "\v-\n");
+ break;
+ default:
+ assert(__LINE__ == 0);
+ }
+ p++;
+ }
+ vsb_finish(e->vsb);
+ AZ(vsb_overflowed(e->vsb));
+ vcc_delete_expr(e1);
+ vcc_delete_expr(e2);
+ e->fmt = fmt;
+ return (e);
+}
+
+/*--------------------------------------------------------------------
+ * Expand finished expression into C-source code
+ */
+
+static void
+vcc_expr_fmt(struct vsb *d, int ind, const struct expr *e1)
+{
+ char *p;
+ int i;
+
+ for (i = 0; i < ind; i++)
+ vsb_cat(d, " ");
+ for (p = vsb_data(e1->vsb); *p != '\0'; p++) {
+ if (*p == '\n') {
+ vsb_putc(d, '\n');
+ if (p[1] != '\0') {
+ for (i = 0; i < ind; i++)
+ vsb_cat(d, " ");
+ }
+ continue;
+ }
+ if (*p != '\v') {
+ vsb_putc(d, *p);
+ continue;
+ }
+ p++;
+ switch(*p) {
+ case '+': ind += 2; break;
+ case '-': ind -= 2; break;
+ default:
+ assert(__LINE__ == 0);
+ }
+ }
+}
+
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * Expr4:
+ * '(' Expr0 ')'
+ * CNUM
+ * CSTR
+ */
+
+static void
+vcc_expr4(struct vcc *tl, struct expr **e, enum var_type fmt)
+{
+ struct expr *e1, *e2;
const struct symbol *sym;
const struct var *vp;
double d;
- int frac;
- *fmt = VOID;
+ *e = NULL;
+ if (tl->t->tok == '(') {
+ SkipToken(tl, '(');
+ vcc_expr0(tl, &e2, fmt);
+ ERRCHK(tl);
+ SkipToken(tl, ')');
+ *e = vcc_expr_edit(e2->fmt, "(\v1)", e2, NULL);
+ return;
+ }
+ e1 = vcc_new_expr();
switch(tl->t->tok) {
case ID:
sym = VCC_FindSymbol(tl, tl->t);
if (sym == NULL) {
- vsb_printf(tl->sb,
- "Unknown symbol in numeric expression:\n");
+ vsb_printf(tl->sb, "Symbol not found: ");
vcc_ErrToken(tl, tl->t);
- vsb_printf(tl->sb, "\n");
vcc_ErrWhere(tl, tl->t);
return;
}
+ AN(sym);
+
vcc_AddUses(tl, tl->t, sym->r_methods, "Not available");
AN(sym->var);
vp = vcc_FindVar(tl, tl->t, 0, "cannot be read");
ERRCHK(tl);
assert(vp != NULL);
- Fb(tl, 1, "%s\n", vp->rname);
- *fmt = sym->fmt;
+ vsb_printf(e1->vsb, "%s", vp->rname);
+ e1->fmt = vp->fmt;
vcc_NextToken(tl);
- return;
+ break;
+ case CSTR:
+ assert(fmt != VOID);
+ EncToken(e1->vsb, tl->t);
+ e1->fmt = STRING;
+ vcc_NextToken(tl);
+ break;
case CNUM:
- vcc_NumVal(tl, &d, &frac);
- ERRCHK(tl);
- if (tl->t->tok == ID) {
- d *= vcc_TimeUnit(tl);
+ assert(fmt != VOID);
+ if (fmt == DURATION) {
+ vcc_RTimeVal(tl, &d);
ERRCHK(tl);
- *fmt = DURATION;
- } else if (!frac) {
- *fmt = INT;
+ vsb_printf(e1->vsb, "%g", d);
+ e1->fmt = DURATION;
} else {
- WRONG("numeric constant botch");
+ vsb_printf(e1->vsb, "%.*s", PF(tl->t));
+ vcc_NextToken(tl);
+ e1->fmt = INT;
}
- Fb(tl, 1, "%g\n", d);
+ break;
+ default:
+ e1->fmt = fmt;
+ vsb_printf(e1->vsb, "<E4 %.*s %u>", PF(tl->t), tl->t->tok);
+ vcc_NextToken(tl);
+ break;
+ }
+
+ vsb_finish(e1->vsb);
+ AZ(vsb_overflowed(e1->vsb));
+ *e = e1;
+}
+
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * Expr3:
+ * Expr4 { {'*'|'/'} Expr4 } *
+ */
+
+static void
+vcc_expr_mul(struct vcc *tl, struct expr **e, enum var_type fmt)
+{
+ struct expr *e2;
+ enum var_type f2, f3;
+
+ *e = NULL;
+ vcc_expr4(tl, e, fmt);
+ ERRCHK(tl);
+ f3 = f2 = (*e)->fmt;
+
+ switch(f2) {
+ case INT: f2 = INT; break;
+ case DURATION: f2 = INT; break; /* XXX: should be Double */
+ default:
return;
+ }
+ while (tl->t->tok == '+' || tl->t->tok == '-') {
+ vcc_NextToken(tl);
+ vcc_expr4(tl, &e2, f2);
+ ERRCHK(tl);
+ if (tl->t->tok == '+')
+ *e = vcc_expr_edit(f3, "(\v1+\v2)", *e, e2);
+ else
+ *e = vcc_expr_edit(f3, "(\v1-\v2)", *e, e2);
+ }
+}
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * ExprAdd:
+ * ExprMul { {'+'|'-'} ExprMul } *
+ */
+
+static void
+vcc_expr_add(struct vcc *tl, struct expr **e, enum var_type fmt)
+{
+ struct expr *e2;
+ enum var_type f2;
+
+ *e = NULL;
+ vcc_expr_mul(tl, e, fmt);
+ ERRCHK(tl);
+ f2 = (*e)->fmt;
+
+ switch(f2) {
+ case INT: break;
+ case TIME: f2 = DURATION; break;
+ case DURATION: f2 = DURATION; break;
default:
- vsb_printf(tl->sb,
- "Unknown token in numeric expression:\n");
- vcc_ErrToken(tl, tl->t);
- vsb_printf(tl->sb, "\n");
- vcc_ErrWhere(tl, tl->t);
return;
}
+
+ while (tl->t->tok == '+' || tl->t->tok == '-') {
+ vcc_NextToken(tl);
+ vcc_expr_mul(tl, &e2, f2);
+ ERRCHK(tl);
+ if (tl->t->tok == '+')
+ *e = vcc_expr_edit(f2, "(\v1+\v2)", *e, e2);
+ else
+ *e = vcc_expr_edit(f2, "(\v1-\v2)", *e, e2);
+ }
}
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * ExprCmp:
+ * ExprAdd
+ * ExprAdd Relation ExprAdd
+ * ExprAdd(STRING) '~' CString
+ * ExprAdd(STRING) '!~' CString
+ * ExprAdd(IP) '~' IP
+ * ExprAdd(IP) '!~' IP
+ */
+
+static const struct cmps {
+ enum var_type fmt;
+ unsigned token;
+ const char *emit;
+} vcc_cmps[] = {
+ {INT, T_EQ, "(\v1 == \v2)" },
+ {INT, T_NEQ, "(\v1 != \v2)" },
+ {INT, T_LEQ, "(\v1 <= \v2)" },
+ {INT, T_GEQ, "(\v1 >= \v2)" },
+ {INT, '<', "(\v1 < \v2)" },
+ {INT, '>', "(\v1 > \v2)" },
+
+ {DURATION, T_EQ, "(\v1 == \v2)" },
+ {DURATION, T_NEQ, "(\v1 != \v2)" },
+ {DURATION, T_LEQ, "(\v1 <= \v2)" },
+ {DURATION, T_GEQ, "(\v1 >= \v2)" },
+ {DURATION, '<', "(\v1 < \v2)" },
+ {DURATION, '>', "(\v1 > \v2)" },
+
+ {STRING, T_EQ, "!VRT_strcmp(\v1, \v2)" },
+ {STRING, T_NEQ, "VRT_strcmp(\v1, \v2)" },
+
+ {VOID, 0, NULL}
+};
+
static void
-vcc_Expr1(struct vcc *tl, enum var_type fmt)
+vcc_expr_cmp(struct vcc *tl, struct expr **e, enum var_type fmt)
{
- enum var_type lfmt, rfmt, afmt;
- struct token *top;
- struct token *tfirst;
+ struct expr *e2;
+ const struct cmps *cp;
+ char buf[256];
+ char *re;
+ const char *not;
+ struct token *tk;
- tfirst = tl->t;
- Fb(tl, 1, "(\n");
- L(tl, vcc_Expr2(tl, &lfmt));
+ *e = NULL;
+
+ if (fmt == BOOL && tl->t->tok == '!') {
+ vcc_NextToken(tl);
+ vcc_expr_add(tl, &e2, fmt);
+ ERRCHK(tl);
+ *e = vcc_expr_edit(BOOL, "!(\v1)", e2, NULL);
+ return;
+ }
+
+ vcc_expr_add(tl, e, fmt);
ERRCHK(tl);
- afmt = lfmt;
- while (1) {
- top = tl->t;
- if (tl->t->tok == '+') {
- vcc_NextToken(tl);
- Fb(tl, 1, " +\n");
- L(tl, vcc_Expr2(tl, &rfmt));
- ERRCHK(tl);
- if (lfmt == INT && rfmt == INT)
- afmt = INT;
- else if (lfmt == DURATION && rfmt == DURATION)
- afmt = DURATION;
- else if (lfmt == TIME && rfmt == DURATION)
- afmt = TIME;
- else if (lfmt == DURATION && rfmt == TIME)
- afmt = TIME;
- else {
- vsb_printf(tl->sb,
- /* XXX print actual types */
- "Incompatible types in addition.\n"
- "Legal combinations:\n"
- "\tINT+INT,\n"
- "\tDURATION+DURATION,\n"
- "\tDURATION+TIME,\n"
- "\tTIME+DURATION\n");
- vcc_ErrWhere(tl, top);
- return;
- }
- } else if (tl->t->tok == '-') {
- vcc_NextToken(tl);
- Fb(tl, 1, " -\n");
- L(tl, vcc_Expr2(tl, &rfmt));
- if (lfmt == INT && rfmt == INT)
- afmt = INT;
- else if (lfmt == DURATION && rfmt == DURATION)
- afmt = DURATION;
- else if (lfmt == TIME && rfmt == DURATION)
- afmt = TIME;
- else if (lfmt == TIME && rfmt == TIME)
- afmt = DURATION;
- else {
- vsb_printf(tl->sb,
- /* XXX print actual types */
- "Incompatible types in subtraction.\n"
- "Legal combinations:\n"
- "\tINT-INT,\n"
- "\tDURATION-DURATION,\n"
- "\tTIME-DURATION,\n"
- "\tTIME-TIME,\n");
- vcc_ErrWhere(tl, top);
- return;
- }
- } else
+
+ if ((*e)->fmt == BOOL)
+ return;
+
+ tk = tl->t;
+ for (cp = vcc_cmps; cp->fmt != VOID; cp++)
+ if ((*e)->fmt == cp->fmt && tl->t->tok == cp->token)
break;
- lfmt = afmt;
+ if (cp->fmt != VOID) {
+ vcc_NextToken(tl);
+ vcc_expr_add(tl, &e2, (*e)->fmt);
+ if (e2->fmt != (*e)->fmt) { /* XXX */
+ vsb_printf(tl->sb, "Comparison of different types\n");
+ vsb_printf(tl->sb, "Left side has type %s\n",
+ vcc_Type((*e)->fmt));
+ vsb_printf(tl->sb, "Right side has type %s\n",
+ vcc_Type(e2->fmt));
+ vcc_ErrToken(tl, tk);
+ vcc_ErrWhere(tl, tk);
+ return;
+ }
+ *e = vcc_expr_edit(BOOL, cp->emit, *e, e2);
+ return;
}
- Fb(tl, 1, ")\n");
- if (fmt != afmt) {
- vsb_printf(tl->sb,
- /* XXX print actual types */
- "Add/Subtract results in wrong type.\n"
- "\nExpression starting at:\n" );
- vcc_ErrWhere(tl, tfirst);
- vsb_printf(tl->sb, "\nending before:\n\n");
- vcc_ErrWhere(tl, tl->t);
+ if ((*e)->fmt == STRING &&
+ (tl->t->tok == '~' || tl->t->tok == T_NOMATCH)) {
+ not = tl->t->tok == '~' ? "" : "!";
+ vcc_NextToken(tl);
+ ExpectErr(tl, CSTR);
+ re = vcc_regexp(tl);
+ ERRCHK(tl);
+ vcc_NextToken(tl);
+ bprintf(buf, "%sVRT_re_match(\v1, %s)", not, re);
+ *e = vcc_expr_edit(BOOL, buf, *e, NULL);
return;
}
+ if ((*e)->fmt == IP &&
+ (tl->t->tok == '~' || tl->t->tok == T_NOMATCH)) {
+ not = tl->t->tok == '~' ? "" : "!";
+ vcc_NextToken(tl);
+ ExpectErr(tl, ID);
+ vcc_AddRef(tl, tl->t, R_ACL);
+ bprintf(buf, "%smatch_acl_named_%.*s(sp, \v1)", not, PF(tl->t));
+ vcc_NextToken(tl);
+ *e = vcc_expr_edit(BOOL, buf, *e, NULL);
+ return;
+ }
+ if ((*e)->fmt == IP && (tl->t->tok == T_EQ || tl->t->tok == T_NEQ)) {
+ vcc_Acl_Hack(tl, buf);
+ *e = vcc_expr_edit(BOOL, buf, *e, NULL);
+ return;
+ }
+ if ((*e)->fmt == BACKEND &&
+ (tl->t->tok == T_EQ || tl->t->tok == T_NEQ)) {
+ vcc_NextToken(tl);
+ ExpectErr(tl, ID);
+ vcc_AddRef(tl, tl->t, R_BACKEND);
+ bprintf(buf, "(\v1 %.*s VGCDIR(_%.*s))", PF(tk), PF(tl->t));
+ vcc_NextToken(tl);
+ *e = vcc_expr_edit(BOOL, buf, *e, NULL);
+ return;
+ }
+ if (fmt == BOOL) {
+ switch((*e)->fmt) {
+ case STRING:
+ *e = vcc_expr_edit(BOOL, "(\v1 != 0)", *e, NULL);
+ return;
+ default:
+ break;
+ }
+ }
+ if (fmt == VOID || fmt != (*e)->fmt) {
+ vsb_printf(tl->sb, "WANT: %s has %s next %.*s (%s)\n",
+ vcc_Type(fmt), vcc_Type((*e)->fmt),
+ PF(tl->t), vsb_data((*e)->vsb));
+ tl->err = 1;
+ }
}
-void
-vcc_Expr(struct vcc *tl, enum var_type fmt)
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * ExprCand:
+ * ExprAdd { '&&' ExprAdd } *
+ */
+
+static void
+vcc_expr_cand(struct vcc *tl, struct expr **e, enum var_type fmt)
{
+ struct expr *e2;
- switch (fmt) {
- case DURATION:
- case INT:
- case TIME:
- /* These types support addition and subtraction */
- Fb(tl, 1, "(\n");
- L(tl, vcc_Expr1(tl, fmt));
+ *e = NULL;
+ vcc_expr_cmp(tl, e, fmt);
+ ERRCHK(tl);
+ if ((*e)->fmt != BOOL)
+ return;
+ while (tl->t->tok == T_CAND) {
+ vcc_NextToken(tl);
+ vcc_expr_cmp(tl, &e2, fmt);
ERRCHK(tl);
- Fb(tl, 1, ")\n");
+ *e = vcc_expr_edit(BOOL, "(\v1&&\v2)", *e, e2);
+ }
+}
+
+/*--------------------------------------------------------------------
+ * SYNTAX:
+ * Expr0:
+ * ExprCand { '||' ExprCand } *
+ */
+
+static void
+vcc_expr0(struct vcc *tl, struct expr **e, enum var_type fmt)
+{
+ struct expr *e2;
+
+ *e = NULL;
+ vcc_expr_cand(tl, e, fmt);
+ ERRCHK(tl);
+ if ((*e)->fmt != BOOL)
return;
- default:
- WRONG("type not implemented yet");
+ while (tl->t->tok == T_COR) {
+ vcc_NextToken(tl);
+ vcc_expr_cand(tl, &e2, fmt);
+ ERRCHK(tl);
+ *e = vcc_expr_edit(BOOL, "(\v1||\v2)", *e, e2);
}
}
+/*--------------------------------------------------------------------
+ * This function parses and emits the C-code to evaluate an expression
+ *
+ * We know up front what kind of type we want the expression to be,
+ * and this function is the backstop if that doesn't succeed.
+ */
+
+void
+vcc_Expr(struct vcc *tl, enum var_type fmt)
+{
+ struct expr *e;
+ struct token *t1;
+
+ assert(fmt != VOID);
+
+ t1 = tl->t;
+ vcc_expr0(tl, &e, fmt);
+ if (!tl->err && fmt != e->fmt) {
+ vsb_printf(tl->sb, "Expression has type %s, expected %s\n",
+ vcc_Type(e->fmt), vcc_Type(fmt));
+ tl->err = 1;
+ }
+ if (!tl->err) {
+ vcc_expr_fmt(tl->fb, tl->indent, e);
+ vsb_putc(tl->fb, '\n');
+ } else {
+ vsb_printf(tl->sb, "Expression starts here:\n");
+ vcc_ErrWhere(tl, t1);
+ if (t1 != tl->t) {
+ vsb_printf(tl->sb, "Expression ends here:\n");
+ vcc_ErrWhere(tl, tl->t);
+ }
+ }
+ vcc_delete_expr(e);
+}
Modified: trunk/varnish-cache/lib/libvcl/vcc_parse.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_parse.c 2010-08-25 09:47:48 UTC (rev 5129)
+++ trunk/varnish-cache/lib/libvcl/vcc_parse.c 2010-08-25 19:01:35 UTC (rev 5130)
@@ -44,7 +44,6 @@
/*--------------------------------------------------------------------*/
static void vcc_Compound(struct vcc *tl);
-static void vcc_Conditional(struct vcc *tl);
/*--------------------------------------------------------------------*/
@@ -59,253 +58,8 @@
tl->t->cnt = tl->cnt; \
} while (0)
-/*--------------------------------------------------------------------*/
-
-static void
-vcc_inval_test(struct vcc *tl, const char *type, const char *valid)
-{
- vsb_printf(tl->sb, "Invalid test ");
- vcc_ErrToken(tl, tl->t);
- vsb_printf(tl->sb, " on expression of type %s.\n", type);
- vsb_printf(tl->sb, " only %s are legal\n", valid);
- vcc_ErrWhere(tl, tl->t);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-vcc_Cond_String(struct vcc *tl, const char *a1)
-{
- char *p;
-
- switch (tl->t->tok) {
- case '~':
- case T_NOMATCH:
- Fb(tl, 1, "%sVRT_re_match(",
- tl->t->tok == '~' ? "" : "!");
- vcc_NextToken(tl);
- ExpectErr(tl, CSTR);
- p = vcc_regexp(tl);
- ERRCHK(tl);
- vcc_NextToken(tl);
- Fb(tl, 1, "%s, %s)\n", a1, p);
- break;
- case T_LEQ:
- case T_GEQ:
- case '>':
- case '<':
- vcc_inval_test(tl, "STRING", "'==', '!=', '~' and '!~'");
- break;
- case T_EQ:
- case T_NEQ:
- Fb(tl, 1, "%sVRT_strcmp(%s, ",
- tl->t->tok == T_EQ ? "!" : "", a1);
- vcc_NextToken(tl);
- if (!vcc_StringVal(tl)) {
- vcc_ExpectedStringval(tl);
- break;
- }
- Fb(tl, 0, ")\n");
- break;
- default:
- Fb(tl, 1, "%s != (void*)0\n", a1);
- break;
- }
-}
-
-static void
-vcc_Cond_Bool(const struct vcc *tl, const char *a1)
-{
-
- Fb(tl, 1, "%s\n", a1);
-}
-
-static void
-vcc_Cond_Backend(struct vcc *tl, const char *a1)
-{
-
- Fb(tl, 1, "%s\n", a1);
- if (tl->t->tok == T_EQ || tl->t->tok == T_NEQ) {
- Fb(tl, 1, " %.*s\n", PF(tl->t));
- } else {
- vcc_inval_test(tl, "BACKEND", "'==' and '!='");
- return;
- }
- vcc_NextToken(tl);
- vcc_ExpectCid(tl);
- ERRCHK(tl);
- vcc_AddRef(tl, tl->t, R_BACKEND);
- Fb(tl, 1, "VGCDIR(_%.*s)\n", PF(tl->t));
- vcc_NextToken(tl);
-}
-
-static void
-vcc_Cond_Num(struct vcc *tl, enum var_type fmt, const char *fmtn,
- const char *a1)
-{
-
- Fb(tl, 1, "%s ", a1);
- switch (tl->t->tok) {
- case T_EQ:
- case T_NEQ:
- case T_LEQ:
- case T_GEQ:
- case '>':
- case '<':
- Fb(tl, 0, "%.*s\n", PF(tl->t));
- vcc_NextToken(tl);
- vcc_Expr(tl, fmt);
- break;
- default:
- vcc_inval_test(tl, fmtn,
- "'==', '!=', '<', '>', '<=' and '>='");
- break;
- }
-}
-
/*--------------------------------------------------------------------
* SYNTAX:
- * Cond_3:
- * Typed_Expr Relation Compat_Typed_Expr
- * Typed_Expr:
- * VarName
- * FuncCall
- * Relation:
- * Subset('==', '!=', '<', '<=', '>', '>=', '~', '!~')
- * Compat_Typed_Expr
- * Typed_Expr
- * Typed_Const
- *
- * Since we cannot tell if "10 s" is a TIME or DURATION type, or for that
- * matter if "127.0.0.1" is a STRING or IP type, we demand that the expression
- * before the relational operator provides us with a type which can be used to
- * guide parsing of other expression.
- */
-
-static void
-vcc_Cond_3(struct vcc *tl)
-{
- const struct var *vp;
- const struct symbol *sym;
- const char *left;
-
- sym = VCC_FindSymbol(tl, tl->t);
- if (sym == NULL) {
- vsb_printf(tl->sb,
- "Syntax error in condition.\n"
- "Expected '(', '!' or variable name.\n"
- "Found ");
- vcc_ErrToken(tl, tl->t);
- vsb_printf(tl->sb, "\n");
- vcc_ErrWhere(tl, tl->t);
- return;
- }
- vcc_AddUses(tl, tl->t, sym->r_methods, "Not available");
- AN(sym->var);
- vp = vcc_FindVar(tl, tl->t, 0, "cannot be read");
- ERRCHK(tl);
- assert(vp != NULL);
- left = vp->rname;
- vcc_NextToken(tl);
-
- switch (vp->fmt) {
- case BACKEND: L(tl, vcc_Cond_Backend(tl, left)); break;
- case BOOL: L(tl, vcc_Cond_Bool(tl, left)); break;
- case DURATION: L(tl, vcc_Cond_Num(tl, DURATION, "DURATION", left)); break;
- case INT: L(tl, vcc_Cond_Num(tl, INT, "INT", left)); break;
- case IP: L(tl, vcc_Cond_Ip(tl, left)); break;
- case STRING: L(tl, vcc_Cond_String(tl, left)); break;
- case TIME: L(tl, vcc_Cond_Num(tl, TIME, "TIME", left)); break;
- default:
- vsb_printf(tl->sb,
- "Variable '%s'"
- " has no conditions that can be checked\n",
- vp->name);
- vcc_ErrWhere(tl, tl->t);
- return;
- }
-}
-
-/*--------------------------------------------------------------------
- * SYNTAX:
- * Cond_2:
- * '!'? '(' Conditional ')'
- * '!'? Cond_3
- */
-
-static void
-vcc_Cond_2(struct vcc *tl)
-{
-
- C(tl, ",");
- if (tl->t->tok == '!') {
- Fb(tl, 1, "!");
- vcc_NextToken(tl);
- }
- if (tl->t->tok == '(') {
- vcc_Conditional(tl);
- return;
- }
- if (tl->t->tok == ID) {
- Fb(tl, 1, "(\n");
- vcc_Cond_3(tl);
- Fb(tl, 1, ")\n");
- return;
- }
- vsb_printf(tl->sb,
- "Syntax error in condition.\n"
- "Expected '(', '!' or variable name.\n"
- "Found ");
- vcc_ErrToken(tl, tl->t);
- vsb_printf(tl->sb, "\n");
- vcc_ErrWhere(tl, tl->t);
- return;
-}
-
-/*--------------------------------------------------------------------
- * SYNTAX:
- * Cond_1:
- * Cond_2 { '&&' Cond_2 }*
- */
-
-static void
-vcc_Cond_1(struct vcc *tl)
-{
-
- Fb(tl, 1, "(\n");
- L(tl, vcc_Cond_2(tl));
- while (tl->t->tok == T_CAND) {
- vcc_NextToken(tl);
- Fb(tl, 1, ") && (\n");
- L(tl, vcc_Cond_2(tl));
- ERRCHK(tl);
- }
- Fb(tl, 1, ")\n");
-}
-
-/*--------------------------------------------------------------------
- * SYNTAX:
- * Cond_0:
- * Cond_1 { '||' Cond_1 }*
- */
-
-static void
-vcc_Cond_0(struct vcc *tl)
-{
-
- Fb(tl, 1, "(\n");
- L(tl, vcc_Cond_1(tl));
- while (tl->t->tok == T_COR) {
- vcc_NextToken(tl);
- Fb(tl, 1, ") || (\n");
- L(tl, vcc_Cond_1(tl));
- ERRCHK(tl);
- }
- Fb(tl, 1, ")\n");
-}
-
-/*--------------------------------------------------------------------
- * SYNTAX:
* Conditional:
* '(' Cond_0 ')'
*/
@@ -316,7 +70,7 @@
SkipToken(tl, '(');
Fb(tl, 1, "(\n");
- L(tl, vcc_Cond_0(tl));
+ vcc_Expr(tl, BOOL);
ERRCHK(tl);
Fb(tl, 1, ")\n");
SkipToken(tl, ')');
@@ -348,7 +102,7 @@
case T_ELSE:
vcc_NextToken(tl);
if (tl->t->tok != T_IF) {
- Fb(tl, 1, "else \n");
+ Fb(tl, 1, "else\n");
L(tl, vcc_Compound(tl));
ERRCHK(tl);
return;
Modified: trunk/varnish-cache/lib/libvcl/vcc_token.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_token.c 2010-08-25 09:47:48 UTC (rev 5129)
+++ trunk/varnish-cache/lib/libvcl/vcc_token.c 2010-08-25 19:01:35 UTC (rev 5130)
@@ -105,6 +105,7 @@
vcc_icoord(vsb, t, NULL);
}
+/* XXX: should take first+last token */
void
vcc_ErrWhere(struct vcc *tl, const struct token *t)
{
More information about the varnish-commit
mailing list