From 383c904c0f2667e8afabc76568a5e8376e617696 Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Thu, 25 Mar 2021 21:21:07 -0600 Subject: allow GNUish macro assignments (`?=`, `+=`) --- yapymake/makefile/__init__.py | 27 +++++++++++++++++++++++++++ yapymake/makefile/token.py | 12 ++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/yapymake/makefile/__init__.py b/yapymake/makefile/__init__.py index 52e2262..b5f96f1 100644 --- a/yapymake/makefile/__init__.py +++ b/yapymake/makefile/__init__.py @@ -196,23 +196,50 @@ class Makefile: comment_split = value.split_once('#') if comment_split is not None: value, _ = comment_split + # GNU make allows for weird assignment operators + expand_value = False + skip_if_defined = False + append = False + if name_tokens.endswith('::'): + self._warn('warning: non-POSIXful `::=` in macro') + name_tokens.rstrip(':') + expand_value = True + elif name_tokens.endswith(':'): + self._warn('warning: non-POSIXful `:=` in macro') + name_tokens.rstrip(':') + expand_value = True + elif name_tokens.endswith('?'): + self._warn('warning: non-POSIXful `?=` in macro') + name_tokens.rstrip('?') + skip_if_defined = True + elif name_tokens.endswith('+'): + self._warn('warning: non-POSIXful `+=` in macro') + name_tokens.rstrip('+') + append = True # > Any characters immediately before or after the shall be ignored. name_tokens.rstrip() value.lstrip() # > Macros in the string before the in a macro definition shall be evaluated when the # > macro assignment is made. name = self.expand_macros(name_tokens) + if expand_value: + value = TokenString.text(self.expand_macros(value)) # > Macros defined in the makefile(s) shall override macro definitions that occur before them in the # > makefile(s) and macro definitions from source 4. If the -e option is not specified, macros defined # > in the makefile(s) shall override macro definitions from source 3. Macros defined in the makefile(s) # > shall not override macro definitions from source 1 or source 2. if name in self._macros: + if skip_if_defined: + continue source, _ = self._macros[name] inviolate_sources = [MacroSource.CommandLine, MacroSource.MAKEFLAGS] if self.args.environment_overrides: inviolate_sources.append(MacroSource.Environment) if any(x is source for x in inviolate_sources): continue + if append and name in self._macros: + _, old_value = self._macros[name] + value = old_value.concat(TokenString.text(' ')).concat(value) self._macros[name] = (MacroSource.File, value) def expand_macros(self, text: TokenString, current_target: Optional['Target'] = None) -> str: diff --git a/yapymake/makefile/token.py b/yapymake/makefile/token.py index 57ad4f9..d9ed5ac 100644 --- a/yapymake/makefile/token.py +++ b/yapymake/makefile/token.py @@ -54,12 +54,20 @@ class TokenString(Iterable['Token']): first_token.text = first_token.text.lstrip() self._tokens[0] = first_token - def rstrip(self) -> None: + def rstrip(self, chars: Optional[str] = None) -> None: last_token = self._tokens[-1] if isinstance(last_token, TextToken): - last_token.text = last_token.text.rstrip() + last_token.text = last_token.text.rstrip(chars) self._tokens[-1] = last_token + def endswith(self, pattern: str) -> bool: + last_token = self._tokens[-1] + return isinstance(last_token, TextToken) and last_token.text.endswith(pattern) + + def concat(self, other: 'TokenString') -> 'TokenString': + return TokenString([*self._tokens, *other._tokens]) + + @dataclass() class Token: pass -- cgit v1.2.3