WIP: fix export/override prefix and ?= first-wins in make variable parser
All checks were successful
check / check (push) Successful in 14s
All checks were successful
check / check (push) Successful in 14s
Two defects in the lint-once resolver's make variable handling: - The assignment pattern anchored at the start of the name, so `export FMT := script/fmt-check` was never collected and `@$(FMT)` went unresolved. An optional `export `/`override ` prefix is now allowed. - `?=` assigns only when the name is unset, so the first assignment wins. The parser called .set() unconditionally, letting a later `FMT ?= script/build` overwrite an earlier `FMT := script/fmt-check` and resolve to a command make never runs. Tests pinning both to follow.
This commit is contained in:
@@ -159,7 +159,7 @@ const MAKE_CONDITIONAL = /^\s*(?:ifeq|ifneq|ifdef|ifndef|else|endif)\b/;
|
|||||||
// not happen. An unresolved reference is left standing verbatim instead, which
|
// not happen. An unresolved reference is left standing verbatim instead, which
|
||||||
// is the same dead end as any other unfollowed edge rather than a wrong answer.
|
// is the same dead end as any other unfollowed edge rather than a wrong answer.
|
||||||
const MAKE_ASSIGNMENT = new RegExp(
|
const MAKE_ASSIGNMENT = new RegExp(
|
||||||
`^([A-Za-z_][A-Za-z0-9_]*)\\s*(?::=|\\?=|=)\\s*(.*)$`,
|
`^(?:(?:export|override)\\s+)*([A-Za-z_][A-Za-z0-9_]*)\\s*(:=|\\?=|=)\\s*(.*)$`,
|
||||||
);
|
);
|
||||||
const MAKE_VARIABLE_REFERENCE = /\$[({]([A-Za-z_][A-Za-z0-9_]*)[)}]/g;
|
const MAKE_VARIABLE_REFERENCE = /\$[({]([A-Za-z_][A-Za-z0-9_]*)[)}]/g;
|
||||||
|
|
||||||
@@ -181,8 +181,13 @@ const makeVariables = (text: string): Map<string, string> => {
|
|||||||
if (inDefine || raw.startsWith("\t")) continue;
|
if (inDefine || raw.startsWith("\t")) continue;
|
||||||
const assignment = MAKE_ASSIGNMENT.exec(raw.replace(/#.*$/, "").trim());
|
const assignment = MAKE_ASSIGNMENT.exec(raw.replace(/#.*$/, "").trim());
|
||||||
if (assignment === null) continue;
|
if (assignment === null) continue;
|
||||||
const [, name, value] = assignment;
|
const [, name, operator, value] = assignment;
|
||||||
if (name === undefined || value === undefined) continue;
|
if (name === undefined || operator === undefined) continue;
|
||||||
|
if (value === undefined) continue;
|
||||||
|
// `?=` assigns only when the name has no value yet, so the first one
|
||||||
|
// wins where `:=` and `=` let the last one win. Overwriting here would
|
||||||
|
// resolve the reference to a string make never uses.
|
||||||
|
if (operator === "?=" && variables.has(name)) continue;
|
||||||
// A value that is itself a reference is the recursive case, and is not
|
// A value that is itself a reference is the recursive case, and is not
|
||||||
// resolved. Recording it would hand the substitution below a string it
|
// resolved. Recording it would hand the substitution below a string it
|
||||||
// cannot finish expanding.
|
// cannot finish expanding.
|
||||||
|
|||||||
Reference in New Issue
Block a user