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 
emit(raw_ostream & OS) const208bcb0991SDimitry 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*a58f00eaSDimitry Andric     if (Current.consume_front("\n")) {
358bcb0991SDimitry Andric       OS << "\n" << Indent;
368bcb0991SDimitry Andric       continue;
378bcb0991SDimitry Andric     }
388bcb0991SDimitry Andric 
39c9157d92SDimitry Andric     if (Current.starts_with("\\$") || Current.starts_with("\\\\")) {
408bcb0991SDimitry Andric       OS << Current[1];
418bcb0991SDimitry Andric       Current = Current.drop_front(2);
428bcb0991SDimitry Andric       continue;
438bcb0991SDimitry Andric     }
448bcb0991SDimitry Andric 
45*a58f00eaSDimitry Andric     if (Current.consume_front("\\"))
468bcb0991SDimitry Andric       continue;
478bcb0991SDimitry Andric 
48c9157d92SDimitry Andric     if (Current.starts_with("${")) {
498bcb0991SDimitry Andric       StringRef StartVar = Current;
508bcb0991SDimitry Andric       Current = Current.drop_front(2);
518bcb0991SDimitry Andric       StringRef Var;
528bcb0991SDimitry Andric       std::tie(Var, Current) = Current.split("}");
538bcb0991SDimitry Andric 
548bcb0991SDimitry Andric       // Warn if we split because no terminator was found.
558bcb0991SDimitry Andric       StringRef EndVar = StartVar.drop_front(2 /* ${ */ + Var.size());
568bcb0991SDimitry Andric       if (EndVar.empty()) {
57e8d8bef9SDimitry Andric         PrintWarning(Loc, "Unterminated expansion '${" + Var + "'");
58e8d8bef9SDimitry Andric         PrintNote("Code: [{" + Code + "}]");
598bcb0991SDimitry Andric       }
608bcb0991SDimitry Andric 
618bcb0991SDimitry Andric       auto ValueI = Expansions.find(Var);
628bcb0991SDimitry Andric       if (ValueI == Expansions.end()) {
63e8d8bef9SDimitry Andric         PrintError(Loc,
64e8d8bef9SDimitry Andric                    "Attempt to expand an undeclared variable '" + Var + "'");
65e8d8bef9SDimitry Andric         PrintNote("Code: [{" + Code + "}]");
668bcb0991SDimitry Andric       }
678bcb0991SDimitry Andric       if (ShowExpansions)
688bcb0991SDimitry Andric         OS << "/*$" << Var << "{*/";
698bcb0991SDimitry Andric       OS << Expansions.lookup(Var);
708bcb0991SDimitry Andric       if (ShowExpansions)
718bcb0991SDimitry Andric         OS << "/*}*/";
728bcb0991SDimitry Andric       continue;
738bcb0991SDimitry Andric     }
748bcb0991SDimitry Andric 
75e8d8bef9SDimitry Andric     PrintWarning(Loc, "Assuming missing escape character: \\$");
76e8d8bef9SDimitry Andric     PrintNote("Code: [{" + Code + "}]");
778bcb0991SDimitry Andric     OS << "$";
788bcb0991SDimitry Andric     Current = Current.drop_front(1);
798bcb0991SDimitry Andric   }
808bcb0991SDimitry Andric }
81