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()) {
618bcb0991SDimitry Andric         size_t LocOffset = StartVar.data() - Code.data();
628bcb0991SDimitry Andric         PrintWarning(
638bcb0991SDimitry Andric             Loc.size() > 0 && Loc[0].isValid()
648bcb0991SDimitry Andric                 ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset)
658bcb0991SDimitry Andric                 : SMLoc(),
668bcb0991SDimitry Andric             "Unterminated expansion");
678bcb0991SDimitry Andric       }
688bcb0991SDimitry Andric 
698bcb0991SDimitry Andric       auto ValueI = Expansions.find(Var);
708bcb0991SDimitry Andric       if (ValueI == Expansions.end()) {
718bcb0991SDimitry Andric         size_t LocOffset = StartVar.data() - Code.data();
728bcb0991SDimitry Andric         PrintError(Loc.size() > 0 && Loc[0].isValid()
738bcb0991SDimitry Andric                        ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset)
748bcb0991SDimitry Andric                        : SMLoc(),
758bcb0991SDimitry Andric                    "Attempting to expand an undeclared variable " + Var);
768bcb0991SDimitry Andric       }
778bcb0991SDimitry Andric       if (ShowExpansions)
788bcb0991SDimitry Andric         OS << "/*$" << Var << "{*/";
798bcb0991SDimitry Andric       OS << Expansions.lookup(Var);
808bcb0991SDimitry Andric       if (ShowExpansions)
818bcb0991SDimitry Andric         OS << "/*}*/";
828bcb0991SDimitry Andric       continue;
838bcb0991SDimitry Andric     }
848bcb0991SDimitry Andric 
858bcb0991SDimitry Andric     size_t LocOffset = Current.data() - Code.data();
868bcb0991SDimitry Andric     PrintWarning(Loc.size() > 0 && Loc[0].isValid()
878bcb0991SDimitry Andric                      ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset)
888bcb0991SDimitry Andric                      : SMLoc(),
898bcb0991SDimitry Andric                  "Assuming missing escape character");
908bcb0991SDimitry Andric     OS << "$";
918bcb0991SDimitry Andric     Current = Current.drop_front(1);
928bcb0991SDimitry Andric   }
938bcb0991SDimitry Andric }
94