18bcb0991SDimitry Andric //===- CodeExpander.cpp - Expand variables in a string --------------------===//
28bcb0991SDimitry Andric //
38bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
48bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
58bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68bcb0991SDimitry Andric //
78bcb0991SDimitry Andric //===----------------------------------------------------------------------===//
88bcb0991SDimitry Andric //
98bcb0991SDimitry Andric /// \file Expand the variables in a string.
108bcb0991SDimitry Andric //
118bcb0991SDimitry Andric //===----------------------------------------------------------------------===//
128bcb0991SDimitry Andric 
138bcb0991SDimitry Andric #include "CodeExpander.h"
148bcb0991SDimitry Andric #include "CodeExpansions.h"
158bcb0991SDimitry Andric #include "llvm/Support/raw_ostream.h"
168bcb0991SDimitry Andric #include "llvm/TableGen/Error.h"
178bcb0991SDimitry Andric 
188bcb0991SDimitry Andric using namespace llvm;
198bcb0991SDimitry Andric 
208bcb0991SDimitry Andric void CodeExpander::emit(raw_ostream &OS) const {
218bcb0991SDimitry Andric   StringRef Current = Code;
228bcb0991SDimitry Andric 
238bcb0991SDimitry Andric   while (!Current.empty()) {
248bcb0991SDimitry Andric     size_t Pos = Current.find_first_of("$\n\\");
258bcb0991SDimitry Andric     if (Pos == StringRef::npos) {
268bcb0991SDimitry Andric       OS << Current;
278bcb0991SDimitry Andric       Current = "";
288bcb0991SDimitry Andric       continue;
298bcb0991SDimitry Andric     }
308bcb0991SDimitry Andric 
318bcb0991SDimitry Andric     OS << Current.substr(0, Pos);
328bcb0991SDimitry Andric     Current = Current.substr(Pos);
338bcb0991SDimitry Andric 
34*c9157d92SDimitry Andric     if (Current.starts_with("\n")) {
358bcb0991SDimitry Andric       OS << "\n" << Indent;
368bcb0991SDimitry Andric       Current = Current.drop_front(1);
378bcb0991SDimitry Andric       continue;
388bcb0991SDimitry Andric     }
398bcb0991SDimitry Andric 
40*c9157d92SDimitry Andric     if (Current.starts_with("\\$") || Current.starts_with("\\\\")) {
418bcb0991SDimitry Andric       OS << Current[1];
428bcb0991SDimitry Andric       Current = Current.drop_front(2);
438bcb0991SDimitry Andric       continue;
448bcb0991SDimitry Andric     }
458bcb0991SDimitry Andric 
46*c9157d92SDimitry Andric     if (Current.starts_with("\\")) {
478bcb0991SDimitry Andric       Current = Current.drop_front(1);
488bcb0991SDimitry Andric       continue;
498bcb0991SDimitry Andric     }
508bcb0991SDimitry Andric 
51*c9157d92SDimitry Andric     if (Current.starts_with("${")) {
528bcb0991SDimitry Andric       StringRef StartVar = Current;
538bcb0991SDimitry Andric       Current = Current.drop_front(2);
548bcb0991SDimitry Andric       StringRef Var;
558bcb0991SDimitry Andric       std::tie(Var, Current) = Current.split("}");
568bcb0991SDimitry Andric 
578bcb0991SDimitry Andric       // Warn if we split because no terminator was found.
588bcb0991SDimitry Andric       StringRef EndVar = StartVar.drop_front(2 /* ${ */ + Var.size());
598bcb0991SDimitry Andric       if (EndVar.empty()) {
60e8d8bef9SDimitry Andric         PrintWarning(Loc, "Unterminated expansion '${" + Var + "'");
61e8d8bef9SDimitry Andric         PrintNote("Code: [{" + Code + "}]");
628bcb0991SDimitry Andric       }
638bcb0991SDimitry Andric 
648bcb0991SDimitry Andric       auto ValueI = Expansions.find(Var);
658bcb0991SDimitry Andric       if (ValueI == Expansions.end()) {
66e8d8bef9SDimitry Andric         PrintError(Loc,
67e8d8bef9SDimitry Andric                    "Attempt to expand an undeclared variable '" + Var + "'");
68e8d8bef9SDimitry Andric         PrintNote("Code: [{" + Code + "}]");
698bcb0991SDimitry Andric       }
708bcb0991SDimitry Andric       if (ShowExpansions)
718bcb0991SDimitry Andric         OS << "/*$" << Var << "{*/";
728bcb0991SDimitry Andric       OS << Expansions.lookup(Var);
738bcb0991SDimitry Andric       if (ShowExpansions)
748bcb0991SDimitry Andric         OS << "/*}*/";
758bcb0991SDimitry Andric       continue;
768bcb0991SDimitry Andric     }
778bcb0991SDimitry Andric 
78e8d8bef9SDimitry Andric     PrintWarning(Loc, "Assuming missing escape character: \\$");
79e8d8bef9SDimitry Andric     PrintNote("Code: [{" + Code + "}]");
808bcb0991SDimitry Andric     OS << "$";
818bcb0991SDimitry Andric     Current = Current.drop_front(1);
828bcb0991SDimitry Andric   }
838bcb0991SDimitry Andric }
84