118350af1SDaniel Sanders //===- CodeExpander.cpp - Expand variables in a string --------------------===//
218350af1SDaniel Sanders //
318350af1SDaniel Sanders // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
418350af1SDaniel Sanders // See https://llvm.org/LICENSE.txt for license information.
518350af1SDaniel Sanders // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
618350af1SDaniel Sanders //
718350af1SDaniel Sanders //===----------------------------------------------------------------------===//
818350af1SDaniel Sanders //
918350af1SDaniel Sanders /// \file Expand the variables in a string.
1018350af1SDaniel Sanders //
1118350af1SDaniel Sanders //===----------------------------------------------------------------------===//
1218350af1SDaniel Sanders 
1318350af1SDaniel Sanders #include "CodeExpander.h"
1418350af1SDaniel Sanders #include "CodeExpansions.h"
1518350af1SDaniel Sanders #include "llvm/Support/raw_ostream.h"
1618350af1SDaniel Sanders #include "llvm/TableGen/Error.h"
1718350af1SDaniel Sanders 
1818350af1SDaniel Sanders using namespace llvm;
1918350af1SDaniel Sanders 
emit(raw_ostream & OS) const2018350af1SDaniel Sanders void CodeExpander::emit(raw_ostream &OS) const {
2118350af1SDaniel Sanders   StringRef Current = Code;
2218350af1SDaniel Sanders 
2318350af1SDaniel Sanders   while (!Current.empty()) {
2418350af1SDaniel Sanders     size_t Pos = Current.find_first_of("$\n\\");
2518350af1SDaniel Sanders     if (Pos == StringRef::npos) {
2618350af1SDaniel Sanders       OS << Current;
2718350af1SDaniel Sanders       Current = "";
2818350af1SDaniel Sanders       continue;
2918350af1SDaniel Sanders     }
3018350af1SDaniel Sanders 
3118350af1SDaniel Sanders     OS << Current.substr(0, Pos);
3218350af1SDaniel Sanders     Current = Current.substr(Pos);
3318350af1SDaniel Sanders 
3418350af1SDaniel Sanders     if (Current.startswith("\n")) {
3518350af1SDaniel Sanders       OS << "\n" << Indent;
3618350af1SDaniel Sanders       Current = Current.drop_front(1);
3718350af1SDaniel Sanders       continue;
3818350af1SDaniel Sanders     }
3918350af1SDaniel Sanders 
4018350af1SDaniel Sanders     if (Current.startswith("\\$") || Current.startswith("\\\\")) {
4118350af1SDaniel Sanders       OS << Current[1];
4218350af1SDaniel Sanders       Current = Current.drop_front(2);
4318350af1SDaniel Sanders       continue;
4418350af1SDaniel Sanders     }
4518350af1SDaniel Sanders 
4618350af1SDaniel Sanders     if (Current.startswith("\\")) {
4718350af1SDaniel Sanders       Current = Current.drop_front(1);
4818350af1SDaniel Sanders       continue;
4918350af1SDaniel Sanders     }
5018350af1SDaniel Sanders 
5118350af1SDaniel Sanders     if (Current.startswith("${")) {
5218350af1SDaniel Sanders       StringRef StartVar = Current;
5318350af1SDaniel Sanders       Current = Current.drop_front(2);
5418350af1SDaniel Sanders       StringRef Var;
5518350af1SDaniel Sanders       std::tie(Var, Current) = Current.split("}");
5618350af1SDaniel Sanders 
5718350af1SDaniel Sanders       // Warn if we split because no terminator was found.
5818350af1SDaniel Sanders       StringRef EndVar = StartVar.drop_front(2 /* ${ */ + Var.size());
5918350af1SDaniel Sanders       if (EndVar.empty()) {
60*b23e84ffSPaul C. Anagnostopoulos         PrintWarning(Loc, "Unterminated expansion '${" + Var + "'");
61*b23e84ffSPaul C. Anagnostopoulos         PrintNote("Code: [{" + Code + "}]");
6218350af1SDaniel Sanders       }
6318350af1SDaniel Sanders 
6418350af1SDaniel Sanders       auto ValueI = Expansions.find(Var);
6518350af1SDaniel Sanders       if (ValueI == Expansions.end()) {
66*b23e84ffSPaul C. Anagnostopoulos         PrintError(Loc,
67*b23e84ffSPaul C. Anagnostopoulos                    "Attempt to expand an undeclared variable '" + Var + "'");
68*b23e84ffSPaul C. Anagnostopoulos         PrintNote("Code: [{" + Code + "}]");
6918350af1SDaniel Sanders       }
7018350af1SDaniel Sanders       if (ShowExpansions)
7118350af1SDaniel Sanders         OS << "/*$" << Var << "{*/";
7218350af1SDaniel Sanders       OS << Expansions.lookup(Var);
7318350af1SDaniel Sanders       if (ShowExpansions)
7418350af1SDaniel Sanders         OS << "/*}*/";
7518350af1SDaniel Sanders       continue;
7618350af1SDaniel Sanders     }
7718350af1SDaniel Sanders 
78*b23e84ffSPaul C. Anagnostopoulos     PrintWarning(Loc, "Assuming missing escape character: \\$");
79*b23e84ffSPaul C. Anagnostopoulos     PrintNote("Code: [{" + Code + "}]");
8018350af1SDaniel Sanders     OS << "$";
8118350af1SDaniel Sanders     Current = Current.drop_front(1);
8218350af1SDaniel Sanders   }
8318350af1SDaniel Sanders }
84