commit edddaa3

shrub  ·  2026-04-16 15:27:53 +0000 UTC
parent 30eeafb
handle double colon
4 files changed,  +34, -22
+1, -0
1@@ -195,6 +195,7 @@ evalnodes(const struct NodeList *in, struct NodeList *out, struct Env *env)
2 				evalassign(env, &src->data.assign);
3 			break;
4 		case NODE_RULE:
5+			node.data.rule.dcolon = src->data.rule.dcolon;
6 			copywords(&node.data.rule.targets, &src->data.rule.targets, env);
7 			copywords(&node.data.rule.prereqs, &src->data.rule.prereqs, env);
8 			copywords(&node.data.rule.order_only, &src->data.rule.order_only, env);
+19, -11
 1@@ -3,6 +3,7 @@
 2 #include "posix.h"
 3 #include "gnu/pattern.h"
 4 
 5+#include <stdio.h>
 6 #include <stdlib.h>
 7 #include <string.h>
 8 
 9@@ -168,7 +169,13 @@ addrule(struct GraphState *gs, const char *name, const struct RuleNode *rule)
10 		t = &gs->graph->v[gs->graph->n++];
11 		memset(t, 0, sizeof(*t));
12 		t->name = xstrdup(name);
13+		t->dcolon = rule->dcolon;
14+	} else if (t->defined && t->dcolon != rule->dcolon) {
15+		fprintf(stderr, "target file `%s' has both : and :: entries, i can't handle that!\n", name);
16+		exit(1);
17 	}
18+	t->defined = 1;
19+	t->dcolon = rule->dcolon;
20 	addwords(&t->prereqs, &rule->prereqs);
21 	addwords(&t->order_only, &rule->order_only);
22 	targetenv(gs, &env, name);
23@@ -276,18 +283,19 @@ buildgraph(const struct Ast *ast, struct Graph *graph)
24 				freeenv(&env);
25 			}
26 			nprereqs = t->prereqs.n;
27-			for (j = 0; j < nprereqs; j++) {
28-				const char *prereq = t->prereqs.v[j];
29-
30-				if (!findtarget(graph, prereq)) {
31-					struct Target *nt;
32-
33-					graph->v = xrealloc(graph->v, (graph->n + 1) * sizeof(graph->v[0]));
34-					nt = &graph->v[graph->n++];
35-					memset(nt, 0, sizeof(*nt));
36-					nt->name = xstrdup(prereq);
37+				for (j = 0; j < nprereqs; j++) {
38+					const char *prereq = t->prereqs.v[j];
39+
40+					if (!findtarget(graph, prereq)) {
41+						struct Target *nt;
42+
43+						graph->v = xrealloc(graph->v, (graph->n + 1) * sizeof(graph->v[0]));
44+						nt = &graph->v[graph->n++];
45+						memset(nt, 0, sizeof(*nt));
46+						nt->name = xstrdup(prereq);
47+						t = &graph->v[i];
48+					}
49 				}
50-			}
51 		}
52 		start = current_n;
53 	}
+11, -11
 1@@ -599,10 +599,11 @@ parseassign(const struct PreLine *line, const char *s, size_t n, size_t base, st
 2 }
 3 
 4 static struct Node
 5-parserule(const struct PreLine *line, const char *s, size_t n, size_t colon)
 6+parserule(const struct PreLine *line, const char *s, size_t n, size_t colon, int dcolon)
 7 {
 8 	struct Node state;
 9 	const char *rhs;
10+	size_t off;
11 	size_t rhsn, split, semi;
12 	char *recipe;
13 
14@@ -610,11 +611,13 @@ parserule(const struct PreLine *line, const char *s, size_t n, size_t colon)
15 	state.kind = NODE_RULE;
16 	state.loc.line0 = line->line0;
17 	state.loc.line1 = line->line1;
18+	state.data.rule.dcolon = dcolon;
19 
20 	splitwords(&state.data.rule.targets, s, colon);
21 
22-	rhs = s + colon + 1;
23-	rhsn = n - colon - 1;
24+	off = dcolon ? 2 : 1;
25+	rhs = s + colon + off;
26+	rhsn = n - colon - off;
27 	semi = (size_t)findtop(rhs, rhsn, ';');
28 	if (semi != (size_t)-1) {
29 		recipe = trimdup(rhs + semi + 1, rhsn - semi - 1);
30@@ -683,6 +686,7 @@ parseline(const struct PreLine *line)
31 	struct Node state;
32 	struct AssignScan as;
33 	char *trim;
34+	int dcolon;
35 	size_t n;
36 	ptrdiff_t colon;
37 
38@@ -731,10 +735,12 @@ parseline(const struct PreLine *line)
39 	}
40 
41 	colon = findtop(trim, n, ':');
42+	dcolon = colon >= 0 && (size_t)colon + 1 < n && trim[colon + 1] == ':';
43 	as = findassign(trim, n, 0);
44 	if (colon >= 0 && as.ok && (size_t)colon < as.pos) {
45 		/* some inline rule like 'all: ; @echo hi' */
46-		ptrdiff_t semi = findtop(trim + colon + 1, as.pos - (size_t)colon - 1, ';');
47+		size_t off = dcolon ? 2 : 1;
48+		ptrdiff_t semi = findtop(trim + colon + off, as.pos - (size_t)colon - off, ';');
49 		if (semi < 0) {
50 			state = parseassign(line, trim, n, (size_t)colon + 1, as, 1, (size_t)colon);
51 			free(trim);
52@@ -746,14 +752,8 @@ parseline(const struct PreLine *line)
53 		free(trim);
54 		return state;
55 	}
56-	if (colon >= 0 && (size_t)colon + 1 < n && trim[colon + 1] == ':') {
57-		parseerr(line, "double-colon rule", trim);
58-		state = blanknode(line);
59-		free(trim);
60-		return state;
61-	}
62 	if (colon >= 0) {
63-		state = parserule(line, trim, n, (size_t)colon);
64+		state = parserule(line, trim, n, (size_t)colon, dcolon);
65 		free(trim);
66 		return state;
67 	}
+3, -0
 1@@ -79,6 +79,7 @@ struct RuleNode {
 2 	struct StrList prereqs;
 3 	struct StrList order_only;
 4 	struct RecipeList recipes;
 5+	int dcolon;
 6 };
 7 
 8 struct IncludeNode {
 9@@ -128,6 +129,8 @@ struct Target {
10 	struct StrList prereqs;
11 	struct StrList order_only;
12 	struct RecipeList recipes;
13+	int dcolon;
14+	int defined;
15 };
16 
17 struct Graph {