1353940Sdim//===- CodeExpander.cpp - Expand variables in a string --------------------===//
2353940Sdim//
3353940Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353940Sdim// See https://llvm.org/LICENSE.txt for license information.
5353940Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353940Sdim//
7353940Sdim//===----------------------------------------------------------------------===//
8353940Sdim//
9353940Sdim/// \file Expand the variables in a string.
10353940Sdim//
11353940Sdim//===----------------------------------------------------------------------===//
12353940Sdim
13353940Sdim#include "CodeExpander.h"
14353940Sdim#include "CodeExpansions.h"
15353940Sdim#include "llvm/Support/CommandLine.h"
16353940Sdim#include "llvm/Support/raw_ostream.h"
17353940Sdim#include "llvm/TableGen/Error.h"
18353940Sdim
19353940Sdimusing namespace llvm;
20353940Sdim
21353940Sdimvoid CodeExpander::emit(raw_ostream &OS) const {
22353940Sdim  StringRef Current = Code;
23353940Sdim
24353940Sdim  while (!Current.empty()) {
25353940Sdim    size_t Pos = Current.find_first_of("$\n\\");
26353940Sdim    if (Pos == StringRef::npos) {
27353940Sdim      OS << Current;
28353940Sdim      Current = "";
29353940Sdim      continue;
30353940Sdim    }
31353940Sdim
32353940Sdim    OS << Current.substr(0, Pos);
33353940Sdim    Current = Current.substr(Pos);
34353940Sdim
35353940Sdim    if (Current.startswith("\n")) {
36353940Sdim      OS << "\n" << Indent;
37353940Sdim      Current = Current.drop_front(1);
38353940Sdim      continue;
39353940Sdim    }
40353940Sdim
41353940Sdim    if (Current.startswith("\\$") || Current.startswith("\\\\")) {
42353940Sdim      OS << Current[1];
43353940Sdim      Current = Current.drop_front(2);
44353940Sdim      continue;
45353940Sdim    }
46353940Sdim
47353940Sdim    if (Current.startswith("\\")) {
48353940Sdim      Current = Current.drop_front(1);
49353940Sdim      continue;
50353940Sdim    }
51353940Sdim
52353940Sdim    if (Current.startswith("${")) {
53353940Sdim      StringRef StartVar = Current;
54353940Sdim      Current = Current.drop_front(2);
55353940Sdim      StringRef Var;
56353940Sdim      std::tie(Var, Current) = Current.split("}");
57353940Sdim
58353940Sdim      // Warn if we split because no terminator was found.
59353940Sdim      StringRef EndVar = StartVar.drop_front(2 /* ${ */ + Var.size());
60353940Sdim      if (EndVar.empty()) {
61353940Sdim        size_t LocOffset = StartVar.data() - Code.data();
62353940Sdim        PrintWarning(
63353940Sdim            Loc.size() > 0 && Loc[0].isValid()
64353940Sdim                ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset)
65353940Sdim                : SMLoc(),
66353940Sdim            "Unterminated expansion");
67353940Sdim      }
68353940Sdim
69353940Sdim      auto ValueI = Expansions.find(Var);
70353940Sdim      if (ValueI == Expansions.end()) {
71353940Sdim        size_t LocOffset = StartVar.data() - Code.data();
72353940Sdim        PrintError(Loc.size() > 0 && Loc[0].isValid()
73353940Sdim                       ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset)
74353940Sdim                       : SMLoc(),
75353940Sdim                   "Attempting to expand an undeclared variable " + Var);
76353940Sdim      }
77353940Sdim      if (ShowExpansions)
78353940Sdim        OS << "/*$" << Var << "{*/";
79353940Sdim      OS << Expansions.lookup(Var);
80353940Sdim      if (ShowExpansions)
81353940Sdim        OS << "/*}*/";
82353940Sdim      continue;
83353940Sdim    }
84353940Sdim
85353940Sdim    size_t LocOffset = Current.data() - Code.data();
86353940Sdim    PrintWarning(Loc.size() > 0 && Loc[0].isValid()
87353940Sdim                     ? SMLoc::getFromPointer(Loc[0].getPointer() + LocOffset)
88353940Sdim                     : SMLoc(),
89353940Sdim                 "Assuming missing escape character");
90353940Sdim    OS << "$";
91353940Sdim    Current = Current.drop_front(1);
92353940Sdim  }
93353940Sdim}
94