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