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