1 //===- CodeExpander.cpp - Expand variables in a string --------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 /// \file Expand the variables in a string. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "CodeExpander.h" 14 #include "CodeExpansions.h" 15 #include "llvm/Support/raw_ostream.h" 16 #include "llvm/TableGen/Error.h" 17 18 using namespace llvm; 19 20 void CodeExpander::emit(raw_ostream &OS) const { 21 StringRef Current = Code; 22 23 while (!Current.empty()) { 24 size_t Pos = Current.find_first_of("$\n\\"); 25 if (Pos == StringRef::npos) { 26 OS << Current; 27 Current = ""; 28 continue; 29 } 30 31 OS << Current.substr(0, Pos); 32 Current = Current.substr(Pos); 33 34 if (Current.startswith("\n")) { 35 OS << "\n" << Indent; 36 Current = Current.drop_front(1); 37 continue; 38 } 39 40 if (Current.startswith("\\$") || Current.startswith("\\\\")) { 41 OS << Current[1]; 42 Current = Current.drop_front(2); 43 continue; 44 } 45 46 if (Current.startswith("\\")) { 47 Current = Current.drop_front(1); 48 continue; 49 } 50 51 if (Current.startswith("${")) { 52 StringRef StartVar = Current; 53 Current = Current.drop_front(2); 54 StringRef Var; 55 std::tie(Var, Current) = Current.split("}"); 56 57 // Warn if we split because no terminator was found. 58 StringRef EndVar = StartVar.drop_front(2 /* ${ */ + Var.size()); 59 if (EndVar.empty()) { 60 PrintWarning(Loc, "Unterminated expansion '${" + Var + "'"); 61 PrintNote("Code: [{" + Code + "}]"); 62 } 63 64 auto ValueI = Expansions.find(Var); 65 if (ValueI == Expansions.end()) { 66 PrintError(Loc, 67 "Attempt to expand an undeclared variable '" + Var + "'"); 68 PrintNote("Code: [{" + Code + "}]"); 69 } 70 if (ShowExpansions) 71 OS << "/*$" << Var << "{*/"; 72 OS << Expansions.lookup(Var); 73 if (ShowExpansions) 74 OS << "/*}*/"; 75 continue; 76 } 77 78 PrintWarning(Loc, "Assuming missing escape character: \\$"); 79 PrintNote("Code: [{" + Code + "}]"); 80 OS << "$"; 81 Current = Current.drop_front(1); 82 } 83 } 84