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 208bcb0991SDimitry 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*c9157d92SDimitry Andric if (Current.starts_with("\n")) { 358bcb0991SDimitry Andric OS << "\n" << Indent; 368bcb0991SDimitry Andric Current = Current.drop_front(1); 378bcb0991SDimitry Andric continue; 388bcb0991SDimitry Andric } 398bcb0991SDimitry Andric 40*c9157d92SDimitry Andric if (Current.starts_with("\\$") || Current.starts_with("\\\\")) { 418bcb0991SDimitry Andric OS << Current[1]; 428bcb0991SDimitry Andric Current = Current.drop_front(2); 438bcb0991SDimitry Andric continue; 448bcb0991SDimitry Andric } 458bcb0991SDimitry Andric 46*c9157d92SDimitry Andric if (Current.starts_with("\\")) { 478bcb0991SDimitry Andric Current = Current.drop_front(1); 488bcb0991SDimitry Andric continue; 498bcb0991SDimitry Andric } 508bcb0991SDimitry Andric 51*c9157d92SDimitry Andric if (Current.starts_with("${")) { 528bcb0991SDimitry Andric StringRef StartVar = Current; 538bcb0991SDimitry Andric Current = Current.drop_front(2); 548bcb0991SDimitry Andric StringRef Var; 558bcb0991SDimitry Andric std::tie(Var, Current) = Current.split("}"); 568bcb0991SDimitry Andric 578bcb0991SDimitry Andric // Warn if we split because no terminator was found. 588bcb0991SDimitry Andric StringRef EndVar = StartVar.drop_front(2 /* ${ */ + Var.size()); 598bcb0991SDimitry Andric if (EndVar.empty()) { 60e8d8bef9SDimitry Andric PrintWarning(Loc, "Unterminated expansion '${" + Var + "'"); 61e8d8bef9SDimitry Andric PrintNote("Code: [{" + Code + "}]"); 628bcb0991SDimitry Andric } 638bcb0991SDimitry Andric 648bcb0991SDimitry Andric auto ValueI = Expansions.find(Var); 658bcb0991SDimitry Andric if (ValueI == Expansions.end()) { 66e8d8bef9SDimitry Andric PrintError(Loc, 67e8d8bef9SDimitry Andric "Attempt to expand an undeclared variable '" + Var + "'"); 68e8d8bef9SDimitry Andric PrintNote("Code: [{" + Code + "}]"); 698bcb0991SDimitry Andric } 708bcb0991SDimitry Andric if (ShowExpansions) 718bcb0991SDimitry Andric OS << "/*$" << Var << "{*/"; 728bcb0991SDimitry Andric OS << Expansions.lookup(Var); 738bcb0991SDimitry Andric if (ShowExpansions) 748bcb0991SDimitry Andric OS << "/*}*/"; 758bcb0991SDimitry Andric continue; 768bcb0991SDimitry Andric } 778bcb0991SDimitry Andric 78e8d8bef9SDimitry Andric PrintWarning(Loc, "Assuming missing escape character: \\$"); 79e8d8bef9SDimitry Andric PrintNote("Code: [{" + Code + "}]"); 808bcb0991SDimitry Andric OS << "$"; 818bcb0991SDimitry Andric Current = Current.drop_front(1); 828bcb0991SDimitry Andric } 838bcb0991SDimitry Andric } 84