about summary refs log tree commit diff stats
path: root/dwm.h
blob: 999f02796e455b0a61be0491c9b9da3b9b5adb8a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* See LICENSE file for copyright and license details.
 *
 * dynamic window manager is designed like any other X client as well. It is
 * driven through handling X events. In contrast to other X clients, a window
 * manager selects for SubstructureRedirectMask on the root window, to receive
 * events about window (dis-)appearance.  Only one X connection at a time is
 * allowed to select for this event mask.
 *
 * Calls to fetch an X event from the event queue are blocking.  Due reading
 * status text from standard input, a select()-driven main loop has been
 * implemented which selects for reads on the X connection and STDIN_FILENO to
 * handle all data smoothly. The event handlers of dwm are organized in an
 * array which is accessed whenever a new event has been fetched. This allows
 * event dispatching in O(1) time.
 *
 * Each child of the root window is called a client, except windows which have
 * set the override_redirect flag.  Clients are organized in a global
 * doubly-linked client list, the focus history is remembered through a global
 * stack list. Each client contains an array of Bools of the same size as the
 * global tags array to indicate the tags of a client.  For each client dwm
 * creates a small title window, which is resized whenever the (_NET_)WM_NAME
 * properties are updated or the client is moved/resized.
 *
 * Keys and tagging rules are organized as arrays and defined in the config.h
 * file. These arrays are kept static in event.o and tag.o respectively,
 * because no other part of dwm needs access to them.  The current layout is
 * represented by the lt pointer.
 *
 * To understand everything else, start reading main.c:main().
 */

#include "config.h"
#include <X11/Xlib.h>

/* mask shorthands, used in event.c and client.c */
#define BUTTONMASK		(ButtonPressMask | ButtonReleaseMask)

enum { BarTop, BarBot, BarOff };			/* bar position */
enum { CurNormal, CurResize, CurMove, CurLast };	/* cursor */
enum { ColBorder, ColFG, ColBG, ColLast };		/* color */
enum { NetSupported, NetWMName, NetLast };		/* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMLast };	/* default atoms */

typedef struct Client Client;
struct Client {
	char name[256];
	int x, y, w, h;
	int rx, ry, rw, rh; /* revert geometry */
	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
	int minax, maxax, minay, maxay;
	long flags; 
	unsigned int border, oldborder;
	Bool isbanned, isfixed, ismax, isfloating;
	Bool *tags;
	Client *next;
	Client *prev;
	Client *snext;
	Window win;
};

typedef struct {
	int x, y, w, h;
	unsigned long norm[ColLast];
	unsigned long sel[ColLast];
	Drawable drawable;
	GC gc;
	struct {
		int ascent;
		int descent;
		int height;
		XFontSet set;
		XFontStruct *xfont;
	} font;
} DC; /* draw context */

typedef struct {
	const char *symbol;
	void (*arrange)(void);
} Layout;

extern const char *tags[];			/* all tags */
extern char stext[256];				/* status text */
extern int screen, sx, sy, sw, sh;		/* screen geometry */
extern int wax, way, wah, waw;			/* windowarea geometry */
extern unsigned int bh, blw, bpos;		/* bar height, bar layout label width, bar position */
extern unsigned int ntags, numlockmask;		/* number of tags, numlock mask */
extern void (*handler[LASTEvent])(XEvent *);	/* event handler */
extern Atom wmatom[WMLast], netatom[NetLast];
extern Bool selscreen, *seltag;			/* seltag is array of Bool */
extern Client *clients, *sel, *stack;		/* global client list and stack */
extern Cursor cursor[CurLast];
extern DC dc;					/* global draw context */
extern Display *dpy;
extern Layout *lt;
extern Window root, barwin;

/* client.c */
void attach(Client *c);			/* attaches c to global client list */
void ban(Client *c);			/* bans c */
void configure(Client *c);		/* send synthetic configure event */
void detach(Client *c);			/* detaches c from global client list */
void focus(Client *c);			/* focus c if visible && !NULL, or focus top visible */
void killclient(const char *arg);	/* kill sel  nicely */
void manage(Window w, XWindowAttributes *wa);	/* manage new client */
void resize(Client *c, int x, int y,
		int w, int h, Bool sizehints);	/* resize with given coordinates c*/
void togglefloating(const char *arg);	/* toggles sel between floating/tiled state */
void unban(Client *c);			/* unbans c */
void unmanage(Client *c);		/* destroy c */
void updatesizehints(Client *c);	/* update the size hint variables of c */
void updatetitle(Client *c);		/* update the name of c */

