Commit f279df55 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Add support for optional arguments to VMOD functions.

parent e446c076
......@@ -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, ')');
}
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment