[master] f279df5 Add support for optional arguments to VMOD functions.
Poul-Henning Kamp
phk at FreeBSD.org
Fri Mar 2 14:16:08 UTC 2018
commit f279df5536424d97a24ee1c9839909a90184c430
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Fri Mar 2 14:14:09 2018 +0000
Add support for optional arguments to VMOD functions.
diff --git a/lib/libvcc/vcc_expr.c b/lib/libvcc/vcc_expr.c
index 2191d4b..ddb1376 100644
--- a/lib/libvcc/vcc_expr.c
+++ b/lib/libvcc/vcc_expr.c
@@ -406,6 +406,8 @@ struct func_arg {
const char *name;
const char *val;
struct expr *result;
+ int avail;
+ int optional;
VTAILQ_ENTRY(func_arg) list;
};
@@ -449,6 +451,7 @@ vcc_do_arg(struct vcc *tl, struct func_arg *fa)
assert(e2->fmt == fa->type);
fa->result = e2;
}
+ fa->avail = 1;
}
static void
@@ -462,6 +465,9 @@ vcc_func(struct vcc *tl, struct expr **e, const void *priv,
VTAILQ_HEAD(,func_arg) head;
struct token *t1;
const struct vjsn_val *vv, *vvp;
+ const char *sa;
+ char ssa[64];
+ char ssa2[64];
CAST_OBJ_NOTNULL(vv, priv, VJSN_VAL_MAGIC);
assert(vv->type == VJSN_ARRAY);
@@ -471,6 +477,15 @@ vcc_func(struct vcc *tl, struct expr **e, const void *priv,
vv = VTAILQ_NEXT(vv, list);
cfunc = vv->value;
vv = VTAILQ_NEXT(vv, list);
+ sa = vv->value;
+ if (*sa == '\0') {
+ sa = NULL;
+ } else {
+ bprintf(ssa, "args_%u", tl->unique++);
+ VSB_printf(tl->curproc->prologue, " %s %s;\n", sa, ssa);
+ sa = ssa;
+ }
+ vv = VTAILQ_NEXT(vv, list);
SkipToken(tl, '(');
if (extra == NULL)
extra = "";
@@ -504,6 +519,10 @@ vcc_func(struct vcc *tl, struct expr **e, const void *priv,
}
}
}
+ if (sa != NULL && vvp != NULL && vvp->type == VJSN_TRUE) {
+ fa->optional = 1;
+ vvp = VTAILQ_NEXT(vvp, list);
+ }
AZ(vvp);
}
@@ -551,23 +570,37 @@ vcc_func(struct vcc *tl, struct expr **e, const void *priv,
SkipToken(tl, ',');
}
- e1 = vcc_mk_expr(rfmt, "%s(ctx%s\v+", cfunc, extra);
+ if (sa != NULL)
+ e1 = vcc_mk_expr(rfmt, "%s(ctx%s,\v+(\n", cfunc, extra);
+ else
+ e1 = vcc_mk_expr(rfmt, "%s(ctx%s\v+", cfunc, extra);
VTAILQ_FOREACH_SAFE(fa, &head, list, fa2) {
+ if (fa->optional)
+ VSB_printf(tl->curproc->prologue,
+ " %s.valid_%s = %d;\n", sa, fa->name, fa->avail);
if (fa->result == NULL && fa->type == ENUM && fa->val != NULL)
vcc_do_enum(tl, fa, strlen(fa->val), fa->val);
if (fa->result == NULL && fa->val != NULL)
fa->result = vcc_mk_expr(fa->type, "%s", fa->val);
- if (fa->result != NULL)
+ if (fa->result != NULL && sa != NULL) {
+ bprintf(ssa2, "\v1%s.%s = \v2,\n", sa, fa->name);
+ e1 = vcc_expr_edit(tl, e1->fmt, ssa2, e1, fa->result);
+ } else if (fa->result != NULL) {
e1 = vcc_expr_edit(tl, e1->fmt, "\v1,\n\v2",
e1, fa->result);
- else {
+ } else if (!fa->optional) {
VSB_printf(tl->sb, "Argument '%s' missing\n",
fa->name);
vcc_ErrWhere(tl, tl->t);
}
free(fa);
}
- *e = vcc_expr_edit(tl, e1->fmt, "\v1\n)\v-", e1, NULL);
+ if (sa != NULL) {
+ bprintf(ssa2, "\v1&%s\v-\n))", sa);
+ *e = vcc_expr_edit(tl, e1->fmt, ssa2, e1, NULL);
+ } else {
+ *e = vcc_expr_edit(tl, e1->fmt, "\v1\n)\v-", e1, NULL);
+ }
SkipToken(tl, ')');
}
diff --git a/lib/libvcc/vmodtool.py b/lib/libvcc/vmodtool.py
index aee9756..853abb7 100755
--- a/lib/libvcc/vmodtool.py
+++ b/lib/libvcc/vmodtool.py
@@ -199,6 +199,7 @@ class ctype(object):
self.nm = None
self.defval = None
self.spec = None
+ self.opt = False
self.vt = wl.pop(0)
self.ct = ctypes.get(self.vt)
@@ -287,6 +288,8 @@ class arg(ctype):
def json(self, jl):
jl.append([self.vt, self.nm, self.defval, self.spec])
+ if self.opt:
+ jl[-1].append(True)
while jl[-1][-1] is None:
jl[-1].pop(-1)
@@ -313,7 +316,7 @@ def lex(l):
if s == 0 and c in (' ', '\t', '\n', '\r'):
continue
- if s == 0 and c in ('(', '{', '}', ')', ',', '='):
+ if s == 0 and c in ('[', '(', '{', '}', ')', ']', ',', '='):
wl.append(c)
elif s == 0 and c in ('"', "'"):
sep = c
@@ -330,10 +333,10 @@ def lex(l):
wl[-1] += c
s = 1
else:
- err("Syntax error at char", i, "'%s'" % c, warn=False)
+ err("Syntax error at char %d '%s'" % (i, c), warn=False)
if s != 0:
- err("Syntax error at char", i, "'%s'" % c, warn=False)
+ err("Syntax error at char %d '%s'" % (i, c), warn=False)
return wl
#######################################################################
@@ -344,6 +347,7 @@ class prototype(object):
self.st = st
self.obj = None
self.args = []
+ self.argstruct = False
wl = lex(st.line[1])
if retval:
@@ -371,13 +375,30 @@ class prototype(object):
wl[-1] = ','
names = {}
+ n = 0
while len(wl) > 0:
+ n += 1
x = wl.pop(0)
if x != ',':
err("Expected ',' found '%s'" % x, warn=False)
if len(wl) == 0:
break
- t = arg(wl, names, st.vcc.enums, ',')
+ if wl[0] == '[':
+ wl.pop(0)
+ t = arg(wl, names, st.vcc.enums, ']')
+ if t.nm is None:
+ err("Optional arguments must have names", warn=False)
+ t.opt = True
+ x = wl.pop(0)
+ if x != ']':
+ err("Expected ']' found '%s'" % x, warn=False)
+ self.argstruct = True
+ else:
+ t = arg(wl, names, st.vcc.enums, ',')
+ if t.nm is None:
+ t.nm2 = "arg%d" % n
+ else:
+ t.nm2 = t.nm
self.args.append(t)
def vcl_proto(self, short, pfx=""):
@@ -406,6 +427,8 @@ class prototype(object):
t += " " + i.nm
if i.defval is not None:
t += "=" + i.defval
+ if i.opt:
+ t = "[" + t + "]"
ll.append(t)
t = ",@".join(ll)
if len(s + t) > 68 and not short:
@@ -440,8 +463,11 @@ class prototype(object):
def proto(self, args, name):
s = self.retval.ct + " " + name + '('
ll = args
- for i in self.args:
- ll.append(i.ct)
+ if self.argstruct:
+ ll.append(self.argstructname() + "*")
+ else:
+ for i in self.args:
+ ll.append(i.ct)
s += ", ".join(ll)
return s + ');'
@@ -449,21 +475,49 @@ class prototype(object):
tn = 'td_' + self.st.vcc.modname + '_' + self.cname()
return "typedef " + self.proto(args, name=tn)
+ def argstructname(self):
+ return "struct %s_arg" % self.cname(True)
+
+ def argstructure(self):
+ s = "\n" + self.argstructname() + " {\n"
+ for i in self.args:
+ if i.opt:
+ assert i.nm is not None
+ s += "\tchar\t\t\tvalid_%s;\n" % i.nm
+ for i in self.args:
+ s += "\t" + i.ct
+ if len(i.ct) < 8:
+ s += "\t"
+ if len(i.ct) < 16:
+ s += "\t"
+ s += "\t" + i.nm2 + ";\n"
+ s += "};\n"
+ return s
+
def cstuff(self, args, where):
+ s = ""
if where == 'h':
- s = self.proto(args, self.cname(True))
+ if self.argstruct:
+ s += self.argstructure()
+ s += lwrap(self.proto(args, self.cname(True)))
elif where == 'c':
- s = self.typedef(args)
+ s += lwrap(self.typedef(args))
elif where == 'o':
- s = self.typedef(args)
+ if self.argstruct:
+ s += self.argstructure()
+ s += lwrap(self.typedef(args))
else:
assert False
- return lwrap(s)
+ return s
def json(self, jl, cfunc):
ll = []
self.retval.json(ll)
ll.append('Vmod_%s_Func.%s' % (self.st.vcc.modname, cfunc))
+ if self.argstruct:
+ ll.append(self.argstructname())
+ else:
+ ll.append("")
for i in self.args:
i.json(ll)
jl.append(ll)
@@ -632,8 +686,7 @@ class s_function(stanza):
self.vcc.contents.append(self)
def cstuff(self, fo, where):
- if where in ('h', 'c'):
- fo.write(self.proto.cstuff(['VRT_CTX'], where))
+ fo.write(self.proto.cstuff(['VRT_CTX'], where))
def cstruct(self, fo, define):
if define:
@@ -948,13 +1001,13 @@ class vcc(object):
for i in self.contents:
if type(i) == s_object:
i.cstuff(fo, 'c')
- i.cstuff(fx, 'c')
+ i.cstuff(fx, 'o')
fx.write("/* Functions */\n")
for i in self.contents:
if type(i) == s_function:
i.cstuff(fo, 'c')
- i.cstuff(fx, 'c')
+ i.cstuff(fx, 'o')
csn = "Vmod_%s_Func" % self.modname
scsn = "struct " + csn
More information about the varnish-commit
mailing list