/* draw.c */
void drawstatus(void);			/* draw the bar */
void drawtext(const char *text, unsigned long col[ColLast]);	/* draw text */
unsigned int textw(const char *text);	/* return the width of text in px*/

/* event.c */
void grabkeys(void);			/* grab all keys defined in config.h */

/* layout.c */
void floating(void);			/* arranges all windows floating */
void focusclient(const char *arg);	/* focuses next(1)/previous(-1) visible client */
void incmasterw(const char *arg);	/* increments the master width with arg's index value */
void incnmaster(const char *arg);	/* increments nmaster with arg's index value */
void initlayouts(void);			/* initialize layout array */
Client *nexttiled(Client *c);		/* returns tiled successor of c */
void restack(void);			/* restores z layers of all clients */
void setlayout(const char *arg);	/* sets layout, NULL means next layout */
void togglebar(const char *arg);	/* shows/hides the bar */
void togglemax(const char *arg);	/* toggles maximization of floating client */
void zoom(const char *arg);		/* zooms the focused client to master area, arg is ignored */

/* main.c */
void updatebarpos(void);		/* updates the bar position */
void quit(const char *arg);		/* quit dwm nicely */
int xerror(Display *dsply, XErrorEvent *ee);	/* dwm's X error handler */

/* tag.c */
void compileregs(void);			/* initialize regexps of rules defined in config.h */
Bool isvisible(Client *c);		/* returns True if client is visible */
void settags(Client *c, Client *trans);	/* sets tags of c */
void tag(const char *arg);		/* tags sel with arg's index */
void toggletag(const char *arg);	/* toggles sel tags with arg's index */
void toggleview(const char *arg);	/* toggles the tag with arg's index (in)visible */
void view(const char *arg);		/* views the tag with arg's index */

