commit 59a6db8

shrub  ·  2026-04-08 17:31:17 +0000 UTC
parent 757e0ed
feat: handle  $< $^ $+ 127
2 files changed,  +61, -50
+0, -35
 1@@ -1,35 +0,0 @@
 2-build all: phony shin
 3-
 4-rule r1
 5-  command = clang -static -o $out $in 
 6-
 7-build shin: r1 cli/main.o src/parse.o src/eval.o src/graph.o backends/ninja.o src/util.o src/functions.o
 8-
 9-rule r2
10-  command = clang -O2 -Wall -Wextra -pedantic -Isrc -Ibackends -c -o $out $in
11-
12-build cli/main.o: r2 cli/main.c
13-
14-build src/parse.o: r2 src/parse.c
15-
16-build src/eval.o: r2 src/eval.c
17-
18-build src/graph.o: r2 src/graph.c
19-
20-build backends/ninja.o: r2 backends/ninja.c
21-
22-build src/util.o: r2 src/util.c
23-
24-build src/functions.o: r2 src/functions.c
25-
26-rule r3
27-  command = clang-format -i cli/main.c src/parse.c src/eval.c src/graph.c backends/ninja.c src/util.c src/functions.c src/shinobi.h src/internal.h backends/ninja.h
28-
29-build fmt: r3
30-
31-rule r4
32-  command = rm -f shin cli/main.o src/parse.o src/eval.o src/graph.o backends/ninja.o src/util.o src/functions.o
33-
34-build clean: r4
35-
36-default all
+61, -15
  1@@ -148,7 +148,32 @@ applystem(const char *s, const char *stem)
  2 }
  3 
  4 static char *
  5-expandauto(const char *s, const struct Target *t)
  6+joinprereqs(const struct Target *t)
  7+{
  8+	size_t k;
  9+	char *joined, *next;
 10+
 11+	joined = xstrdup("");
 12+	for (k = 0; k < t->prereqs.n; k++) {
 13+		next = joined[0] ? cat3(joined, " ", t->prereqs.v[k]) : xstrdup(t->prereqs.v[k]);
 14+		free(joined);
 15+		joined = next;
 16+	}
 17+	return joined;
 18+}
 19+
 20+/*
 21+ * expand gnu make automatic variables 
 22+ *   $@  target
 23+ *   $<  first prereq
 24+ *   $^  all prereqs 
 25+ *   $+  all prereqs
 26+ *   $?  all prereqs, let ninja decide 
 27+ *   $*  stem 
 28+ *   $$  literal $
 29+ */
 30+static char *
 31+expandauto(const char *s, const struct Target *t, const char *stem)
 32 {
 33 	size_t i, n, cap, len;
 34 	char *out;
 35@@ -159,36 +184,46 @@ expandauto(const char *s, const struct Target *t)
 36 	out = xmalloc(cap);
 37 	for (i = 0; i < n; i++) {
 38 		if (s[i] == '$' && i + 1 < n) {
 39-			char *val = 0;
 40-			int mustfree = 0;
 41+			const char *val;
 42+			int mustfree;
 43 
 44+			val = 0;
 45+			mustfree = 0;
 46+
 47+			if (s[i + 1] == '$') {
 48+				if (len + 3 > cap) {
 49+					cap = len + 3 + (n - i);
 50+					out = xrealloc(out, cap);
 51+				}
 52+				out[len++] = '$';
 53+				out[len++] = '$';
 54+				i++;
 55+				continue;
 56+			}
 57 			if (s[i + 1] == '@') {
 58 				val = t->name;
 59 			} else if (s[i + 1] == '<') {
 60 				if (t->prereqs.n > 0)
 61 					val = t->prereqs.v[0];
 62-			} else if (s[i + 1] == '^') {
 63-				size_t k;
 64-				char *joined = xstrdup("");
 65-				for (k = 0; k < t->prereqs.n; k++) {
 66-					char *next = joined[0] ? cat3(joined, " ", t->prereqs.v[k]) : xstrdup(t->prereqs.v[k]);
 67-					free(joined);
 68-					joined = next;
 69-				}
 70-				val = joined;
 71+				else
 72+					val = "";
 73+			} else if (s[i + 1] == '^' || s[i + 1] == '+' || s[i + 1] == '?') {
 74+				val = joinprereqs(t);
 75 				mustfree = 1;
 76+			} else if (s[i + 1] == '*') {
 77+				val = stem ? stem : "";
 78 			}
 79 
 80 			if (val) {
 81 				size_t vlen = strlen(val);
 82 				if (len + vlen + 1 > cap) {
 83-					cap = len + vlen + n - i + 1;
 84+					cap = len + vlen + (n - i) + 1;
 85 					out = xrealloc(out, cap);
 86 				}
 87 				memcpy(out + len, val, vlen);
 88 				len += vlen;
 89 				if (mustfree)
 90-					free(val);
 91+					free((char *)val);
 92 				i++;
 93 				continue;
 94 			}
 95@@ -220,7 +255,7 @@ instantiate(struct Target *t, struct Pattern *p, const char *stem)
 96 	}
 97 	for (i = 0; i < p->recipes.n; i++) {
 98 		char *s = applystem(p->recipes.v[i], stem);
 99-		char *exp = expandauto(s, t);
100+		char *exp = expandauto(s, t, stem);
101 		free(s);
102 		t->recipes.v = xrealloc(t->recipes.v, (t->recipes.n + 1) * sizeof(t->recipes.v[0]));
103 		t->recipes.v[t->recipes.n++] = exp;
104@@ -269,6 +304,17 @@ buildgraph(const struct Ast *ast, struct Graph *graph)
105 		start = current_n;
106 	}
107 
108+	for (i = 0; i < graph->n; i++) {
109+		struct Target *t = &graph->v[i];
110+		size_t k;
111+
112+		for (k = 0; k < t->recipes.n; k++) {
113+			char *exp = expandauto(t->recipes.v[k], t, 0);
114+			free(t->recipes.v[k]);
115+			t->recipes.v[k] = exp;
116+		}
117+	}
118+
119 	for (i = 0; i < gs.npats; i++) {
120 		free(gs.pats[i].target);
121 		freestrs(&gs.pats[i].prereqs);