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
18using namespace llvm;
19
20void CodeExpander::emit(raw_ostream &OS) const {
21 StringRef Current = Code;
22
23 while (!Current.empty()) {
24 size_t Pos = Current.find_first_of(Chars: "$\n\\");
25 if (Pos == StringRef::npos) {
26 OS << Current;
27 Current = "";
28 continue;
29 }
30
31 OS << Current.substr(Start: 0, N: Pos);
32 Current = Current.substr(Start: Pos);
33
34 if (Current.consume_front(Prefix: "\n")) {
35 OS << "\n" << Indent;
36 continue;
37 }
38
39 if (Current.starts_with(Prefix: "\\$") || Current.starts_with(Prefix: "\\\\")) {
40 OS << Current[1];
41 Current = Current.drop_front(N: 2);
42 continue;
43 }
44
45 if (Current.consume_front(Prefix: "\\"))
46 continue;
47
48 if (Current.starts_with(Prefix: "${")) {
49 StringRef StartVar = Current;
50 Current = Current.drop_front(N: 2);
51 StringRef Var;
52 std::tie(args&: Var, args&: Current) = Current.split(Separator: "}");
53
54 // Warn if we split because no terminator was found.
55 StringRef EndVar = StartVar.drop_front(N: 2 /* ${ */ + Var.size());
56 if (EndVar.empty()) {
57 PrintWarning(WarningLoc: Loc, Msg: "Unterminated expansion '${" + Var + "'");
58 PrintNote(Msg: "Code: [{" + Code + "}]");
59 }
60
61 auto ValueI = Expansions.find(Variable: Var);
62 if (ValueI == Expansions.end()) {
63 PrintError(ErrorLoc: Loc,
64 Msg: "Attempt to expand an undeclared variable '" + Var + "'");
65 PrintNote(Msg: "Code: [{" + Code + "}]");
66 }
67 if (ShowExpansions)
68 OS << "/*$" << Var << "{*/";
69 OS << Expansions.lookup(Variable: Var);
70 if (ShowExpansions)
71 OS << "/*}*/";
72 continue;
73 }
74
75 PrintWarning(WarningLoc: Loc, Msg: "Assuming missing escape character: \\$");
76 PrintNote(Msg: "Code: [{" + Code + "}]");
77 OS << "$";
78 Current = Current.drop_front(N: 1);
79 }
80}
81