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