commit d34ce1a
shrub
·
2026-04-16 16:19:03 +0000 UTC
parent edddaa3
make eval state less shitty
9 files changed,
+155,
-92
+58,
-0
1@@ -0,0 +1,58 @@
2+digraph shin {
3+ rankdir=LR;
4+ node [fontname="monospace"];
5+ n0 [label="all", style=dashed];
6+ n1 [label="shin", shape=box];
7+ n2 [label="cli/main.o", shape=box];
8+ n3 [label="src/parse.o", shape=box];
9+ n4 [label="src/eval/eval.o", shape=box];
10+ n5 [label="src/eval/dollar.o", shape=box];
11+ n6 [label="src/graph.o", shape=box];
12+ n7 [label="src/posix.o", shape=box];
13+ n8 [label="src/gnu/pattern.o", shape=box];
14+ n9 [label="backends/ninja.o", shape=box];
15+ n10 [label="backends/graphviz.o", shape=box];
16+ n11 [label="src/util.o", shape=box];
17+ n12 [label="src/gnu/functions.o", shape=box];
18+ n13 [label="fmt", shape=box];
19+ n14 [label="test", shape=box];
20+ n15 [label="install", shape=box];
21+ n16 [label="clean", shape=box];
22+ n17 [label="cli/main.c"];
23+ n18 [label="src/parse.c"];
24+ n19 [label="src/eval/eval.c"];
25+ n20 [label="src/eval/dollar.c"];
26+ n21 [label="src/graph.c"];
27+ n22 [label="src/posix.c"];
28+ n23 [label="src/gnu/pattern.c"];
29+ n24 [label="backends/ninja.c"];
30+ n25 [label="backends/graphviz.c"];
31+ n26 [label="src/util.c"];
32+ n27 [label="src/gnu/functions.c"];
33+
34+ n1 -> n0;
35+ n2 -> n1;
36+ n3 -> n1;
37+ n4 -> n1;
38+ n5 -> n1;
39+ n6 -> n1;
40+ n7 -> n1;
41+ n8 -> n1;
42+ n9 -> n1;
43+ n10 -> n1;
44+ n11 -> n1;
45+ n12 -> n1;
46+ n17 -> n2;
47+ n18 -> n3;
48+ n19 -> n4;
49+ n20 -> n5;
50+ n21 -> n6;
51+ n22 -> n7;
52+ n23 -> n8;
53+ n24 -> n9;
54+ n25 -> n10;
55+ n26 -> n11;
56+ n27 -> n12;
57+ n1 -> n14;
58+ n1 -> n15;
59+}
+27,
-41
1@@ -8,8 +8,6 @@
2
3 /* $() ${} expansion is handled here */
4
5-static int evalerrs;
6-
7 struct Buf {
8 char *s;
9 size_t len;
10@@ -17,25 +15,13 @@ struct Buf {
11 };
12
13 static void
14-evalerr(const char *msg, const char *detail)
15+evalerr(struct EvalCtx *ctx, const char *msg, const char *detail)
16 {
17 if (detail)
18 fprintf(stderr, "eval: unsupported: %s: %s\n", msg, detail);
19 else
20 fprintf(stderr, "eval: unsupported: %s\n", msg);
21- evalerrs++;
22-}
23-
24-void
25-resetevalerrs(void)
26-{
27- evalerrs = 0;
28-}
29-
30-int
31-getevalerrs(void)
32-{
33- return evalerrs;
34+ ctx->errors++;
35 }
36
37 static void
38@@ -241,20 +227,20 @@ findclose(const char *s, size_t i, size_t n, char close)
39 }
40
41 static char *
42-expandvarref(struct Env *env, const char *s, size_t n)
43+expandvarref(struct EvalCtx *ctx, const char *s, size_t n)
44 {
45 char *name, *val;
46 struct Var *v;
47
48 name = xstrndup(s, n);
49- v = findvar(env, name);
50+ v = findvar(ctx->env, name);
51 free(name);
52- val = v ? expandstr(env, v->val) : xstrdup("");
53+ val = v ? expandstr(ctx, v->val) : xstrdup("");
54 return val;
55 }
56
57 static char *
58-expandsubstref(struct Env *env, const char *s, size_t colon, size_t eq, size_t n)
59+expandsubstref(struct EvalCtx *ctx, const char *s, size_t colon, size_t eq, size_t n)
60 {
61 char *name, *from, *to, *val;
62 struct Var *v;
63@@ -265,17 +251,17 @@ expandsubstref(struct Env *env, const char *s, size_t colon, size_t eq, size_t n
64 name = xstrndup(s, colon);
65 fromraw = xstrndup(s + colon + 1, eq - colon - 1);
66 toraw = xstrndup(s + eq + 1, n - eq - 1);
67- from = expandstr(env, fromraw);
68- to = expandstr(env, toraw);
69+ from = expandstr(ctx, fromraw);
70+ to = expandstr(ctx, toraw);
71 free(fromraw);
72 free(toraw);
73- v = findvar(env, name);
74+ v = findvar(ctx->env, name);
75 free(name);
76 }
77 if (v) {
78 char *base;
79
80- base = expandstr(env, v->val);
81+ base = expandstr(ctx, v->val);
82 val = substval(base, from, to);
83 free(base);
84 } else {
85@@ -324,7 +310,7 @@ static const struct func funcs[] = {
86 };
87
88 static char *
89-funcref(struct Env *env, const char *s, size_t n)
90+funcref(struct EvalCtx *ctx, const char *s, size_t n)
91 {
92 size_t i, namelen, start;
93 const struct func *f;
94@@ -342,7 +328,7 @@ funcref(struct Env *env, const char *s, size_t n)
95 char *raw, *exp;
96
97 raw = xstrndup(s + start, n - start);
98- exp = expandstr(env, raw);
99+ exp = expandstr(ctx, raw);
100 free(raw);
101 val = f->fn.f1(exp);
102 free(exp);
103@@ -354,7 +340,7 @@ funcref(struct Env *env, const char *s, size_t n)
104 comma = findargcomma(args, strlen(args));
105 if (comma < 0) {
106 detail = cat3("$(", f->name, ")");
107- evalerr("malformed function arguments", detail);
108+ evalerr(ctx, "malformed function arguments", detail);
109 free(detail);
110 free(args);
111 return xstrdup("");
112@@ -362,8 +348,8 @@ funcref(struct Env *env, const char *s, size_t n)
113 lhs_raw = xstrndup(args, (size_t)comma);
114 rhs_raw = xstrdup(args + comma + 1);
115 free(args);
116- lhs_exp = expandstr(env, lhs_raw);
117- rhs_exp = expandstr(env, rhs_raw);
118+ lhs_exp = expandstr(ctx, lhs_raw);
119+ rhs_exp = expandstr(ctx, rhs_raw);
120 free(lhs_raw);
121 free(rhs_raw);
122 val = f->fn.f2(lhs_exp, rhs_exp);
123@@ -378,7 +364,7 @@ funcref(struct Env *env, const char *s, size_t n)
124 c1 = findargcomma(args, strlen(args));
125 if (c1 < 0) {
126 detail = cat3("$(", f->name, ")");
127- evalerr("malformed function arguments", detail);
128+ evalerr(ctx, "malformed function arguments", detail);
129 free(detail);
130 free(args);
131 return xstrdup("");
132@@ -394,9 +380,9 @@ funcref(struct Env *env, const char *s, size_t n)
133 a3r = xstrdup(args + rest + (size_t)c2 + 1);
134 }
135 free(args);
136- a1e = expandstr(env, a1r);
137- a2e = expandstr(env, a2r);
138- a3e = expandstr(env, a3r);
139+ a1e = expandstr(ctx, a1r);
140+ a2e = expandstr(ctx, a2r);
141+ a3e = expandstr(ctx, a3r);
142 free(a1r);
143 free(a2r);
144 free(a3r);
145@@ -411,26 +397,26 @@ funcref(struct Env *env, const char *s, size_t n)
146 }
147
148 static char *
149-expandref(struct Env *env, const char *s, size_t n)
150+expandref(struct EvalCtx *ctx, const char *s, size_t n)
151 {
152 size_t colon, eq;
153 char *val, *unsup;
154
155 if (isplainvar(s, n))
156- return expandvarref(env, s, n);
157+ return expandvarref(ctx, s, n);
158 if (issubstref(s, n, &colon, &eq))
159- return expandsubstref(env, s, colon, eq, n);
160- val = funcref(env, s, n);
161+ return expandsubstref(ctx, s, colon, eq, n);
162+ val = funcref(ctx, s, n);
163 if (val)
164 return val;
165 unsup = xstrndup(s - 2, n + 3);
166- evalerr("variable reference or function", unsup);
167+ evalerr(ctx, "variable reference or function", unsup);
168 free(unsup);
169 return xstrndup(s - 2, n + 3);
170 }
171
172 char *
173-expandstr(struct Env *env, const char *s)
174+expandstr(struct EvalCtx *ctx, const char *s)
175 {
176 size_t i, j, n;
177 char close;
178@@ -458,7 +444,7 @@ expandstr(struct Env *env, const char *s)
179 continue;
180 }
181 /* some single char variable like $x */
182- val = expandvarref(env, s + i + 1, 1);
183+ val = expandvarref(ctx, s + i + 1, 1);
184 bufappend(&out, val);
185 free(val);
186 i++;
187@@ -470,7 +456,7 @@ expandstr(struct Env *env, const char *s)
188 bufappendn(&out, s + i, n - i);
189 break;
190 }
191- val = expandref(env, s + i + 2, j - i - 3);
192+ val = expandref(ctx, s + i + 2, j - i - 3);
193 bufappend(&out, val);
194 free(val);
195 i = j - 1;
+30,
-26
1@@ -54,17 +54,19 @@ copyenv(struct Env *dst, const struct Env *src)
2 }
3
4 void
5-evalassign(struct Env *env, const struct AssignNode *in)
6+evalassign(struct EvalCtx *ctx, const struct AssignNode *in)
7 {
8+ struct Env *env;
9 struct Var *v;
10 char *rhs, *joined;
11
12+ env = ctx->env;
13 switch (in->op) {
14 case ASSIGN_EQ:
15 envsetvar(env, in->lhs, xstrdup(in->rhs), 0);
16 break;
17 case ASSIGN_COLON_EQ:
18- envsetvar(env, in->lhs, expandstr(env, in->rhs), 1);
19+ envsetvar(env, in->lhs, expandstr(ctx, in->rhs), 1);
20 break;
21 case ASSIGN_QMARK_EQ:
22 if (!findvar(env, in->lhs))
23@@ -76,28 +78,28 @@ evalassign(struct Env *env, const struct AssignNode *in)
24 envsetvar(env, in->lhs, xstrdup(in->rhs), 0);
25 break;
26 }
27- rhs = v->simple ? expandstr(env, in->rhs) : xstrdup(in->rhs);
28+ rhs = v->simple ? expandstr(ctx, in->rhs) : xstrdup(in->rhs);
29 joined = cat3(v->val, " ", rhs);
30 free(rhs);
31 free(v->val);
32 v->val = joined;
33 break;
34 case ASSIGN_BANG_EQ:
35- envsetvar(env, in->lhs, expandstr(env, in->rhs), 1);
36+ envsetvar(env, in->lhs, expandstr(ctx, in->rhs), 1);
37 break;
38 }
39 }
40
41 static int
42-testcond(struct Env *env, const struct CondNode *cond)
43+testcond(struct EvalCtx *ctx, const struct CondNode *cond)
44 {
45 char *a, *b, *name;
46 struct Var *v;
47 int ok;
48
49 if (cond->kind == COND_IFDEF || cond->kind == COND_IFNDEF) {
50- name = expandstr(env, cond->arg1);
51- v = findvar(env, name);
52+ name = expandstr(ctx, cond->arg1);
53+ v = findvar(ctx->env, name);
54 ok = v != 0;
55 free(name);
56 if (cond->kind == COND_IFNDEF)
57@@ -105,8 +107,8 @@ testcond(struct Env *env, const struct CondNode *cond)
58 return ok;
59 }
60
61- a = cond->arg1 ? expandstr(env, cond->arg1) : xstrdup("");
62- b = cond->arg2 ? expandstr(env, cond->arg2) : xstrdup("");
63+ a = cond->arg1 ? expandstr(ctx, cond->arg1) : xstrdup("");
64+ b = cond->arg2 ? expandstr(ctx, cond->arg2) : xstrdup("");
65 ok = strcmp(a, b) == 0;
66 free(a);
67 free(b);
68@@ -116,7 +118,7 @@ testcond(struct Env *env, const struct CondNode *cond)
69 }
70
71 static void
72-copywords(struct StrList *out, const struct StrList *in, struct Env *env)
73+copywords(struct StrList *out, const struct StrList *in, struct EvalCtx *ctx)
74 {
75 size_t i;
76
77@@ -124,7 +126,7 @@ copywords(struct StrList *out, const struct StrList *in, struct Env *env)
78 for (i = 0; i < in->n; i++) {
79 char *s;
80
81- s = expandstr(env, in->v[i]);
82+ s = expandstr(ctx, in->v[i]);
83 splitwords(out, s, strlen(s));
84 free(s);
85 }
86@@ -143,7 +145,7 @@ copyrecipes(struct RecipeList *out, const struct RecipeList *in)
87 }
88
89 static int
90-evalnodes(const struct NodeList *in, struct NodeList *out, struct Env *env)
91+evalnodes(const struct NodeList *in, struct NodeList *out, struct EvalCtx *ctx)
92 {
93 size_t i;
94
95@@ -164,21 +166,21 @@ evalnodes(const struct NodeList *in, struct NodeList *out, struct Env *env)
96 case NODE_RAW: {
97 char *exp;
98
99- exp = expandstr(env, src->data.raw.text);
100+ exp = expandstr(ctx, src->data.raw.text);
101 free(exp);
102 node.kind = NODE_BLANK;
103 break;
104 }
105 case NODE_INCLUDE:
106 node.data.include.optional = src->data.include.optional;
107- node.data.include.path = expandstr(env, src->data.include.path);
108+ node.data.include.path = expandstr(ctx, src->data.include.path);
109 break;
110 case NODE_COND:
111- if (testcond(env, &src->data.cond)) {
112- if (evalnodes(&src->data.cond.thenpart, out, env) < 0)
113+ if (testcond(ctx, &src->data.cond)) {
114+ if (evalnodes(&src->data.cond.thenpart, out, ctx) < 0)
115 return -1;
116 } else {
117- if (evalnodes(&src->data.cond.elsepart, out, env) < 0)
118+ if (evalnodes(&src->data.cond.elsepart, out, ctx) < 0)
119 return -1;
120 }
121 continue;
122@@ -187,18 +189,18 @@ evalnodes(const struct NodeList *in, struct NodeList *out, struct Env *env)
123 node.data.assign.op = src->data.assign.op;
124 node.data.assign.tspec = src->data.assign.tspec;
125 if (src->data.assign.op == ASSIGN_COLON_EQ || src->data.assign.op == ASSIGN_BANG_EQ)
126- node.data.assign.rhs = expandstr(env, src->data.assign.rhs);
127+ node.data.assign.rhs = expandstr(ctx, src->data.assign.rhs);
128 else
129 node.data.assign.rhs = xstrdup(src->data.assign.rhs);
130- copywords(&node.data.assign.targets, &src->data.assign.targets, env);
131+ copywords(&node.data.assign.targets, &src->data.assign.targets, ctx);
132 if (!src->data.assign.tspec)
133- evalassign(env, &src->data.assign);
134+ evalassign(ctx, &src->data.assign);
135 break;
136 case NODE_RULE:
137 node.data.rule.dcolon = src->data.rule.dcolon;
138- copywords(&node.data.rule.targets, &src->data.rule.targets, env);
139- copywords(&node.data.rule.prereqs, &src->data.rule.prereqs, env);
140- copywords(&node.data.rule.order_only, &src->data.rule.order_only, env);
141+ copywords(&node.data.rule.targets, &src->data.rule.targets, ctx);
142+ copywords(&node.data.rule.prereqs, &src->data.rule.prereqs, ctx);
143+ copywords(&node.data.rule.order_only, &src->data.rule.order_only, ctx);
144 copyrecipes(&node.data.rule.recipes, &src->data.rule.recipes);
145 break;
146 }
147@@ -211,15 +213,17 @@ int
148 eval(const struct Ast *ast, struct Ast *out)
149 {
150 struct Env env;
151+ struct EvalCtx ctx;
152 int rc;
153
154 memset(out, 0, sizeof(*out));
155 memset(&env, 0, sizeof(env));
156+ memset(&ctx, 0, sizeof(ctx));
157 seedenv(&env);
158- resetevalerrs();
159- rc = evalnodes((const struct NodeList *)ast, (struct NodeList *)out, &env);
160+ ctx.env = &env;
161+ rc = evalnodes((const struct NodeList *)ast, (struct NodeList *)out, &ctx);
162 freeenv(&env);
163- if (rc == 0 && getevalerrs())
164+ if (rc == 0 && ctx.errors)
165 return -1;
166 return rc;
167 }
+2,
-2
1@@ -157,7 +157,7 @@ patruleviable(const struct PatRule *rule, const struct Graph *graph, const char
2 }
3
4 int
5-instpatrule(const struct PatRules *rules, const struct Graph *graph, struct Target *t, struct Env *env)
6+instpatrule(const struct PatRules *rules, const struct Graph *graph, struct Target *t, struct EvalCtx *ctx)
7 {
8 size_t i, j;
9
10@@ -195,7 +195,7 @@ instpatrule(const struct PatRules *rules, const struct Graph *graph, struct Targ
11 char *s, *vars, *exp;
12
13 s = applystem(rules->v[i].recipes.v[j], stem);
14- vars = expandstr(env, s);
15+ vars = expandstr(ctx, s);
16 exp = expandstem(vars, stem);
17 free(vars);
18 free(s);
+1,
-1
1@@ -18,7 +18,7 @@ struct PatRules {
2 int ispat(const char *s);
3 int patmatches(const char *pat, const char *name);
4 void collectpat(struct PatRules *rules, const struct RuleNode *rule);
5-int instpatrule(const struct PatRules *rules, const struct Graph *graph, struct Target *t, struct Env *env);
6+int instpatrule(const struct PatRules *rules, const struct Graph *graph, struct Target *t, struct EvalCtx *ctx);
7 void freepatrule(struct PatRules *rules);
8
9 #endif
+26,
-14
1@@ -104,14 +104,14 @@ targetmatches(const char *pat, const char *name)
2 }
3
4 static void
5-addexprecipes(struct RecipeList *dest, const struct RecipeList *src, struct Env *env)
6+addexprecipes(struct RecipeList *dest, const struct RecipeList *src, struct EvalCtx *ctx)
7 {
8 size_t i;
9
10 for (i = 0; i < src->n; i++) {
11 char *exp;
12
13- exp = expandstr(env, src->v[i]);
14+ exp = expandstr(ctx, src->v[i]);
15 if (!exp[0]) {
16 free(exp);
17 continue;
18@@ -127,7 +127,7 @@ addexprecipes(struct RecipeList *dest, const struct RecipeList *src, struct Env
19 * binary : LDFLAGS += -static
20 */
21 static void
22-applytassigns(struct GraphState *gs, struct Env *env, const char *name)
23+applytassigns(struct GraphState *gs, struct EvalCtx *ctx, const char *name)
24 {
25 size_t i, j;
26
27@@ -141,16 +141,16 @@ applytassigns(struct GraphState *gs, struct Env *env, const char *name)
28 in.lhs = gs->tas[i].lhs;
29 in.rhs = gs->tas[i].rhs;
30 in.op = gs->tas[i].op;
31- evalassign(env, &in);
32+ evalassign(ctx, &in);
33 }
34 }
35 }
36
37 static void
38-targetenv(struct GraphState *gs, struct Env *env, const char *name)
39+targetenv(struct GraphState *gs, struct EvalCtx *ctx, const char *name)
40 {
41- copyenv(env, &gs->env);
42- applytassigns(gs, env, name);
43+ copyenv(ctx->env, &gs->env);
44+ applytassigns(gs, ctx, name);
45 }
46
47 /* add an explicit target rule to the graph, and add all
48@@ -162,6 +162,10 @@ addrule(struct GraphState *gs, const char *name, const struct RuleNode *rule)
49 size_t i;
50 struct Target *t;
51 struct Env env;
52+ struct EvalCtx ctx;
53+
54+ memset(&ctx, 0, sizeof(ctx));
55+ ctx.env = &env;
56
57 t = findtarget(gs->graph, name);
58 if (!t) {
59@@ -178,8 +182,8 @@ addrule(struct GraphState *gs, const char *name, const struct RuleNode *rule)
60 t->dcolon = rule->dcolon;
61 addwords(&t->prereqs, &rule->prereqs);
62 addwords(&t->order_only, &rule->order_only);
63- targetenv(gs, &env, name);
64- addexprecipes(&t->recipes, &rule->recipes, &env);
65+ targetenv(gs, &ctx, name);
66+ addexprecipes(&t->recipes, &rule->recipes, &ctx);
67 freeenv(&env);
68
69 for (i = 0; i < rule->prereqs.n; i++) {
70@@ -216,11 +220,14 @@ buildgraph(const struct Ast *ast, struct Graph *graph)
71 {
72 size_t i, j, start;
73 struct GraphState gs;
74+ struct EvalCtx ctx;
75
76 memset(graph, 0, sizeof(*graph));
77 memset(&gs, 0, sizeof(gs));
78+ memset(&ctx, 0, sizeof(ctx));
79 gs.graph = graph;
80 seedenv(&gs.env);
81+ ctx.env = &gs.env;
82 imprules(&gs.sufs);
83
84 /* get the state, env vars in gs.env, target-specific var in gs.tas,
85@@ -230,7 +237,7 @@ buildgraph(const struct Ast *ast, struct Graph *graph)
86 if (ast->v[i].data.assign.tspec)
87 addtassign(&gs, &ast->v[i].data.assign);
88 else
89- evalassign(&gs.env, &ast->v[i].data.assign);
90+ evalassign(&ctx, &ast->v[i].data.assign);
91 } else if (ast->v[i].kind == NODE_RULE) {
92 if (issufrule(&ast->v[i].data.rule)) {
93 gs.saw_suffixes = 1;
94@@ -273,14 +280,19 @@ buildgraph(const struct Ast *ast, struct Graph *graph)
95 if (t->recipes.n == 0) {
96 int matched;
97 struct Env env;
98+ struct EvalCtx targetctx;
99
100- targetenv(&gs, &env, t->name);
101- instpatrule(&gs.patterns, graph, t, &env);
102+ memset(&targetctx, 0, sizeof(targetctx));
103+ targetctx.env = &env;
104+ targetenv(&gs, &targetctx, t->name);
105+ instpatrule(&gs.patterns, graph, t, &targetctx);
106 matched = t->recipes.n > 0;
107 if (!matched) {
108- instsufrule(&gs.sufs, graph, t, &env);
109+ instsufrule(&gs.sufs, graph, t, &targetctx);
110 }
111 freeenv(&env);
112+ if (targetctx.errors)
113+ ctx.errors += targetctx.errors;
114 }
115 nprereqs = t->prereqs.n;
116 for (j = 0; j < nprereqs; j++) {
117@@ -311,7 +323,7 @@ buildgraph(const struct Ast *ast, struct Graph *graph)
118 free(gs.rules);
119 freeenv(&gs.env);
120
121- return 0;
122+ return ctx.errors ? -1 : 0;
123 }
124
125 void
+7,
-4
1@@ -14,6 +14,11 @@ struct Env {
2 size_t n;
3 };
4
5+struct EvalCtx {
6+ struct Env *env;
7+ int errors;
8+};
9+
10 void *xmalloc(size_t n);
11 void *xrealloc(void *p, size_t n);
12 char *xstrndup(const char *s, size_t n);
13@@ -30,13 +35,11 @@ struct Target *findtarget(struct Graph *graph, const char *name);
14 const struct Target *findctarget(const struct Graph *graph, const char *name);
15
16 struct Var *findvar(struct Env *env, const char *name);
17-char *expandstr(struct Env *env, const char *s);
18-void resetevalerrs(void);
19-int getevalerrs(void);
20+char *expandstr(struct EvalCtx *ctx, const char *s);
21 void seedenv(struct Env *env);
22 void freeenv(struct Env *env);
23 void copyenv(struct Env *dst, const struct Env *src);
24-void evalassign(struct Env *env, const struct AssignNode *in);
25+void evalassign(struct EvalCtx *ctx, const struct AssignNode *in);
26
27 char *fnwildcard(const char *patterns);
28 char *fnshell(const char *cmd);
+3,
-3
1@@ -406,7 +406,7 @@ int
2 instsufrule(const struct SufRules *rules,
3 const struct Graph *graph,
4 struct Target *t,
5- struct Env *env)
6+ struct EvalCtx *ctx)
7 {
8 size_t i, k;
9
10@@ -436,7 +436,7 @@ instsufrule(const struct SufRules *rules,
11 for (k = 0; k < rules->sufs[r].recipes.n; k++) {
12 char *vars, *exp;
13
14- vars = expandstr(env, rules->sufs[r].recipes.v[k]);
15+ vars = expandstr(ctx, rules->sufs[r].recipes.v[k]);
16 exp = expandauto(vars, t, stem);
17 free(vars);
18 if (!exp[0]) {
19@@ -474,7 +474,7 @@ instsufrule(const struct SufRules *rules,
20 for (k = 0; k < rules->singlesuf[j].recipes.n; k++) {
21 char *vars, *exp;
22
23- vars = expandstr(env, rules->singlesuf[j].recipes.v[k]);
24+ vars = expandstr(ctx, rules->singlesuf[j].recipes.v[k]);
25 exp = expandauto(vars, t, t->name);
26 free(vars);
27 if (!exp[0]) {
+1,
-1
1@@ -39,7 +39,7 @@ int collectsufrule(struct SufRules *rules, const struct RuleNode *rule);
2 int instsufrule(const struct SufRules *rules,
3 const struct Graph *graph,
4 struct Target *t,
5- struct Env *env);
6+ struct EvalCtx *ctx);
7 int issufrule(const struct RuleNode *rule);
8 void addsufs(struct SuffixList *list, const struct StrList *sufs);
9 void clearsufs(struct SuffixList *list);