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