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/CommandLine.h"
168bcb0991SDimitry Andric #include "llvm/Support/raw_ostream.h"
178bcb0991SDimitry Andric #include "llvm/TableGen/Error.h"
188bcb0991SDimitry Andric 
198bcb0991SDimitry Andric using namespace llvm;
208bcb0991SDimitry Andric 
218bcb0991SDimitry Andric void CodeExpander::emit(raw_ostream &OS) const {
228bcb0991SDimitry Andric   StringRef Current = Code;
238bcb0991SDimitry Andric 
248bcb0991SDimitry Andric   while (!Current.empty()) {
258bcb0991SDimitry Andric     size_t Pos = Current.find_first_of("$\n\\");
268bcb0991SDimitry Andric     if (Pos == StringRef::npos) {
278bcb0991SDimitry Andric       OS << Current;
288bcb0991SDimitry Andric       Current = "";
298bcb0991SDimitry Andric       continue;
308bcb0991SDimitry Andric     }
318bcb0991SDimitry Andric 
328bcb0991SDimitry Andric     OS << Current.substr(0, Pos);
338bcb0991SDimitry Andric     Current = Current.substr(Pos);
348bcb0991SDimitry Andric 
358bcb0991SDimitry Andric     if (Current.startswith("\n")) {
368bcb0991SDimitry Andric       OS << "\n" << Indent;
378bcb0991SDimitry Andric       Current = Current.drop_front(1);
388bcb0991SDimitry Andric       continue;
398bcb0991SDimitry Andric     }
408bcb0991SDimitry Andric 
418bcb0991SDimitry Andric     if (Current.startswith("\\$") || Current.startswith("\\\\")) {
428bcb0991SDimitry Andric       OS << Current[1];
438bcb0991SDimitry Andric       Current = Current.drop_front(2);
448bcb0991SDimitry Andric       continue;
458bcb0991SDimitry Andric     }
468bcb0991SDimitry Andric 
478bcb0991SDimitry Andric     if (Current.startswith("\\")) {
488bcb0991SDimitry Andric       Current = Current.drop_front(1);
498bcb0991SDimitry Andric       continue;
508bcb0991SDimitry Andric     }
518bcb0991SDimitry Andric 
528bcb0991SDimitry Andric     if (Current.startswith("${")) {
538bcb0991SDimitry Andric       StringRef StartVar = Current;
548bcb0991SDimitry Andric       Current = Current.drop_front(2);
558bcb0991SDimitry Andric       StringRef Var;
568bcb0991SDimitry Andric       std::tie(Var, Current) = Current.split("}");
578bcb0991SDimitry Andric 
588bcb0991SDimitry Andric       // Warn if we split because no terminator was found.
598bcb0991SDimitry Andric       StringRef EndVar = StartVar.drop_front(2 /* ${ */ + Var.size());
608bcb0991SDimitry Andric       if (EndVar.empty()) {
61e8d8bef9SDimitry Andric         PrintWarning(Loc, "Unterminated expansion '${" + Var + "'");
62e8d8bef9SDimitry Andric         PrintNote("Code: [{" + Code + "}]");
638bcb0991SDimitry Andric       }
648bcb0991SDimitry Andric 
658bcb0991SDimitry Andric       auto ValueI = Expansions.find(Var);
668bcb0991SDimitry Andric       if (ValueI == Expansions.end()) {
67e8d8bef9SDimitry Andric         PrintError(Loc,
68e8d8bef9SDimitry Andric                    "Attempt to expand an undeclared variable '" + Var + "'");
69e8d8bef9SDimitry Andric         PrintNote("Code: [{" + Code + "}]");
708bcb0991SDimitry Andric       }
718bcb0991SDimitry Andric       if (ShowExpansions)
728bcb0991SDimitry Andric         OS << "/*$" << Var << "{*/";
738bcb0991SDimitry Andric       OS << Expansions.lookup(Var);
748bcb0991SDimitry Andric       if (ShowExpansions)
758bcb0991SDimitry Andric         OS << "/*}*/";
768bcb0991SDimitry Andric       continue;
778bcb0991SDimitry Andric     }
788bcb0991SDimitry Andric 
79e8d8bef9SDimitry Andric     PrintWarning(Loc, "Assuming missing escape character: \\$");
80e8d8bef9SDimitry Andric     PrintNote("Code: [{" + Code + "}]");
818bcb0991SDimitry Andric     OS << "$";
828bcb0991SDimitry Andric     Current = Current.drop_front(1);
838bcb0991SDimitry Andric   }
848bcb0991SDimitry Andric }
85