/* util.c */
void *emallocz(unsigned int size);	/* allocates zero-initialized memory, exits on error */
void eprint(const char *errstr, ...);	/* prints errstr and exits with 1 */
void spawn(const char *arg);		/* forks a new subprocess with arg's cmd */
> p.prc.id == n.sym.owner.id of nkDotExpr, nkBracketExpr: if skipTypes(n.sons[0].typ, abstractInst).kind notin {tyVar,tyPtr,tyRef}: result = isInCurrentFrame(p, n.sons[0]) of nkHiddenStdConv, nkHiddenSubConv, nkConv: result = isInCurrentFrame(p, n.sons[1]) of nkHiddenDeref, nkDerefExpr: # what about: var x = addr(y); callAsOpenArray(x[])? # *shrug* ``addr`` is unsafe anyway. result = false of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: result = isInCurrentFrame(p, n.sons[0]) else: discard proc openArrayLoc(p: BProc, n: PNode): Rope = var a: TLoc let q = skipConv(n) if getMagic(q) == mSlice: # magic: pass slice to openArray: var b, c: TLoc initLocExpr(p, q[1], a) initLocExpr(p, q[2], b) initLocExpr(p, q[3], c) let fmt = case skipTypes(a.t, abstractVar+{tyPtr}).kind of tyOpenArray, tyVarargs, tyArray: "($1)+($2), ($3)-($2)+1" of tyString, tySequence: if skipTypes(n.typ, abstractInst).kind == tyVar and not compileToCpp(p.module): "(*$1)->data+($2), ($3)-($2)+1" else: "$1->data+($2), ($3)-($2)+1" else: (internalError("openArrayLoc: " & typeToString(a.t)); "") result = fmt % [rdLoc(a), rdLoc(b), rdLoc(c)] else: initLocExpr(p, n, a) case skipTypes(a.t, abstractVar).kind of tyOpenArray, tyVarargs: result = "$1, $1Len_0" % [rdLoc(a)] of tyString, tySequence: if skipTypes(n.typ, abstractInst).kind == tyVar and not compileToCpp(p.module): result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)] else: result = "$1->data, $1->$2" % [a.rdLoc, lenField(p)] of tyArray: result = "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))] of tyPtr, tyRef: case lastSon(a.t).kind of tyString, tySequence: result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)] of tyArray: result = "$1, $2" % [rdLoc(a), rope(lengthOrd(lastSon(a.t)))] else: internalError("openArrayLoc: " & typeToString(a.t)) else: internalError("openArrayLoc: " & typeToString(a.t)) proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} = var a: TLoc initLocExpr(p, n.sons[0], a) result = "$1->data" % [a.rdLoc] proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope = var a: TLoc if n.kind == nkStringToCString: result = genArgStringToCString(p, n) elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: var n = if n.kind != nkHiddenAddr: n else: n.sons[0] result = openArrayLoc(p, n) elif ccgIntroducedPtr(param): initLocExpr(p, n, a) result = addrLoc(a) elif p.module.compileToCpp and param.typ.kind == tyVar and n.kind == nkHiddenAddr: initLocExprSingleUse(p, n.sons[0], a) # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still # means '*T'. See posix.nim for lots of examples that do that in the wild. let callee = call.sons[0] if callee.kind == nkSym and {sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}: result = addrLoc(a) else: result = rdLoc(a) else: initLocExprSingleUse(p, n, a) result = rdLoc(a) proc genArgNoParam(p: BProc, n: PNode): Rope = var a: TLoc if n.kind == nkStringToCString: result = genArgStringToCString(p, n) else: initLocExprSingleUse(p, n, a) result = rdLoc(a) template genParamLoop(params) {.dirty.} = if i < sonsLen(typ): assert(typ.n.sons[i].kind == nkSym) let paramType = typ.n.sons[i] if not paramType.typ.isCompileTimeOnly: if params != nil: add(params, ~", ") add(params, genArg(p, ri.sons[i], paramType.sym, ri)) else: if params != nil: add(params, ~", ") add(params, genArgNoParam(p, ri.sons[i])) proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = var op: TLoc # this is a hotspot in the compiler initLocExpr(p, ri.sons[0], op) var params: Rope # getUniqueType() is too expensive here: var typ = skipTypes(ri.sons[0].typ, abstractInst) assert(typ.kind == tyProc) assert(sonsLen(typ) == sonsLen(typ.n)) var length = sonsLen(ri) for i in countup(1, length - 1): genParamLoop(params) fixupCall(p, le, ri, d, op.r, params) proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = proc getRawProcType(p: BProc, t: PType): Rope = result = getClosureType(p.module, t, clHalf) proc addComma(r: Rope): Rope = result = if r == nil: r else: r & ~", " const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)" const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists var op: TLoc initLocExpr(p, ri.sons[0], op) var pl: Rope var typ = skipTypes(ri.sons[0].typ, abstractInst) assert(typ.kind == tyProc) var length = sonsLen(ri) for i in countup(1, length - 1): assert(sonsLen(typ) == sonsLen(typ.n)) genParamLoop(pl) template genCallPattern {.dirty.} = lineF(p, cpsStmts, callPattern & ";$n", [op.r, pl, pl.addComma, rawProc]) let rawProc = getRawProcType(p, typ) let callPattern = if tfIterator in typ.flags: PatIter else: PatProc if typ.sons[0] != nil: if isInvalidReturnType(typ.sons[0]): if sonsLen(ri) > 1: add(pl, ~", ") # beware of 'result = p(result)'. We may need to allocate a temporary: if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri): # Great, we can use 'd': if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true) elif d.k notin {locTemp} and not hasNoInit(ri): # reset before pass as 'result' var: resetLoc(p, d) add(pl, addrLoc(d)) genCallPattern() else: var tmp: TLoc getTemp(p, typ.sons[0], tmp, needsInit=true) add(pl, addrLoc(tmp)) genCallPattern() genAssignment(p, d, tmp, {}) # no need for deep copying else: if d.k == locNone: getTemp(p, typ.sons[0], d) assert(d.t != nil) # generate an assignment to d: var list: TLoc initLoc(list, locCall, d.t, OnUnknown) list.r = callPattern % [op.r, pl, pl.addComma, rawProc] genAssignment(p, d, list, {}) # no need for deep copying else: genCallPattern() proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = if i < sonsLen(typ): # 'var T' is 'T&' in C++. This means we ignore the request of # any nkHiddenAddr when it's a 'var T'. let paramType = typ.n.sons[i] assert(paramType.kind == nkSym) if paramType.typ.isCompileTimeOnly: result = nil elif typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr: result = genArgNoParam(p, ri.sons[i][0]) else: result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym) else: if tfVarargs notin typ.flags: localError(ri.info, "wrong argument count") result = nil else: result = genArgNoParam(p, ri.sons[i]) discard """ Dot call syntax in C++ ====================== so c2nim translates 'this' sometimes to 'T' and sometimes to 'var T' both of which are wrong, but often more convenient to use. For manual wrappers it can also be 'ptr T' Fortunately we know which parameter is the 'this' parameter and so can fix this mess in the codegen. now ... if the *argument* is a 'ptr' the codegen shall emit -> and otherwise . but this only depends on the argument and not on how the 'this' was declared however how the 'this' was declared affects whether we end up with wrong 'addr' and '[]' ops... Since I'm tired I'll enumerate all the cases here: var x: ptr T y: T proc t(x: T) x[].t() --> (*x).t() is correct. y.t() --> y.t() is correct proc u(x: ptr T) x.u() --> needs to become x->u() (addr y).u() --> needs to become y.u() proc v(x: var T) --> first skip the implicit 'nkAddr' node x[].v() --> (*x).v() is correct, but might have been eliminated due to the nkAddr node! So for this case we need to generate '->' y.v() --> y.v() is correct """ proc skipAddrDeref(node: PNode): PNode = var n = node var isAddr = false case n.kind of nkAddr, nkHiddenAddr: n = n.sons[0] isAddr = true of nkDerefExpr, nkHiddenDeref: n = n.sons[0] else: return n if n.kind == nkObjDownConv: n = n.sons[0] if isAddr and n.kind in {nkDerefExpr, nkHiddenDeref}: result = n.sons[0] elif n.kind in {nkAddr, nkHiddenAddr}: result = n.sons[0] else: result = node proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope = # for better or worse c2nim translates the 'this' argument to a 'var T'. # However manual wrappers may also use 'ptr T'. In any case we support both # for convenience. internalAssert i < sonsLen(typ) assert(typ.n.sons[i].kind == nkSym) # if the parameter is lying (tyVar) and thus we required an additional deref, # skip the deref: var ri = ri[i] while ri.kind == nkObjDownConv: ri = ri[0] let t = typ.sons[i].skipTypes({tyGenericInst, tyAlias}) if t.kind == tyVar: let x = if ri.kind == nkHiddenAddr: ri[0] else: ri if x.typ.kind == tyPtr: result = genArgNoParam(p, x) result.add("->") elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr: result = genArgNoParam(p, x[0]) result.add("->") else: result = genArgNoParam(p, x) result.add(".") elif t.kind == tyPtr: if ri.kind in {nkAddr, nkHiddenAddr}: result = genArgNoParam(p, ri[0]) result.add(".") else: result = genArgNoParam(p, ri) result.add("->") else: ri = skipAddrDeref(ri) if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0] result = genArgNoParam(p, ri) #, typ.n.sons[i].sym) result.add(".") proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope = var i = 0 var j = 1 while i < pat.len: case pat[i] of '@': if j < ri.len: result.add genOtherArg(p, ri, j, typ) for k in j+1 .. < ri.len: result.add(~", ") result.add genOtherArg(p, ri, k, typ) inc i of '#': if pat[i+1] in {'+', '@'}: let ri = ri[j] if ri.kind in nkCallKinds: let typ = skipTypes(ri.sons[0].typ, abstractInst) if pat[i+1] == '+': result.add genArgNoParam(p, ri.sons[0]) result.add(~"(") if 1 < ri.len: result.add genOtherArg(p, ri, 1, typ) for k in j+1 .. < ri.len: result.add(~", ") result.add genOtherArg(p, ri, k, typ) result.add(~")") else: localError(ri.info, "call expression expected for C++ pattern") inc i elif pat[i+1] == '.': result.add genThisArg(p, ri, j, typ) inc i elif pat[i+1] == '[': var arg = ri.sons[j].skipAddrDeref while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg[0] result.add genArgNoParam(p, arg) #result.add debugTree(arg, 0, 10) else: result.add genOtherArg(p, ri, j, typ) inc j inc i of '\'': var idx, stars: int if scanCppGenericSlot(pat, i, idx, stars): var t = resolveStarsInCppType(typ, idx, stars) if t == nil: result.add(~"void") else: result.add(getTypeDesc(p.module, t)) else: let start = i while i < pat.len: if pat[i] notin {'@', '#', '\''}: inc(i) else: break if i - 1 >= start: add(result, substr(pat, start, i - 1)) proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = var op: TLoc initLocExpr(p, ri.sons[0], op) # getUniqueType() is too expensive here: var typ = skipTypes(ri.sons[0].typ, abstractInst) assert(typ.kind == tyProc) var length = sonsLen(ri) assert(sonsLen(typ) == sonsLen(typ.n)) # don't call '$' here for efficiency: let pat = ri.sons[0].sym.loc.r.data internalAssert pat != nil if pat.contains({'#', '(', '@', '\''}): var pl = genPatternCall(p, ri, pat, typ) # simpler version of 'fixupCall' that works with the pl+params combination: var typ = skipTypes(ri.sons[0].typ, abstractInst) if typ.sons[0] != nil: if p.module.compileToCpp and lfSingleUse in d.flags: # do not generate spurious temporaries for C++! For C we're better off # with them to prevent undefined behaviour and because the codegen # is free to emit expressions multiple times! d.k = locCall d.r = pl excl d.flags, lfSingleUse else: if d.k == locNone: getTemp(p, typ.sons[0], d) assert(d.t != nil) # generate an assignment to d: var list: TLoc initLoc(list, locCall, d.t, OnUnknown) list.r = pl genAssignment(p, d, list, {}) # no need for deep copying else: add(pl, ~";$n") line(p, cpsStmts, pl) else: var pl: Rope = nil #var param = typ.n.sons[1].sym if 1 < ri.len: add(pl, genThisArg(p, ri, 1, typ)) add(pl, op.r) var params: Rope for i in countup(2, length - 1): if params != nil: params.add(~", ") assert(sonsLen(typ) == sonsLen(typ.n)) add(params, genOtherArg(p, ri, i, typ)) fixupCall(p, le, ri, d, pl, params) proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = # generates a crappy ObjC call var op: TLoc initLocExpr(p, ri.sons[0], op) var pl = ~"[" # getUniqueType() is too expensive here: var typ = skipTypes(ri.sons[0].typ, abstractInst) assert(typ.kind == tyProc) var length = sonsLen(ri) assert(sonsLen(typ) == sonsLen(typ.n)) # don't call '$' here for efficiency: let pat = ri.sons[0].sym.loc.r.data internalAssert pat != nil var start = 3 if ' ' in pat: start = 1 add(pl, op.r) if length > 1: add(pl, ~": ") add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri)) start = 2 else: if length > 1: add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri)) add(pl, ~" ") add(pl, op.r) if length > 2: add(pl, ~": ") add(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri)) for i in countup(start, length-1): assert(sonsLen(typ) == sonsLen(typ.n)) if i >= sonsLen(typ): internalError(ri.info, "varargs for objective C method?") assert(typ.n.sons[i].kind == nkSym) var param = typ.n.sons[i].sym add(pl, ~" ") add(pl, param.name.s) add(pl, ~": ") add(pl, genArg(p, ri.sons[i], param, ri)) if typ.sons[0] != nil: if isInvalidReturnType(typ.sons[0]): if sonsLen(ri) > 1: add(pl, ~" ") # beware of 'result = p(result)'. We always allocate a temporary: if d.k in {locTemp, locNone}: # We already got a temp. Great, special case it: if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true) add(pl, ~"Result: ") add(pl, addrLoc(d)) add(pl, ~"];$n") line(p, cpsStmts, pl) else: var tmp: TLoc getTemp(p, typ.sons[0], tmp, needsInit=true) add(pl, addrLoc(tmp)) add(pl, ~"];$n") line(p, cpsStmts, pl) genAssignment(p, d, tmp, {}) # no need for deep copying else: add(pl, ~"]") if d.k == locNone: getTemp(p, typ.sons[0], d) assert(d.t != nil) # generate an assignment to d: var list: TLoc initLoc(list, locCall, nil, OnUnknown) list.r = pl genAssignment(p, d, list, {}) # no need for deep copying else: add(pl, ~"];$n") line(p, cpsStmts, pl) proc genCall(p: BProc, e: PNode, d: var TLoc) = if e.sons[0].typ.skipTypes({tyGenericInst, tyAlias}).callConv == ccClosure: genClosureCall(p, nil, e, d) elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags: genInfixCall(p, nil, e, d) elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags: genNamedParamCall(p, e, d) else: genPrefixCall(p, nil, e, d) postStmtActions(p) proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) = if ri.sons[0].typ.skipTypes({tyGenericInst, tyAlias}).callConv == ccClosure: genClosureCall(p, le, ri, d) elif ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags: genInfixCall(p, le, ri, d) elif ri.sons[0].kind == nkSym and sfNamedParamCall in ri.sons[0].sym.flags: genNamedParamCall(p, ri, d) else: genPrefixCall(p, le, ri, d) postStmtActions(p)