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 { ...@@ -406,6 +406,8 @@ struct func_arg {
const char *name; const char *name;
const char *val; const char *val;
struct expr *result; struct expr *result;
int avail;
int optional;
VTAILQ_ENTRY(func_arg) list; VTAILQ_ENTRY(func_arg) list;
}; };
...@@ -449,6 +451,7 @@ vcc_do_arg(struct vcc *tl, struct func_arg *fa) ...@@ -449,6 +451,7 @@ vcc_do_arg(struct vcc *tl, struct func_arg *fa)
assert(e2->fmt == fa->type); assert(e2->fmt == fa->type);
fa->result = e2; fa->result = e2;
} }
fa->avail = 1;
} }
static void static void
...@@ -462,6 +465,9 @@ vcc_func(struct vcc *tl, struct expr **e, const void *priv, ...@@ -462,6 +465,9 @@ vcc_func(struct vcc *tl, struct expr **e, const void *priv,
VTAILQ_HEAD(,func_arg) head; VTAILQ_HEAD(,func_arg) head;
struct token *t1; struct token *t1;
const struct vjsn_val *vv, *vvp; const struct vjsn_val *vv, *vvp;
const char *sa;
char ssa[64];
char ssa2[64];
CAST_OBJ_NOTNULL(vv, priv, VJSN_VAL_MAGIC); CAST_OBJ_NOTNULL(vv, priv, VJSN_VAL_MAGIC);
assert(vv->type == VJSN_ARRAY); assert(vv->type == VJSN_ARRAY);
...@@ -471,6 +477,15 @@ vcc_func(struct vcc *tl, struct expr **e, const void *priv, ...@@ -471,6 +477,15 @@ vcc_func(struct vcc *tl, struct expr **e, const void *priv,
vv = VTAILQ_NEXT(vv, list); vv = VTAILQ_NEXT(vv, list);
cfunc = vv->value; cfunc = vv->value;
vv = VTAILQ_NEXT(vv, list); 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, '('); SkipToken(tl, '(');
if (extra == NULL) if (extra == NULL)
extra = ""; extra = "";
...@@ -504,6 +519,10 @@ vcc_func(struct vcc *tl, struct expr **e, const void *priv, ...@@ -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); AZ(vvp);
} }
...@@ -551,23 +570,37 @@ vcc_func(struct vcc *tl, struct expr **e, const void *priv, ...@@ -551,23 +570,37 @@ vcc_func(struct vcc *tl, struct expr **e, const void *priv,
SkipToken(tl, ','); 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) { 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) if (fa->result == NULL && fa->type == ENUM && fa->val != NULL)
vcc_do_enum(tl, fa, strlen(fa->val), fa->val); vcc_do_enum(tl, fa, strlen(fa->val), fa->val);
if (fa->result == NULL && fa->val != NULL) if (fa->result == NULL && fa->val != NULL)
fa->result = vcc_mk_expr(fa->type, "%s", fa->val); 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 = vcc_expr_edit(tl, e1->fmt, "\v1,\n\v2",
e1, fa->result); e1, fa->result);
else { } else if (!fa->optional) {
VSB_printf(tl->sb, "Argument '%s' missing\n", VSB_printf(tl->sb, "Argument '%s' missing\n",
fa->name); fa->name);
vcc_ErrWhere(tl, tl->t); vcc_ErrWhere(tl, tl->t);
} }
free(fa); 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, ')'); SkipToken(tl, ')');
} }
......
...@@ -199,6 +199,7 @@ class ctype(object): ...@@ -199,6 +199,7 @@ class ctype(object):
self.nm = None self.nm = None
self.defval = None self.defval = None
self.spec = None self.spec = None
self.opt = False
self.vt = wl.pop(0) self.vt = wl.pop(0)
self.ct = ctypes.get(self.vt) self.ct = ctypes.get(self.vt)
...@@ -287,6 +288,8 @@ class arg(ctype): ...@@ -287,6 +288,8 @@ class arg(ctype):
def json(self, jl): def json(self, jl):
jl.append([self.vt, self.nm, self.defval, self.spec]) jl.append([self.vt, self.nm, self.defval, self.spec])
if self.opt:
jl[-1].append(True)
while jl[-1][-1] is None: while jl[-1][-1] is None:
jl[-1].pop(-1) jl[-1].pop(-1)
...@@ -313,7 +316,7 @@ def lex(l): ...@@ -313,7 +316,7 @@ def lex(l):
if s == 0 and c in (' ', '\t', '\n', '\r'): if s == 0 and c in (' ', '\t', '\n', '\r'):
continue continue
if s == 0 and c in ('(', '{', '}', ')', ',', '='): if s == 0 and c in ('[', '(', '{', '}', ')', ']', ',', '='):
wl.append(c) wl.append(c)
elif s == 0 and c in ('"', "'"): elif s == 0 and c in ('"', "'"):
sep = c sep = c
...@@ -330,10 +333,10 @@ def lex(l): ...@@ -330,10 +333,10 @@ def lex(l):
wl[-1] += c wl[-1] += c
s = 1 s = 1
else: 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: 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 return wl
####################################################################### #######################################################################
...@@ -344,6 +347,7 @@ class prototype(object): ...@@ -344,6 +347,7 @@ class prototype(object):
self.st = st self.st = st
self.obj = None self.obj = None
self.args = [] self.args = []
self.argstruct = False
wl = lex(st.line[1]) wl = lex(st.line[1])
if retval: if retval:
...@@ -371,13 +375,30 @@ class prototype(object): ...@@ -371,13 +375,30 @@ class prototype(object):
wl[-1] = ',' wl[-1] = ','
names = {} names = {}
n = 0
while len(wl) > 0: while len(wl) > 0:
n += 1
x = wl.pop(0) x = wl.pop(0)
if x != ',': if x != ',':
err("Expected ',' found '%s'" % x, warn=False) err("Expected ',' found '%s'" % x, warn=False)
if len(wl) == 0: if len(wl) == 0:
break 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) self.args.append(t)
def vcl_proto(self, short, pfx=""): def vcl_proto(self, short, pfx=""):
...@@ -406,6 +427,8 @@ class prototype(object): ...@@ -406,6 +427,8 @@ class prototype(object):
t += " " + i.nm t += " " + i.nm
if i.defval is not None: if i.defval is not None:
t += "=" + i.defval t += "=" + i.defval
if i.opt:
t = "[" + t + "]"
ll.append(t) ll.append(t)
t = ",@".join(ll) t = ",@".join(ll)
if len(s + t) > 68 and not short: if len(s + t) > 68 and not short:
...@@ -440,8 +463,11 @@ class prototype(object): ...@@ -440,8 +463,11 @@ class prototype(object):
def proto(self, args, name): def proto(self, args, name):
s = self.retval.ct + " " + name + '(' s = self.retval.ct + " " + name + '('
ll = args ll = args
for i in self.args: if self.argstruct:
ll.append(i.ct) ll.append(self.argstructname() + "*")
else:
for i in self.args:
ll.append(i.ct)
s += ", ".join(ll) s += ", ".join(ll)
return s + ');' return s + ');'
...@@ -449,21 +475,49 @@ class prototype(object): ...@@ -449,21 +475,49 @@ class prototype(object):
tn = 'td_' + self.st.vcc.modname + '_' + self.cname() tn = 'td_' + self.st.vcc.modname + '_' + self.cname()
return "typedef " + self.proto(args, name=tn) 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): def cstuff(self, args, where):
s = ""
if where == 'h': 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': elif where == 'c':
s = self.typedef(args) s += lwrap(self.typedef(args))
elif where == 'o': elif where == 'o':
s = self.typedef(args) if self.argstruct:
s += self.argstructure()
s += lwrap(self.typedef(args))
else: else:
assert False assert False
return lwrap(s) return s
def json(self, jl, cfunc): def json(self, jl, cfunc):
ll = [] ll = []
self.retval.json(ll) self.retval.json(ll)
ll.append('Vmod_%s_Func.%s' % (self.st.vcc.modname, cfunc)) 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: for i in self.args:
i.json(ll) i.json(ll)
jl.append(ll) jl.append(ll)
...@@ -632,8 +686,7 @@ class s_function(stanza): ...@@ -632,8 +686,7 @@ class s_function(stanza):
self.vcc.contents.append(self) self.vcc.contents.append(self)
def cstuff(self, fo, where): 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): def cstruct(self, fo, define):
if define: if define:
...@@ -948,13 +1001,13 @@ class vcc(object): ...@@ -948,13 +1001,13 @@ class vcc(object):
for i in self.contents: for i in self.contents:
if type(i) == s_object: if type(i) == s_object:
i.cstuff(fo, 'c') i.cstuff(fo, 'c')
i.cstuff(fx, 'c') i.cstuff(fx, 'o')
fx.write("/* Functions */\n") fx.write("/* Functions */\n")
for i in self.contents: for i in self.contents:
if type(i) == s_function: if type(i) == s_function:
i.cstuff(fo, 'c') i.cstuff(fo, 'c')
i.cstuff(fx, 'c') i.cstuff(fx, 'o')
csn = "Vmod_%s_Func" % self.modname csn = "Vmod_%s_Func" % self.modname
scsn = "struct " + csn 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